2 * "$Id: string.c 7460 2008-04-16 02:19:54Z mike $"
4 * String functions for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * _cupsStrAlloc() - Allocate/reference a string.
20 * _cupsStrFlush() - Flush the string pool.
21 * _cupsStrFormatd() - Format a floating-point number.
22 * _cupsStrFree() - Free/dereference a string.
23 * _cupsStrRetain() - Increment the reference count of a string.
24 * _cupsStrScand() - Scan a string for a floating-point number.
25 * _cupsStrStatistics() - Return allocation statistics for string pool.
26 * _cups_strcpy() - Copy a string allowing for overlapping strings.
27 * _cups_strdup() - Duplicate a string.
28 * _cups_strcasecmp() - Do a case-insensitive comparison.
29 * _cups_strncasecmp() - Do a case-insensitive comparison on up to N chars.
30 * _cups_strlcat() - Safely concatenate two strings.
31 * _cups_strlcpy() - Safely copy two strings.
32 * compare_sp_items() - Compare two string pool items...
36 * Include necessary headers...
47 #endif /* HAVE_PTHREAD_H */
55 static pthread_mutex_t sp_mutex
= PTHREAD_MUTEX_INITIALIZER
;
56 /* Mutex to control access to pool */
57 #endif /* HAVE_PTHREAD_H */
58 static cups_array_t
*stringpool
= NULL
;
59 /* Global string pool */
66 static int compare_sp_items(_cups_sp_item_t
*a
, _cups_sp_item_t
*b
);
70 * '_cupsStrAlloc()' - Allocate/reference a string.
73 char * /* O - String pointer */
74 _cupsStrAlloc(const char *s
) /* I - String */
76 _cups_sp_item_t
*item
, /* String pool item */
77 *key
; /* Search key */
81 * Range check input...
88 * Get the string pool...
92 pthread_mutex_lock(&sp_mutex
);
93 #endif /* HAVE_PTHREAD_H */
96 stringpool
= cupsArrayNew((cups_array_func_t
)compare_sp_items
, NULL
);
100 #ifdef HAVE_PTHREAD_H
101 pthread_mutex_unlock(&sp_mutex
);
102 #endif /* HAVE_PTHREAD_H */
108 * See if the string is already in the pool...
111 key
= (_cups_sp_item_t
*)(s
- offsetof(_cups_sp_item_t
, str
));
113 if ((item
= (_cups_sp_item_t
*)cupsArrayFind(stringpool
, key
)) != NULL
)
116 * Found it, return the cached string...
122 DEBUG_printf(("_cupsStrAlloc: Using string %p(%s) for \"%s\", guard=%08x, "
123 "ref_count=%d\n", item
, item
->str
, s
, item
->guard
,
126 if (item
->guard
!= _CUPS_STR_GUARD
)
128 #endif /* DEBUG_GUARDS */
130 #ifdef HAVE_PTHREAD_H
131 pthread_mutex_unlock(&sp_mutex
);
132 #endif /* HAVE_PTHREAD_H */
138 * Not found, so allocate a new one...
141 item
= (_cups_sp_item_t
*)calloc(1, sizeof(_cups_sp_item_t
) + strlen(s
));
144 #ifdef HAVE_PTHREAD_H
145 pthread_mutex_unlock(&sp_mutex
);
146 #endif /* HAVE_PTHREAD_H */
152 strcpy(item
->str
, s
);
155 item
->guard
= _CUPS_STR_GUARD
;
157 DEBUG_printf(("_cupsStrAlloc: Created string %p(%s) for \"%s\", guard=%08x, "
158 "ref_count=%d\n", item
, item
->str
, s
, item
->guard
,
160 #endif /* DEBUG_GUARDS */
163 * Add the string to the pool and return it...
166 cupsArrayAdd(stringpool
, item
);
168 #ifdef HAVE_PTHREAD_H
169 pthread_mutex_unlock(&sp_mutex
);
170 #endif /* HAVE_PTHREAD_H */
177 * '_cupsStrFlush()' - Flush the string pool.
183 _cups_sp_item_t
*item
; /* Current item */
186 DEBUG_printf(("_cupsStrFlush: %d strings in array\n",
187 cupsArrayCount(stringpool
)));
189 #ifdef HAVE_PTHREAD_H
190 pthread_mutex_lock(&sp_mutex
);
191 #endif /* HAVE_PTHREAD_H */
193 for (item
= (_cups_sp_item_t
*)cupsArrayFirst(stringpool
);
195 item
= (_cups_sp_item_t
*)cupsArrayNext(stringpool
))
198 cupsArrayDelete(stringpool
);
201 #ifdef HAVE_PTHREAD_H
202 pthread_mutex_unlock(&sp_mutex
);
203 #endif /* HAVE_PTHREAD_H */
208 * '_cupsStrFormatd()' - Format a floating-point number.
211 char * /* O - Pointer to end of string */
212 _cupsStrFormatd(char *buf
, /* I - String */
213 char *bufend
, /* I - End of string buffer */
214 double number
, /* I - Number to format */
215 struct lconv
*loc
) /* I - Locale data */
217 char *bufptr
, /* Pointer into buffer */
218 temp
[1024], /* Temporary string */
219 *tempdec
, /* Pointer to decimal point */
220 *tempptr
; /* Pointer into temporary string */
221 const char *dec
; /* Decimal point */
222 int declen
; /* Length of decimal point */
226 * Format the number using the "%.12f" format and then eliminate
227 * unnecessary trailing 0's.
230 snprintf(temp
, sizeof(temp
), "%.12f", number
);
231 for (tempptr
= temp
+ strlen(temp
) - 1;
232 tempptr
> temp
&& *tempptr
== '0';
236 * Next, find the decimal point...
239 if (loc
&& loc
->decimal_point
)
241 dec
= loc
->decimal_point
;
242 declen
= (int)strlen(dec
);
251 tempdec
= strchr(temp
, *dec
);
253 tempdec
= strstr(temp
, dec
);
256 * Copy everything up to the decimal point...
261 for (tempptr
= temp
, bufptr
= buf
;
262 tempptr
< tempdec
&& bufptr
< bufend
;
263 *bufptr
++ = *tempptr
++);
267 if (*tempptr
&& bufptr
< bufend
)
271 while (*tempptr
&& bufptr
< bufend
)
272 *bufptr
++ = *tempptr
++;
279 strlcpy(buf
, temp
, bufend
- buf
+ 1);
280 bufptr
= buf
+ strlen(buf
);
288 * '_cupsStrFree()' - Free/dereference a string.
292 _cupsStrFree(const char *s
) /* I - String to free */
294 _cups_sp_item_t
*item
, /* String pool item */
295 *key
; /* Search key */
299 * Range check input...
306 * Check the string pool...
308 * We don't need to lock the mutex yet, as we only want to know if
309 * the stringpool is initialized. The rest of the code will still
310 * work if it is initialized before we lock...
317 * See if the string is already in the pool...
320 #ifdef HAVE_PTHREAD_H
321 pthread_mutex_lock(&sp_mutex
);
322 #endif /* HAVE_PTHREAD_H */
324 key
= (_cups_sp_item_t
*)(s
- offsetof(_cups_sp_item_t
, str
));
327 if (key
->guard
!= _CUPS_STR_GUARD
)
329 DEBUG_printf(("_cupsStrFree: Freeing string %p(%s), guard=%08x, "
330 "ref_count=%d\n", key
, key
->str
, key
->guard
, key
->ref_count
));
333 #endif /* DEBUG_GUARDS */
335 if ((item
= (_cups_sp_item_t
*)cupsArrayFind(stringpool
, key
)) != NULL
&&
339 * Found it, dereference...
344 if (!item
->ref_count
)
350 cupsArrayRemove(stringpool
, item
);
356 #ifdef HAVE_PTHREAD_H
357 pthread_mutex_unlock(&sp_mutex
);
358 #endif /* HAVE_PTHREAD_H */
363 * '_cupsStrRetain()' - Increment the reference count of a string.
365 * Note: This function does not verify that the passed pointer is in the
366 * string pool, so any calls to it MUST know they are passing in a
370 char * /* O - Pointer to string */
371 _cupsStrRetain(char *s
) /* I - String to retain */
373 _cups_sp_item_t
*item
; /* Pointer to string pool item */
378 item
= (_cups_sp_item_t
*)(s
- offsetof(_cups_sp_item_t
, str
));
381 if (item
->guard
!= _CUPS_STR_GUARD
)
383 DEBUG_printf(("_cupsStrRetain: Retaining string %p(%s), guard=%08x, "
384 "ref_count=%d\n", item
, s
, item
->guard
, item
->ref_count
));
387 #endif /* DEBUG_GUARDS */
389 #ifdef HAVE_PTHREAD_H
390 pthread_mutex_lock(&sp_mutex
);
391 #endif /* HAVE_PTHREAD_H */
395 #ifdef HAVE_PTHREAD_H
396 pthread_mutex_unlock(&sp_mutex
);
397 #endif /* HAVE_PTHREAD_H */
405 * '_cupsStrScand()' - Scan a string for a floating-point number.
407 * This function handles the locale-specific BS so that a decimal
408 * point is always the period (".")...
411 double /* O - Number */
412 _cupsStrScand(const char *buf
, /* I - Pointer to number */
413 char **bufptr
, /* O - New pointer or NULL on error */
414 struct lconv
*loc
) /* I - Locale data */
416 char temp
[1024], /* Temporary buffer */
417 *tempptr
; /* Pointer into temporary buffer */
421 * Range check input...
428 * Skip leading whitespace...
431 while (isspace(*buf
& 255))
435 * Copy leading sign, numbers, period, and then numbers...
439 if (*buf
== '-' || *buf
== '+')
442 while (isdigit(*buf
& 255))
443 if (tempptr
< (temp
+ sizeof(temp
) - 1))
456 * Read fractional portion of number...
461 if (loc
&& loc
->decimal_point
)
463 strlcpy(tempptr
, loc
->decimal_point
, sizeof(temp
) - (tempptr
- temp
));
464 tempptr
+= strlen(tempptr
);
466 else if (tempptr
< (temp
+ sizeof(temp
) - 1))
476 while (isdigit(*buf
& 255))
477 if (tempptr
< (temp
+ sizeof(temp
) - 1))
488 if (*buf
== 'e' || *buf
== 'E')
494 if (tempptr
< (temp
+ sizeof(temp
) - 1))
504 if (*buf
== '+' || *buf
== '-')
506 if (tempptr
< (temp
+ sizeof(temp
) - 1))
517 while (isdigit(*buf
& 255))
518 if (tempptr
< (temp
+ sizeof(temp
) - 1))
530 * Nul-terminate the temporary string and return the value...
534 *bufptr
= (char *)buf
;
538 return (strtod(temp
, NULL
));
543 * '_cupsStrStatistics()' - Return allocation statistics for string pool.
546 size_t /* O - Number of strings */
547 _cupsStrStatistics(size_t *alloc_bytes
, /* O - Allocated bytes */
548 size_t *total_bytes
) /* O - Total string bytes */
550 size_t count
, /* Number of strings */
551 abytes
, /* Allocated string bytes */
552 tbytes
, /* Total string bytes */
553 len
; /* Length of string */
554 _cups_sp_item_t
*item
; /* Current item */
558 * Loop through strings in pool, counting everything up...
561 #ifdef HAVE_PTHREAD_H
562 pthread_mutex_lock(&sp_mutex
);
563 #endif /* HAVE_PTHREAD_H */
565 for (count
= 0, abytes
= 0, tbytes
= 0,
566 item
= (_cups_sp_item_t
*)cupsArrayFirst(stringpool
);
568 item
= (_cups_sp_item_t
*)cupsArrayNext(stringpool
))
571 * Count allocated memory, using a 64-bit aligned buffer as a basis.
574 count
+= item
->ref_count
;
575 len
= (strlen(item
->str
) + 8) & ~7;
576 abytes
+= sizeof(_cups_sp_item_t
) + len
;
577 tbytes
+= item
->ref_count
* len
;
580 #ifdef HAVE_PTHREAD_H
581 pthread_mutex_unlock(&sp_mutex
);
582 #endif /* HAVE_PTHREAD_H */
589 *alloc_bytes
= abytes
;
592 *total_bytes
= tbytes
;
599 * '_cups_strcpy()' - Copy a string allowing for overlapping strings.
603 _cups_strcpy(char *dst
, /* I - Destination string */
604 const char *src
) /* I - Source string */
614 * '_cups_strdup()' - Duplicate a string.
618 char * /* O - New string pointer */
619 _cups_strdup(const char *s
) /* I - String to duplicate */
621 char *t
; /* New string pointer */
627 if ((t
= malloc(strlen(s
) + 1)) == NULL
)
630 return (strcpy(t
, s
));
632 #endif /* !HAVE_STRDUP */
636 * '_cups_strcasecmp()' - Do a case-insensitive comparison.
639 #ifndef HAVE_STRCASECMP
640 int /* O - Result of comparison (-1, 0, or 1) */
641 _cups_strcasecmp(const char *s
, /* I - First string */
642 const char *t
) /* I - Second string */
644 while (*s
!= '\0' && *t
!= '\0')
646 if (tolower(*s
& 255) < tolower(*t
& 255))
648 else if (tolower(*s
& 255) > tolower(*t
& 255))
655 if (*s
== '\0' && *t
== '\0')
662 #endif /* !HAVE_STRCASECMP */
665 * '_cups_strncasecmp()' - Do a case-insensitive comparison on up to N chars.
668 #ifndef HAVE_STRNCASECMP
669 int /* O - Result of comparison (-1, 0, or 1) */
670 _cups_strncasecmp(const char *s
, /* I - First string */
671 const char *t
, /* I - Second string */
672 size_t n
) /* I - Maximum number of characters to compare */
674 while (*s
!= '\0' && *t
!= '\0' && n
> 0)
676 if (tolower(*s
& 255) < tolower(*t
& 255))
678 else if (tolower(*s
& 255) > tolower(*t
& 255))
688 else if (*s
== '\0' && *t
== '\0')
695 #endif /* !HAVE_STRNCASECMP */
700 * '_cups_strlcat()' - Safely concatenate two strings.
703 size_t /* O - Length of string */
704 _cups_strlcat(char *dst
, /* O - Destination string */
705 const char *src
, /* I - Source string */
706 size_t size
) /* I - Size of destination string buffer */
708 size_t srclen
; /* Length of source string */
709 size_t dstlen
; /* Length of destination string */
713 * Figure out how much room is left...
716 dstlen
= strlen(dst
);
720 return (dstlen
); /* No room, return immediately... */
723 * Figure out how much room is needed...
726 srclen
= strlen(src
);
729 * Copy the appropriate amount...
735 memcpy(dst
+ dstlen
, src
, srclen
);
736 dst
[dstlen
+ srclen
] = '\0';
738 return (dstlen
+ srclen
);
740 #endif /* !HAVE_STRLCAT */
745 * '_cups_strlcpy()' - Safely copy two strings.
748 size_t /* O - Length of string */
749 _cups_strlcpy(char *dst
, /* O - Destination string */
750 const char *src
, /* I - Source string */
751 size_t size
) /* I - Size of destination string buffer */
753 size_t srclen
; /* Length of source string */
757 * Figure out how much room is needed...
762 srclen
= strlen(src
);
765 * Copy the appropriate amount...
771 memcpy(dst
, src
, srclen
);
776 #endif /* !HAVE_STRLCPY */
780 * 'compare_sp_items()' - Compare two string pool items...
783 static int /* O - Result of comparison */
784 compare_sp_items(_cups_sp_item_t
*a
, /* I - First item */
785 _cups_sp_item_t
*b
) /* I - Second item */
787 return (strcmp(a
->str
, b
->str
));
792 * End of "$Id: string.c 7460 2008-04-16 02:19:54Z mike $".