]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
b19ccc9e | 2 | * "$Id: interpret.c 7852 2008-08-21 04:19:45Z mike $" |
ef416fc2 | 3 | * |
71e16022 | 4 | * PPD command interpreter for CUPS. |
ef416fc2 | 5 | * |
a4845881 | 6 | * Copyright 2007-2011 by Apple Inc. |
b86bc4cf | 7 | * Copyright 1993-2007 by Easy Software Products. |
ef416fc2 | 8 | * |
9 | * These coded instructions, statements, and computer programs are the | |
bc44d920 | 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/". | |
ef416fc2 | 14 | * |
15 | * This file is subject to the Apple OS-Developed Software exception. | |
16 | * | |
17 | * Contents: | |
18 | * | |
19 | * cupsRasterInterpretPPD() - Interpret PPD commands to create a page header. | |
b86bc4cf | 20 | * _cupsRasterExecPS() - Execute PostScript code to initialize a page |
21 | * header. | |
22 | * cleartomark_stack() - Clear to the last mark ([) on the stack. | |
23 | * copy_stack() - Copy the top N stack objects. | |
24 | * delete_stack() - Free memory used by a stack. | |
f7deaa1a | 25 | * error_object() - Add an object's value to the current error |
26 | * message. | |
27 | * error_stack() - Add a stack to the current error message. | |
b86bc4cf | 28 | * index_stack() - Copy the Nth value on the stack. |
29 | * new_stack() - Create a new stack. | |
30 | * pop_stock() - Pop the top object off the stack. | |
31 | * push_stack() - Push an object on the stack. | |
32 | * roll_stack() - Rotate stack objects. | |
33 | * scan_ps() - Scan a string for the next PS object. | |
34 | * setpagedevice() - Simulate the PostScript setpagedevice operator. | |
35 | * DEBUG_object() - Print an object value. | |
36 | * DEBUG_stack() - Print a stack. | |
ef416fc2 | 37 | */ |
38 | ||
39 | /* | |
40 | * Include necessary headers... | |
41 | */ | |
42 | ||
a4845881 | 43 | #include <cups/raster-private.h> |
ef416fc2 | 44 | |
45 | ||
46 | /* | |
b86bc4cf | 47 | * Stack values for the PostScript mini-interpreter... |
ef416fc2 | 48 | */ |
49 | ||
b86bc4cf | 50 | typedef enum |
51 | { | |
52 | CUPS_PS_NAME, | |
53 | CUPS_PS_NUMBER, | |
54 | CUPS_PS_STRING, | |
55 | CUPS_PS_BOOLEAN, | |
56 | CUPS_PS_NULL, | |
57 | CUPS_PS_START_ARRAY, | |
58 | CUPS_PS_END_ARRAY, | |
59 | CUPS_PS_START_DICT, | |
60 | CUPS_PS_END_DICT, | |
61 | CUPS_PS_START_PROC, | |
62 | CUPS_PS_END_PROC, | |
63 | CUPS_PS_CLEARTOMARK, | |
64 | CUPS_PS_COPY, | |
65 | CUPS_PS_DUP, | |
66 | CUPS_PS_INDEX, | |
67 | CUPS_PS_POP, | |
68 | CUPS_PS_ROLL, | |
69 | CUPS_PS_SETPAGEDEVICE, | |
70 | CUPS_PS_STOPPED, | |
71 | CUPS_PS_OTHER | |
72 | } _cups_ps_type_t; | |
73 | ||
74 | typedef struct | |
75 | { | |
76 | _cups_ps_type_t type; /* Object type */ | |
77 | union | |
78 | { | |
79 | int boolean; /* Boolean value */ | |
80 | char name[64]; /* Name value */ | |
81 | double number; /* Number value */ | |
82 | char other[64]; /* Other operator */ | |
83 | char string[64]; /* Sring value */ | |
84 | } value; /* Value */ | |
85 | } _cups_ps_obj_t; | |
86 | ||
87 | typedef struct | |
88 | { | |
89 | int num_objs, /* Number of objects on stack */ | |
90 | alloc_objs; /* Number of allocated objects */ | |
91 | _cups_ps_obj_t *objs; /* Objects in stack */ | |
92 | } _cups_ps_stack_t; | |
ef416fc2 | 93 | |
94 | ||
95 | /* | |
96 | * Local functions... | |
97 | */ | |
98 | ||
b86bc4cf | 99 | static int cleartomark_stack(_cups_ps_stack_t *st); |
100 | static int copy_stack(_cups_ps_stack_t *st, int count); | |
101 | static void delete_stack(_cups_ps_stack_t *st); | |
f7deaa1a | 102 | static void error_object(_cups_ps_obj_t *obj); |
103 | static void error_stack(_cups_ps_stack_t *st, const char *title); | |
b86bc4cf | 104 | static _cups_ps_obj_t *index_stack(_cups_ps_stack_t *st, int n); |
105 | static _cups_ps_stack_t *new_stack(void); | |
106 | static _cups_ps_obj_t *pop_stack(_cups_ps_stack_t *st); | |
107 | static _cups_ps_obj_t *push_stack(_cups_ps_stack_t *st, | |
108 | _cups_ps_obj_t *obj); | |
109 | static int roll_stack(_cups_ps_stack_t *st, int c, int s); | |
110 | static _cups_ps_obj_t *scan_ps(_cups_ps_stack_t *st, char **ptr); | |
111 | static int setpagedevice(_cups_ps_stack_t *st, | |
112 | cups_page_header2_t *h, | |
113 | int *preferred_bits); | |
114 | #ifdef DEBUG | |
115 | static void DEBUG_object(_cups_ps_obj_t *obj); | |
116 | static void DEBUG_stack(_cups_ps_stack_t *st); | |
117 | #endif /* DEBUG */ | |
ef416fc2 | 118 | |
119 | ||
120 | /* | |
121 | * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header. | |
122 | * | |
db0bd74a MS |
123 | * This function is used by raster image processing (RIP) filters like |
124 | * cgpdftoraster and imagetoraster when writing CUPS raster data for a page. | |
125 | * It is not used by raster printer driver filters which only read CUPS | |
126 | * raster data. | |
127 | * | |
128 | * | |
129 | * @code cupsRasterInterpretPPD@ does not mark the options in the PPD using | |
130 | * the "num_options" and "options" arguments. Instead, mark the options with | |
131 | * @code cupsMarkOptions@ and @code ppdMarkOption@ prior to calling it - | |
132 | * this allows for per-page options without manipulating the options array. | |
923edb68 | 133 | * |
a74454a7 | 134 | * The "func" argument specifies an optional callback function that is |
135 | * called prior to the computation of the final raster data. The function | |
5a738aea | 136 | * can make changes to the @link cups_page_header2_t@ data as needed to use a |
a74454a7 | 137 | * supported raster format and then returns 0 on success and -1 if the |
138 | * requested attributes cannot be supported. | |
139 | * | |
db0bd74a | 140 | * |
5a738aea MS |
141 | * @code cupsRasterInterpretPPD@ supports a subset of the PostScript language. |
142 | * Currently only the @code [@, @code ]@, @code <<@, @code >>@, @code {@, | |
143 | * @code }@, @code cleartomark@, @code copy@, @code dup@, @code index@, | |
144 | * @code pop@, @code roll@, @code setpagedevice@, and @code stopped@ operators | |
145 | * are supported. | |
b86bc4cf | 146 | * |
db0bd74a | 147 | * @since CUPS 1.2/Mac OS X 10.5@ |
ef416fc2 | 148 | */ |
149 | ||
150 | int /* O - 0 on success, -1 on failure */ | |
151 | cupsRasterInterpretPPD( | |
db0bd74a | 152 | cups_page_header2_t *h, /* O - Page header to create */ |
923edb68 | 153 | ppd_file_t *ppd, /* I - PPD file */ |
154 | int num_options, /* I - Number of options */ | |
a74454a7 | 155 | cups_option_t *options, /* I - Options */ |
db0bd74a | 156 | cups_interpret_cb_t func) /* I - Optional page header callback (@code NULL@ for none) */ |
ef416fc2 | 157 | { |
ef416fc2 | 158 | int status; /* Cummulative status */ |
b86bc4cf | 159 | char *code; /* Code to run */ |
923edb68 | 160 | const char *val; /* Option value */ |
ef416fc2 | 161 | ppd_size_t *size; /* Current size */ |
162 | float left, /* Left position */ | |
163 | bottom, /* Bottom position */ | |
164 | right, /* Right position */ | |
165 | top; /* Top position */ | |
a74454a7 | 166 | int preferred_bits; /* Preferred bits per color */ |
ef416fc2 | 167 | |
168 | ||
169 | /* | |
170 | * Range check input... | |
171 | */ | |
172 | ||
f7deaa1a | 173 | _cupsRasterClearError(); |
174 | ||
ef416fc2 | 175 | if (!h) |
f7deaa1a | 176 | { |
177 | _cupsRasterAddError("Page header cannot be NULL!\n"); | |
ef416fc2 | 178 | return (-1); |
f7deaa1a | 179 | } |
ef416fc2 | 180 | |
181 | /* | |
182 | * Reset the page header to the defaults... | |
183 | */ | |
184 | ||
185 | memset(h, 0, sizeof(cups_page_header2_t)); | |
186 | ||
923edb68 | 187 | h->NumCopies = 1; |
188 | h->PageSize[0] = 612; | |
189 | h->PageSize[1] = 792; | |
190 | h->HWResolution[0] = 100; | |
191 | h->HWResolution[1] = 100; | |
192 | h->cupsBitsPerColor = 1; | |
193 | h->cupsColorOrder = CUPS_ORDER_CHUNKED; | |
194 | h->cupsColorSpace = CUPS_CSPACE_K; | |
195 | h->cupsBorderlessScalingFactor = 1.0f; | |
196 | h->cupsPageSize[0] = 612.0f; | |
197 | h->cupsPageSize[1] = 792.0f; | |
198 | h->cupsImagingBBox[0] = 0.0f; | |
199 | h->cupsImagingBBox[1] = 0.0f; | |
200 | h->cupsImagingBBox[2] = 612.0f; | |
201 | h->cupsImagingBBox[3] = 792.0f; | |
fa73b229 | 202 | |
203 | strcpy(h->cupsPageSizeName, "Letter"); | |
ef416fc2 | 204 | |
e38f5e9c MS |
205 | #ifdef __APPLE__ |
206 | /* | |
207 | * cupsInteger0 is also used for the total page count on Mac OS X; set an | |
208 | * uncommon default value so we can tell if the driver is using cupsInteger0. | |
209 | */ | |
210 | ||
211 | h->cupsInteger[0] = 0x80000000; | |
212 | #endif /* __APPLE__ */ | |
213 | ||
ef416fc2 | 214 | /* |
215 | * Apply patches and options to the page header... | |
216 | */ | |
217 | ||
a74454a7 | 218 | status = 0; |
219 | preferred_bits = 0; | |
ef416fc2 | 220 | |
221 | if (ppd) | |
222 | { | |
223 | /* | |
224 | * Apply any patch code (used to override the defaults...) | |
225 | */ | |
226 | ||
227 | if (ppd->patches) | |
b86bc4cf | 228 | status |= _cupsRasterExecPS(h, &preferred_bits, ppd->patches); |
ef416fc2 | 229 | |
230 | /* | |
231 | * Then apply printer options in the proper order... | |
232 | */ | |
233 | ||
b86bc4cf | 234 | if ((code = ppdEmitString(ppd, PPD_ORDER_DOCUMENT, 0.0)) != NULL) |
ef416fc2 | 235 | { |
b86bc4cf | 236 | status |= _cupsRasterExecPS(h, &preferred_bits, code); |
237 | free(code); | |
ef416fc2 | 238 | } |
239 | ||
b86bc4cf | 240 | if ((code = ppdEmitString(ppd, PPD_ORDER_ANY, 0.0)) != NULL) |
ef416fc2 | 241 | { |
b86bc4cf | 242 | status |= _cupsRasterExecPS(h, &preferred_bits, code); |
243 | free(code); | |
ef416fc2 | 244 | } |
245 | ||
b86bc4cf | 246 | if ((code = ppdEmitString(ppd, PPD_ORDER_PROLOG, 0.0)) != NULL) |
ef416fc2 | 247 | { |
b86bc4cf | 248 | status |= _cupsRasterExecPS(h, &preferred_bits, code); |
249 | free(code); | |
ef416fc2 | 250 | } |
251 | ||
b86bc4cf | 252 | if ((code = ppdEmitString(ppd, PPD_ORDER_PAGE, 0.0)) != NULL) |
ef416fc2 | 253 | { |
b86bc4cf | 254 | status |= _cupsRasterExecPS(h, &preferred_bits, code); |
255 | free(code); | |
ef416fc2 | 256 | } |
257 | } | |
258 | ||
923edb68 | 259 | /* |
260 | * Allow option override for page scaling... | |
261 | */ | |
262 | ||
263 | if ((val = cupsGetOption("cupsBorderlessScalingFactor", num_options, | |
264 | options)) != NULL) | |
265 | { | |
c8fef167 | 266 | double sc = atof(val); /* Scale factor */ |
923edb68 | 267 | |
06d4e77b | 268 | if (sc >= 0.1 && sc <= 2.0) |
c8fef167 | 269 | h->cupsBorderlessScalingFactor = (float)sc; |
923edb68 | 270 | } |
271 | ||
ef416fc2 | 272 | /* |
273 | * Get the margins for the current size... | |
274 | */ | |
275 | ||
276 | if ((size = ppdPageSize(ppd, NULL)) != NULL) | |
277 | { | |
278 | /* | |
279 | * Use the margins from the PPD file... | |
280 | */ | |
281 | ||
282 | left = size->left; | |
283 | bottom = size->bottom; | |
284 | right = size->right; | |
285 | top = size->top; | |
fa73b229 | 286 | |
287 | strlcpy(h->cupsPageSizeName, size->name, sizeof(h->cupsPageSizeName)); | |
07725fee | 288 | |
289 | h->cupsPageSize[0] = size->width; | |
290 | h->cupsPageSize[1] = size->length; | |
ef416fc2 | 291 | } |
292 | else | |
293 | { | |
294 | /* | |
295 | * Use the default margins... | |
296 | */ | |
297 | ||
298 | left = 0.0f; | |
299 | bottom = 0.0f; | |
300 | right = 612.0f; | |
301 | top = 792.0f; | |
302 | } | |
303 | ||
c8fef167 MS |
304 | h->PageSize[0] = (unsigned)(h->cupsPageSize[0] * |
305 | h->cupsBorderlessScalingFactor); | |
306 | h->PageSize[1] = (unsigned)(h->cupsPageSize[1] * | |
307 | h->cupsBorderlessScalingFactor); | |
308 | h->Margins[0] = (unsigned)(left * | |
309 | h->cupsBorderlessScalingFactor); | |
310 | h->Margins[1] = (unsigned)(bottom * | |
311 | h->cupsBorderlessScalingFactor); | |
312 | h->ImagingBoundingBox[0] = (unsigned)(left * | |
313 | h->cupsBorderlessScalingFactor); | |
314 | h->ImagingBoundingBox[1] = (unsigned)(bottom * | |
315 | h->cupsBorderlessScalingFactor); | |
316 | h->ImagingBoundingBox[2] = (unsigned)(right * | |
317 | h->cupsBorderlessScalingFactor); | |
318 | h->ImagingBoundingBox[3] = (unsigned)(top * | |
319 | h->cupsBorderlessScalingFactor); | |
320 | h->cupsImagingBBox[0] = (float)left; | |
321 | h->cupsImagingBBox[1] = (float)bottom; | |
322 | h->cupsImagingBBox[2] = (float)right; | |
323 | h->cupsImagingBBox[3] = (float)top; | |
ef416fc2 | 324 | |
a74454a7 | 325 | /* |
326 | * Use the callback to validate the page header... | |
327 | */ | |
328 | ||
329 | if (func && (*func)(h, preferred_bits)) | |
f7deaa1a | 330 | { |
331 | _cupsRasterAddError("Page header callback returned error.\n"); | |
a74454a7 | 332 | return (-1); |
f7deaa1a | 333 | } |
a74454a7 | 334 | |
a9252913 | 335 | /* |
336 | * Check parameters... | |
337 | */ | |
338 | ||
339 | if (!h->HWResolution[0] || !h->HWResolution[1] || | |
340 | !h->PageSize[0] || !h->PageSize[1] || | |
341 | (h->cupsBitsPerColor != 1 && h->cupsBitsPerColor != 2 && | |
342 | h->cupsBitsPerColor != 4 && h->cupsBitsPerColor != 8 && | |
343 | h->cupsBitsPerColor != 16) || | |
06d4e77b | 344 | h->cupsBorderlessScalingFactor < 0.1 || |
b86bc4cf | 345 | h->cupsBorderlessScalingFactor > 2.0) |
f7deaa1a | 346 | { |
347 | _cupsRasterAddError("Page header uses unsupported values.\n"); | |
a9252913 | 348 | return (-1); |
f7deaa1a | 349 | } |
a9252913 | 350 | |
ef416fc2 | 351 | /* |
352 | * Compute the bitmap parameters... | |
353 | */ | |
354 | ||
923edb68 | 355 | h->cupsWidth = (int)((right - left) * h->cupsBorderlessScalingFactor * |
fa73b229 | 356 | h->HWResolution[0] / 72.0f + 0.5f); |
923edb68 | 357 | h->cupsHeight = (int)((top - bottom) * h->cupsBorderlessScalingFactor * |
fa73b229 | 358 | h->HWResolution[1] / 72.0f + 0.5f); |
ef416fc2 | 359 | |
360 | switch (h->cupsColorSpace) | |
361 | { | |
362 | case CUPS_CSPACE_W : | |
363 | case CUPS_CSPACE_K : | |
364 | case CUPS_CSPACE_WHITE : | |
365 | case CUPS_CSPACE_GOLD : | |
366 | case CUPS_CSPACE_SILVER : | |
88f9aafc | 367 | case CUPS_CSPACE_SW : |
ef416fc2 | 368 | h->cupsNumColors = 1; |
369 | h->cupsBitsPerPixel = h->cupsBitsPerColor; | |
370 | break; | |
371 | ||
372 | default : | |
373 | /* | |
374 | * Ensure that colorimetric colorspaces use at least 8 bits per | |
375 | * component... | |
376 | */ | |
377 | ||
378 | if (h->cupsColorSpace >= CUPS_CSPACE_CIEXYZ && | |
379 | h->cupsBitsPerColor < 8) | |
380 | h->cupsBitsPerColor = 8; | |
381 | ||
382 | /* | |
383 | * Figure out the number of bits per pixel... | |
384 | */ | |
385 | ||
386 | if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) | |
387 | { | |
388 | if (h->cupsBitsPerColor >= 8) | |
389 | h->cupsBitsPerPixel = h->cupsBitsPerColor * 3; | |
390 | else | |
391 | h->cupsBitsPerPixel = h->cupsBitsPerColor * 4; | |
392 | } | |
393 | else | |
394 | h->cupsBitsPerPixel = h->cupsBitsPerColor; | |
395 | ||
396 | h->cupsNumColors = 3; | |
397 | break; | |
398 | ||
399 | case CUPS_CSPACE_KCMYcm : | |
f301802f | 400 | if (h->cupsBitsPerColor == 1) |
ef416fc2 | 401 | { |
402 | if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) | |
403 | h->cupsBitsPerPixel = 8; | |
404 | else | |
405 | h->cupsBitsPerPixel = 1; | |
406 | ||
407 | h->cupsNumColors = 6; | |
408 | break; | |
409 | } | |
410 | ||
411 | /* | |
412 | * Fall through to CMYK code... | |
413 | */ | |
414 | ||
415 | case CUPS_CSPACE_RGBA : | |
a74454a7 | 416 | case CUPS_CSPACE_RGBW : |
ef416fc2 | 417 | case CUPS_CSPACE_CMYK : |
418 | case CUPS_CSPACE_YMCK : | |
419 | case CUPS_CSPACE_KCMY : | |
420 | case CUPS_CSPACE_GMCK : | |
421 | case CUPS_CSPACE_GMCS : | |
422 | if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) | |
423 | h->cupsBitsPerPixel = h->cupsBitsPerColor * 4; | |
424 | else | |
425 | h->cupsBitsPerPixel = h->cupsBitsPerColor; | |
426 | ||
427 | h->cupsNumColors = 4; | |
428 | break; | |
88f9aafc MS |
429 | |
430 | case CUPS_CSPACE_DEVICE1 : | |
431 | case CUPS_CSPACE_DEVICE2 : | |
432 | case CUPS_CSPACE_DEVICE3 : | |
433 | case CUPS_CSPACE_DEVICE4 : | |
434 | case CUPS_CSPACE_DEVICE5 : | |
435 | case CUPS_CSPACE_DEVICE6 : | |
436 | case CUPS_CSPACE_DEVICE7 : | |
437 | case CUPS_CSPACE_DEVICE8 : | |
438 | case CUPS_CSPACE_DEVICE9 : | |
439 | case CUPS_CSPACE_DEVICEA : | |
440 | case CUPS_CSPACE_DEVICEB : | |
441 | case CUPS_CSPACE_DEVICEC : | |
442 | case CUPS_CSPACE_DEVICED : | |
443 | case CUPS_CSPACE_DEVICEE : | |
444 | case CUPS_CSPACE_DEVICEF : | |
445 | h->cupsNumColors = h->cupsColorSpace - CUPS_CSPACE_DEVICE1 + 1; | |
446 | ||
447 | if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) | |
448 | h->cupsBitsPerPixel = h->cupsBitsPerColor * h->cupsNumColors; | |
449 | else | |
450 | h->cupsBitsPerPixel = h->cupsBitsPerColor; | |
451 | break; | |
ef416fc2 | 452 | } |
453 | ||
454 | h->cupsBytesPerLine = (h->cupsBitsPerPixel * h->cupsWidth + 7) / 8; | |
455 | ||
456 | if (h->cupsColorOrder == CUPS_ORDER_BANDED) | |
457 | h->cupsBytesPerLine *= h->cupsNumColors; | |
458 | ||
459 | return (status); | |
460 | } | |
461 | ||
462 | ||
463 | /* | |
b86bc4cf | 464 | * '_cupsRasterExecPS()' - Execute PostScript code to initialize a page header. |
ef416fc2 | 465 | */ |
466 | ||
b86bc4cf | 467 | int /* O - 0 on success, -1 on error */ |
468 | _cupsRasterExecPS( | |
a74454a7 | 469 | cups_page_header2_t *h, /* O - Page header */ |
470 | int *preferred_bits,/* O - Preferred bits per color */ | |
b86bc4cf | 471 | const char *code) /* I - PS code to execute */ |
ef416fc2 | 472 | { |
b86bc4cf | 473 | _cups_ps_stack_t *st; /* PostScript value stack */ |
474 | _cups_ps_obj_t *obj; /* Object from top of stack */ | |
475 | char *codecopy, /* Copy of code */ | |
476 | *codeptr; /* Pointer into copy of code */ | |
477 | ||
ef416fc2 | 478 | |
b86bc4cf | 479 | DEBUG_printf(("_cupsRasterExecPS(h=%p, preferred_bits=%p, code=\"%s\")\n", |
480 | h, preferred_bits, code ? code : "(null)")); | |
ef416fc2 | 481 | |
482 | /* | |
b86bc4cf | 483 | * Copy the PostScript code and create a stack... |
ef416fc2 | 484 | */ |
485 | ||
b86bc4cf | 486 | if ((codecopy = strdup(code)) == NULL) |
f7deaa1a | 487 | { |
488 | _cupsRasterAddError("Unable to duplicate code string.\n"); | |
b86bc4cf | 489 | return (-1); |
f7deaa1a | 490 | } |
b86bc4cf | 491 | |
492 | if ((st = new_stack()) == NULL) | |
493 | { | |
f7deaa1a | 494 | _cupsRasterAddError("Unable to create stack.\n"); |
b86bc4cf | 495 | free(codecopy); |
ef416fc2 | 496 | return (-1); |
b86bc4cf | 497 | } |
ef416fc2 | 498 | |
499 | /* | |
b86bc4cf | 500 | * Parse the PS string until we run out of data... |
ef416fc2 | 501 | */ |
502 | ||
b86bc4cf | 503 | codeptr = codecopy; |
504 | ||
505 | while ((obj = scan_ps(st, &codeptr)) != NULL) | |
ef416fc2 | 506 | { |
b86bc4cf | 507 | #ifdef DEBUG |
ae71f5de | 508 | DEBUG_printf(("_cupsRasterExecPS: Stack (%d objects)\n", st->num_objs)); |
b86bc4cf | 509 | DEBUG_object(obj); |
b86bc4cf | 510 | #endif /* DEBUG */ |
511 | ||
512 | switch (obj->type) | |
513 | { | |
514 | default : | |
515 | /* Do nothing for regular values */ | |
516 | break; | |
517 | ||
518 | case CUPS_PS_CLEARTOMARK : | |
519 | pop_stack(st); | |
520 | ||
f7deaa1a | 521 | if (cleartomark_stack(st)) |
522 | _cupsRasterAddError("cleartomark: Stack underflow!\n"); | |
b86bc4cf | 523 | |
524 | #ifdef DEBUG | |
ae71f5de | 525 | DEBUG_puts(" dup: "); |
b86bc4cf | 526 | DEBUG_stack(st); |
527 | #endif /* DEBUG */ | |
528 | break; | |
529 | ||
530 | case CUPS_PS_COPY : | |
531 | pop_stack(st); | |
532 | if ((obj = pop_stack(st)) != NULL) | |
533 | { | |
534 | copy_stack(st, (int)obj->value.number); | |
535 | ||
536 | #ifdef DEBUG | |
ae71f5de | 537 | DEBUG_puts("_cupsRasterExecPS: copy"); |
b86bc4cf | 538 | DEBUG_stack(st); |
539 | #endif /* DEBUG */ | |
540 | } | |
541 | break; | |
542 | ||
543 | case CUPS_PS_DUP : | |
544 | pop_stack(st); | |
545 | copy_stack(st, 1); | |
546 | ||
547 | #ifdef DEBUG | |
ae71f5de | 548 | DEBUG_puts("_cupsRasterExecPS: dup"); |
b86bc4cf | 549 | DEBUG_stack(st); |
550 | #endif /* DEBUG */ | |
551 | break; | |
552 | ||
553 | case CUPS_PS_INDEX : | |
554 | pop_stack(st); | |
555 | if ((obj = pop_stack(st)) != NULL) | |
556 | { | |
557 | index_stack(st, (int)obj->value.number); | |
558 | ||
559 | #ifdef DEBUG | |
ae71f5de | 560 | DEBUG_puts("_cupsRasterExecPS: index"); |
b86bc4cf | 561 | DEBUG_stack(st); |
562 | #endif /* DEBUG */ | |
563 | } | |
564 | break; | |
565 | ||
566 | case CUPS_PS_POP : | |
567 | pop_stack(st); | |
568 | pop_stack(st); | |
569 | ||
570 | #ifdef DEBUG | |
ae71f5de | 571 | DEBUG_puts("_cupsRasterExecPS: pop"); |
b86bc4cf | 572 | DEBUG_stack(st); |
573 | #endif /* DEBUG */ | |
574 | break; | |
575 | ||
576 | case CUPS_PS_ROLL : | |
577 | pop_stack(st); | |
578 | if ((obj = pop_stack(st)) != NULL) | |
579 | { | |
580 | int c; /* Count */ | |
ef416fc2 | 581 | |
ef416fc2 | 582 | |
b86bc4cf | 583 | c = (int)obj->value.number; |
584 | ||
585 | if ((obj = pop_stack(st)) != NULL) | |
586 | { | |
587 | roll_stack(st, (int)obj->value.number, c); | |
588 | ||
589 | #ifdef DEBUG | |
ae71f5de | 590 | DEBUG_puts("_cupsRasterExecPS: roll"); |
b86bc4cf | 591 | DEBUG_stack(st); |
592 | #endif /* DEBUG */ | |
593 | } | |
594 | } | |
595 | break; | |
596 | ||
597 | case CUPS_PS_SETPAGEDEVICE : | |
598 | pop_stack(st); | |
599 | setpagedevice(st, h, preferred_bits); | |
600 | ||
601 | #ifdef DEBUG | |
ae71f5de | 602 | DEBUG_puts("_cupsRasterExecPS: setpagedevice"); |
b86bc4cf | 603 | DEBUG_stack(st); |
604 | #endif /* DEBUG */ | |
605 | break; | |
606 | ||
607 | case CUPS_PS_START_PROC : | |
608 | case CUPS_PS_END_PROC : | |
609 | case CUPS_PS_STOPPED : | |
610 | pop_stack(st); | |
611 | break; | |
612 | ||
613 | case CUPS_PS_OTHER : | |
f7deaa1a | 614 | _cupsRasterAddError("Unknown operator \"%s\"!\n", obj->value.other); |
ae71f5de MS |
615 | DEBUG_printf(("_cupsRasterExecPS: Unknown operator \"%s\"!\n", |
616 | obj->value.other)); | |
b86bc4cf | 617 | break; |
618 | } | |
619 | ||
91c84a35 | 620 | if (obj && obj->type == CUPS_PS_OTHER) |
ef416fc2 | 621 | break; |
b86bc4cf | 622 | } |
623 | ||
624 | /* | |
625 | * Cleanup... | |
626 | */ | |
627 | ||
628 | free(codecopy); | |
629 | ||
630 | if (st->num_objs > 0) | |
631 | { | |
f7deaa1a | 632 | error_stack(st, "Stack not empty:"); |
633 | ||
b86bc4cf | 634 | #ifdef DEBUG |
ae71f5de | 635 | DEBUG_puts("_cupsRasterExecPS: Stack not empty:"); |
b86bc4cf | 636 | DEBUG_stack(st); |
637 | #endif /* DEBUG */ | |
ef416fc2 | 638 | |
b86bc4cf | 639 | delete_stack(st); |
640 | ||
641 | return (-1); | |
642 | } | |
643 | ||
644 | delete_stack(st); | |
645 | ||
646 | /* | |
647 | * Return success... | |
648 | */ | |
649 | ||
650 | return (0); | |
651 | } | |
652 | ||
653 | ||
654 | /* | |
655 | * 'cleartomark_stack()' - Clear to the last mark ([) on the stack. | |
656 | */ | |
657 | ||
658 | static int /* O - 0 on success, -1 on error */ | |
659 | cleartomark_stack(_cups_ps_stack_t *st) /* I - Stack */ | |
660 | { | |
661 | _cups_ps_obj_t *obj; /* Current object on stack */ | |
662 | ||
663 | ||
664 | while ((obj = pop_stack(st)) != NULL) | |
665 | if (obj->type == CUPS_PS_START_ARRAY) | |
666 | break; | |
667 | ||
668 | return (obj ? 0 : -1); | |
669 | } | |
670 | ||
671 | ||
672 | /* | |
673 | * 'copy_stack()' - Copy the top N stack objects. | |
674 | */ | |
675 | ||
676 | static int /* O - 0 on success, -1 on error */ | |
677 | copy_stack(_cups_ps_stack_t *st, /* I - Stack */ | |
678 | int c) /* I - Number of objects to copy */ | |
679 | { | |
680 | int n; /* Index */ | |
681 | ||
682 | ||
683 | if (c < 0) | |
684 | return (-1); | |
685 | else if (c == 0) | |
686 | return (0); | |
687 | ||
688 | if ((n = st->num_objs - c) < 0) | |
689 | return (-1); | |
690 | ||
691 | while (c > 0) | |
692 | { | |
693 | if (!push_stack(st, st->objs + n)) | |
694 | return (-1); | |
695 | ||
696 | n ++; | |
697 | c --; | |
698 | } | |
699 | ||
700 | return (0); | |
701 | } | |
702 | ||
703 | ||
704 | /* | |
705 | * 'delete_stack()' - Free memory used by a stack. | |
706 | */ | |
707 | ||
708 | static void | |
709 | delete_stack(_cups_ps_stack_t *st) /* I - Stack */ | |
710 | { | |
711 | free(st->objs); | |
712 | free(st); | |
713 | } | |
714 | ||
715 | ||
f7deaa1a | 716 | /* |
717 | * 'error_object()' - Add an object's value to the current error message. | |
718 | */ | |
719 | ||
720 | static void | |
721 | error_object(_cups_ps_obj_t *obj) /* I - Object to add */ | |
722 | { | |
723 | switch (obj->type) | |
724 | { | |
725 | case CUPS_PS_NAME : | |
726 | _cupsRasterAddError(" /%s", obj->value.name); | |
727 | break; | |
728 | ||
729 | case CUPS_PS_NUMBER : | |
730 | _cupsRasterAddError(" %g", obj->value.number); | |
731 | break; | |
732 | ||
733 | case CUPS_PS_STRING : | |
734 | _cupsRasterAddError(" (%s)", obj->value.string); | |
735 | break; | |
736 | ||
737 | case CUPS_PS_BOOLEAN : | |
738 | if (obj->value.boolean) | |
739 | _cupsRasterAddError(" true"); | |
740 | else | |
741 | _cupsRasterAddError(" false"); | |
742 | break; | |
743 | ||
744 | case CUPS_PS_NULL : | |
745 | _cupsRasterAddError(" null"); | |
746 | break; | |
747 | ||
748 | case CUPS_PS_START_ARRAY : | |
749 | _cupsRasterAddError(" ["); | |
750 | break; | |
751 | ||
752 | case CUPS_PS_END_ARRAY : | |
753 | _cupsRasterAddError(" ]"); | |
754 | break; | |
755 | ||
756 | case CUPS_PS_START_DICT : | |
757 | _cupsRasterAddError(" <<"); | |
758 | break; | |
759 | ||
760 | case CUPS_PS_END_DICT : | |
761 | _cupsRasterAddError(" >>"); | |
762 | break; | |
763 | ||
764 | case CUPS_PS_START_PROC : | |
765 | _cupsRasterAddError(" {"); | |
766 | break; | |
767 | ||
768 | case CUPS_PS_END_PROC : | |
769 | _cupsRasterAddError(" }"); | |
770 | break; | |
771 | ||
772 | case CUPS_PS_COPY : | |
773 | _cupsRasterAddError(" --copy--"); | |
774 | break; | |
775 | ||
776 | case CUPS_PS_CLEARTOMARK : | |
777 | _cupsRasterAddError(" --cleartomark--"); | |
778 | break; | |
779 | ||
780 | case CUPS_PS_DUP : | |
781 | _cupsRasterAddError(" --dup--"); | |
782 | break; | |
783 | ||
784 | case CUPS_PS_INDEX : | |
785 | _cupsRasterAddError(" --index--"); | |
786 | break; | |
787 | ||
788 | case CUPS_PS_POP : | |
789 | _cupsRasterAddError(" --pop--"); | |
790 | break; | |
791 | ||
792 | case CUPS_PS_ROLL : | |
793 | _cupsRasterAddError(" --roll--"); | |
794 | break; | |
795 | ||
796 | case CUPS_PS_SETPAGEDEVICE : | |
797 | _cupsRasterAddError(" --setpagedevice--"); | |
798 | break; | |
799 | ||
800 | case CUPS_PS_STOPPED : | |
801 | _cupsRasterAddError(" --stopped--"); | |
802 | break; | |
803 | ||
804 | case CUPS_PS_OTHER : | |
805 | _cupsRasterAddError(" --%s--", obj->value.other); | |
806 | break; | |
807 | } | |
808 | } | |
809 | ||
810 | ||
811 | /* | |
812 | * 'error_stack()' - Add a stack to the current error message... | |
813 | */ | |
814 | ||
815 | static void | |
816 | error_stack(_cups_ps_stack_t *st, /* I - Stack */ | |
817 | const char *title) /* I - Title string */ | |
818 | { | |
819 | int c; /* Looping var */ | |
820 | _cups_ps_obj_t *obj; /* Current object on stack */ | |
821 | ||
822 | ||
85dda01c | 823 | _cupsRasterAddError("%s", title); |
f7deaa1a | 824 | |
825 | for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++) | |
826 | error_object(obj); | |
827 | ||
828 | _cupsRasterAddError("\n"); | |
829 | } | |
830 | ||
831 | ||
b86bc4cf | 832 | /* |
833 | * 'index_stack()' - Copy the Nth value on the stack. | |
834 | */ | |
835 | ||
836 | static _cups_ps_obj_t * /* O - New object */ | |
837 | index_stack(_cups_ps_stack_t *st, /* I - Stack */ | |
838 | int n) /* I - Object index */ | |
839 | { | |
840 | if (n < 0 || (n = st->num_objs - n - 1) < 0) | |
841 | return (NULL); | |
842 | ||
843 | return (push_stack(st, st->objs + n)); | |
844 | } | |
845 | ||
846 | ||
847 | /* | |
848 | * 'new_stack()' - Create a new stack. | |
849 | */ | |
850 | ||
851 | static _cups_ps_stack_t * /* O - New stack */ | |
852 | new_stack(void) | |
853 | { | |
854 | _cups_ps_stack_t *st; /* New stack */ | |
855 | ||
856 | ||
857 | if ((st = calloc(1, sizeof(_cups_ps_stack_t))) == NULL) | |
858 | return (NULL); | |
859 | ||
860 | st->alloc_objs = 32; | |
861 | ||
862 | if ((st->objs = calloc(32, sizeof(_cups_ps_obj_t))) == NULL) | |
863 | { | |
864 | free(st); | |
865 | return (NULL); | |
866 | } | |
867 | else | |
868 | return (st); | |
869 | } | |
870 | ||
871 | ||
872 | /* | |
873 | * 'pop_stock()' - Pop the top object off the stack. | |
874 | */ | |
875 | ||
876 | static _cups_ps_obj_t * /* O - Object */ | |
877 | pop_stack(_cups_ps_stack_t *st) /* I - Stack */ | |
878 | { | |
879 | if (st->num_objs > 0) | |
880 | { | |
881 | st->num_objs --; | |
882 | ||
883 | return (st->objs + st->num_objs); | |
884 | } | |
885 | else | |
886 | return (NULL); | |
887 | } | |
888 | ||
889 | ||
890 | /* | |
891 | * 'push_stack()' - Push an object on the stack. | |
892 | */ | |
893 | ||
894 | static _cups_ps_obj_t * /* O - New object */ | |
895 | push_stack(_cups_ps_stack_t *st, /* I - Stack */ | |
896 | _cups_ps_obj_t *obj) /* I - Object */ | |
897 | { | |
898 | _cups_ps_obj_t *temp; /* New object */ | |
899 | ||
900 | ||
901 | if (st->num_objs >= st->alloc_objs) | |
902 | { | |
903 | ||
904 | ||
905 | st->alloc_objs += 32; | |
906 | ||
907 | if ((temp = realloc(st->objs, st->alloc_objs * | |
908 | sizeof(_cups_ps_obj_t))) == NULL) | |
909 | return (NULL); | |
910 | ||
911 | st->objs = temp; | |
912 | memset(temp + st->num_objs, 0, 32 * sizeof(_cups_ps_obj_t)); | |
913 | } | |
914 | ||
915 | temp = st->objs + st->num_objs; | |
916 | st->num_objs ++; | |
917 | ||
918 | memcpy(temp, obj, sizeof(_cups_ps_obj_t)); | |
919 | ||
920 | return (temp); | |
921 | } | |
922 | ||
923 | ||
924 | /* | |
925 | * 'roll_stack()' - Rotate stack objects. | |
926 | */ | |
927 | ||
928 | static int /* O - 0 on success, -1 on error */ | |
929 | roll_stack(_cups_ps_stack_t *st, /* I - Stack */ | |
930 | int c, /* I - Number of objects */ | |
931 | int s) /* I - Amount to shift */ | |
932 | { | |
933 | _cups_ps_obj_t *temp; /* Temporary array of objects */ | |
934 | int n; /* Index into array */ | |
935 | ||
936 | ||
937 | DEBUG_printf((" roll_stack(st=%p, s=%d, c=%d)\n", st, s, c)); | |
938 | ||
939 | /* | |
940 | * Range check input... | |
941 | */ | |
942 | ||
943 | if (c < 0) | |
944 | return (-1); | |
945 | else if (c == 0) | |
946 | return (0); | |
947 | ||
948 | if ((n = st->num_objs - c) < 0) | |
949 | return (-1); | |
950 | ||
951 | s %= c; | |
952 | ||
953 | if (s == 0) | |
954 | return (0); | |
955 | ||
956 | /* | |
957 | * Copy N objects and move things around... | |
958 | */ | |
959 | ||
960 | if (s < 0) | |
961 | { | |
ef416fc2 | 962 | /* |
b86bc4cf | 963 | * Shift down... |
ef416fc2 | 964 | */ |
965 | ||
b86bc4cf | 966 | s = -s; |
ef416fc2 | 967 | |
b86bc4cf | 968 | if ((temp = calloc(s, sizeof(_cups_ps_obj_t))) == NULL) |
969 | return (-1); | |
ef416fc2 | 970 | |
b86bc4cf | 971 | memcpy(temp, st->objs + n, s * sizeof(_cups_ps_obj_t)); |
972 | memmove(st->objs + n, st->objs + n + s, (c - s) * sizeof(_cups_ps_obj_t)); | |
973 | memcpy(st->objs + n + c - s, temp, s * sizeof(_cups_ps_obj_t)); | |
974 | } | |
975 | else | |
976 | { | |
ef416fc2 | 977 | /* |
b86bc4cf | 978 | * Shift up... |
ef416fc2 | 979 | */ |
980 | ||
b86bc4cf | 981 | if ((temp = calloc(s, sizeof(_cups_ps_obj_t))) == NULL) |
982 | return (-1); | |
ef416fc2 | 983 | |
b86bc4cf | 984 | memcpy(temp, st->objs + n + c - s, s * sizeof(_cups_ps_obj_t)); |
985 | memmove(st->objs + n + s, st->objs + n, | |
986 | (c - s) * sizeof(_cups_ps_obj_t)); | |
987 | memcpy(st->objs + n, temp, s * sizeof(_cups_ps_obj_t)); | |
988 | } | |
ef416fc2 | 989 | |
b86bc4cf | 990 | free(temp); |
991 | ||
992 | return (0); | |
993 | } | |
ef416fc2 | 994 | |
ef416fc2 | 995 | |
b86bc4cf | 996 | /* |
997 | * 'scan_ps()' - Scan a string for the next PS object. | |
998 | */ | |
999 | ||
1000 | static _cups_ps_obj_t * /* O - New object or NULL on EOF */ | |
1001 | scan_ps(_cups_ps_stack_t *st, /* I - Stack */ | |
1002 | char **ptr) /* IO - String pointer */ | |
1003 | { | |
1004 | _cups_ps_obj_t obj; /* Current object */ | |
1005 | char *start, /* Start of object */ | |
1006 | *cur, /* Current position */ | |
1007 | *valptr, /* Pointer into value string */ | |
1008 | *valend; /* End of value string */ | |
1009 | int parens; /* Parenthesis nesting level */ | |
ef416fc2 | 1010 | |
ef416fc2 | 1011 | |
b86bc4cf | 1012 | /* |
1013 | * Skip leading whitespace... | |
1014 | */ | |
1015 | ||
1016 | for (cur = *ptr; *cur; cur ++) | |
1017 | { | |
1018 | if (*cur == '%') | |
ef416fc2 | 1019 | { |
1020 | /* | |
b86bc4cf | 1021 | * Comment, skip to end of line... |
ef416fc2 | 1022 | */ |
1023 | ||
b86bc4cf | 1024 | for (cur ++; *cur && *cur != '\n' && *cur != '\r'; cur ++); |
b0f6947b MS |
1025 | |
1026 | if (!*cur) | |
1027 | cur --; | |
b86bc4cf | 1028 | } |
1029 | else if (!isspace(*cur & 255)) | |
1030 | break; | |
1031 | } | |
ef416fc2 | 1032 | |
b86bc4cf | 1033 | if (!*cur) |
1034 | { | |
1035 | *ptr = NULL; | |
ef416fc2 | 1036 | |
b86bc4cf | 1037 | return (NULL); |
1038 | } | |
ef416fc2 | 1039 | |
b86bc4cf | 1040 | /* |
1041 | * See what we have... | |
1042 | */ | |
ef416fc2 | 1043 | |
b86bc4cf | 1044 | memset(&obj, 0, sizeof(obj)); |
ef416fc2 | 1045 | |
b86bc4cf | 1046 | switch (*cur) |
1047 | { | |
1048 | case '(' : /* (string) */ | |
1049 | obj.type = CUPS_PS_STRING; | |
1050 | start = cur; | |
1051 | ||
1052 | for (cur ++, parens = 1, valptr = obj.value.string, | |
1053 | valend = obj.value.string + sizeof(obj.value.string) - 1; | |
1054 | *cur; | |
1055 | cur ++) | |
1056 | { | |
1057 | if (*cur == ')' && parens == 1) | |
1058 | break; | |
1059 | ||
1060 | if (*cur == '(') | |
1061 | parens ++; | |
1062 | else if (*cur == ')') | |
1063 | parens --; | |
1064 | ||
1065 | if (valptr >= valend) | |
1066 | { | |
1067 | *ptr = start; | |
1068 | ||
1069 | return (NULL); | |
1070 | } | |
1071 | ||
1072 | if (*cur == '\\') | |
1073 | { | |
1074 | /* | |
1075 | * Decode escaped character... | |
1076 | */ | |
1077 | ||
1078 | cur ++; | |
1079 | ||
1080 | if (*cur == 'b') | |
1081 | *valptr++ = '\b'; | |
1082 | else if (*cur == 'f') | |
1083 | *valptr++ = '\f'; | |
1084 | else if (*cur == 'n') | |
1085 | *valptr++ = '\n'; | |
1086 | else if (*cur == 'r') | |
1087 | *valptr++ = '\r'; | |
1088 | else if (*cur == 't') | |
1089 | *valptr++ = '\t'; | |
1090 | else if (*cur >= '0' && *cur <= '7') | |
1091 | { | |
1092 | int ch = *cur - '0'; | |
1093 | ||
1094 | if (cur[1] >= '0' && cur[1] <= '7') | |
1095 | { | |
1096 | cur ++; | |
1097 | ch = (ch << 3) + *cur - '0'; | |
1098 | } | |
1099 | ||
1100 | if (cur[1] >= '0' && cur[1] <= '7') | |
1101 | { | |
1102 | cur ++; | |
1103 | ch = (ch << 3) + *cur - '0'; | |
1104 | } | |
1105 | ||
1106 | *valptr++ = ch; | |
1107 | } | |
1108 | else if (*cur == '\r') | |
1109 | { | |
1110 | if (cur[1] == '\n') | |
1111 | cur ++; | |
1112 | } | |
1113 | else if (*cur != '\n') | |
1114 | *valptr++ = *cur; | |
1115 | } | |
1116 | else | |
1117 | *valptr++ = *cur; | |
1118 | } | |
1119 | ||
1120 | if (*cur != ')') | |
1121 | { | |
1122 | *ptr = start; | |
1123 | ||
1124 | return (NULL); | |
1125 | } | |
1126 | ||
1127 | cur ++; | |
1128 | break; | |
1129 | ||
1130 | case '[' : /* Start array */ | |
1131 | obj.type = CUPS_PS_START_ARRAY; | |
1132 | cur ++; | |
1133 | break; | |
1134 | ||
1135 | case ']' : /* End array */ | |
1136 | obj.type = CUPS_PS_END_ARRAY; | |
1137 | cur ++; | |
1138 | break; | |
1139 | ||
1140 | case '<' : /* Start dictionary or hex string */ | |
1141 | if (cur[1] == '<') | |
1142 | { | |
1143 | obj.type = CUPS_PS_START_DICT; | |
1144 | cur += 2; | |
1145 | } | |
ef416fc2 | 1146 | else |
b86bc4cf | 1147 | { |
1148 | obj.type = CUPS_PS_STRING; | |
1149 | start = cur; | |
1150 | ||
1151 | for (cur ++, valptr = obj.value.string, | |
1152 | valend = obj.value.string + sizeof(obj.value.string) - 1; | |
1153 | *cur; | |
1154 | cur ++) | |
1155 | { | |
1156 | int ch; /* Current character */ | |
1157 | ||
1158 | ||
1159 | ||
1160 | if (*cur == '>') | |
1161 | break; | |
1162 | else if (valptr >= valend || !isxdigit(*cur & 255)) | |
1163 | { | |
1164 | *ptr = start; | |
1165 | return (NULL); | |
1166 | } | |
1167 | ||
1168 | if (*cur >= '0' && *cur <= '9') | |
1169 | ch = (*cur - '0') << 4; | |
1170 | else | |
1171 | ch = (tolower(*cur) - 'a' + 10) << 4; | |
1172 | ||
1173 | if (isxdigit(cur[1] & 255)) | |
1174 | { | |
1175 | cur ++; | |
1176 | ||
1177 | if (*cur >= '0' && *cur <= '9') | |
1178 | ch |= *cur - '0'; | |
1179 | else | |
1180 | ch |= tolower(*cur) - 'a' + 10; | |
1181 | } | |
1182 | ||
1183 | *valptr++ = ch; | |
1184 | } | |
1185 | ||
1186 | if (*cur != '>') | |
1187 | { | |
1188 | *ptr = start; | |
1189 | return (NULL); | |
1190 | } | |
1191 | ||
1192 | cur ++; | |
1193 | } | |
1194 | break; | |
ef416fc2 | 1195 | |
b86bc4cf | 1196 | case '>' : /* End dictionary? */ |
1197 | if (cur[1] == '>') | |
1198 | { | |
1199 | obj.type = CUPS_PS_END_DICT; | |
1200 | cur += 2; | |
1201 | } | |
1202 | else | |
1203 | { | |
1204 | obj.type = CUPS_PS_OTHER; | |
1205 | obj.value.other[0] = *cur; | |
1206 | ||
1207 | cur ++; | |
1208 | } | |
1209 | break; | |
1210 | ||
1211 | case '{' : /* Start procedure */ | |
1212 | obj.type = CUPS_PS_START_PROC; | |
1213 | cur ++; | |
1214 | break; | |
1215 | ||
1216 | case '}' : /* End procedure */ | |
1217 | obj.type = CUPS_PS_END_PROC; | |
1218 | cur ++; | |
1219 | break; | |
1220 | ||
1221 | case '-' : /* Possible number */ | |
1222 | case '+' : | |
1223 | if (!isdigit(cur[1] & 255) && cur[1] != '.') | |
1224 | { | |
1225 | obj.type = CUPS_PS_OTHER; | |
1226 | obj.value.other[0] = *cur; | |
1227 | ||
1228 | cur ++; | |
1229 | break; | |
1230 | } | |
1231 | ||
1232 | case '0' : /* Number */ | |
1233 | case '1' : | |
1234 | case '2' : | |
1235 | case '3' : | |
1236 | case '4' : | |
1237 | case '5' : | |
1238 | case '6' : | |
1239 | case '7' : | |
1240 | case '8' : | |
1241 | case '9' : | |
1242 | case '.' : | |
1243 | obj.type = CUPS_PS_NUMBER; | |
1244 | ||
1245 | start = cur; | |
1246 | for (cur ++; *cur; cur ++) | |
1247 | if (!isdigit(*cur & 255)) | |
1248 | break; | |
1249 | ||
1250 | if (*cur == '#') | |
1251 | { | |
1252 | /* | |
1253 | * Integer with radix... | |
1254 | */ | |
1255 | ||
1256 | obj.value.number = strtol(cur + 1, &cur, atoi(start)); | |
1257 | break; | |
1258 | } | |
1259 | else if (strchr(".Ee()<>[]{}/%", *cur) || isspace(*cur & 255)) | |
1260 | { | |
1261 | /* | |
1262 | * Integer or real number... | |
1263 | */ | |
ef416fc2 | 1264 | |
b86bc4cf | 1265 | obj.value.number = _cupsStrScand(start, &cur, localeconv()); |
1266 | break; | |
1267 | } | |
1268 | else | |
1269 | cur = start; | |
ef416fc2 | 1270 | |
b86bc4cf | 1271 | default : /* Operator/variable name */ |
1272 | start = cur; | |
1273 | ||
1274 | if (*cur == '/') | |
1275 | { | |
1276 | obj.type = CUPS_PS_NAME; | |
1277 | valptr = obj.value.name; | |
1278 | valend = obj.value.name + sizeof(obj.value.name) - 1; | |
1279 | cur ++; | |
1280 | } | |
ef416fc2 | 1281 | else |
b86bc4cf | 1282 | { |
1283 | obj.type = CUPS_PS_OTHER; | |
1284 | valptr = obj.value.other; | |
1285 | valend = obj.value.other + sizeof(obj.value.other) - 1; | |
1286 | } | |
ef416fc2 | 1287 | |
b86bc4cf | 1288 | while (*cur) |
1289 | { | |
1290 | if (strchr("()<>[]{}/%", *cur) || isspace(*cur & 255)) | |
1291 | break; | |
1292 | else if (valptr < valend) | |
1293 | *valptr++ = *cur++; | |
1294 | else | |
1295 | { | |
1296 | *ptr = start; | |
1297 | return (NULL); | |
1298 | } | |
1299 | } | |
1300 | ||
1301 | if (obj.type == CUPS_PS_OTHER) | |
1302 | { | |
1303 | if (!strcmp(obj.value.other, "true")) | |
1304 | { | |
1305 | obj.type = CUPS_PS_BOOLEAN; | |
1306 | obj.value.boolean = 1; | |
1307 | } | |
1308 | else if (!strcmp(obj.value.other, "false")) | |
1309 | { | |
1310 | obj.type = CUPS_PS_BOOLEAN; | |
1311 | obj.value.boolean = 0; | |
1312 | } | |
1313 | else if (!strcmp(obj.value.other, "null")) | |
1314 | obj.type = CUPS_PS_NULL; | |
1315 | else if (!strcmp(obj.value.other, "cleartomark")) | |
1316 | obj.type = CUPS_PS_CLEARTOMARK; | |
1317 | else if (!strcmp(obj.value.other, "copy")) | |
1318 | obj.type = CUPS_PS_COPY; | |
1319 | else if (!strcmp(obj.value.other, "dup")) | |
1320 | obj.type = CUPS_PS_DUP; | |
1321 | else if (!strcmp(obj.value.other, "index")) | |
1322 | obj.type = CUPS_PS_INDEX; | |
1323 | else if (!strcmp(obj.value.other, "pop")) | |
1324 | obj.type = CUPS_PS_POP; | |
1325 | else if (!strcmp(obj.value.other, "roll")) | |
1326 | obj.type = CUPS_PS_ROLL; | |
1327 | else if (!strcmp(obj.value.other, "setpagedevice")) | |
1328 | obj.type = CUPS_PS_SETPAGEDEVICE; | |
1329 | else if (!strcmp(obj.value.other, "stopped")) | |
1330 | obj.type = CUPS_PS_STOPPED; | |
1331 | } | |
1332 | break; | |
1333 | } | |
1334 | ||
1335 | /* | |
1336 | * Save the current position in the string and return the new object... | |
1337 | */ | |
1338 | ||
1339 | *ptr = cur; | |
1340 | ||
1341 | return (push_stack(st, &obj)); | |
1342 | } | |
1343 | ||
1344 | ||
1345 | /* | |
1346 | * 'setpagedevice()' - Simulate the PostScript setpagedevice operator. | |
1347 | */ | |
1348 | ||
1349 | static int /* O - 0 on success, -1 on error */ | |
1350 | setpagedevice( | |
1351 | _cups_ps_stack_t *st, /* I - Stack */ | |
1352 | cups_page_header2_t *h, /* O - Page header */ | |
1353 | int *preferred_bits)/* O - Preferred bits per color */ | |
1354 | { | |
1355 | int i; /* Index into array */ | |
1356 | _cups_ps_obj_t *obj, /* Current object */ | |
1357 | *end; /* End of dictionary */ | |
1358 | const char *name; /* Attribute name */ | |
1359 | ||
1360 | ||
1361 | /* | |
1362 | * Make sure we have a dictionary on the stack... | |
1363 | */ | |
1364 | ||
1365 | if (st->num_objs == 0) | |
1366 | return (-1); | |
1367 | ||
1368 | obj = end = st->objs + st->num_objs - 1; | |
1369 | ||
1370 | if (obj->type != CUPS_PS_END_DICT) | |
1371 | return (-1); | |
1372 | ||
1373 | obj --; | |
1374 | ||
1375 | while (obj > st->objs) | |
1376 | { | |
1377 | if (obj->type == CUPS_PS_START_DICT) | |
1378 | break; | |
1379 | ||
1380 | obj --; | |
1381 | } | |
1382 | ||
1383 | if (obj < st->objs) | |
1384 | return (-1); | |
ef416fc2 | 1385 | |
b86bc4cf | 1386 | /* |
1387 | * Found the start of the dictionary, empty the stack to this point... | |
1388 | */ | |
1389 | ||
1390 | st->num_objs = obj - st->objs; | |
1391 | ||
1392 | /* | |
1393 | * Now pull /name and value pairs from the dictionary... | |
1394 | */ | |
1395 | ||
ae71f5de | 1396 | DEBUG_puts("setpagedevice: Dictionary:"); |
b86bc4cf | 1397 | |
1398 | for (obj ++; obj < end; obj ++) | |
1399 | { | |
ef416fc2 | 1400 | /* |
b86bc4cf | 1401 | * Grab the name... |
ef416fc2 | 1402 | */ |
1403 | ||
b86bc4cf | 1404 | if (obj->type != CUPS_PS_NAME) |
1405 | return (-1); | |
1406 | ||
1407 | name = obj->value.name; | |
1408 | obj ++; | |
1409 | ||
1410 | #ifdef DEBUG | |
ae71f5de | 1411 | DEBUG_printf(("setpagedevice: /%s ", name)); |
b86bc4cf | 1412 | DEBUG_object(obj); |
b86bc4cf | 1413 | #endif /* DEBUG */ |
1414 | ||
1415 | /* | |
1416 | * Then grab the value... | |
1417 | */ | |
1418 | ||
1419 | if (!strcmp(name, "MediaClass") && obj->type == CUPS_PS_STRING) | |
1420 | strlcpy(h->MediaClass, obj->value.string, sizeof(h->MediaClass)); | |
1421 | else if (!strcmp(name, "MediaColor") && obj->type == CUPS_PS_STRING) | |
1422 | strlcpy(h->MediaColor, obj->value.string, sizeof(h->MediaColor)); | |
1423 | else if (!strcmp(name, "MediaType") && obj->type == CUPS_PS_STRING) | |
1424 | strlcpy(h->MediaType, obj->value.string, sizeof(h->MediaType)); | |
1425 | else if (!strcmp(name, "OutputType") && obj->type == CUPS_PS_STRING) | |
1426 | strlcpy(h->OutputType, obj->value.string, sizeof(h->OutputType)); | |
1427 | else if (!strcmp(name, "AdvanceDistance") && obj->type == CUPS_PS_NUMBER) | |
1428 | h->AdvanceDistance = (unsigned)obj->value.number; | |
1429 | else if (!strcmp(name, "AdvanceMedia") && obj->type == CUPS_PS_NUMBER) | |
1430 | h->AdvanceMedia = (unsigned)obj->value.number; | |
1431 | else if (!strcmp(name, "Collate") && obj->type == CUPS_PS_BOOLEAN) | |
1432 | h->Collate = (unsigned)obj->value.boolean; | |
1433 | else if (!strcmp(name, "CutMedia") && obj->type == CUPS_PS_NUMBER) | |
1434 | h->CutMedia = (cups_cut_t)(unsigned)obj->value.number; | |
1435 | else if (!strcmp(name, "Duplex") && obj->type == CUPS_PS_BOOLEAN) | |
1436 | h->Duplex = (unsigned)obj->value.boolean; | |
1437 | else if (!strcmp(name, "HWResolution") && obj->type == CUPS_PS_START_ARRAY) | |
ef416fc2 | 1438 | { |
b86bc4cf | 1439 | if (obj[1].type == CUPS_PS_NUMBER && obj[2].type == CUPS_PS_NUMBER && |
1440 | obj[3].type == CUPS_PS_END_ARRAY) | |
1441 | { | |
1442 | h->HWResolution[0] = (unsigned)obj[1].value.number; | |
1443 | h->HWResolution[1] = (unsigned)obj[2].value.number; | |
1444 | obj += 3; | |
1445 | } | |
1446 | else | |
ef416fc2 | 1447 | return (-1); |
1448 | } | |
b86bc4cf | 1449 | else if (!strcmp(name, "InsertSheet") && obj->type == CUPS_PS_BOOLEAN) |
1450 | h->InsertSheet = (unsigned)obj->value.boolean; | |
1451 | else if (!strcmp(name, "Jog") && obj->type == CUPS_PS_NUMBER) | |
1452 | h->Jog = (unsigned)obj->value.number; | |
1453 | else if (!strcmp(name, "LeadingEdge") && obj->type == CUPS_PS_NUMBER) | |
1454 | h->LeadingEdge = (unsigned)obj->value.number; | |
1455 | else if (!strcmp(name, "ManualFeed") && obj->type == CUPS_PS_BOOLEAN) | |
1456 | h->ManualFeed = (unsigned)obj->value.boolean; | |
09a101d6 | 1457 | else if ((!strcmp(name, "cupsMediaPosition") || |
b86bc4cf | 1458 | !strcmp(name, "MediaPosition")) && obj->type == CUPS_PS_NUMBER) |
09a101d6 | 1459 | { |
1460 | /* | |
1461 | * cupsMediaPosition is supported for backwards compatibility only. | |
1462 | * We added it back in the Ghostscript 5.50 days to work around a | |
1463 | * bug in Ghostscript WRT handling of MediaPosition and setpagedevice. | |
1464 | * | |
1465 | * All new development should set MediaPosition... | |
1466 | */ | |
1467 | ||
b86bc4cf | 1468 | h->MediaPosition = (unsigned)obj->value.number; |
09a101d6 | 1469 | } |
b86bc4cf | 1470 | else if (!strcmp(name, "MediaWeight") && obj->type == CUPS_PS_NUMBER) |
1471 | h->MediaWeight = (unsigned)obj->value.number; | |
1472 | else if (!strcmp(name, "MirrorPrint") && obj->type == CUPS_PS_BOOLEAN) | |
1473 | h->MirrorPrint = (unsigned)obj->value.boolean; | |
1474 | else if (!strcmp(name, "NegativePrint") && obj->type == CUPS_PS_BOOLEAN) | |
1475 | h->NegativePrint = (unsigned)obj->value.boolean; | |
1476 | else if (!strcmp(name, "NumCopies") && obj->type == CUPS_PS_NUMBER) | |
1477 | h->NumCopies = (unsigned)obj->value.number; | |
1478 | else if (!strcmp(name, "Orientation") && obj->type == CUPS_PS_NUMBER) | |
1479 | h->Orientation = (unsigned)obj->value.number; | |
1480 | else if (!strcmp(name, "OutputFaceUp") && obj->type == CUPS_PS_BOOLEAN) | |
1481 | h->OutputFaceUp = (unsigned)obj->value.boolean; | |
1482 | else if (!strcmp(name, "PageSize") && obj->type == CUPS_PS_START_ARRAY) | |
ef416fc2 | 1483 | { |
b86bc4cf | 1484 | if (obj[1].type == CUPS_PS_NUMBER && obj[2].type == CUPS_PS_NUMBER && |
1485 | obj[3].type == CUPS_PS_END_ARRAY) | |
1486 | { | |
c8fef167 MS |
1487 | h->cupsPageSize[0] = (float)obj[1].value.number; |
1488 | h->cupsPageSize[1] = (float)obj[2].value.number; | |
b86bc4cf | 1489 | |
1490 | h->PageSize[0] = (unsigned)obj[1].value.number; | |
1491 | h->PageSize[1] = (unsigned)obj[2].value.number; | |
1492 | ||
1493 | obj += 3; | |
1494 | } | |
1495 | else | |
fa73b229 | 1496 | return (-1); |
ef416fc2 | 1497 | } |
b86bc4cf | 1498 | else if (!strcmp(name, "Separations") && obj->type == CUPS_PS_BOOLEAN) |
1499 | h->Separations = (unsigned)obj->value.boolean; | |
1500 | else if (!strcmp(name, "TraySwitch") && obj->type == CUPS_PS_BOOLEAN) | |
1501 | h->TraySwitch = (unsigned)obj->value.boolean; | |
1502 | else if (!strcmp(name, "Tumble") && obj->type == CUPS_PS_BOOLEAN) | |
1503 | h->Tumble = (unsigned)obj->value.boolean; | |
1504 | else if (!strcmp(name, "cupsMediaType") && obj->type == CUPS_PS_NUMBER) | |
1505 | h->cupsMediaType = (unsigned)obj->value.number; | |
1506 | else if (!strcmp(name, "cupsBitsPerColor") && obj->type == CUPS_PS_NUMBER) | |
1507 | h->cupsBitsPerColor = (unsigned)obj->value.number; | |
1508 | else if (!strcmp(name, "cupsPreferredBitsPerColor") && | |
1509 | obj->type == CUPS_PS_NUMBER) | |
1510 | *preferred_bits = (int)obj->value.number; | |
1511 | else if (!strcmp(name, "cupsColorOrder") && obj->type == CUPS_PS_NUMBER) | |
1512 | h->cupsColorOrder = (cups_order_t)(unsigned)obj->value.number; | |
1513 | else if (!strcmp(name, "cupsColorSpace") && obj->type == CUPS_PS_NUMBER) | |
1514 | h->cupsColorSpace = (cups_cspace_t)(unsigned)obj->value.number; | |
1515 | else if (!strcmp(name, "cupsCompression") && obj->type == CUPS_PS_NUMBER) | |
1516 | h->cupsCompression = (unsigned)obj->value.number; | |
1517 | else if (!strcmp(name, "cupsRowCount") && obj->type == CUPS_PS_NUMBER) | |
1518 | h->cupsRowCount = (unsigned)obj->value.number; | |
1519 | else if (!strcmp(name, "cupsRowFeed") && obj->type == CUPS_PS_NUMBER) | |
1520 | h->cupsRowFeed = (unsigned)obj->value.number; | |
1521 | else if (!strcmp(name, "cupsRowStep") && obj->type == CUPS_PS_NUMBER) | |
1522 | h->cupsRowStep = (unsigned)obj->value.number; | |
923edb68 | 1523 | else if (!strcmp(name, "cupsBorderlessScalingFactor") && |
b86bc4cf | 1524 | obj->type == CUPS_PS_NUMBER) |
c8fef167 | 1525 | h->cupsBorderlessScalingFactor = (float)obj->value.number; |
b86bc4cf | 1526 | else if (!strncmp(name, "cupsInteger", 11) && obj->type == CUPS_PS_NUMBER) |
ef416fc2 | 1527 | { |
b86bc4cf | 1528 | if ((i = atoi(name + 11)) < 0 || i > 15) |
ef416fc2 | 1529 | return (-1); |
1530 | ||
b86bc4cf | 1531 | h->cupsInteger[i] = (unsigned)obj->value.number; |
ef416fc2 | 1532 | } |
b86bc4cf | 1533 | else if (!strncmp(name, "cupsReal", 8) && obj->type == CUPS_PS_NUMBER) |
ef416fc2 | 1534 | { |
b86bc4cf | 1535 | if ((i = atoi(name + 8)) < 0 || i > 15) |
ef416fc2 | 1536 | return (-1); |
1537 | ||
c8fef167 | 1538 | h->cupsReal[i] = (float)obj->value.number; |
ef416fc2 | 1539 | } |
b86bc4cf | 1540 | else if (!strncmp(name, "cupsString", 10) && obj->type == CUPS_PS_STRING) |
ef416fc2 | 1541 | { |
b86bc4cf | 1542 | if ((i = atoi(name + 10)) < 0 || i > 15) |
ef416fc2 | 1543 | return (-1); |
1544 | ||
b86bc4cf | 1545 | strlcpy(h->cupsString[i], obj->value.string, sizeof(h->cupsString[i])); |
ef416fc2 | 1546 | } |
b86bc4cf | 1547 | else if (!strcmp(name, "cupsMarkerType") && obj->type == CUPS_PS_STRING) |
1548 | strlcpy(h->cupsMarkerType, obj->value.string, sizeof(h->cupsMarkerType)); | |
1549 | else if (!strcmp(name, "cupsPageSizeName") && obj->type == CUPS_PS_STRING) | |
1550 | strlcpy(h->cupsPageSizeName, obj->value.string, | |
1551 | sizeof(h->cupsPageSizeName)); | |
1552 | else if (!strcmp(name, "cupsRenderingIntent") && | |
1553 | obj->type == CUPS_PS_STRING) | |
1554 | strlcpy(h->cupsRenderingIntent, obj->value.string, | |
1555 | sizeof(h->cupsRenderingIntent)); | |
1556 | else | |
ef416fc2 | 1557 | { |
b86bc4cf | 1558 | /* |
1559 | * Ignore unknown name+value... | |
1560 | */ | |
1561 | ||
1562 | DEBUG_printf((" Unknown name (\"%s\") or value...\n", name)); | |
1563 | ||
1564 | while (obj[1].type != CUPS_PS_NAME && obj < end) | |
1565 | obj ++; | |
ef416fc2 | 1566 | } |
ef416fc2 | 1567 | } |
1568 | ||
ef416fc2 | 1569 | return (0); |
1570 | } | |
1571 | ||
1572 | ||
b86bc4cf | 1573 | #ifdef DEBUG |
1574 | /* | |
1575 | * 'DEBUG_object()' - Print an object's value... | |
1576 | */ | |
1577 | ||
1578 | static void | |
1579 | DEBUG_object(_cups_ps_obj_t *obj) /* I - Object to print */ | |
1580 | { | |
1581 | switch (obj->type) | |
1582 | { | |
1583 | case CUPS_PS_NAME : | |
ae71f5de | 1584 | DEBUG_printf(("/%s\n", obj->value.name)); |
b86bc4cf | 1585 | break; |
1586 | ||
1587 | case CUPS_PS_NUMBER : | |
ae71f5de | 1588 | DEBUG_printf(("%g\n", obj->value.number)); |
b86bc4cf | 1589 | break; |
1590 | ||
1591 | case CUPS_PS_STRING : | |
ae71f5de | 1592 | DEBUG_printf(("(%s)\n", obj->value.string)); |
b86bc4cf | 1593 | break; |
1594 | ||
1595 | case CUPS_PS_BOOLEAN : | |
1596 | if (obj->value.boolean) | |
ae71f5de | 1597 | DEBUG_puts("true"); |
b86bc4cf | 1598 | else |
ae71f5de | 1599 | DEBUG_puts("false"); |
b86bc4cf | 1600 | break; |
1601 | ||
1602 | case CUPS_PS_NULL : | |
ae71f5de | 1603 | DEBUG_puts("null"); |
b86bc4cf | 1604 | break; |
1605 | ||
1606 | case CUPS_PS_START_ARRAY : | |
ae71f5de | 1607 | DEBUG_puts("["); |
b86bc4cf | 1608 | break; |
1609 | ||
1610 | case CUPS_PS_END_ARRAY : | |
ae71f5de | 1611 | DEBUG_puts("]"); |
b86bc4cf | 1612 | break; |
1613 | ||
1614 | case CUPS_PS_START_DICT : | |
ae71f5de | 1615 | DEBUG_puts("<<"); |
b86bc4cf | 1616 | break; |
1617 | ||
1618 | case CUPS_PS_END_DICT : | |
ae71f5de | 1619 | DEBUG_puts(">>"); |
b86bc4cf | 1620 | break; |
1621 | ||
1622 | case CUPS_PS_START_PROC : | |
ae71f5de | 1623 | DEBUG_puts("{"); |
b86bc4cf | 1624 | break; |
1625 | ||
1626 | case CUPS_PS_END_PROC : | |
ae71f5de | 1627 | DEBUG_puts("}"); |
b86bc4cf | 1628 | break; |
1629 | ||
1630 | case CUPS_PS_CLEARTOMARK : | |
ae71f5de | 1631 | DEBUG_puts("--cleartomark--"); |
b86bc4cf | 1632 | break; |
1633 | ||
1634 | case CUPS_PS_COPY : | |
ae71f5de | 1635 | DEBUG_puts("--copy--"); |
b86bc4cf | 1636 | break; |
1637 | ||
1638 | case CUPS_PS_DUP : | |
ae71f5de | 1639 | DEBUG_puts("--dup--"); |
b86bc4cf | 1640 | break; |
1641 | ||
1642 | case CUPS_PS_INDEX : | |
ae71f5de | 1643 | DEBUG_puts("--index--"); |
b86bc4cf | 1644 | break; |
1645 | ||
1646 | case CUPS_PS_POP : | |
ae71f5de | 1647 | DEBUG_puts("--pop--"); |
b86bc4cf | 1648 | break; |
1649 | ||
1650 | case CUPS_PS_ROLL : | |
ae71f5de | 1651 | DEBUG_puts("--roll--"); |
b86bc4cf | 1652 | break; |
1653 | ||
1654 | case CUPS_PS_SETPAGEDEVICE : | |
ae71f5de | 1655 | DEBUG_puts("--setpagedevice--"); |
b86bc4cf | 1656 | break; |
1657 | ||
1658 | case CUPS_PS_STOPPED : | |
ae71f5de | 1659 | DEBUG_puts("--stopped--"); |
b86bc4cf | 1660 | break; |
1661 | ||
1662 | case CUPS_PS_OTHER : | |
ae71f5de | 1663 | DEBUG_printf(("--%s--\n", obj->value.other)); |
b86bc4cf | 1664 | break; |
1665 | } | |
1666 | } | |
1667 | ||
1668 | ||
1669 | /* | |
1670 | * 'DEBUG_stack()' - Print a stack... | |
1671 | */ | |
1672 | ||
1673 | static void | |
1674 | DEBUG_stack(_cups_ps_stack_t *st) /* I - Stack */ | |
1675 | { | |
1676 | int c; /* Looping var */ | |
1677 | _cups_ps_obj_t *obj; /* Current object on stack */ | |
1678 | ||
1679 | ||
1680 | for (obj = st->objs, c = st->num_objs; c > 0; c --, obj ++) | |
b86bc4cf | 1681 | DEBUG_object(obj); |
b86bc4cf | 1682 | } |
1683 | #endif /* DEBUG */ | |
1684 | ||
1685 | ||
ef416fc2 | 1686 | /* |
b19ccc9e | 1687 | * End of "$Id: interpret.c 7852 2008-08-21 04:19:45Z mike $". |
ef416fc2 | 1688 | */ |