]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/emit.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / emit.c
CommitLineData
ef416fc2 1/*
8ca02f3c 2 * "$Id: emit.c 5700 2006-06-26 19:20:39Z mike $"
ef416fc2 3 *
4 * PPD code emission routines for the Common UNIX Printing System (CUPS).
5 *
bd7854cb 6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
ef416fc2 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 * PostScript is a trademark of Adobe Systems, Inc.
25 *
26 * This file is subject to the Apple OS-Developed Software exception.
27 *
28 * Contents:
29 *
fa73b229 30 * ppdCollect() - Collect all marked options that reside in the
31 * specified section.
32 * ppdCollect2() - Collect all marked options that reside in the
33 * specified section and minimum order.
34 * ppdEmit() - Emit code for marked options to a file.
757d2cad 35 * ppdEmitAfterOrder() - Emit a subset of the code for marked options to a
36 * file.
fa73b229 37 * ppdEmitFd() - Emit code for marked options to a file.
38 * ppdEmitJCL() - Emit code for JCL options to a file.
39 * ppdEmitJCLEnd() - Emit JCLEnd code to a file.
757d2cad 40 * ppdEmitString() - Get a string containing the code for marked options.
fa73b229 41 * ppd_handle_media() - Handle media selection...
42 * ppd_sort() - Sort options by ordering numbers...
ef416fc2 43 */
44
45/*
46 * Include necessary headers...
47 */
48
49#include "ppd.h"
50#include <stdlib.h>
51#include "string.h"
757d2cad 52#include <errno.h>
8ca02f3c 53#include "debug.h"
ef416fc2 54
55#if defined(WIN32) || defined(__EMX__)
56# include <io.h>
57#else
58# include <unistd.h>
59#endif /* WIN32 || __EMX__ */
60
61
62/*
63 * Local functions...
64 */
65
66static void ppd_handle_media(ppd_file_t *ppd);
67static int ppd_sort(ppd_choice_t **c1, ppd_choice_t **c2);
68
69
70/*
71 * Local globals...
72 */
73
74static const char ppd_custom_code[] =
75 "pop pop pop\n"
76 "<</PageSize[5 -2 roll]/ImagingBBox null>>setpagedevice\n";
77
78
79/*
80 * 'ppdCollect()' - Collect all marked options that reside in the specified
81 * section.
82 */
83
84int /* O - Number of options marked */
85ppdCollect(ppd_file_t *ppd, /* I - PPD file data */
86 ppd_section_t section, /* I - Section to collect */
87 ppd_choice_t ***choices) /* O - Pointers to choices */
fa73b229 88{
89 return (ppdCollect2(ppd, section, 0.0, choices));
90}
91
92
93/*
94 * 'ppdCollect2()' - Collect all marked options that reside in the
95 * specified section and minimum order.
96 *
97 * @since CUPS 1.2@
98 */
99
100int /* O - Number of options marked */
101ppdCollect2(ppd_file_t *ppd, /* I - PPD file data */
102 ppd_section_t section, /* I - Section to collect */
103 float min_order, /* I - Minimum OrderDependency value */
104 ppd_choice_t ***choices) /* O - Pointers to choices */
ef416fc2 105{
106 int i, j, k, m; /* Looping vars */
107 ppd_group_t *g, /* Current group */
108 *sg; /* Current sub-group */
109 ppd_option_t *o; /* Current option */
110 ppd_choice_t *c; /* Current choice */
111 int count; /* Number of choices collected */
112 ppd_choice_t **collect; /* Collected choices */
113
114
8ca02f3c 115 DEBUG_printf(("ppdCollect2(ppd=%p, section=%d, min_order=%f, choices=%p)\n",
116 ppd, section, min_order, choices));
117
ef416fc2 118 if (ppd == NULL)
119 return (0);
120
121 /*
122 * Allocate memory for up to 1000 selected choices...
123 */
124
125 count = 0;
126 collect = calloc(sizeof(ppd_choice_t *), 1000);
127
128 /*
129 * Loop through all options and add choices as needed...
130 */
131
132 for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
133 {
134 for (j = g->num_options, o = g->options; j > 0; j --, o ++)
fa73b229 135 if (o->section == section && o->order >= min_order)
ef416fc2 136 for (k = o->num_choices, c = o->choices; k > 0; k --, c ++)
137 if (c->marked && count < 1000)
138 {
8ca02f3c 139 DEBUG_printf(("ppdCollect2: %s=%s marked...\n", o->keyword,
140 c->choice));
ef416fc2 141 collect[count] = c;
142 count ++;
143 }
144
145 for (j = g->num_subgroups, sg = g->subgroups; j > 0; j --, sg ++)
146 for (k = sg->num_options, o = sg->options; k > 0; k --, o ++)
fa73b229 147 if (o->section == section && o->order >= min_order)
ef416fc2 148 for (m = o->num_choices, c = o->choices; m > 0; m --, c ++)
149 if (c->marked && count < 1000)
150 {
8ca02f3c 151 DEBUG_printf(("ppdCollect2: %s=%s marked...\n", o->keyword,
152 c->choice));
ef416fc2 153 collect[count] = c;
154 count ++;
155 }
156 }
157
158 /*
159 * If we have more than 1 marked choice, sort them...
160 */
161
162 if (count > 1)
163 qsort(collect, count, sizeof(ppd_choice_t *),
164 (int (*)(const void *, const void *))ppd_sort);
165
8ca02f3c 166 DEBUG_printf(("ppdCollect2: %d marked choices...\n", count));
167
ef416fc2 168 /*
169 * Return the array and number of choices; if 0, free the array since
170 * it isn't needed.
171 */
172
173 if (count > 0)
174 {
175 *choices = collect;
176 return (count);
177 }
178 else
179 {
180 *choices = NULL;
181 free(collect);
182 return (0);
183 }
184}
185
186
187/*
188 * 'ppdEmit()' - Emit code for marked options to a file.
189 */
190
191int /* O - 0 on success, -1 on failure */
192ppdEmit(ppd_file_t *ppd, /* I - PPD file record */
193 FILE *fp, /* I - File to write to */
194 ppd_section_t section) /* I - Section to write */
fa73b229 195{
196 return (ppdEmitAfterOrder(ppd, fp, section, 0, 0.0));
197}
198
199
200/*
201 * 'ppdEmitAfterOrder()' - Emit a subset of the code for marked options to a file.
202 *
203 * When "limit" is non-zero, this function only emits options whose
204 * OrderDependency value is greater than or equal to "min_order".
205 *
206 * When "limit" is zero, this function is identical to ppdEmit().
207 *
208 * @since CUPS 1.2@
209 */
210
211int /* O - 0 on success, -1 on failure */
212ppdEmitAfterOrder(
213 ppd_file_t *ppd, /* I - PPD file record */
214 FILE *fp, /* I - File to write to */
215 ppd_section_t section, /* I - Section to write */
757d2cad 216 int limit, /* I - Non-zero to use min_order */
217 float min_order) /* I - Lowest OrderDependency */
ef416fc2 218{
757d2cad 219 char *buffer; /* Option code */
220 int status; /* Return status */
ef416fc2 221
222
223 /*
757d2cad 224 * Range check input...
ef416fc2 225 */
226
757d2cad 227 if (!ppd || !fp)
228 return (-1);
ef416fc2 229
230 /*
757d2cad 231 * Get the string...
ef416fc2 232 */
233
757d2cad 234 buffer = ppdEmitString(ppd, section, min_order);
ef416fc2 235
757d2cad 236 /*
237 * Write it as needed and return...
238 */
ef416fc2 239
757d2cad 240 if (buffer)
241 {
242 status = fputs(buffer, fp) < 0 ? -1 : 0;
ef416fc2 243
757d2cad 244 free(buffer);
245 }
246 else
247 status = 0;
ef416fc2 248
757d2cad 249 return (status);
ef416fc2 250}
251
252
253/*
254 * 'ppdEmitFd()' - Emit code for marked options to a file.
255 */
256
257int /* O - 0 on success, -1 on failure */
258ppdEmitFd(ppd_file_t *ppd, /* I - PPD file record */
259 int fd, /* I - File to write to */
260 ppd_section_t section) /* I - Section to write */
261{
757d2cad 262 char *buffer, /* Option code */
263 *bufptr; /* Pointer into code */
264 size_t buflength; /* Length of option code */
265 ssize_t bytes; /* Bytes written */
266 int status; /* Return status */
ef416fc2 267
268
269 /*
757d2cad 270 * Range check input...
ef416fc2 271 */
272
757d2cad 273 if (!ppd || fd < 0)
274 return (-1);
ef416fc2 275
276 /*
757d2cad 277 * Get the string...
ef416fc2 278 */
279
757d2cad 280 buffer = ppdEmitString(ppd, section, 0.0);
ef416fc2 281
757d2cad 282 /*
283 * Write it as needed and return...
284 */
ef416fc2 285
757d2cad 286 if (buffer)
287 {
288 buflength = strlen(buffer);
289 bufptr = buffer;
290 bytes = 0;
ef416fc2 291
757d2cad 292 while (buflength > 0)
293 {
294 if ((bytes = write(fd, bufptr, buflength)) < 0)
ef416fc2 295 {
757d2cad 296 if (errno == EAGAIN || errno == EINTR)
297 continue;
ef416fc2 298
757d2cad 299 break;
ef416fc2 300 }
757d2cad 301
302 buflength -= bytes;
303 bufptr += bytes;
ef416fc2 304 }
305
757d2cad 306 status = bytes < 0 ? -1 : 0;
307
308 free(buffer);
309 }
310 else
311 status = 0;
312
313 return (status);
ef416fc2 314}
315
316
317/*
318 * 'ppdEmitJCL()' - Emit code for JCL options to a file.
319 */
320
321int /* O - 0 on success, -1 on failure */
322ppdEmitJCL(ppd_file_t *ppd, /* I - PPD file record */
323 FILE *fp, /* I - File to write to */
324 int job_id, /* I - Job ID */
325 const char *user, /* I - Username */
326 const char *title) /* I - Title */
327{
328 char *ptr; /* Pointer into JCL string */
329 char temp[81]; /* Local title string */
330
331
332 /*
333 * Range check the input...
334 */
335
757d2cad 336 if (!ppd || !ppd->jcl_begin || !ppd->jcl_ps)
ef416fc2 337 return (0);
338
339 /*
340 * See if the printer supports HP PJL...
341 */
342
343 if (!strncmp(ppd->jcl_begin, "\033%-12345X@", 10))
344 {
345 /*
346 * This printer uses HP PJL commands for output; filter the output
347 * so that we only have a single "@PJL JOB" command in the header...
348 *
349 * To avoid bugs in the PJL implementation of certain vendors' products
350 * (Xerox in particular), we add a dummy "@PJL" command at the beginning
351 * of the PJL commands to initialize PJL processing.
352 */
353
354 fputs("\033%-12345X@PJL\n", fp);
355 for (ptr = ppd->jcl_begin + 9; *ptr;)
356 if (!strncmp(ptr, "@PJL JOB", 8))
357 {
358 /*
359 * Skip job command...
360 */
361
362 for (;*ptr; ptr ++)
363 if (*ptr == '\n')
364 break;
365
366 if (*ptr)
367 ptr ++;
368 }
369 else
370 {
371 /*
372 * Copy line...
373 */
374
375 for (;*ptr; ptr ++)
376 {
377 putc(*ptr, fp);
378 if (*ptr == '\n')
379 break;
380 }
381
382 if (*ptr)
383 ptr ++;
384 }
385
386 /*
387 * Eliminate any path info from the job title...
388 */
389
390 if ((ptr = strrchr(title, '/')) != NULL)
391 title = ptr + 1;
392
393 /*
394 * Replace double quotes with single quotes so that the title
395 * does not cause a PJL syntax error.
396 */
397
398 strlcpy(temp, title, sizeof(temp));
399
400 for (ptr = temp; *ptr; ptr ++)
401 if (*ptr == '\"')
402 *ptr = '\'';
403
404 /*
405 * Send PJL JOB and PJL RDYMSG commands before we enter PostScript mode...
406 */
407
408 fprintf(fp, "@PJL JOB NAME = \"%s\" DISPLAY = \"%d %s %s\"\n", temp,
409 job_id, user, temp);
410 fprintf(fp, "@PJL RDYMSG DISPLAY = \"%d %s %s\"\n", job_id, user, temp);
411 }
412 else
413 fputs(ppd->jcl_begin, fp);
414
415 ppdEmit(ppd, fp, PPD_ORDER_JCL);
416 fputs(ppd->jcl_ps, fp);
417
418 return (0);
419}
420
421
422/*
423 * 'ppdEmitJCLEnd()' - Emit JCLEnd code to a file.
424 *
425 * @since CUPS 1.2@
426 */
427
428int /* O - 0 on success, -1 on failure */
429ppdEmitJCLEnd(ppd_file_t *ppd, /* I - PPD file record */
430 FILE *fp) /* I - File to write to */
431{
ef416fc2 432 /*
433 * Range check the input...
434 */
435
757d2cad 436 if (!ppd)
ef416fc2 437 return (0);
438
757d2cad 439 if (!ppd->jcl_end)
ef416fc2 440 {
441 if (ppd->num_filters == 0)
757d2cad 442 putc(0x04, fp);
ef416fc2 443
444 return (0);
445 }
446
447 /*
448 * See if the printer supports HP PJL...
449 */
450
451 if (!strncmp(ppd->jcl_end, "\033%-12345X@", 10))
452 {
453 /*
454 * This printer uses HP PJL commands for output; filter the output
455 * so that we only have a single "@PJL JOB" command in the header...
456 *
457 * To avoid bugs in the PJL implementation of certain vendors' products
458 * (Xerox in particular), we add a dummy "@PJL" command at the beginning
459 * of the PJL commands to initialize PJL processing.
460 */
461
462 fputs("\033%-12345X@PJL\n", fp);
463 fputs("@PJL RDYMSG DISPLAY = \"READY\"\n", fp);
464 fputs(ppd->jcl_end + 9, fp);
465 }
466 else
467 fputs(ppd->jcl_end, fp);
468
469 return (0);
470}
471
472
757d2cad 473/*
474 * 'ppdEmitString()' - Get a string containing the code for marked options.
475 *
476 * When "min_order" is greater than zero, this function only includes options
477 * whose OrderDependency value is greater than or equal to "min_order".
478 * Otherwise, all options in the specified section are included in the
479 * returned string.
480 *
481 * The return string is allocated on the heap and should be freed using
482 * free() when you are done with it.
483 *
484 * @since CUPS 1.2@
485 */
486
487char * /* O - String containing option code */
488ppdEmitString(ppd_file_t *ppd, /* I - PPD file record */
489 ppd_section_t section, /* I - Section to write */
490 float min_order) /* I - Lowest OrderDependency */
491{
492 int i, j, /* Looping vars */
493 count; /* Number of choices */
494 ppd_choice_t **choices; /* Choices */
495 ppd_size_t *size; /* Custom page size */
496 ppd_coption_t *coption; /* Custom option */
497 ppd_cparam_t *cparam; /* Custom parameter */
498 size_t bufsize; /* Size of string buffer needed */
499 char *buffer, /* String buffer */
500 *bufptr, /* Pointer into buffer */
501 *bufend; /* End of buffer */
502 struct lconv *loc; /* Locale data */
503
504
8ca02f3c 505 DEBUG_printf(("ppdEmitString(ppd=%p, section=%d, min_order=%f)\n",
506 ppd, section, min_order));
507
757d2cad 508 /*
509 * Range check input...
510 */
511
512 if (!ppd)
513 return (NULL);
514
515 /*
516 * Use PageSize or PageRegion as required...
517 */
518
519 ppd_handle_media(ppd);
520
521 /*
522 * Collect the options we need to emit...
523 */
524
525 if ((count = ppdCollect2(ppd, section, min_order, &choices)) == 0)
526 return (NULL);
527
528 /*
529 * Count the number of bytes that are required to hold all of the
530 * option code...
531 */
532
533 for (i = 0, bufsize = 1; i < count; i ++)
534 {
535 if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
536 {
537 bufsize += 3; /* [{\n */
538
539 if ((!strcasecmp(choices[i]->option->keyword, "PageSize") ||
540 !strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
541 !strcasecmp(choices[i]->choice, "Custom"))
542 {
8ca02f3c 543 DEBUG_puts("ppdEmitString: Custom size set!");
544
e1d6a774 545 bufsize += 37; /* %%BeginFeature: *CustomPageSize True\n */
757d2cad 546 bufsize += 50; /* Five 9-digit numbers + newline */
547 }
548 else if (!strcasecmp(choices[i]->choice, "Custom") &&
549 (coption = ppdFindCustomOption(ppd,
550 choices[i]->option->keyword))
551 != NULL)
552 {
e1d6a774 553 bufsize += 17 + strlen(choices[i]->option->keyword) + 6;
554 /* %%BeginFeature: *keyword True\n */
757d2cad 555
556
557 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
558 cparam;
559 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
560 {
561 switch (cparam->type)
562 {
563 case PPD_CUSTOM_CURVE :
564 case PPD_CUSTOM_INVCURVE :
565 case PPD_CUSTOM_POINTS :
566 case PPD_CUSTOM_REAL :
567 case PPD_CUSTOM_INT :
568 bufsize += 10;
569 break;
570
571 case PPD_CUSTOM_PASSCODE :
572 case PPD_CUSTOM_PASSWORD :
573 case PPD_CUSTOM_STRING :
574 bufsize += 3 + 4 * strlen(cparam->current.custom_string);
575 break;
576 }
577 }
578 }
579 else
e1d6a774 580 bufsize += 17 + strlen(choices[i]->option->keyword) + 1 +
581 strlen(choices[i]->choice) + 1;
582 /* %%BeginFeature: *keyword choice\n */
757d2cad 583
584 bufsize += 13; /* %%EndFeature\n */
585 bufsize += 22; /* } stopped cleartomark\n */
586 }
587
588 if (choices[i]->code)
e1d6a774 589 bufsize += strlen(choices[i]->code) + 1;
757d2cad 590 else
591 bufsize += strlen(ppd_custom_code);
592 }
593
594 /*
595 * Allocate memory...
596 */
597
8ca02f3c 598 DEBUG_printf(("ppdEmitString: Allocating %d bytes for string...\n", bufsize));
599
757d2cad 600 if ((buffer = calloc(1, bufsize)) == NULL)
601 {
602 free(choices);
603 return (NULL);
604 }
605
606 bufend = buffer + bufsize - 1;
607 loc = localeconv();
608
609 /*
610 * Copy the option code to the buffer...
611 */
612
613 for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr))
614 if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
615 {
616 /*
617 * Add wrapper commands to prevent printer errors for unsupported
618 * options...
619 */
620
621 strlcpy(bufptr, "[{\n", bufend - bufptr + 1);
622 bufptr += 3;
623
624 /*
625 * Send DSC comments with option...
626 */
627
8ca02f3c 628 DEBUG_printf(("Adding code for %s=%s...\n", choices[i]->option->keyword,
629 choices[i]->choice));
630
757d2cad 631 if ((!strcasecmp(choices[i]->option->keyword, "PageSize") ||
632 !strcasecmp(choices[i]->option->keyword, "PageRegion")) &&
633 !strcasecmp(choices[i]->choice, "Custom"))
634 {
635 /*
636 * Variable size; write out standard size options, using the
637 * parameter positions defined in the PPD file...
638 */
639
640 ppd_attr_t *attr; /* PPD attribute */
641 int pos, /* Position of custom value */
642 orientation; /* Orientation to use */
643 float values[5]; /* Values for custom command */
644
645
646 strlcpy(bufptr, "%%BeginFeature: *CustomPageSize True\n",
647 bufend - bufptr + 1);
648 bufptr += 37;
649
650 size = ppdPageSize(ppd, "Custom");
651
652 memset(values, 0, sizeof(values));
653
654 if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL)
655 {
656 pos = atoi(attr->value) - 1;
657
658 if (pos < 0 || pos > 4)
659 pos = 0;
660 }
661 else
662 pos = 0;
663
664 values[pos] = size->width;
665
666 if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL)
667 {
668 pos = atoi(attr->value) - 1;
669
670 if (pos < 0 || pos > 4)
671 pos = 1;
672 }
673 else
674 pos = 1;
675
676 values[pos] = size->length;
677
678 /*
679 * According to the Adobe PPD specification, an orientation of 1
680 * will produce a print that comes out upside-down with the X
681 * axis perpendicular to the direction of feed, which is exactly
682 * what we want to be consistent with non-PS printers.
683 *
684 * We could also use an orientation of 3 to produce output that
685 * comes out rightside-up (this is the default for many large format
686 * printer PPDs), however for consistency we will stick with the
687 * value 1.
688 *
689 * If we wanted to get fancy, we could use orientations of 0 or
690 * 2 and swap the width and length, however we don't want to get
691 * fancy, we just want it to work consistently.
692 *
693 * The orientation value is range limited by the Orientation
694 * parameter definition, so certain non-PS printer drivers that
695 * only support an Orientation of 0 will get the value 0 as
696 * expected.
697 */
698
699 orientation = 1;
700
701 if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize",
702 "Orientation")) != NULL)
703 {
704 int min_orient, max_orient; /* Minimum and maximum orientations */
705
706
707 if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient,
708 &max_orient) != 3)
709 pos = 4;
710 else
711 {
712 pos --;
713
714 if (pos < 0 || pos > 4)
715 pos = 4;
716
717 if (orientation > max_orient)
718 orientation = max_orient;
719 else if (orientation < min_orient)
720 orientation = min_orient;
721 }
722 }
723 else
724 pos = 4;
725
726 values[pos] = orientation;
727
728 for (pos = 0; pos < 5; pos ++)
729 {
730 bufptr = _cupsStrFormatd(bufptr, bufend, values[pos], loc);
731 *bufptr++ = '\n';
732 }
733
734 if (!choices[i]->code)
735 {
736 /*
737 * This can happen with certain buggy PPD files that don't include
738 * a CustomPageSize command sequence... We just use a generic
739 * Level 2 command sequence...
740 */
741
742 strlcpy(bufptr, ppd_custom_code, bufend - bufptr + 1);
743 bufptr += strlen(bufptr);
744 }
745 }
746 else if (!strcasecmp(choices[i]->choice, "Custom") &&
747 (coption = ppdFindCustomOption(ppd,
748 choices[i]->option->keyword))
749 != NULL)
750 {
751 /*
752 * Custom option...
753 */
754
755 const char *s; /* Pointer into string value */
756
757
758 snprintf(bufptr, bufend - bufptr + 1,
759 "%%%%BeginFeature: *Custom%s True\n", coption->keyword);
760 bufptr += strlen(bufptr);
761
762 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
763 cparam;
764 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
765 {
766 switch (cparam->type)
767 {
768 case PPD_CUSTOM_CURVE :
769 case PPD_CUSTOM_INVCURVE :
770 case PPD_CUSTOM_POINTS :
771 case PPD_CUSTOM_REAL :
772 bufptr = _cupsStrFormatd(bufptr, bufend,
773 cparam->current.custom_real, loc);
774 *bufptr++ = '\n';
775 break;
776
777 case PPD_CUSTOM_INT :
778 snprintf(bufptr, bufend - bufptr + 1, "%d\n",
779 cparam->current.custom_int);
780 bufptr += strlen(bufptr);
781 break;
782
783 case PPD_CUSTOM_PASSCODE :
784 case PPD_CUSTOM_PASSWORD :
785 case PPD_CUSTOM_STRING :
786 *bufptr++ = '(';
787
788 for (s = cparam->current.custom_string; *s; s ++)
789 if (*s < ' ' || *s == '(' || *s == ')' || *s >= 127)
790 {
791 snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *s & 255);
792 bufptr += strlen(bufptr);
793 }
794 else
795 *bufptr++ = *s;
796
797 *bufptr++ = ')';
798 *bufptr++ = '\n';
799 break;
800 }
801 }
802 }
803 else
804 {
805 snprintf(bufptr, bufend - bufptr + 1, "%%%%BeginFeature: *%s %s\n",
806 choices[i]->option->keyword, choices[i]->choice);
807 bufptr += strlen(bufptr);
808 }
809
810 if (choices[i]->code && choices[i]->code[0])
811 {
812 j = strlen(choices[i]->code);
813 memcpy(bufptr, choices[i]->code, j);
814 bufptr += j;
815
816 if (choices[i]->code[j - 1] != '\n')
817 *bufptr++ = '\n';
818 }
819
820 strlcpy(bufptr, "%%EndFeature\n"
821 "} stopped cleartomark\n", bufend - bufptr + 1);
822 bufptr += strlen(bufptr);
8ca02f3c 823
824 DEBUG_printf(("ppdEmitString: Offset in string is %d...\n",
825 bufptr - buffer));
757d2cad 826 }
827 else
828 {
829 strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
830 bufptr += strlen(bufptr);
831 }
832
833 /*
834 * Nul-terminate, free, and return...
835 */
836
837 *bufptr = '\0';
838
839 free(choices);
840
841 return (buffer);
842}
843
844
ef416fc2 845/*
846 * 'ppd_handle_media()' - Handle media selection...
847 */
848
849static void
850ppd_handle_media(ppd_file_t *ppd)
851{
852 ppd_choice_t *manual_feed, /* ManualFeed choice, if any */
853 *input_slot, /* InputSlot choice, if any */
854 *page; /* PageSize/PageRegion */
855 ppd_size_t *size; /* Current media size */
856 ppd_attr_t *rpr; /* RequiresPageRegion value */
857
858
859 /*
860 * This function determines if the user has selected a media source
861 * via the InputSlot or ManualFeed options; if so, it marks the
862 * PageRegion option corresponding to the current media size.
863 * Otherwise it marks the PageSize option.
864 */
865
866 if ((size = ppdPageSize(ppd, NULL)) == NULL)
867 return;
868
869 manual_feed = ppdFindMarkedChoice(ppd, "ManualFeed");
870 input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
871
872 if (input_slot != NULL)
873 rpr = ppdFindAttr(ppd, "RequiresPageRegion", input_slot->choice);
874 else
875 rpr = NULL;
876
877 if (!rpr)
878 rpr = ppdFindAttr(ppd, "RequiresPageRegion", "All");
879
fa73b229 880 if (!strcasecmp(size->name, "Custom") || (!manual_feed && !input_slot) ||
881 !((manual_feed && !strcasecmp(manual_feed->choice, "True")) ||
882 (input_slot && input_slot->code && input_slot->code[0])))
ef416fc2 883 {
884 /*
885 * Manual feed was not selected and/or the input slot selection does
886 * not contain any PostScript code. Use the PageSize option...
887 */
888
889 ppdMarkOption(ppd, "PageSize", size->name);
890 }
891 else
892 {
893 /*
894 * Manual feed was selected and/or the input slot selection contains
895 * PostScript code. Use the PageRegion option...
896 */
897
898 ppdMarkOption(ppd, "PageRegion", size->name);
899
900 /*
901 * RequiresPageRegion does not apply to manual feed so we need to
902 * check that we are not doing manual feed before unmarking PageRegion.
903 */
904
905 if (!(manual_feed && !strcasecmp(manual_feed->choice, "True")) &&
906 ((rpr && rpr->value && !strcmp(rpr->value, "False")) ||
907 (!rpr && !ppd->num_filters)))
908 {
909 /*
910 * Either the PPD file specifies no PageRegion code or the PPD file
911 * not for a CUPS raster driver and thus defaults to no PageRegion
912 * code... Unmark the PageRegion choice so that we don't output the
913 * code...
914 */
915
916 page = ppdFindMarkedChoice(ppd, "PageRegion");
917
918 if (page)
919 page->marked = 0;
920 }
921 }
922}
923
924
925/*
926 * 'ppd_sort()' - Sort options by ordering numbers...
927 */
928
929static int /* O - -1 if c1 < c2, 0 if equal, 1 otherwise */
930ppd_sort(ppd_choice_t **c1, /* I - First choice */
931 ppd_choice_t **c2) /* I - Second choice */
932{
fa73b229 933 if ((*c1)->option->order < (*c2)->option->order)
ef416fc2 934 return (-1);
fa73b229 935 else if ((*c1)->option->order > (*c2)->option->order)
ef416fc2 936 return (1);
937 else
938 return (0);
939}
940
941
942/*
8ca02f3c 943 * End of "$Id: emit.c 5700 2006-06-26 19:20:39Z mike $".
ef416fc2 944 */