]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/string.c
Clean up installation of private headers.
[thirdparty/cups.git] / cups / string.c
index b30c77075edd64d85a953b34b8ade26378f54c67..e91ba40d4660490e0b2f5862b5f03525cb9beb57 100644 (file)
@@ -1,52 +1,31 @@
 /*
- * "$Id: string.c 5047 2006-02-02 05:14:15Z mike $"
+ * String functions for CUPS.
  *
- *   String functions for the Common UNIX Printing System (CUPS).
+ * Copyright 2007-2014 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
  *
- *   Copyright 1997-2006 by Easy Software Products.
- *
- *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
- *
- *   This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- *   _cups_sp_alloc()      - Allocate/reference a string.
- *   _cups_sp_flush()      - Flush the string pool...
- *   _cups_sp_free()       - Free/dereference a string.
- *   _cups_sp_statistics() - Return allocation statistics for string pool.
- *   _cups_strcpy()        - Copy a string allowing for overlapping strings.
- *   _cups_strdup()        - Duplicate a string.
- *   _cups_strcasecmp()    - Do a case-insensitive comparison.
- *   _cups_strncasecmp()   - Do a case-insensitive comparison on up to N chars.
- *   _cups_strlcat()       - Safely concatenate two strings.
- *   _cups_strlcpy()       - Safely copy two strings.
- *   compare_sp_items()    - Compare two string pool items...
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
 
 /*
  * Include necessary headers...
  */
 
-#include <stdlib.h>
+#define _CUPS_STRING_C_
+#include "cups-private.h"
+#include "debug-internal.h"
+#include <stddef.h>
 #include <limits.h>
-#include "debug.h"
-#include "string.h"
-#include "globals.h"
+
+
+/*
+ * Local globals...
+ */
+
+static _cups_mutex_t   sp_mutex = _CUPS_MUTEX_INITIALIZER;
+                                       /* Mutex to control access to pool */
+static cups_array_t    *stringpool = NULL;
+                                       /* Global string pool */
 
 
 /*
@@ -57,15 +36,15 @@ static int  compare_sp_items(_cups_sp_item_t *a, _cups_sp_item_t *b);
 
 
 /*
- * '_cups_sp_alloc()' - Allocate/reference a string.
+ * '_cupsStrAlloc()' - Allocate/reference a string.
  */
 
 char *                                 /* O - String pointer */
-_cups_sp_alloc(const char *s)          /* I - String */
+_cupsStrAlloc(const char *s)           /* I - String */
 {
-  _cups_globals_t      *cg;            /* Global data */
+  size_t               slen;           /* Length of string */
   _cups_sp_item_t      *item,          /* String pool item */
-                       key;            /* Search key */
+                       *key;           /* Search key */
 
 
  /*
@@ -79,21 +58,25 @@ _cups_sp_alloc(const char *s)               /* I - String */
   * Get the string pool...
   */
 
-  cg = _cupsGlobals();
+  _cupsMutexLock(&sp_mutex);
 
-  if (!cg->stringpool)
-    cg->stringpool = cupsArrayNew((cups_array_func_t)compare_sp_items, NULL);
+  if (!stringpool)
+    stringpool = cupsArrayNew((cups_array_func_t)compare_sp_items, NULL);
+
+  if (!stringpool)
+  {
+    _cupsMutexUnlock(&sp_mutex);
 
-  if (!cg->stringpool)
     return (NULL);
+  }
 
  /*
   * See if the string is already in the pool...
   */
 
-  key.str = (char *)s;
+  key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
 
-  if ((item = (_cups_sp_item_t *)cupsArrayFind(cg->stringpool, &key)) != NULL)
+  if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL)
   {
    /*
     * Found it, return the cached string...
@@ -101,6 +84,17 @@ _cups_sp_alloc(const char *s)               /* I - String */
 
     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 /* DEBUG_GUARDS */
+
+    _cupsMutexUnlock(&sp_mutex);
+
     return (item->str);
   }
 
@@ -108,61 +102,187 @@ _cups_sp_alloc(const char *s)            /* I - String */
   * Not found, so allocate a new one...
   */
 
-  item = (_cups_sp_item_t *)calloc(1, sizeof(_cups_sp_item_t));
+  slen = strlen(s);
+  item = (_cups_sp_item_t *)calloc(1, sizeof(_cups_sp_item_t) + slen);
   if (!item)
+  {
+    _cupsMutexUnlock(&sp_mutex);
+
     return (NULL);
+  }
 
   item->ref_count = 1;
-  item->str       = strdup(s);
+  memcpy(item->str, s, slen + 1);
 
-  if (!item->str)
-  {
-    free(item);
-    return (NULL);
-  }
+#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 /* DEBUG_GUARDS */
 
  /*
   * Add the string to the pool and return it...
   */
 
