]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/string.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / cups / string.c
index a7fa441a1eab641d15f0637aa167d86495a36723..5d5c3bff70e8febfcdc8b10d255055254b1474df 100644 (file)
@@ -1,67 +1,28 @@
 /*
- * "$Id: string.c 177 2006-06-21 00:20:03Z jlovell $"
+ * 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:
- *
- *   _cupsStrAlloc()       - Allocate/reference a string.
- *   _cupsStrFlush()       - Flush the string pool...
- *   _cupsStrFormatd()     - Format a floating-point number.
- *   _cupsStrFree()        - Free/dereference a string.
- *   _cupsStrScand()       - Scan a string for a floating-point number.
- *   _cupsStrStatistics()  - 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 <stddef.h>
 #include <limits.h>
-#include "array.h"
-#include "debug.h"
-#include "string.h"
-#ifdef HAVE_PTHREAD_H
-#  include <pthread.h>
-#endif /* HAVE_PTHREAD_H */
 
 
 /*
  * Local globals...
  */
 
-#ifdef HAVE_PTHREAD_H
-static pthread_mutex_t sp_mutex = PTHREAD_MUTEX_INITIALIZER;
+static _cups_mutex_t   sp_mutex = _CUPS_MUTEX_INITIALIZER;
                                        /* Mutex to control access to pool */
-#endif /* HAVE_PTHREAD_H */
 static cups_array_t    *stringpool = NULL;
                                        /* Global string pool */
 
@@ -80,8 +41,9 @@ static int    compare_sp_items(_cups_sp_item_t *a, _cups_sp_item_t *b);
 char *                                 /* O - String pointer */
 _cupsStrAlloc(const char *s)           /* I - String */
 {
+  size_t               slen;           /* Length of string */
   _cups_sp_item_t      *item,          /* String pool item */
-                       key;            /* Search key */
+                       *key;           /* Search key */
 
 
  /*
@@ -95,18 +57,14 @@ _cupsStrAlloc(const char *s)                /* I - String */
   * Get the string pool...
   */
 
-#ifdef HAVE_PTHREAD_H
-  pthread_mutex_lock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+  _cupsMutexLock(&sp_mutex);
 
   if (!stringpool)
     stringpool = cupsArrayNew((cups_array_func_t)compare_sp_items, NULL);
 
   if (!stringpool)
   {
-#ifdef HAVE_PTHREAD_H
-    pthread_mutex_unlock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+    _cupsMutexUnlock(&sp_mutex);
 
     return (NULL);
   }
@@ -115,9 +73,9 @@ _cupsStrAlloc(const char *s)         /* I - String */
   * 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(stringpool, &key)) != NULL)
+  if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL)
   {
    /*
     * Found it, return the cached string...
@@ -125,9 +83,16 @@ _cupsStrAlloc(const char *s)                /* I - String */
 
     item->ref_count ++;
 
-#ifdef HAVE_PTHREAD_H
-    pthread_mutex_unlock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+#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);
   }
@@ -136,29 +101,25 @@ _cupsStrAlloc(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)
   {
-#ifdef HAVE_PTHREAD_H
-    pthread_mutex_unlock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+    _cupsMutexUnlock(&sp_mutex);
 
     return (NULL);
   }
 
   item->ref_count = 1;
-  item->str       = strdup(s);
-
-  if (!item->str)
-  {
-    free(item);
+  memcpy(item->str, s, slen + 1);
 
-#ifdef HAVE_PTHREAD_H
-    pthread_mutex_unlock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+#ifdef DEBUG_GUARDS
+  item->guard = _CUPS_STR_GUARD;
 
-    return (NULL);
-  }
+  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...
@@ -166,16 +127,47 @@ _cupsStrAlloc(const char *s)              /* I - String */
 
   cupsArrayAdd(stringpool, item);
 
-#ifdef HAVE_PTHREAD_H
-  pthread_mutex_unlock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+  _cupsMutexUnlock(&sp_mutex);
 
   return (item->str);
 }
 
 
 /*
- * '_cupsStrFlush()' - 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
@@ -184,27 +176,20 @@ _cupsStrFlush(void)
   _cups_sp_item_t      *item;          /* Current item */
 
 
-  DEBUG_printf(("_cupsStrFlush(cg=%p)\n", cg));
-  DEBUG_printf(("    %d strings in array\n", cupsArrayCount(stringpool)));
+  DEBUG_printf(("4_cupsStrFlush: %d strings in array",
+                cupsArrayCount(stringpool)));
 
-#ifdef HAVE_PTHREAD_H
-  pthread_mutex_lock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+  _cupsMutexLock(&sp_mutex);
 
   for (item = (_cups_sp_item_t *)cupsArrayFirst(stringpool);
        item;
        item = (_cups_sp_item_t *)cupsArrayNext(stringpool))
-  {
-    free(item->str);
     free(item);
-  }
 
   cupsArrayDelete(stringpool);
   stringpool = NULL;
 
