#define _CUPS_STRING_C_
#include "string-private.h"
#include "debug-private.h"
#include "thread-private.h"
#include "array.h"
#include <stddef.h>
#include <limits.h>
static _cups_mutex_t sp_mutex = _CUPS_MUTEX_INITIALIZER;
static cups_array_t *stringpool = NULL;
static int compare_sp_items(_cups_sp_item_t *a, _cups_sp_item_t *b);
char *
_cupsStrAlloc(const char *s)
{
_cups_sp_item_t *item,
*key;
if (!s)
return (NULL);
_cupsMutexLock(&sp_mutex);
if (!stringpool)
stringpool = cupsArrayNew((cups_array_func_t)compare_sp_items, NULL);
if (!stringpool)
{
_cupsMutexUnlock(&sp_mutex);
return (NULL);
}
key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL)
{
item->ref_count ++;
#ifdef DEBUG_GUARDS
DEBUG_printf(("5_cupsStrAlloc: Using string %p(%s) for \"%s\", guard=%08x, "
"ref_count=%d", item, item->str, s, item->guard,
item->ref_count));
if (item->guard != _CUPS_STR_GUARD)
abort();
#endif
_cupsMutexUnlock(&sp_mutex);
return (item->str);
}
item = (_cups_sp_item_t *)calloc(1, sizeof(_cups_sp_item_t) + strlen(s));
if (!item)
{
_cupsMutexUnlock(&sp_mutex);
return (NULL);
}
item->ref_count = 1;
strcpy(item->str, s);
#ifdef DEBUG_GUARDS
item->guard = _CUPS_STR_GUARD;
DEBUG_printf(("5_cupsStrAlloc: Created string %p(%s) for \"%s\", guard=%08x, "
"ref_count=%d", item, item->str, s, item->guard,
item->ref_count));
#endif
cupsArrayAdd(stringpool, item);
_cupsMutexUnlock(&sp_mutex);
return (item->str);
}
void
_cupsStrFlush(void)
{
_cups_sp_item_t *item;
DEBUG_printf(("4_cupsStrFlush: %d strings in array",
cupsArrayCount(stringpool)));
_cupsMutexLock(&sp_mutex);
for (item = (_cups_sp_item_t *)cupsArrayFirst(stringpool);
item;
item = (_cups_sp_item_t *)cupsArrayNext(stringpool))
free(item);
cupsArrayDelete(stringpool);
stringpool = NULL;
_cupsMutexUnlock(&sp_mutex);
}
char *
_cupsStrFormatd(char *buf,
char *bufend,
double number,
struct lconv *loc)
{
char *bufptr,
temp[1024],
*tempdec,
*tempptr;
const char *dec;
int declen;
snprintf(temp, sizeof(temp), "%.12f", number);
for (tempptr = temp + strlen(temp) - 1;
tempptr > temp && *tempptr == '0';
*tempptr-- = '\0');
if (loc && loc->decimal_point)
{
dec = loc->decimal_point;
declen = (int)strlen(dec);
}
else
{
dec = ".";
declen = 1;
}
if (declen == 1)
tempdec = strchr(temp, *dec);
else
tempdec = strstr(temp, dec);
if (tempdec)
{
for (tempptr = temp, bufptr = buf;
tempptr < tempdec && bufptr < bufend;
*bufptr++ = *tempptr++);
tempptr += declen;
if (*tempptr && bufptr < bufend)
{
*bufptr++ = '.';
while (*tempptr && bufptr < bufend)
*bufptr++ = *tempptr++;
}
*bufptr = '\0';
}
else
{
strlcpy(buf, temp, bufend - buf + 1);
bufptr = buf + strlen(buf);
}
return (bufptr);
}
void
_cupsStrFree(const char *s)
{
_cups_sp_item_t *item,
*key;
if (!s)
return;
if (!stringpool)
return;
_cupsMutexLock(&sp_mutex);
key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
#ifdef DEBUG_GUARDS
if (key->guard != _CUPS_STR_GUARD)
{
DEBUG_printf(("5_cupsStrFree: Freeing string %p(%s), guard=%08x, "
"ref_count=%d", key, key->str, key->guard, key->ref_count));
abort();
}
#endif
if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL &&
item == key)
{
item->ref_count --;
if (!item->ref_count)
{
cupsArrayRemove(stringpool, item);
free(item);
}
}
_cupsMutexUnlock(&sp_mutex);
}
char *
_cupsStrRetain(const char *s)
{
_cups_sp_item_t *item;
if (s)
{
item = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
#ifdef DEBUG_GUARDS
if (item->guard != _CUPS_STR_GUARD)
{
DEBUG_printf(("5_cupsStrRetain: Retaining string %p(%s), guard=%08x, "
"ref_count=%d", item, s, item->guard, item->ref_count));
abort();
}
#endif
_cupsMutexLock(&sp_mutex);
item->ref_count ++;
_cupsMutexUnlock(&sp_mutex);
}
return ((char *)s);
}
double
_cupsStrScand(const char *buf,
char **bufptr,
struct lconv *loc)
{
char temp[1024],
*tempptr;
if (!buf)
return (0.0);
while (_cups_isspace(*buf))
buf ++;
tempptr = temp;
if (*buf == '-' || *buf == '+')
*tempptr++ = *buf++;
while (isdigit(*buf & 255))
if (tempptr < (temp + sizeof(temp) - 1))
*tempptr++ = *buf++;
else
{
if (bufptr)
*bufptr = NULL;
return (0.0);
}
if (*buf == '.')
{
buf ++;
if (loc && loc->decimal_point)
{
strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (tempptr - temp));
tempptr += strlen(tempptr);
}
else if (tempptr < (temp + sizeof(temp) - 1))
*tempptr++ = '.';
else
{
if (bufptr)
*bufptr = NULL;
return (0.0);
}
while (isdigit(*buf & 255))
if (tempptr < (temp + sizeof(temp) - 1))
*tempptr++ = *buf++;
else
{
if (bufptr)
*bufptr = NULL;
return (0.0);
}
}
if (*buf == 'e' || *buf == 'E')
{
if (tempptr < (temp + sizeof(temp) - 1))
*tempptr++ = *buf++;
else
{
if (bufptr)
*bufptr = NULL;
return (0.0);
}
if (*buf == '+' || *buf == '-')
{
if (tempptr < (temp + sizeof(temp) - 1))
*tempptr++ = *buf++;
else
{
if (bufptr)
*bufptr = NULL;
return (0.0);
}
}
while (isdigit(*buf & 255))
if (tempptr < (temp + sizeof(temp) - 1))
*tempptr++ = *buf++;
else
{
if (bufptr)
*bufptr = NULL;
return (0.0);
}
}
if (bufptr)
*bufptr = (char *)buf;
*tempptr = '\0';
return (strtod(temp, NULL));
}
size_t
_cupsStrStatistics(size_t *alloc_bytes,
size_t *total_bytes)
{
size_t count,
abytes,
tbytes,
len;
_cups_sp_item_t *item;
_cupsMutexLock(&sp_mutex);
for (count = 0, abytes = 0, tbytes = 0,
item = (_cups_sp_item_t *)cupsArrayFirst(stringpool);
item;
item = (_cups_sp_item_t *)cupsArrayNext(stringpool))
{
count += item->ref_count;
len = (strlen(item->str) + 8) & ~7;
abytes += sizeof(_cups_sp_item_t) + len;
tbytes += item->ref_count * len;
}
_cupsMutexUnlock(&sp_mutex);
if (alloc_bytes)
*alloc_bytes = abytes;
if (total_bytes)
*total_bytes = tbytes;
return (count);
}
void
_cups_strcpy(char *dst,
const char *src)
{
while (*src)
*dst++ = *src++;
*dst = '\0';
}
#ifndef HAVE_STRDUP
char *
_cups_strdup(const char *s)
{
char *t;
if (s == NULL)
return (NULL);
if ((t = malloc(strlen(s) + 1)) == NULL)
return (NULL);
return (strcpy(t, s));
}
#endif
int
_cups_strcasecmp(const char *s,
const char *t)
{
while (*s != '\0' && *t != '\0')
{
if (_cups_tolower(*s) < _cups_tolower(*t))
return (-1);
else if (_cups_tolower(*s) > _cups_tolower(*t))
return (1);
s ++;
t ++;
}
if (*s == '\0' && *t == '\0')
return (0);
else if (*s != '\0')
return (1);
else
return (-1);
}
int
_cups_strncasecmp(const char *s,
const char *t,
size_t n)
{
while (*s != '\0' && *t != '\0' && n > 0)
{
if (_cups_tolower(*s) < _cups_tolower(*t))
return (-1);
else if (_cups_tolower(*s) > _cups_tolower(*t))
return (1);
s ++;
t ++;
n --;
}
if (n == 0)
return (0);
else if (*s == '\0' && *t == '\0')
return (0);
else if (*s != '\0')
return (1);
else
return (-1);
}
#ifndef HAVE_STRLCAT
size_t
_cups_strlcat(char *dst,
const char *src,
size_t size)
{
size_t srclen;
size_t dstlen;
dstlen = strlen(dst);
size -= dstlen + 1;
if (!size)
return (dstlen);
srclen = strlen(src);
if (srclen > size)
srclen = size;
memcpy(dst + dstlen, src, srclen);
dst[dstlen + srclen] = '\0';
return (dstlen + srclen);
}
#endif
#ifndef HAVE_STRLCPY
size_t
_cups_strlcpy(char *dst,
const char *src,
size_t size)
{
size_t srclen;
size --;
srclen = strlen(src);
if (srclen > size)
srclen = size;
memcpy(dst, src, srclen);
dst[srclen] = '\0';
return (srclen);
}
#endif
static int
compare_sp_items(_cups_sp_item_t *a,
_cups_sp_item_t *b)
{
return (strcmp(a->str, b->str));
}