1 /* 2 * Raster error handling for CUPS. 3 * 4 * Copyright 2007-2015 by Apple Inc. 5 * Copyright 2007 by Easy Software Products. 6 * 7 * These coded instructions, statements, and computer programs are the 8 * property of Apple Inc. and are protected by Federal copyright 9 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 10 * which should have been included with this file. If this file is 11 * missing or damaged, see the license at "http://www.cups.org/". 12 * 13 * This file is subject to the Apple OS-Developed Software exception. 14 */ 15 16 /* 17 * Include necessary headers... 18 */ 19 20 #include <cups/raster-private.h> 21 22 23 /* 24 * Local structures... 25 */ 26 27 typedef struct _cups_raster_error_s /**** Error buffer structure ****/ 28 { 29 char *start, /* Start of buffer */ 30 *current, /* Current position in buffer */ 31 *end; /* End of buffer */ 32 } _cups_raster_error_t; 33 34 35 /* 36 * Local functions... 37 */ 38 39 static _cups_raster_error_t *get_error_buffer(void); 40 41 42 /* 43 * '_cupsRasterAddError()' - Add an error message to the error buffer. 44 */ 45 46 void 47 _cupsRasterAddError(const char *f, /* I - Printf-style error message */ 48 ...) /* I - Additional arguments as needed */ 49 { 50 _cups_raster_error_t *buf = get_error_buffer(); 51 /* Error buffer */ 52 va_list ap; /* Pointer to additional arguments */ 53 char s[2048]; /* Message string */ 54 ssize_t bytes; /* Bytes in message string */ 55 56 57 DEBUG_printf(("_cupsRasterAddError(f=\"%s\", ...)", f)); 58 59 va_start(ap, f); 60 bytes = vsnprintf(s, sizeof(s), f, ap); 61 va_end(ap); 62 63 if (bytes <= 0) 64 return; 65 66 DEBUG_printf(("1_cupsRasterAddError: %s", s)); 67 68 bytes ++; 69 70 if ((size_t)bytes >= sizeof(s)) 71 return; 72 73 if (bytes > (ssize_t)(buf->end - buf->current)) 74 { 75 /* 76 * Allocate more memory... 77 */ 78 79 char *temp; /* New buffer */ 80 size_t size; /* Size of buffer */ 81 82 83 size = (size_t)(buf->end - buf->start + 2 * bytes + 1024); 84 85 if (buf->start) 86 temp = realloc(buf->start, size); 87 else 88 temp = malloc(size); 89 90 if (!temp) 91 return; 92 93 /* 94 * Update pointers... 95 */ 96 97 buf->end = temp + size; 98 buf->current = temp + (buf->current - buf->start); 99 buf->start = temp; 100 } 101 102 /* 103 * Append the message to the end of the current string... 104 */ 105 106 memcpy(buf->current, s, (size_t)bytes); 107 buf->current += bytes - 1; 108 } 109 110 111 /* 112 * '_cupsRasterClearError()' - Clear the error buffer. 113 */ 114 115 void 116 _cupsRasterClearError(void) 117 { 118 _cups_raster_error_t *buf = get_error_buffer(); 119 /* Error buffer */ 120 121 122 buf->current = buf->start; 123 124 if (buf->start) 125 *(buf->start) = '\0'; 126 } 127 128 129 /* 130 * 'cupsRasterErrorString()' - Return the last error from a raster function. 131 * 132 * If there are no recent errors, NULL is returned. 133 * 134 * @since CUPS 1.3/macOS 10.5@ 135 */ 136 137 const char * /* O - Last error */ 138 cupsRasterErrorString(void) 139 { 140 _cups_raster_error_t *buf = get_error_buffer(); 141 /* Error buffer */ 142 143 144 if (buf->current == buf->start) 145 return (NULL); 146 else 147 return (buf->start); 148 } 149 150 151 #ifdef HAVE_PTHREAD_H 152 /* 153 * Implement per-thread globals... 154 */ 155 156 # include <pthread.h> 157 158 159 /* 160 * Local globals... 161 */ 162 163 static pthread_key_t raster_key = 0; /* Thread local storage key */ 164 static pthread_once_t raster_key_once = PTHREAD_ONCE_INIT; 165 /* One-time initialization object */ 166 167 168 /* 169 * Local functions... 170 */ 171 172 static void raster_init(void); 173 static void raster_destructor(void *value); 174 175 176 /* 177 * 'get_error_buffer()' - Return a pointer to thread local storage. 178 */ 179 180 _cups_raster_error_t * /* O - Pointer to error buffer */ 181 get_error_buffer(void) 182 { 183 _cups_raster_error_t *buf; /* Pointer to error buffer */ 184 185 186 /* 187 * Initialize the global data exactly once... 188 */ 189 190 DEBUG_puts("3get_error_buffer()"); 191 192 pthread_once(&raster_key_once, raster_init); 193 194 /* 195 * See if we have allocated the data yet... 196 */ 197 198 if ((buf = (_cups_raster_error_t *)pthread_getspecific(raster_key)) 199 == NULL) 200 { 201 DEBUG_puts("4get_error_buffer: allocating memory for thread."); 202 203 /* 204 * No, allocate memory as set the pointer for the key... 205 */ 206 207 buf = calloc(1, sizeof(_cups_raster_error_t)); 208 pthread_setspecific(raster_key, buf); 209 210 DEBUG_printf(("4get_error_buffer: buf=%p", (void *)buf)); 211 } 212 213 /* 214 * Return the pointer to the data... 215 */ 216 217 return (buf); 218 } 219 220 221 /* 222 * 'raster_init()' - Initialize error buffer once. 223 */ 224 225 static void 226 raster_init(void) 227 { 228 pthread_key_create(&raster_key, raster_destructor); 229 230 DEBUG_printf(("3raster_init(): raster_key=%x(%u)", (unsigned)raster_key, (unsigned)raster_key)); 231 } 232 233 234 /* 235 * 'raster_destructor()' - Free memory allocated by get_error_buffer(). 236 */ 237 238 static void 239 raster_destructor(void *value) /* I - Data to free */ 240 { 241 _cups_raster_error_t *buf = (_cups_raster_error_t *)value; 242 /* Error buffer */ 243 244 245 DEBUG_printf(("3raster_destructor(value=%p)", value)); 246 247 if (buf->start) 248 free(buf->start); 249 250 free(value); 251 } 252 253 254 #else 255 /* 256 * Implement static globals... 257 */ 258 259 /* 260 * 'get_error_buffer()' - Return a pointer to thread local storage. 261 */ 262 263 _cups_raster_error_t * /* O - Pointer to error buffer */ 264 get_error_buffer(void) 265 { 266 static _cups_raster_error_t buf = { 0, 0, 0 }; 267 /* Error buffer */ 268 269 270 return (&buf); 271 } 272 #endif /* HAVE_PTHREAD_H */ 273