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