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