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