-  cupsArrayAdd(cg->stringpool, item);
+  cupsArrayAdd(stringpool, item);
+
+  _cupsMutexUnlock(&sp_mutex);
 
   return (item->str);
 }
 
 
 /*
- * '_cups_sp_flush()' - Flush the string pool...
+ * '_cupsStrDate()' - Return a localized date for a given time value.
+ *
+ * This function works around the locale encoding issues of strftime...
+ */
+
+char *                                 /* O - Buffer */
+_cupsStrDate(char   *buf,              /* I - Buffer */
+             size_t bufsize,           /* I - Size of buffer */
+            time_t timeval)            /* I - Time value */
+{
+  struct tm    *dateval;               /* Local date/time */
+  char         temp[1024];             /* Temporary buffer */
+  _cups_globals_t *cg = _cupsGlobals();        /* Per-thread globals */
+
+
+  if (!cg->lang_default)
+    cg->lang_default = cupsLangDefault();
+
+  dateval = localtime(&timeval);
+
+  if (cg->lang_default->encoding != CUPS_UTF8)
+  {
+    strftime(temp, sizeof(temp), "%c", dateval);
+    cupsCharsetToUTF8((cups_utf8_t *)buf, temp, (int)bufsize, cg->lang_default->encoding);
+  }
+  else
+    strftime(buf, bufsize, "%c", dateval);
+
+  return (buf);
+}
+
+
+/*
+ * '_cupsStrFlush()' - Flush the string pool.
  */
 
 void
-_cups_sp_flush(_cups_globals_t *cg)    /* I - Global data */
+_cupsStrFlush(void)
 {
   _cups_sp_item_t      *item;          /* Current item */
 
 
-  for (item = (_cups_sp_item_t *)cupsArrayFirst(cg->stringpool);
+  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(cg->stringpool))
-  {
-    free(item->str);
+       item = (_cups_sp_item_t *)cupsArrayNext(stringpool))
     free(item);
+
+  cupsArrayDelete(stringpool);
+  stringpool = NULL;
+
+  _cupsMutexUnlock(&sp_mutex);
+}
+
+
+/*
+ * '_cupsStrFormatd()' - Format a floating-point number.
+ */
+
+char *                                 /* O - Pointer to end of string */
+_cupsStrFormatd(char         *buf,     /* I - String */
+                char         *bufend,  /* I - End of string buffer */
+               double       number,    /* I - Number to format */
+                struct lconv *loc)     /* I - Locale data */
+{
+  char         *bufptr,                /* Pointer into buffer */
+               temp[1024],             /* Temporary string */
+               *tempdec,               /* Pointer to decimal point */
+               *tempptr;               /* Pointer into temporary string */
+  const char   *dec;                   /* Decimal point */
+  int          declen;                 /* Length of decimal point */
+
+
+ /*
+  * Format the number using the "%.12f" format and then eliminate
+  * unnecessary trailing 0's.
+  */
+
+  snprintf(temp, sizeof(temp), "%.12f", number);
+  for (tempptr = temp + strlen(temp) - 1;
+       tempptr > temp && *tempptr == '0';
+       *tempptr-- = '\0');
+
+ /*
+  * Next, find the decimal point...
+  */
+
+  if (loc && loc->decimal_point)
+  {
+    dec    = loc->decimal_point;
+    declen = (int)strlen(dec);
+  }
+  else
+  {
+    dec    = ".";
+    declen = 1;
   }
 
-  cupsArrayDelete(cg->stringpool);
+  if (declen == 1)
+    tempdec = strchr(temp, *dec);
+  else
+    tempdec = strstr(temp, dec);
+
+ /*
+  * Copy everything up to the decimal point...
+  */
+
+  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, (size_t)(bufend - buf + 1));
+    bufptr = buf + strlen(buf);
+  }
+
+  return (bufptr);
 }
 
 
 /*
- * '_cups_sp_free()' - Free/dereference a string.
+ * '_cupsStrFree()' - Free/dereference a string.
  */
 
 void
