]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/string.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / string.c
1 /*
2 * "$Id: string.c 5238 2006-03-07 04:41:42Z mike $"
3 *
4 * String functions for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * _cupsStrAlloc() - Allocate/reference a string.
29 * _cupsStrFlush() - Flush the string pool...
30 * _cupsStrFormatd() - Format a floating-point number.
31 * _cupsStrFree() - Free/dereference a string.
32 * _cupsStrScand() - Scan a string for a floating-point number.
33 * _cupsStrStatistics() - Return allocation statistics for string pool.
34 * _cups_strcpy() - Copy a string allowing for overlapping strings.
35 * _cups_strdup() - Duplicate a string.
36 * _cups_strcasecmp() - Do a case-insensitive comparison.
37 * _cups_strncasecmp() - Do a case-insensitive comparison on up to N chars.
38 * _cups_strlcat() - Safely concatenate two strings.
39 * _cups_strlcpy() - Safely copy two strings.
40 * compare_sp_items() - Compare two string pool items...
41 */
42
43 /*
44 * Include necessary headers...
45 */
46
47 #include <stdlib.h>
48 #include <limits.h>
49 #include "debug.h"
50 #include "string.h"
51 #include "globals.h"
52
53
54 /*
55 * Local functions...
56 */
57
58 static int compare_sp_items(_cups_sp_item_t *a, _cups_sp_item_t *b);
59
60
61 /*
62 * '_cupsStrAlloc()' - Allocate/reference a string.
63 */
64
65 char * /* O - String pointer */
66 _cupsStrAlloc(const char *s) /* I - String */
67 {
68 _cups_globals_t *cg; /* Global data */
69 _cups_sp_item_t *item, /* String pool item */
70 key; /* Search key */
71
72
73 /*
74 * Range check input...
75 */
76
77 if (!s)
78 return (NULL);
79
80 /*
81 * Get the string pool...
82 */
83
84 cg = _cupsGlobals();
85
86 if (!cg->stringpool)
87 cg->stringpool = cupsArrayNew((cups_array_func_t)compare_sp_items, NULL);
88
89 if (!cg->stringpool)
90 return (NULL);
91
92 /*
93 * See if the string is already in the pool...
94 */
95
96 key.str = (char *)s;
97
98 if ((item = (_cups_sp_item_t *)cupsArrayFind(cg->stringpool, &key)) != NULL)
99 {
100 /*
101 * Found it, return the cached string...
102 */
103
104 item->ref_count ++;
105
106 return (item->str);
107 }
108
109 /*
110 * Not found, so allocate a new one...
111 */
112
113 item = (_cups_sp_item_t *)calloc(1, sizeof(_cups_sp_item_t));
114 if (!item)
115 return (NULL);
116
117 item->ref_count = 1;
118 item->str = strdup(s);
119
120 if (!item->str)
121 {
122 free(item);
123 return (NULL);
124 }
125
126 /*
127 * Add the string to the pool and return it...
128 */
129
130 cupsArrayAdd(cg->stringpool, item);
131
132 return (item->str);
133 }
134
135
136 /*
137 * '_cupsStrFlush()' - Flush the string pool...
138 */
139
140 void
141 _cupsStrFlush(_cups_globals_t *cg) /* I - Global data */
142 {
143 _cups_sp_item_t *item; /* Current item */
144
145
146 for (item = (_cups_sp_item_t *)cupsArrayFirst(cg->stringpool);
147 item;
148 item = (_cups_sp_item_t *)cupsArrayNext(cg->stringpool))
149 {
150 free(item->str);
151 free(item);
152 }
153
154 cupsArrayDelete(cg->stringpool);
155 }
156
157
158 /*
159 * '_cupsStrFormatd()' - Format a floating-point number.
160 */
161
162 char * /* O - Pointer to end of string */
163 _cupsStrFormatd(char *buf, /* I - String */
164 char *bufend, /* I - End of string buffer */
165 double number, /* I - Number to format */
166 struct lconv *loc) /* I - Locale data */
167 {
168 char *bufptr, /* Pointer into buffer */
169 temp[1024], /* Temporary string */
170 *tempdec, /* Pointer to decimal point */
171 *tempptr; /* Pointer into temporary string */
172 const char *dec; /* Decimal point */
173 int declen; /* Length of decimal point */
174
175
176 /*
177 * Format the number using the "%.12f" format and then eliminate
178 * unnecessary trailing 0's.
179 */
180
181 snprintf(temp, sizeof(temp), "%.12f", number);
182 for (tempptr = temp + strlen(temp) - 1;
183 tempptr > temp && *tempptr == '0';
184 *tempptr-- = '\0');
185
186 /*
187 * Next, find the decimal point...
188 */
189
190 if (loc && loc->decimal_point)
191 {
192 dec = loc->decimal_point;
193 declen = strlen(dec);
194 }
195 else
196 {
197 dec = ".";
198 declen = 1;
199 }
200
201 if (declen == 1)
202 tempdec = strchr(temp, *dec);
203 else
204 tempdec = strstr(temp, dec);
205
206 /*
207 * Copy everything up to the decimal point...
208 */
209
210 if (tempdec)
211 {
212 for (tempptr = temp, bufptr = buf;
213 tempptr < tempdec && bufptr < bufend;
214 *bufptr++ = *tempptr++);
215
216 tempdec += declen;
217
218 if (*tempdec && bufptr < bufend)
219 {
220 *bufptr++ = '.';
221
222 while (*tempptr && bufptr < bufend)
223 *bufptr++ = *tempptr++;
224 }
225
226 *bufptr = '\0';
227 }
228 else
229 {
230 strlcpy(buf, temp, bufend - buf + 1);
231 bufptr = buf + strlen(buf);
232 }
233
234 return (bufptr);
235 }
236
237
238 /*
239 * '_cupsStrFree()' - Free/dereference a string.
240 */
241
242 void
243 _cupsStrFree(const char *s) /* I - String to free */
244 {
245 _cups_globals_t *cg; /* Global data */
246 _cups_sp_item_t *item, /* String pool item */
247 key; /* Search key */
248
249
250 /*
251 * Range check input...
252 */
253
254 if (!s)
255 return;
256
257 /*
258 * Get the string pool...
259 */
260
261 cg = _cupsGlobals();
262
263 if (!cg->stringpool)
264 return;
265
266 /*
267 * See if the string is already in the pool...
268 */
269
270 key.str = (char *)s;
271
272 if ((item = (_cups_sp_item_t *)cupsArrayFind(cg->stringpool, &key)) != NULL)
273 {
274 /*
275 * Found it, dereference...
276 */
277
278 item->ref_count --;
279
280 if (!item->ref_count)
281 {
282 /*
283 * Remove and free...
284 */
285
286 cupsArrayRemove(cg->stringpool, item);
287
288 free(item->str);
289 free(item);
290 }
291 }
292 }
293
294
295 /*
296 * '_cupsStrScand()' - Scan a string for a floating-point number.
297 *
298 * This function handles the locale-specific BS so that a decimal
299 * point is always the period (".")...
300 */
301
302 double /* O - Number */
303 _cupsStrScand(const char *buf, /* I - Pointer to number */
304 char **bufptr, /* O - New pointer or NULL on error */
305 struct lconv *loc) /* I - Locale data */
306 {
307 char temp[1024], /* Temporary buffer */
308 *tempptr; /* Pointer into temporary buffer */
309
310
311 /*
312 * Range check input...
313 */
314
315 if (!buf)
316 return (0.0);
317
318 /*
319 * Skip leading whitespace...
320 */
321
322 while (isspace(*buf & 255))
323 buf ++;
324
325 /*
326 * Copy leading sign, numbers, period, and then numbers...
327 */
328
329 tempptr = temp;
330 if (*buf == '-' || *buf == '+')
331 *tempptr++ = *buf++;
332
333 while (isdigit(*buf & 255))
334 if (tempptr < (temp + sizeof(temp) - 1))
335 *tempptr++ = *buf++;
336 else
337 {
338 if (bufptr)
339 *bufptr = NULL;
340
341 return (0.0);
342 }
343
344 if (*buf == '.')
345 {
346 if (loc && loc->decimal_point)
347 {
348 strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (tempptr - temp));
349 tempptr += strlen(tempptr);
350 }
351 else if (tempptr < (temp + sizeof(temp) - 1))
352 *tempptr++ = '.';
353 else
354 {
355 if (bufptr)
356 *bufptr = NULL;
357
358 return (0.0);
359 }
360
361 while (isdigit(*buf & 255))
362 if (tempptr < (temp + sizeof(temp) - 1))
363 *tempptr++ = *buf++;
364 else
365 {
366 if (bufptr)
367 *bufptr = NULL;
368
369 return (0.0);
370 }
371 }
372
373 /*
374 * Nul-terminate the temporary string and return the value...
375 */
376
377 if (bufptr)
378 *bufptr = (char *)buf;
379
380 *tempptr = '\0';
381
382 return (strtod(temp, NULL));
383 }
384
385
386 /*
387 * '_cupsStrStatistics()' - Return allocation statistics for string pool.
388 */
389
390 size_t /* O - Number of strings */
391 _cupsStrStatistics(size_t *alloc_bytes, /* O - Allocated bytes */
392 size_t *total_bytes) /* O - Total string bytes */
393 {
394 size_t count, /* Number of strings */
395 abytes, /* Allocated string bytes */
396 tbytes, /* Total string bytes */
397 len; /* Length of string */
398 _cups_sp_item_t *item; /* Current item */
399 _cups_globals_t *cg; /* Global data */
400
401
402 /*
403 * Loop through strings in pool, counting everything up...
404 */
405
406 cg = _cupsGlobals();
407
408 for (count = 0, abytes = 0, tbytes = 0,
409 item = (_cups_sp_item_t *)cupsArrayFirst(cg->stringpool);
410 item;
411 item = (_cups_sp_item_t *)cupsArrayNext(cg->stringpool))
412 {
413 /*
414 * Count allocated memory, using a 64-bit aligned buffer as a basis.
415 */
416
417 count += item->ref_count;
418 len = (strlen(item->str) + 8) & ~7;
419 abytes += sizeof(_cups_sp_item_t) + len;
420 tbytes += item->ref_count * len;
421 }
422
423 /*
424 * Return values...
425 */
426
427 if (alloc_bytes)
428 *alloc_bytes = abytes;
429
430 if (total_bytes)
431 *total_bytes = tbytes;
432
433 return (count);
434 }
435
436
437 /*
438 * '_cups_strcpy()' - Copy a string allowing for overlapping strings.
439 */
440
441 void
442 _cups_strcpy(char *dst, /* I - Destination string */
443 const char *src) /* I - Source string */
444 {
445 while (*src)
446 *dst++ = *src++;
447
448 *dst = '\0';
449 }
450
451
452 /*
453 * '_cups_strdup()' - Duplicate a string.
454 */
455
456 #ifndef HAVE_STRDUP
457 char * /* O - New string pointer */
458 _cups_strdup(const char *s) /* I - String to duplicate */
459 {
460 char *t; /* New string pointer */
461
462
463 if (s == NULL)
464 return (NULL);
465
466 if ((t = malloc(strlen(s) + 1)) == NULL)
467 return (NULL);
468
469 return (strcpy(t, s));
470 }
471 #endif /* !HAVE_STRDUP */
472
473
474 /*
475 * '_cups_strcasecmp()' - Do a case-insensitive comparison.
476 */
477
478 #ifndef HAVE_STRCASECMP
479 int /* O - Result of comparison (-1, 0, or 1) */
480 _cups_strcasecmp(const char *s, /* I - First string */
481 const char *t) /* I - Second string */
482 {
483 while (*s != '\0' && *t != '\0')
484 {
485 if (tolower(*s & 255) < tolower(*t & 255))
486 return (-1);
487 else if (tolower(*s & 255) > tolower(*t & 255))
488 return (1);
489
490 s ++;
491 t ++;
492 }
493
494 if (*s == '\0' && *t == '\0')
495 return (0);
496 else if (*s != '\0')
497 return (1);
498 else
499 return (-1);
500 }
501 #endif /* !HAVE_STRCASECMP */
502
503 /*
504 * '_cups_strncasecmp()' - Do a case-insensitive comparison on up to N chars.
505 */
506
507 #ifndef HAVE_STRNCASECMP
508 int /* O - Result of comparison (-1, 0, or 1) */
509 _cups_strncasecmp(const char *s, /* I - First string */
510 vconst char *t, /* I - Second string */
511 size_t n) /* I - Maximum number of characters to compare */
512 {
513 while (*s != '\0' && *t != '\0' && n > 0)
514 {
515 if (tolower(*s & 255) < tolower(*t & 255))
516 return (-1);
517 else if (tolower(*s & 255) > tolower(*t & 255))
518 return (1);
519
520 s ++;
521 t ++;
522 n --;
523 }
524
525 if (n == 0)
526 return (0);
527 else if (*s == '\0' && *t == '\0')
528 return (0);
529 else if (*s != '\0')
530 return (1);
531 else
532 return (-1);
533 }
534 #endif /* !HAVE_STRNCASECMP */
535
536
537 #ifndef HAVE_STRLCAT
538 /*
539 * '_cups_strlcat()' - Safely concatenate two strings.
540 */
541
542 size_t /* O - Length of string */
543 _cups_strlcat(char *dst, /* O - Destination string */
544 const char *src, /* I - Source string */
545 size_t size) /* I - Size of destination string buffer */
546 {
547 size_t srclen; /* Length of source string */
548 size_t dstlen; /* Length of destination string */
549
550
551 /*
552 * Figure out how much room is left...
553 */
554
555 dstlen = strlen(dst);
556 size -= dstlen + 1;
557
558 if (!size)
559 return (dstlen); /* No room, return immediately... */
560
561 /*
562 * Figure out how much room is needed...
563 */
564
565 srclen = strlen(src);
566
567 /*
568 * Copy the appropriate amount...
569 */
570
571 if (srclen > size)
572 srclen = size;
573
574 memcpy(dst + dstlen, src, srclen);
575 dst[dstlen + srclen] = '\0';
576
577 return (dstlen + srclen);
578 }
579 #endif /* !HAVE_STRLCAT */
580
581
582 #ifndef HAVE_STRLCPY
583 /*
584 * '_cups_strlcpy()' - Safely copy two strings.
585 */
586
587 size_t /* O - Length of string */
588 _cups_strlcpy(char *dst, /* O - Destination string */
589 const char *src, /* I - Source string */
590 size_t size) /* I - Size of destination string buffer */
591 {
592 size_t srclen; /* Length of source string */
593
594
595 /*
596 * Figure out how much room is needed...
597 */
598
599 size --;
600
601 srclen = strlen(src);
602
603 /*
604 * Copy the appropriate amount...
605 */
606
607 if (srclen > size)
608 srclen = size;
609
610 memcpy(dst, src, srclen);
611 dst[srclen] = '\0';
612
613 return (srclen);
614 }
615 #endif /* !HAVE_STRLCPY */
616
617
618 /*
619 * 'compare_sp_items()' - Compare two string pool items...
620 */
621
622 static int /* O - Result of comparison */
623 compare_sp_items(_cups_sp_item_t *a, /* I - First item */
624 _cups_sp_item_t *b) /* I - Second item */
625 {
626 return (strcmp(a->str, b->str));
627 }
628
629
630 /*
631 * End of "$Id: string.c 5238 2006-03-07 04:41:42Z mike $".
632 */