c434cad322
Files correlati : Ricompilazione Demo : [ ] Commento : Riportata la versione 3.1 patch 650 git-svn-id: svn://10.65.10.50/trunk@14148 c028cbd2-c16b-5b4b-a496-9718f37d4682
1933 lines
45 KiB
C
Executable File
1933 lines
45 KiB
C
Executable File
/*---------------------------------------------------------------------------*
|
|
| PDFlib - A library for generating PDF on the fly |
|
|
+---------------------------------------------------------------------------+
|
|
| Copyright (c) 1997-2005 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.2 2006-07-11 13:10:33 alex Exp $
|
|
*
|
|
* PDFlib various utility routines
|
|
*
|
|
*/
|
|
|
|
#include <errno.h>
|
|
|
|
#include "pc_util.h"
|
|
|
|
#ifdef AS400
|
|
#include <qp0z1170.h> /* for getenv() emulation */
|
|
#endif
|
|
|
|
#if defined (isfinite)
|
|
#define PDC_ISFINITE isfinite
|
|
#else /* isfinite */
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <float.h>
|
|
#define PDC_ISFINITE _finite
|
|
#else /* _WIN32 */
|
|
#define PDC_ISFINITE finite
|
|
#endif
|
|
#endif
|
|
|
|
|
|
/* ------------------- Floating-point number check ----------------------- */
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
}
|
|
|
|
/* -------------------------- 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)
|
|
{
|
|
#ifndef WINCE
|
|
time_t timer, gtimer;
|
|
struct tm ltime;
|
|
double diffminutes;
|
|
int utcoffset;
|
|
#else
|
|
SYSTEMTIME st;
|
|
#endif
|
|
|
|
#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 (isupper((int)language[i]))
|
|
{
|
|
language[i] = (char)tolower((int)language[i]);
|
|
}
|
|
}
|
|
|
|
|
|
country_code = 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 = 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 ------------------------------ */
|
|
|
|
void
|
|
pdc_setbit(char *bitarr, int bit)
|
|
{
|
|
bitarr[bit/8] |= (char) (1<<(bit%8));
|
|
}
|
|
|
|
pdc_bool
|
|
pdc_getbit(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(pdc_byte *data)
|
|
{
|
|
return (pdc_short) ((pdc_short) (data[1] << 8) | data[0]);
|
|
}
|
|
|
|
pdc_ushort
|
|
pdc_get_le_ushort(pdc_byte *data)
|
|
{
|
|
return (pdc_ushort) ((data[1] << 8) | data[0]);
|
|
}
|
|
|
|
pdc_uint32
|
|
pdc_get_le_ulong3(pdc_byte *data)
|
|
{
|
|
return (pdc_uint32) (((((data[2]) << 8) | data[1]) << 8) | data[0]);
|
|
}
|
|
|
|
pdc_sint32
|
|
pdc_get_le_long(pdc_byte *data)
|
|
{
|
|
return ((pdc_sint32)
|
|
(((((data[3] << 8) | data[2]) << 8) | data[1]) << 8) | data[0]);
|
|
}
|
|
|
|
pdc_uint32
|
|
pdc_get_le_ulong(pdc_byte *data)
|
|
{
|
|
return (pdc_uint32)
|
|
((((((data[3] << 8) | data[2]) << 8) | data[1]) << 8) | data[0]);
|
|
}
|
|
|
|
pdc_short
|
|
pdc_get_be_short(pdc_byte *data)
|
|
{
|
|
return (pdc_short) ((pdc_short) (data[0] << 8) | data[1]);
|
|
}
|
|
|
|
pdc_ushort
|
|
pdc_get_be_ushort(pdc_byte *data)
|
|
{
|
|
return (pdc_ushort) ((data[0] << 8) | data[1]);
|
|
}
|
|
|
|
pdc_uint32
|
|
pdc_get_be_ulong3(pdc_byte *data)
|
|
{
|
|
return (pdc_uint32) (((((data[0]) << 8) | data[1]) << 8) | data[2]);
|
|
}
|
|
|
|
pdc_sint32
|
|
pdc_get_be_long(pdc_byte *data)
|
|
{
|
|
return ((pdc_sint32)
|
|
(((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]);
|
|
}
|
|
|
|
pdc_uint32
|
|
pdc_get_be_ulong(pdc_byte *data)
|
|
{
|
|
return (pdc_uint32)
|
|
((((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]);
|
|
}
|
|
|
|
|
|
/* ----------------- String handling for Unicode too ------------------- */
|
|
|
|
/* strlen() for unicode strings, which are terminated by two zero bytes.
|
|
* wstrlen() returns the number of bytes in the Unicode string,
|
|
* not including the two terminating null bytes.
|
|
*/
|
|
static size_t
|
|
wstrlen(const char *s)
|
|
{
|
|
size_t len = 0;
|
|
|
|
while(s[len] != 0 || s[len+1] != 0)
|
|
{
|
|
len += 2;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
/*
|
|
* This function returns the length in bytes for C and Unicode strings.
|
|
* Note that unlike strlen() it returns the length _including_ the
|
|
* terminator, which may be one or two null bytes.
|
|
*/
|
|
size_t
|
|
pdc_strlen(const char *text)
|
|
{
|
|
if (pdc_is_utf16be_unicode(text) || pdc_is_utf16le_unicode(text))
|
|
return wstrlen(text);
|
|
else
|
|
return strlen(text);
|
|
}
|
|
|
|
|
|
/* 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.
|
|
*/
|
|
char *
|
|
pdc_strdup(pdc_core *pdc, const char *text)
|
|
{
|
|
char *buf;
|
|
size_t len;
|
|
static const char fn[] = "pdc_strdup";
|
|
|
|
if (text == NULL)
|
|
pdc_error(pdc, PDC_E_INT_NULLARG, fn, 0, 0, 0);
|
|
|
|
len = pdc_strlen(text) + 1;
|
|
buf = (char *) pdc_malloc(pdc, len + 1, fn);
|
|
memcpy(buf, text, len);
|
|
buf[len] = 0;
|
|
|
|
return buf;
|
|
}
|
|
|
|
char *
|
|
pdc_strdup_tmp(pdc_core *pdc, const char *text)
|
|
{
|
|
char *buf;
|
|
size_t len;
|
|
static const char fn[] = "pdc_strdup_tmp";
|
|
|
|
if (text == NULL)
|
|
pdc_error(pdc, PDC_E_INT_NULLARG, fn, 0, 0, 0);
|
|
|
|
len = pdc_strlen(text) + 1;
|
|
buf = (char *) pdc_malloc_tmp(pdc, len + 1, fn, NULL, NULL);
|
|
memcpy(buf, text, len);
|
|
buf[len] = 0;
|
|
|
|
return buf;
|
|
}
|
|
|
|
/* Allocate a local buffer and copy a locale UTF-8 string
|
|
* provided with an UTF-8 BOM.
|
|
* The caller is responsible for freeing the buffer.
|
|
*/
|
|
char *
|
|
pdc_strdup_withbom(pdc_core *pdc, const char *text)
|
|
{
|
|
char *buf;
|
|
size_t len;
|
|
static const char fn[] = "pdc_strdup_withbom";
|
|
|
|
if (text == NULL)
|
|
pdc_error(pdc, PDC_E_INT_NULLARG, fn, 0, 0, 0);
|
|
|
|
len = strlen(text);
|
|
buf = (char *) pdc_malloc(pdc, len + 4, fn);
|
|
|
|
pdc_copy_utf8_bom(buf);
|
|
strcpy(&buf[3], text);
|
|
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
char *ts, *tmpstr;
|
|
pdc_byte c = ' ', cp = '.';
|
|
pdc_ushort *ush = (pdc_ushort *) str;
|
|
int i, im;
|
|
|
|
tmpstr = (char *) pdc_calloc_tmp(pdc, (size_t) (4 * (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] > 0x00FF)
|
|
{
|
|
sf = strform_java;
|
|
}
|
|
else
|
|
{
|
|
c = (pdc_byte) ush[i];
|
|
sf = strform_readable;
|
|
}
|
|
}
|
|
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 == 0x0 && sf == strform_readable0)
|
|
c = 0x20;
|
|
if (c < 0x20 || (c >= 0x7F && c <= 0xA0))
|
|
{
|
|
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);
|
|
}
|
|
|
|
const char *
|
|
pdc_utf8strprint(pdc_core *pdc, const char *str)
|
|
{
|
|
int i = pdc_is_utf8_bytecode(str) ? 3 : 0;
|
|
return pdc_errprintf(pdc, "%.*s", PDC_ET_MAXSTRLEN, &str[i]);
|
|
}
|
|
|
|
/*
|
|
* 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,
|
|
char ***stringlist)
|
|
{
|
|
static const char fn[] = "pdc_split_stringlist";
|
|
const char *separstr = " \f\n\r\t\v";
|
|
const char *oldtext;
|
|
char **strlist = NULL, *newtext;
|
|
int i, it, len, jt = 0, jtb = 0, maxk = 0, count = 0, inside = 0;
|
|
|
|
if (text == NULL)
|
|
pdc_error(pdc, PDC_E_INT_NULLARG, fn, 0, 0, 0);
|
|
|
|
if (stringlist)
|
|
*stringlist = NULL;
|
|
if (i_separstr)
|
|
separstr = i_separstr;
|
|
|
|
/* check for empty string */
|
|
i = (int) strspn(text, separstr);
|
|
oldtext = &text[i];
|
|
len = (int) strlen(oldtext);
|
|
if (!len) return 0;
|
|
|
|
/* check for UTF-8-BOM */
|
|
if (pdc_is_utf8_bytecode(oldtext))
|
|
{
|
|
oldtext = &text[i + 3];
|
|
len -= 3;
|
|
i = (int) strspn(oldtext, separstr);
|
|
oldtext = &oldtext[i];
|
|
len -= i;
|
|
if (!len) return 0;
|
|
}
|
|
|
|
/* new string */
|
|
newtext = (char *) pdc_malloc(pdc, (size_t) (len + 1), fn);
|
|
for (it = 0; it <= len; it++)
|
|
{
|
|
/* check for separators */
|
|
if (it == len)
|
|
i = 1;
|
|
else if (inside <= 0)
|
|
i = (int) strspn(&oldtext[it], separstr);
|
|
else
|
|
i = 0;
|
|
|
|
/* close text part */
|
|
if (i)
|
|
{
|
|
newtext[jt] = 0;
|
|
if (count == maxk)
|
|
{
|
|
maxk += 16;
|
|
strlist = (strlist == NULL) ?
|
|
(char **) pdc_malloc(pdc, maxk * sizeof(char *), fn):
|
|
(char **) pdc_realloc(pdc, strlist, maxk *
|
|
sizeof(char *), fn);
|
|
}
|
|
strlist[count] = &newtext[jtb];
|
|
count++;
|
|
|
|
/* Exit */
|
|
it += i;
|
|
if (it >= len ) break;
|
|
|
|
/* new text part */
|
|
jt++;
|
|
jtb = jt;
|
|
}
|
|
|
|
/* open and close brace */
|
|
if (oldtext[it] == '{')
|
|
{
|
|
inside++;
|
|
if (inside == 1)
|
|
continue;
|
|
}
|
|
else if (oldtext[it] == '}')
|
|
{
|
|
inside--;
|
|
if (inside == 0)
|
|
continue;
|
|
}
|
|
|
|
/* masked braces */
|
|
if (oldtext[it] == '\\' &&
|
|
(oldtext[it+1] == '{' || oldtext[it+1] == '}'))
|
|
{
|
|
if (it > 0 && oldtext[it-1] == '\\')
|
|
continue;
|
|
it++;
|
|
}
|
|
|
|
/* save character */
|
|
newtext[jt] = oldtext[it];
|
|
jt++;
|
|
}
|
|
|
|
if (stringlist)
|
|
*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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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_stricmp(const char *s1, const char *s2)
|
|
{
|
|
char c1, c2;
|
|
|
|
if (s1 == s2) return (0);
|
|
if (s1 == NULL) return (-1);
|
|
if (s2 == NULL) return (1);
|
|
|
|
for (; *s1 != '\0' && *s2 != '\0'; s1++, s2++)
|
|
{
|
|
if ((c1 = *s1) == (c2 = *s2))
|
|
continue;
|
|
|
|
if (isupper((int)c1)) c1 = (char) tolower((int)c1);
|
|
if (isupper((int)c2)) c2 = (char) tolower((int)c2);
|
|
if (c1 != c2)
|
|
break;
|
|
}
|
|
|
|
/* TODO: this function is useful for checks on (in)equality only;
|
|
** it does NOT compare correctly!
|
|
*/
|
|
return (*s1 - *s2);
|
|
}
|
|
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
char c1, c2;
|
|
int i;
|
|
|
|
if (s1 == s2) return (0);
|
|
if (s1 == NULL) return (-1);
|
|
if (s2 == NULL) return (1);
|
|
|
|
for (i=0; i < n && *s1 != '\0' && *s2 != '\0'; i++, s1++, s2++)
|
|
{
|
|
if ((c1 = *s1) == (c2 = *s2))
|
|
continue;
|
|
|
|
if (isupper((int)c1)) c1 = (char) tolower((int)c1);
|
|
if (isupper((int)c2)) c2 = (char) tolower((int)c2);
|
|
if (c1 != c2)
|
|
break;
|
|
}
|
|
return ((i < n) ? (int)(*s1 - *s2) : 0);
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
|
|
for (i = (int) strlen(str) - 1; i >= 0; i--)
|
|
if (!isspace((unsigned char) str[i])) break;
|
|
str[i + 1] = '\0';
|
|
|
|
return str;
|
|
}
|
|
|
|
char *
|
|
pdc_str2trim(char *str)
|
|
{
|
|
int i;
|
|
|
|
for (i = (int) strlen(str) - 1; i >= 0; i--)
|
|
if (!isspace((unsigned char) str[i])) break;
|
|
str[i + 1] = '\0';
|
|
|
|
for (i = 0; ; i++)
|
|
if (!isspace((unsigned char) str[i])) break;
|
|
if (i > 0)
|
|
memmove(str, &str[i], strlen(&str[i]) + 1);
|
|
|
|
return str;
|
|
}
|
|
|
|
void
|
|
pdc_swap_bytes(char *instring, int inlen, char *outstring)
|
|
{
|
|
char c;
|
|
int i,j;
|
|
|
|
if (instring == NULL)
|
|
return;
|
|
|
|
if (outstring == NULL)
|
|
outstring = instring;
|
|
|
|
inlen = 2 * inlen / 2;
|
|
for (i = 0; i < inlen; i++)
|
|
{
|
|
j = i;
|
|
i++;
|
|
c = instring[j];
|
|
outstring[j] = instring[i];
|
|
outstring[i] = c;
|
|
}
|
|
}
|
|
|
|
void
|
|
pdc_swap_unicodes(char *instring)
|
|
{
|
|
if (instring &&
|
|
((pdc_is_utf16be_unicode(instring) && !PDC_ISBIGENDIAN) ||
|
|
(pdc_is_utf16le_unicode(instring) && PDC_ISBIGENDIAN)))
|
|
pdc_swap_bytes(&instring[2], (int) (wstrlen(instring) - 2), NULL);
|
|
}
|
|
|
|
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++;
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------- number converting ----------------------- */
|
|
|
|
/*
|
|
* pdc_str2double converts a null terminated and trimed 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 = isdigit((int) *s);
|
|
if (isd)
|
|
{
|
|
do
|
|
{
|
|
dz = 10 * dz + *s - '0';
|
|
s++;
|
|
}
|
|
while (isdigit((int) *s));
|
|
}
|
|
|
|
/* decimal point */
|
|
if (*s == '.' || *s == ',')
|
|
{
|
|
const char *sa;
|
|
double adz = 0;
|
|
|
|
s++;
|
|
isd = isdigit((int) *s);
|
|
if (!isd)
|
|
return pdc_false;
|
|
|
|
/* places after decimal point */
|
|
sa = s;
|
|
do
|
|
{
|
|
adz = 10 * adz + *s - '0';
|
|
s++;
|
|
}
|
|
while (isdigit((int) *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 (!isdigit((int) *s))
|
|
return pdc_false;
|
|
do
|
|
{
|
|
pdz = 10 * pdz + *s - '0';
|
|
s++;
|
|
}
|
|
while (isdigit((int) *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 trimed 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))
|
|
{
|
|
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 > string)
|
|
{
|
|
if (!*s)
|
|
return pdc_false;
|
|
flags |= PDC_INT_HEXADEC;
|
|
}
|
|
}
|
|
|
|
/* hexadecimal */
|
|
if (flags & PDC_INT_HEXADEC)
|
|
{
|
|
while (isxdigit((int) *s))
|
|
{
|
|
if (isalpha(*s))
|
|
lzd = (isupper((int) *s) ? 'A' : 'a') - 10;
|
|
else
|
|
lzd = '0';
|
|
dz = 16 * dz + *s - lzd;
|
|
s++;
|
|
}
|
|
if (*string == '<')
|
|
{
|
|
if (*s == '>')
|
|
s += 1;
|
|
else
|
|
return pdc_false;
|
|
}
|
|
}
|
|
|
|
/* decimal */
|
|
else
|
|
{
|
|
while (isdigit((int) *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_off_t2a(char *buf, pdc_off_t 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_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_get_floatdigits(pdc);
|
|
powd = pow10[ifd];
|
|
|
|
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 */
|
|
|
|
static int
|
|
pdc_vxprintf(
|
|
pdc_core *pdc,
|
|
pdc_bool pdfconf,
|
|
char *cp,
|
|
FILE *fp,
|
|
const char *format,
|
|
va_list args)
|
|
{
|
|
const char *format_p;
|
|
char aux[1024];
|
|
char *buf = cp ? cp : aux;
|
|
char *dest = buf;
|
|
|
|
for (/* */ ; /* */ ; /* */)
|
|
{
|
|
int width = 0;
|
|
int prec = 0;
|
|
char pad = ' ';
|
|
pdc_bool left_justify = pdc_false;
|
|
|
|
/* as long as there is no '%', just print.
|
|
*/
|
|
while (*format != 0 && *format != '%')
|
|
*(dest++) = *(format++);
|
|
|
|
if (*format == 0)
|
|
{
|
|
if (fp != (FILE *) 0)
|
|
{
|
|
if (dest > buf)
|
|
fwrite(buf, 1, (size_t) (dest - buf), fp);
|
|
}
|
|
else
|
|
*dest = 0;
|
|
|
|
return (int) (dest - buf);
|
|
}
|
|
format_p = format;
|
|
|
|
/* get the "flags", if any.
|
|
*/
|
|
if (*(++format) == '-')
|
|
{
|
|
left_justify = pdc_true;
|
|
++format;
|
|
}
|
|
|
|
if (*format == '0')
|
|
{
|
|
if (!left_justify)
|
|
pad = '0';
|
|
|
|
++format;
|
|
}
|
|
|
|
/* get the "width", if present.
|
|
*/
|
|
if (*format == '*')
|
|
{
|
|
width = va_arg(args, int); /* TODO: sign? */
|
|
++format;
|
|
}
|
|
else
|
|
{
|
|
while (isdigit((int) *format))
|
|
width = 10 * width + *(format++) - '0';
|
|
}
|
|
|
|
/* get the "precision", if present.
|
|
*/
|
|
if (*format == '.')
|
|
{
|
|
++format;
|
|
|
|
if (*format == '*')
|
|
{
|
|
prec = va_arg(args, int); /* TODO: sign? */
|
|
++format;
|
|
}
|
|
else
|
|
{
|
|
while (isdigit((int) *format))
|
|
prec = 10 * prec + *(format++) - '0';
|
|
}
|
|
}
|
|
|
|
switch (*format)
|
|
{
|
|
case 'x':
|
|
case 'X':
|
|
dest = pdc_off_t2a(
|
|
dest, (pdc_off_t) va_arg(args, unsigned int),
|
|
width, pad, 16);
|
|
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, 10);
|
|
break;
|
|
|
|
case 'g':
|
|
case 'f':
|
|
if (pdfconf)
|
|
{
|
|
dest = pdc_ftoa_pdfconf(pdc, dest, va_arg(args, double));
|
|
}
|
|
else
|
|
{
|
|
char ff[32];
|
|
size_t n = (size_t) (format - format_p + 1);
|
|
|
|
strncpy(ff, format_p, n);
|
|
ff[n] = 0;
|
|
dest = pdc_ftoa(pdc, ff, dest, va_arg(args, double));
|
|
}
|
|
break;
|
|
|
|
case 'l':
|
|
{
|
|
pdc_off_t n;
|
|
|
|
if (format[1] == 'l')
|
|
{
|
|
n = va_arg(args, pdc_off_t);
|
|
++format;
|
|
}
|
|
else
|
|
{
|
|
n = va_arg(args, long);
|
|
}
|
|
|
|
switch (*(++format))
|
|
{
|
|
case 'x':
|
|
case 'X':
|
|
dest = pdc_off_t2a(dest, n, width, pad, 16);
|
|
break;
|
|
|
|
case 'd':
|
|
dest = pdc_off_t2a(dest, n, width, pad, 10);
|
|
break;
|
|
|
|
default:
|
|
pdc_error(pdc, PDC_E_INT_BADFORMAT,
|
|
pdc_errprintf(pdc, "l%c",
|
|
isprint((int) *format) ? *format : '?'),
|
|
pdc_errprintf(pdc, "0x%02X", *format),
|
|
0, 0);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'p':
|
|
{
|
|
void *ptr = va_arg(args, void *);
|
|
dest += sprintf(dest, "%p", ptr);
|
|
break;
|
|
}
|
|
|
|
case 's':
|
|
case 'T':
|
|
{
|
|
char * str = va_arg(args, char *);
|
|
const char *cstr = str;
|
|
size_t len;
|
|
|
|
if (str == 0)
|
|
cstr = "(NULL)";
|
|
len = strlen(cstr);
|
|
|
|
if (*format == 'T')
|
|
{
|
|
int l = va_arg(args, int);
|
|
|
|
if (str != 0)
|
|
{
|
|
cstr = pdc_print_tracestring(pdc, str, l);
|
|
len = strlen(cstr);
|
|
}
|
|
}
|
|
|
|
if (left_justify && len < (size_t) width)
|
|
{
|
|
memset(dest, pad, width - len);
|
|
dest += width - len;
|
|
}
|
|
|
|
if (len != 0)
|
|
{
|
|
if (fp != (FILE *) 0)
|
|
{
|
|
if (dest > buf)
|
|
{
|
|
fwrite(buf, 1, (size_t) (dest - buf), fp);
|
|
dest = buf;
|
|
}
|
|
|
|
fwrite(cstr, 1, len, fp);
|
|
}
|
|
else
|
|
{
|
|
memcpy(dest, cstr, len);
|
|
dest += len;
|
|
}
|
|
}
|
|
|
|
if (!left_justify && len < (size_t) width)
|
|
{
|
|
memset(dest, pad, width - len);
|
|
dest += width - len;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case '%':
|
|
*(dest++) = '%';
|
|
break;
|
|
|
|
default:
|
|
pdc_error(pdc, PDC_E_INT_BADFORMAT,
|
|
pdc_errprintf(pdc, "%c", 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, 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, 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, buf, 0, 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, buf, 0, format, ap);
|
|
va_end(ap);
|
|
|
|
return result;
|
|
} /* pdc_sprintf */
|
|
|
|
|
|
/* --------------------- 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,
|
|
&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_errprintf(pdc, "%.*s", PDC_ET_MAXSTRLEN, 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_errprintf(pdc, "%.*s", PDC_ET_MAXSTRLEN, 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);
|
|
}
|