-_cups_sp_free(const char *s)
+_cupsStrFree(const char *s)            /* I - String to free */
 {
-  _cups_globals_t      *cg;            /* Global data */
   _cups_sp_item_t      *item,          /* String pool item */
-                       key;            /* Search key */
+                       *key;           /* Search key */
 
 
  /*
@@ -173,21 +293,35 @@ _cups_sp_free(const char *s)
     return;
 
  /*
-  * Get the string pool...
+  * Check the string pool...
+  *
+  * We don't need to lock the mutex yet, as we only want to know if
+  * the stringpool is initialized.  The rest of the code will still
+  * work if it is initialized before we lock...
   */
 
-  cg = _cupsGlobals();
-
-  if (!cg->stringpool)
+  if (!stringpool)
     return;
 
  /*
   * See if the string is already in the pool...
   */
 
-  key.str = (char *)s;
+  _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 /* DEBUG_GUARDS */
 
-  if ((item = (_cups_sp_item_t *)cupsArrayFind(cg->stringpool, &key)) != NULL)
+  if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL &&
+      item == key)
   {
    /*
     * Found it, dereference...
@@ -201,52 +335,230 @@ _cups_sp_free(const char *s)
       * Remove and free...
       */
 
-      cupsArrayRemove(cg->stringpool, item);
+      cupsArrayRemove(stringpool, item);
 
-      free(item->str);
       free(item);
     }
   }
+
+  _cupsMutexUnlock(&sp_mutex);
 }
 
 
 /*
- * '_cups_sp_statistics()' - Return allocation statistics for string pool.
+ * '_cupsStrRetain()' - Increment the reference count of a string.
+ *
+ * Note: This function does not verify that the passed pointer is in the
+ *       string pool, so any calls to it MUST know they are passing in a
+ *       good pointer.
+ */
+
+char *                                 /* O - Pointer to string */
+_cupsStrRetain(const char *s)          /* I - String to retain */
+{
+  _cups_sp_item_t      *item;          /* Pointer to string pool 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 /* DEBUG_GUARDS */
+
+    _cupsMutexLock(&sp_mutex);
+
+    item->ref_count ++;
+
+    _cupsMutexUnlock(&sp_mutex);
+  }
+
+  return ((char *)s);
+}
+
+
+/*
+ * '_cupsStrScand()' - Scan a string for a floating-point number.
+ *
+ * This function handles the locale-specific BS so that a decimal
+ * point is always the period (".")...
+ */
+
+double                                 /* O - Number */
+_cupsStrScand(const char   *buf,       /* I - Pointer to number */
+              char         **bufptr,   /* O - New pointer or NULL on error */
+              struct lconv *loc)       /* I - Locale data */
+{
+  char temp[1024],                     /* Temporary buffer */
+       *tempptr;                       /* Pointer into temporary buffer */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!buf)
+    return (0.0);
+
+ /*
+  * Skip leading whitespace...
+  */
+
+  while (_cups_isspace(*buf))
+    buf ++;
+
+ /*
+  * Copy leading sign, numbers, period, and then numbers...
+  */
+
+  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 == '.')
+  {
+   /*
+    * Read fractional portion of number...
+    */
+
+    buf ++;
+
+    if (loc && loc->decimal_point)
+    {
+      strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (size_t)(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')
+  {
+   /*
+    * Read exponent...
+    */
+
+    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);
+      }
+  }
+
+ /*
+  * Nul-terminate the temporary string and return the value...
+  */
+
+  if (bufptr)
+    *bufptr = (char *)buf;
+
+  *tempptr = '\0';
+
+  return (strtod(temp, NULL));
+}
+
+
+/*
+ * '_cupsStrStatistics()' - Return allocation statistics for string pool.
  */
 
 size_t                                 /* O - Number of strings */
-_cups_sp_statistics(size_t *alloc_bytes,/* O - Allocated bytes */
-                    size_t *total_bytes)/* O - Total string bytes */
+_cupsStrStatistics(size_t *alloc_bytes,        /* O - Allocated bytes */
+                   size_t *total_bytes)        /* O - Total string bytes */
 {
   size_t               count,          /* Number of strings */
                        abytes,         /* Allocated string bytes */
                        tbytes,         /* Total string bytes */
                        len;            /* Length of string */
   _cups_sp_item_t      *item;          /* Current item */
-  _cups_globals_t      *cg;            /* Global data */
 
 
  /*
   * Loop through strings in pool, counting everything up...
   */
 
-  cg = _cupsGlobals();
+  _cupsMutexLock(&sp_mutex);
 
   for (count = 0, abytes = 0, tbytes = 0,
-           item = (_cups_sp_item_t *)cupsArrayFirst(cg->stringpool);
+           item = (_cups_sp_item_t *)cupsArrayFirst(stringpool);
        item;
-       item = (_cups_sp_item_t *)cupsArrayNext(cg->stringpool))
+       item = (_cups_sp_item_t *)cupsArrayNext(stringpool))
   {
    /*
     * Count allocated memory, using a 64-bit aligned buffer as a basis.
     */
 
     count  += item->ref_count;
-    len    = (strlen(item->str) + 8) & ~7;
+    len    = (strlen(item->str) + 8) & (size_t)~7;
     abytes += sizeof(_cups_sp_item_t) + len;
     tbytes += item->ref_count * len;
   }
 
+  _cupsMutexUnlock(&sp_mutex);
+
  /*
   * Return values...
   */
