]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/string.c
Fix build errors on Fedora.
[thirdparty/cups.git] / cups / string.c
1 /*
2 * "$Id$"
3 *
4 * String functions for CUPS.
5 *
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
8 *
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/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 */
17
18 /*
19 * Include necessary headers...
20 */
21
22 #define _CUPS_STRING_C_
23 #include "string-private.h"
24 #include "debug-private.h"
25 #include "thread-private.h"
26 #include "array.h"
27 #include <stddef.h>
28 #include <limits.h>
29
30
31 /*
32 * Local globals...
33 */
34
35 static _cups_mutex_t sp_mutex = _CUPS_MUTEX_INITIALIZER;
36 /* Mutex to control access to pool */
37 static cups_array_t *stringpool = NULL;
38 /* Global string pool */
39
40
41 /*
42 * Local functions...
43 */
44
45 static int compare_sp_items(_cups_sp_item_t *a, _cups_sp_item_t *b);
46
47
48 /*
49 * '_cupsStrAlloc()' - Allocate/reference a string.
50 */
51
52 char * /* O - String pointer */
53 _cupsStrAlloc(const char *s) /* I - String */
54 {
55 size_t slen; /* Length of string */
56 _cups_sp_item_t *item, /* String pool item */
57 *key; /* Search key */
58
59
60 /*
61 * Range check input...
62 */
63
64 if (!s)
65 return (NULL);
66
67 /*
68 * Get the string pool...
69 */
70
71 _cupsMutexLock(&sp_mutex);
72
73 if (!stringpool)
74 stringpool = cupsArrayNew((cups_array_func_t)compare_sp_items, NULL);
75
76 if (!stringpool)
77 {
78 _cupsMutexUnlock(&sp_mutex);
79
80 return (NULL);
81 }
82
83 /*
84 * See if the string is already in the pool...
85 */
86
87 key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
88
89 if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL)
90 {
91 /*
92 * Found it, return the cached string...
93 */
94
95 item->ref_count ++;
96
97 #ifdef DEBUG_GUARDS
98 DEBUG_printf(("5_cupsStrAlloc: Using string %p(%s) for \"%s\", guard=%08x, "
99 "ref_count=%d", item, item->str, s, item->guard,
100 item->ref_count));
101
102 if (item->guard != _CUPS_STR_GUARD)
103 abort();
104 #endif /* DEBUG_GUARDS */
105
106 _cupsMutexUnlock(&sp_mutex);
107
108 return (item->str);
109 }
110
111 /*
112 * Not found, so allocate a new one...
113 */
114
115 slen = strlen(s);
116 item = (_cups_sp_item_t *)calloc(1, sizeof(_cups_sp_item_t) + slen);
117 if (!item)
118 {
119 _cupsMutexUnlock(&sp_mutex);
120
121 return (NULL);
122 }
123
124 item->ref_count = 1;
125 memcpy(item->str, s, slen + 1);
126
127 #ifdef DEBUG_GUARDS
128 item->guard = _CUPS_STR_GUARD;
129
130 DEBUG_printf(("5_cupsStrAlloc: Created string %p(%s) for \"%s\", guard=%08x, "
131 "ref_count=%d", item, item->str, s, item->guard,
132 item->ref_count));
133 #endif /* DEBUG_GUARDS */
134
135 /*
136 * Add the string to the pool and return it...
137 */
138
139 cupsArrayAdd(stringpool, item);
140
141 _cupsMutexUnlock(&sp_mutex);
142
143 return (item->str);
144 }
145
146
147 /*
148 * '_cupsStrFlush()' - Flush the string pool.
149 */
150
151 void
152 _cupsStrFlush(void)
153 {
154 _cups_sp_item_t *item; /* Current item */
155
156
157 DEBUG_printf(("4_cupsStrFlush: %d strings in array",
158 cupsArrayCount(stringpool)));
159
160 _cupsMutexLock(&sp_mutex);
161
162 for (item = (_cups_sp_item_t *)cupsArrayFirst(stringpool);
163 item;
164 item = (_cups_sp_item_t *)cupsArrayNext(stringpool))
165 free(item);
166
167 cupsArrayDelete(stringpool);
168 stringpool = NULL;
169
170 _cupsMutexUnlock(&sp_mutex);
171 }
172
173
174 /*
175 * '_cupsStrFormatd()' - Format a floating-point number.
176 */
177
178 char * /* O - Pointer to end of string */
179 _cupsStrFormatd(char *buf, /* I - String */
180 char *bufend, /* I - End of string buffer */
181 double number, /* I - Number to format */
182 struct lconv *loc) /* I - Locale data */
183 {
184 char *bufptr, /* Pointer into buffer */
185 temp[1024], /* Temporary string */
186 *tempdec, /* Pointer to decimal point */
187 *tempptr; /* Pointer into temporary string */
188 const char *dec; /* Decimal point */
189 int declen; /* Length of decimal point */
190
191
192 /*
193 * Format the number using the "%.12f" format and then eliminate
194 * unnecessary trailing 0's.
195 */
196
197 snprintf(temp, sizeof(temp), "%.12f", number);
198 for (tempptr = temp + strlen(temp) - 1;
199 tempptr > temp && *tempptr == '0';
200 *tempptr-- = '\0');
201
202 /*
203 * Next, find the decimal point...
204 */
205
206 if (loc && loc->decimal_point)
207 {
208 dec = loc->decimal_point;
209 declen = (int)strlen(dec);
210 }
211 else
212 {
213 dec = ".";
214 declen = 1;
215 }
216
217 if (declen == 1)
218 tempdec = strchr(temp, *dec);
219 else
220 tempdec = strstr(temp, dec);
221
222 /*
223 * Copy everything up to the decimal point...
224 */
225
226 if (tempdec)
227 {
228 for (tempptr = temp, bufptr = buf;
229 tempptr < tempdec && bufptr < bufend;
230 *bufptr++ = *tempptr++);
231
232 tempptr += declen;
233
234 if (*tempptr && bufptr < bufend)
235 {
236 *bufptr++ = '.';
237
238 while (*tempptr && bufptr < bufend)
239 *bufptr++ = *tempptr++;
240 }
241
242 *bufptr = '\0';
243 }
244 else
245 {
246 strlcpy(buf, temp, (size_t)(bufend - buf + 1));
247 bufptr = buf + strlen(buf);
248 }
249
250 return (bufptr);
251 }
252
253
254 /*
255 * '_cupsStrFree()' - Free/dereference a string.
256 */
257
258 void
259 _cupsStrFree(const char *s) /* I - String to free */
260 {
261 _cups_sp_item_t *item, /* String pool item */
262 *key; /* Search key */
263
264
265 /*
266 * Range check input...
267 */
268
269 if (!s)
270 return;
271
272 /*
273 * Check the string pool...
274 *
275 * We don't need to lock the mutex yet, as we only want to know if
276 * the stringpool is initialized. The rest of the code will still
277 * work if it is initialized before we lock...
278 */
279
280 if (!stringpool)
281 return;
282
283 /*
284 * See if the string is already in the pool...
285 */
286
287 _cupsMutexLock(&sp_mutex);
288
289 key = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
290
291 #ifdef DEBUG_GUARDS
292 if (key->guard != _CUPS_STR_GUARD)
293 {
294 DEBUG_printf(("5_cupsStrFree: Freeing string %p(%s), guard=%08x, "
295 "ref_count=%d", key, key->str, key->guard, key->ref_count));
296 abort();
297 }
298 #endif /* DEBUG_GUARDS */
299
300 if ((item = (_cups_sp_item_t *)cupsArrayFind(stringpool, key)) != NULL &&
301 item == key)
302 {
303 /*
304 * Found it, dereference...
305 */
306
307 item->ref_count --;
308
309 if (!item->ref_count)
310 {
311 /*
312 * Remove and free...
313 */
314
315 cupsArrayRemove(stringpool, item);
316
317 free(item);
318 }
319 }
320
321 _cupsMutexUnlock(&sp_mutex);
322 }
323
324
325 /*
326 * '_cupsStrRetain()' - Increment the reference count of a string.
327 *
328 * Note: This function does not verify that the passed pointer is in the
329 * string pool, so any calls to it MUST know they are passing in a
330 * good pointer.
331 */
332
333 char * /* O - Pointer to string */
334 _cupsStrRetain(const char *s) /* I - String to retain */
335 {
336 _cups_sp_item_t *item; /* Pointer to string pool item */
337
338
339 if (s)
340 {
341 item = (_cups_sp_item_t *)(s - offsetof(_cups_sp_item_t, str));
342
343 #ifdef DEBUG_GUARDS
344 if (item->guard != _CUPS_STR_GUARD)
345 {
346 DEBUG_printf(("5_cupsStrRetain: Retaining string %p(%s), guard=%08x, "
347 "ref_count=%d", item, s, item->guard, item->ref_count));
348 abort();
349 }
350 #endif /* DEBUG_GUARDS */
351
352 _cupsMutexLock(&sp_mutex);
353
354 item->ref_count ++;
355
356 _cupsMutexUnlock(&sp_mutex);
357 }
358
359 return ((char *)s);
360 }
361
362
363 /*
364 * '_cupsStrScand()' - Scan a string for a floating-point number.
365 *
366 * This function handles the locale-specific BS so that a decimal
367 * point is always the period (".")...
368 */
369
370 double /* O - Number */
371 _cupsStrScand(const char *buf, /* I - Pointer to number */
372 char **bufptr, /* O - New pointer or NULL on error */
373 struct lconv *loc) /* I - Locale data */
374 {
375 char temp[1024], /* Temporary buffer */
376 *tempptr; /* Pointer into temporary buffer */
377
378
379 /*
380 * Range check input...
381 */
382
383 if (!buf)
384 return (0.0);
385
386 /*
387 * Skip leading whitespace...
388 */
389
390 while (_cups_isspace(*buf))
391 buf ++;
392
393 /*
394 * Copy leading sign, numbers, period, and then numbers...
395 */
396
397 tempptr = temp;
398 if (*buf == '-' || *buf == '+')
399 *tempptr++ = *buf++;
400
401 while (isdigit(*buf & 255))
402 if (tempptr < (temp + sizeof(temp) - 1))
403 *tempptr++ = *buf++;
404 else
405 {
406 if (bufptr)
407 *bufptr = NULL;
408
409 return (0.0);
410 }
411
412 if (*buf == '.')
413 {
414 /*
415 * Read fractional portion of number...
416 */
417
418 buf ++;
419
420 if (loc && loc->decimal_point)
421 {
422 strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (size_t)(tempptr - temp));
423 tempptr += strlen(tempptr);
424 }
425 else if (tempptr < (temp + sizeof(temp) - 1))
426 *tempptr++ = '.';
427 else
428 {
429 if (bufptr)
430 *bufptr = NULL;
431
432 return (0.0);
433 }
434
435 while (isdigit(*buf & 255))
436 if (tempptr < (temp + sizeof(temp) - 1))
437 *tempptr++ = *buf++;
438 else
439 {
440 if (bufptr)
441 *bufptr = NULL;
442
443 return (0.0);
444 }
445 }
446
447 if (*buf == 'e' || *buf == 'E')
448 {
449 /*
450 * Read exponent...
451 */
452
453 if (tempptr < (temp + sizeof(temp) - 1))
454 *tempptr++ = *buf++;
455 else
456 {
457 if (bufptr)
458 *bufptr = NULL;
459
460 return (0.0);
461 }
462
463 if (*buf == '+' || *buf == '-')
464 {
465 if (tempptr < (temp + sizeof(temp) - 1))
466 *tempptr++ = *buf++;
467 else
468 {
469 if (bufptr)
470 *bufptr = NULL;
471
472 return (0.0);
473 }
474 }
475
476 while (isdigit(*buf & 255))
477 if (tempptr < (temp + sizeof(temp) - 1))
478 *tempptr++ = *buf++;
479 else
480 {
481 if (bufptr)
482 *bufptr = NULL;
483
484 return (0.0);
485 }
486 }
487
488 /*
489 * Nul-terminate the temporary string and return the value...
490 */
491
492 if (bufptr)
493 *bufptr = (char *)buf;
494
495 *tempptr = '\0';
496
497 return (strtod(temp, NULL));
498 }
499
500
501 /*
502 * '_cupsStrStatistics()' - Return allocation statistics for string pool.
503 */
504
505 size_t /* O - Number of strings */
506 _cupsStrStatistics(size_t *alloc_bytes, /* O - Allocated bytes */
507 size_t *total_bytes) /* O - Total string bytes */
508 {
509 size_t count, /* Number of strings */
510 abytes, /* Allocated string bytes */
511 tbytes, /* Total string bytes */
512 len; /* Length of string */
513 _cups_sp_item_t *item; /* Current item */
514
515
516 /*
517 * Loop through strings in pool, counting everything up...
518 */
519
520 _cupsMutexLock(&sp_mutex);
521
522 for (count = 0, abytes = 0, tbytes = 0,
523 item = (_cups_sp_item_t *)cupsArrayFirst(stringpool);
524 item;
525 item = (_cups_sp_item_t *)cupsArrayNext(stringpool))
526 {
527 /*
528 * Count allocated memory, using a 64-bit aligned buffer as a basis.
529 */
530
531 count += item->ref_count;
532 len = (strlen(item->str) + 8) & (size_t)~7;
533 abytes += sizeof(_cups_sp_item_t) + len;
534 tbytes += item->ref_count * len;
535 }
536
537 _cupsMutexUnlock(&sp_mutex);
538
539 /*
540 * Return values...
541 */
542
543 if (alloc_bytes)
544 *alloc_bytes = abytes;
545
546 if (total_bytes)
547 *total_bytes = tbytes;
548
549 return (count);
550 }
551
552
553 /*
554 * '_cups_strcpy()' - Copy a string allowing for overlapping strings.
555 */
556
557 void
558 _cups_strcpy(char *dst, /* I - Destination string */
559 const char *src) /* I - Source string */
560 {
561 while (*src)
562 *dst++ = *src++;
563
564 *dst = '\0';
565 }
566
567
568 /*
569 * '_cups_strdup()' - Duplicate a string.
570 */
571
572 #ifndef HAVE_STRDUP
573 char * /* O - New string pointer */
574 _cups_strdup(const char *s) /* I - String to duplicate */
575 {
576 char *t; /* New string pointer */
577 size_t slen; /* Length of string */
578
579
580 if (!s)
581 return (NULL);
582
583 slen = strlen(s);
584 if ((t = malloc(slen + 1)) == NULL)
585 return (NULL);
586
587 return (memcpy(t, s, slen + 1));
588 }
589 #endif /* !HAVE_STRDUP */
590
591
592 /*
593 * '_cups_strcasecmp()' - Do a case-insensitive comparison.
594 */
595
596 int /* O - Result of comparison (-1, 0, or 1) */
597 _cups_strcasecmp(const char *s, /* I - First string */
598 const char *t) /* I - Second string */
599 {
600 while (*s != '\0' && *t != '\0')
601 {
602 if (_cups_tolower(*s) < _cups_tolower(*t))
603 return (-1);
604 else if (_cups_tolower(*s) > _cups_tolower(*t))
605 return (1);
606
607 s ++;
608 t ++;
609 }
610
611 if (*s == '\0' && *t == '\0')
612 return (0);
613 else if (*s != '\0')
614 return (1);
615 else
616 return (-1);
617 }
618
619 /*
620 * '_cups_strncasecmp()' - Do a case-insensitive comparison on up to N chars.
621 */
622
623 int /* O - Result of comparison (-1, 0, or 1) */
624 _cups_strncasecmp(const char *s, /* I - First string */
625 const char *t, /* I - Second string */
626 size_t n) /* I - Maximum number of characters to compare */
627 {
628 while (*s != '\0' && *t != '\0' && n > 0)
629 {
630 if (_cups_tolower(*s) < _cups_tolower(*t))
631 return (-1);
632 else if (_cups_tolower(*s) > _cups_tolower(*t))
633 return (1);
634
635 s ++;
636 t ++;
637 n --;
638 }
639
640 if (n == 0)
641 return (0);
642 else if (*s == '\0' && *t == '\0')
643 return (0);
644 else if (*s != '\0')
645 return (1);
646 else
647 return (-1);
648 }
649
650
651 #ifndef HAVE_STRLCAT
652 /*
653 * '_cups_strlcat()' - Safely concatenate two strings.
654 */
655
656 size_t /* O - Length of string */
657 _cups_strlcat(char *dst, /* O - Destination string */
658 const char *src, /* I - Source string */
659 size_t size) /* I - Size of destination string buffer */
660 {
661 size_t srclen; /* Length of source string */
662 size_t dstlen; /* Length of destination string */
663
664
665 /*
666 * Figure out how much room is left...
667 */
668
669 dstlen = strlen(dst);
670 size -= dstlen + 1;
671
672 if (!size)
673 return (dstlen); /* No room, return immediately... */
674
675 /*
676 * Figure out how much room is needed...
677 */
678
679 srclen = strlen(src);
680
681 /*
682 * Copy the appropriate amount...
683 */
684
685 if (srclen > size)
686 srclen = size;
687
688 memmove(dst + dstlen, src, srclen);
689 dst[dstlen + srclen] = '\0';
690
691 return (dstlen + srclen);
692 }
693 #endif /* !HAVE_STRLCAT */
694
695
696 #ifndef HAVE_STRLCPY
697 /*
698 * '_cups_strlcpy()' - Safely copy two strings.
699 */
700
701 size_t /* O - Length of string */
702 _cups_strlcpy(char *dst, /* O - Destination string */
703 const char *src, /* I - Source string */
704 size_t size) /* I - Size of destination string buffer */
705 {
706 size_t srclen; /* Length of source string */
707
708
709 /*
710 * Figure out how much room is needed...
711 */
712
713 size --;
714
715 srclen = strlen(src);
716
717 /*
718 * Copy the appropriate amount...
719 */
720
721 if (srclen > size)
722 srclen = size;
723
724 memmove(dst, src, srclen);
725 dst[srclen] = '\0';
726
727 return (srclen);
728 }
729 #endif /* !HAVE_STRLCPY */
730
731
732 /*
733 * 'compare_sp_items()' - Compare two string pool items...
734 */
735
736 static int /* O - Result of comparison */
737 compare_sp_items(_cups_sp_item_t *a, /* I - First item */
738 _cups_sp_item_t *b) /* I - Second item */
739 {
740 return (strcmp(a->str, b->str));
741 }
742
743
744 /*
745 * End of "$Id$".
746 */