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