@@ -267,7 +579,7 @@ _cups_sp_statistics(size_t *alloc_bytes,/* O - Allocated bytes */
 
 void
 _cups_strcpy(char       *dst,          /* I - Destination string */
-            const char *src)           /* I - Source string */
+             const char *src)          /* I - Source string */
 {
   while (*src)
     *dst++ = *src++;
@@ -284,16 +596,18 @@ _cups_strcpy(char       *dst,             /* I - Destination string */
 char   *                               /* O - New string pointer */
 _cups_strdup(const char *s)            /* I - String to duplicate */
 {
-  char *t;                             /* New string pointer */
+  char         *t;                     /* New string pointer */
+  size_t       slen;                   /* Length of string */
 
 
-  if (s == NULL)
+  if (!s)
     return (NULL);
 
-  if ((t = malloc(strlen(s) + 1)) == NULL)
+  slen = strlen(s);
+  if ((t = malloc(slen + 1)) == NULL)
     return (NULL);
 
-  return (strcpy(t, s));
+  return (memcpy(t, s, slen + 1));
 }
 #endif /* !HAVE_STRDUP */
 
@@ -302,16 +616,15 @@ _cups_strdup(const char *s)               /* I - String to duplicate */
  * '_cups_strcasecmp()' - Do a case-insensitive comparison.
  */
 
-#ifndef HAVE_STRCASECMP
 int                            /* O - Result of comparison (-1, 0, or 1) */
 _cups_strcasecmp(const char *s,        /* I - First string */
-                const char *t) /* I - Second string */
+                 const char *t)        /* I - Second string */
 {
   while (*s != '\0' && *t != '\0')
   {
-    if (tolower(*s & 255) < tolower(*t & 255))
+    if (_cups_tolower(*s) < _cups_tolower(*t))
       return (-1);
-    else if (tolower(*s & 255) > tolower(*t & 255))
+    else if (_cups_tolower(*s) > _cups_tolower(*t))
       return (1);
 
     s ++;
@@ -325,23 +638,21 @@ _cups_strcasecmp(const char *s,   /* I - First string */
   else
     return (-1);
 }
-#endif /* !HAVE_STRCASECMP */
 
 /*
  * '_cups_strncasecmp()' - Do a case-insensitive comparison on up to N chars.
  */
 
-#ifndef HAVE_STRNCASECMP
 int                                    /* O - Result of comparison (-1, 0, or 1) */
 _cups_strncasecmp(const char *s,       /* I - First string */
-                 vconst char *t,       /* I - Second string */
+                  const char *t,       /* I - Second string */
                  size_t     n)         /* I - Maximum number of characters to compare */
 {
   while (*s != '\0' && *t != '\0' && n > 0)
   {
-    if (tolower(*s & 255) < tolower(*t & 255))
+    if (_cups_tolower(*s) < _cups_tolower(*t))
       return (-1);
-    else if (tolower(*s & 255) > tolower(*t & 255))
+    else if (_cups_tolower(*s) > _cups_tolower(*t))
       return (1);
 
     s ++;
@@ -358,7 +669,6 @@ _cups_strncasecmp(const char *s,    /* I - First string */
   else
     return (-1);
 }
-#endif /* !HAVE_STRNCASECMP */
 
 
 #ifndef HAVE_STRLCAT
@@ -380,10 +690,11 @@ _cups_strlcat(char       *dst,            /* O - Destination string */
   */
 
   dstlen = strlen(dst);
-  size   -= dstlen + 1;
 
-  if (!size)
-    return (dstlen);           /* No room, return immediately... */
+  if (size < (dstlen + 1))
+    return (dstlen);                   /* No room, return immediately... */
+
+  size -= dstlen + 1;
 
  /*
   * Figure out how much room is needed...
@@ -398,7 +709,7 @@ _cups_strlcat(char       *dst,              /* O - Destination string */
   if (srclen > size)
     srclen = size;
 
-  memcpy(dst + dstlen, src, srclen);
+  memmove(dst + dstlen, src, srclen);
   dst[dstlen + srclen] = '\0';
 
   return (dstlen + srclen);
@@ -434,7 +745,7 @@ _cups_strlcpy(char       *dst,              /* O - Destination string */
   if (srclen > size)
     srclen = size;
 
-  memcpy(dst, src, srclen);
+  memmove(dst, src, srclen);
   dst[srclen] = '\0';
 
   return (srclen);
@@ -452,8 +763,3 @@ compare_sp_items(_cups_sp_item_t *a,        /* I - First item */
 {
   return (strcmp(a->str, b->str));
 }
-
-
-/*
- * End of "$Id: string.c 5047 2006-02-02 05:14:15Z mike $".
- */