-#ifdef HAVE_PTHREAD_H
-  pthread_mutex_unlock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+  _cupsMutexUnlock(&sp_mutex);
 }
 
 
@@ -243,7 +228,7 @@ _cupsStrFormatd(char         *buf,  /* I - String */
   if (loc && loc->decimal_point)
   {
     dec    = loc->decimal_point;
-    declen = strlen(dec);
+    declen = (int)strlen(dec);
   }
   else
   {
@@ -266,9 +251,9 @@ _cupsStrFormatd(char         *buf,  /* I - String */
          tempptr < tempdec && bufptr < bufend;
         *bufptr++ = *tempptr++);
 
-    tempdec += declen;
+    tempptr += declen;
 
-    if (*tempdec && bufptr < bufend)
+    if (*tempptr && bufptr < bufend)
     {
       *bufptr++ = '.';
 
@@ -280,7 +265,7 @@ _cupsStrFormatd(char         *buf,  /* I - String */
   }
   else
   {
-    strlcpy(buf, temp, bufend - buf + 1);
+    strlcpy(buf, temp, (size_t)(bufend - buf + 1));
     bufptr = buf + strlen(buf);
   }
 
@@ -296,7 +281,7 @@ void
 _cupsStrFree(const char *s)            /* I - String to free */
 {
   _cups_sp_item_t      *item,          /* String pool item */
-                       key;            /* Search key */
+                       *key;           /* Search key */
 
 
  /*
@@ -321,14 +306,21 @@ _cupsStrFree(const char *s)               /* I - String to free */
   * See if the string is already in the pool...
   */
 
-#ifdef HAVE_PTHREAD_H
-  pthread_mutex_lock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+  _cupsMutexLock(&sp_mutex);
 
-  key.str = (char *)s;
+  key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
 
-  if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, &key)) != NULL &&
-      item->str == s)
+#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(stringpool, key)) != NULL &&
+      item == key)
   {
    /*
     * Found it, dereference...
@@ -344,14 +336,49 @@ _cupsStrFree(const char *s)               /* I - String to free */
 
       cupsArrayRemove(stringpool, item);
 
-      free(item->str);
       free(item);
     }
   }
 
-#ifdef HAVE_PTHREAD_H
-  pthread_mutex_unlock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+  _cupsMutexUnlock(&sp_mutex);
+}
+
+
+/*
+ * '_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);
 }
 
 
@@ -382,7 +409,7 @@ _cupsStrScand(const char   *buf,    /* I - Pointer to number */
   * Skip leading whitespace...
   */
 
-  while (isspace(*buf & 255))
+  while (_cups_isspace(*buf))
     buf ++;
 
  /*
@@ -414,7 +441,7 @@ _cupsStrScand(const char   *buf,    /* I - Pointer to number */
 
     if (loc && loc->decimal_point)
     {
-      strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (tempptr - temp));
+      strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (size_t)(tempptr - temp));
       tempptr += strlen(tempptr);
     }
     else if (tempptr < (temp + sizeof(temp) - 1))
@@ -439,6 +466,47 @@ _cupsStrScand(const char   *buf,   /* I - Pointer to number */
       }
   }
 
+  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...
   */
@@ -471,9 +539,7 @@ _cupsStrStatistics(size_t *alloc_bytes,     /* O - Allocated bytes */
   * Loop through strings in pool, counting everything up...
   */
 
-#ifdef HAVE_PTHREAD_H
-  pthread_mutex_lock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+  _cupsMutexLock(&sp_mutex);
 
   for (count = 0, abytes = 0, tbytes = 0,
            item = (_cups_sp_item_t *)cupsArrayFirst(stringpool);
@@ -485,14 +551,12 @@ _cupsStrStatistics(size_t *alloc_bytes,   /* O - Allocated bytes */
     */
 
     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;
   }
 
-#ifdef HAVE_PTHREAD_H
-  pthread_mutex_unlock(&sp_mutex);
-#endif /* HAVE_PTHREAD_H */
+  _cupsMutexUnlock(&sp_mutex);
 
  /*
   * Return values...
@@ -514,7 +578,7 @@ _cupsStrStatistics(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++;
@@ -531,16 +595,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 */
 
@@ -549,16 +615,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 ++;
@@ -572,23 +637,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 ++;
@@ -605,7 +668,6 @@ _cups_strncasecmp(const char *s,    /* I - First string */
   else
     return (-1);
 }
-#endif /* !HAVE_STRNCASECMP */
 
 
 #ifndef HAVE_STRLCAT
@@ -627,10 +689,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...
@@ -645,7 +708,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);
@@ -681,7 +744,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);
@@ -699,8 +762,3 @@ compare_sp_items(_cups_sp_item_t *a,        /* I - First item */
 {
   return (strcmp(a->str, b->str));
 }
-
-
-/*
- * End of "$Id: string.c 177 2006-06-21 00:20:03Z jlovell $".
- */