]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/emit.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / cups / emit.c
CommitLineData
ea930040 1/*
6f83172d 2 * "$Id: emit.c,v 1.23.2.13 2004/02/03 04:08:18 mike Exp $"
ea930040 3 *
3a193f5e 4 * PPD code emission routines for the Common UNIX Printing System (CUPS).
ea930040 5 *
1d9595ab 6 * Copyright 1997-2003 by Easy Software Products, all rights reserved.
ea930040 7 *
3a193f5e 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
ea930040 16 * Easy Software Products
58ec2a95 17 * 44141 Airport View Drive, Suite 204
ea930040 18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
2b85e375 24 * PostScript is a trademark of Adobe Systems, Inc.
25 *
dab1a4d8 26 * This file is subject to the Apple OS-Developed Software exception.
27 *
ea930040 28 * Contents:
29 *
ed6078a4 30 * ppdCollect() - Collect all marked options that reside in the
31 * specified section.
32 * ppdEmit() - Emit code for marked options to a file.
33 * ppdEmitFd() - Emit code for marked options to a file.
34 * ppdEmitJCL() - Emit code for JCL options to a file.
35 * ppd_handle_media() - Handle media selection...
36 * ppd_sort() - Sort options by ordering numbers...
ea930040 37 */
38
39/*
2b85e375 40 * Include necessary headers...
41 */
42
43#include "ppd.h"
3b960317 44#include <stdlib.h>
aaa5608c 45#include "string.h"
3b960317 46
47#if defined(WIN32) || defined(__EMX__)
2456b740 48# include <io.h>
49#else
50# include <unistd.h>
3b960317 51#endif /* WIN32 || __EMX__ */
2b85e375 52
53
8c1333e2 54/*
55 * Local functions...
56 */
57
ed6078a4 58static void ppd_handle_media(ppd_file_t *ppd);
8c1333e2 59static int ppd_sort(ppd_choice_t **c1, ppd_choice_t **c2);
cbcf8057 60
61
ed6078a4 62/*
63 * Local globals...
64 */
65
66static const char *ppd_custom_code =
67 "pop pop pop\n"
68 "<</PageSize[5 -2 roll]/ImagingBBox null>>setpagedevice\n";
69
70
cbcf8057 71/*
72 * 'ppdCollect()' - Collect all marked options that reside in the specified
73 * section.
74 */
75
76int /* O - Number of options marked */
77ppdCollect(ppd_file_t *ppd, /* I - PPD file data */
78 ppd_section_t section, /* I - Section to collect */
79 ppd_choice_t ***choices) /* O - Pointers to choices */
80{
81 int i, j, k, m; /* Looping vars */
82 ppd_group_t *g, /* Current group */
83 *sg; /* Current sub-group */
84 ppd_option_t *o; /* Current option */
85 ppd_choice_t *c; /* Current choice */
86 int count; /* Number of choices collected */
87 ppd_choice_t **collect; /* Collected choices */
88
89
90 if (ppd == NULL)
91 return (0);
92
93 /*
94 * Allocate memory for up to 1000 selected choices...
95 */
96
97 count = 0;
98 collect = calloc(sizeof(ppd_choice_t *), 1000);
99
100 /*
101 * Loop through all options and add choices as needed...
102 */
103
104 for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
105 {
106 for (j = g->num_options, o = g->options; j > 0; j --, o ++)
107 if (o->section == section)
108 for (k = o->num_choices, c = o->choices; k > 0; k --, c ++)
109 if (c->marked && count < 1000)
110 {
111 collect[count] = c;
112 count ++;
113 }
114
115 for (j = g->num_subgroups, sg = g->subgroups; j > 0; j --, sg ++)
116 for (k = sg->num_options, o = sg->options; k > 0; k --, o ++)
117 if (o->section == section)
118 for (m = o->num_choices, c = o->choices; m > 0; m --, c ++)
119 if (c->marked && count < 1000)
120 {
121 collect[count] = c;
122 count ++;
123 }
124 }
125
126 /*
127 * If we have more than 1 marked choice, sort them...
128 */
129
130 if (count > 1)
131 qsort(collect, count, sizeof(ppd_choice_t *),
132 (int (*)(const void *, const void *))ppd_sort);
133
134 /*
135 * Return the array and number of choices; if 0, free the array since
136 * it isn't needed.
137 */
138
139 if (count > 0)
140 {
141 *choices = collect;
142 return (count);
143 }
144 else
145 {
146 *choices = NULL;
147 free(collect);
148 return (0);
149 }
150}
8c1333e2 151
152
2b85e375 153/*
154 * 'ppdEmit()' - Emit code for marked options to a file.
155 */
156
157int /* O - 0 on success, -1 on failure */
158ppdEmit(ppd_file_t *ppd, /* I - PPD file record */
159 FILE *fp, /* I - File to write to */
160 ppd_section_t section) /* I - Section to write */
161{
8c1333e2 162 int i, /* Looping var */
163 count; /* Number of choices */
164 ppd_choice_t **choices; /* Choices */
6fdf969a 165 ppd_size_t *size; /* Custom page size */
8c1333e2 166
167
ed6078a4 168 /*
169 * Use PageSize or PageRegion as required...
170 */
171
172 ppd_handle_media(ppd);
173
174 /*
175 * Collect the options we need to emit and emit them!
176 */
177
cbcf8057 178 if ((count = ppdCollect(ppd, section, &choices)) == 0)
8c1333e2 179 return (0);
180
181 for (i = 0; i < count; i ++)
182 if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
183 {
96831d7f 184 /*
185 * Send wrapper commands to prevent printer errors for unsupported
186 * options...
187 */
188
189 if (fputs("[{\n", fp) < 0)
190 {
191 free(choices);
192 return (-1);
193 }
194
8c1333e2 195 /*
196 * Send DSC comments with option...
197 */
198
ed6078a4 199 if ((strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageSize") == 0 ||
200 strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageRegion") == 0) &&
a7b3e92e 201 strcasecmp(choices[i]->choice, "Custom") == 0)
6fdf969a 202 {
203 /*
8c5f90ff 204 * Variable size; write out standard size options, using the
205 * parameter positions defined in the PPD file...
6fdf969a 206 */
207
8c5f90ff 208 ppd_attr_t *attr; /* PPD attribute */
209 int pos, /* Position of custom value */
ae90e335 210 values[5], /* Values for custom command */
211 orientation; /* Orientation to use */
8c5f90ff 212
213
214 fputs("%%BeginFeature: *CustomPageSize True\n", fp);
215
6fdf969a 216 size = ppdPageSize(ppd, "Custom");
8c5f90ff 217
218 memset(values, 0, sizeof(values));
219
220 if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL)
221 {
222 pos = atoi(attr->value) - 1;
223
224 if (pos < 0 || pos > 4)
225 pos = 0;
226 }
227 else
228 pos = 0;
229
230 values[pos] = (int)size->width;
231
232 if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL)
233 {
234 pos = atoi(attr->value) - 1;
235
236 if (pos < 0 || pos > 4)
237 pos = 1;
238 }
239 else
240 pos = 1;
241
242 values[pos] = (int)size->length;
243
ae90e335 244 if (size->width < size->length)
245 orientation = 1;
246 else
247 orientation = 0;
248
249 if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize",
250 "Orientation")) != NULL)
251 {
252 int min_orient, max_orient; /* Minimum and maximum orientations */
253
254
255 if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient,
256 &max_orient) != 3)
257 pos = 4;
258 else
259 {
5edf6841 260 pos --;
261
ae90e335 262 if (pos < 0 || pos > 4)
263 pos = 4;
264
265 if (orientation > max_orient)
266 orientation = max_orient;
267 else if (orientation < min_orient)
268 orientation = min_orient;
269 }
270 }
271 else
272 pos = 4;
273
274 values[pos] = orientation;
275
8c5f90ff 276 fprintf(fp, "%d %d %d %d %d\n", values[0], values[1],
277 values[2], values[3], values[4]);
6fdf969a 278
279 if (choices[i]->code == NULL)
280 {
281 /*
282 * This can happen with certain buggy PPD files that don't include
283 * a CustomPageSize command sequence... We just use a generic
284 * Level 2 command sequence...
285 */
286
ed6078a4 287 fputs(ppd_custom_code, fp);
6fdf969a 288 }
289 }
8c5f90ff 290 else if (fprintf(fp, "%%%%BeginFeature: *%s %s\n",
291 ((ppd_option_t *)choices[i]->option)->keyword,
292 choices[i]->choice) < 0)
293 {
294 free(choices);
295 return (-1);
296 }
6fdf969a 297
298 if (choices[i]->code != NULL && choices[i]->code[0] != '\0')
8c1333e2 299 {
d23a857a 300 if (fputs(choices[i]->code, fp) < 0)
58ec2a95 301 {
302 free(choices);
303 return (-1);
304 }
305
d23a857a 306 if (choices[i]->code[strlen(choices[i]->code) - 1] != '\n')
58ec2a95 307 putc('\n', fp);
8c1333e2 308 }
309
58ec2a95 310 if (fputs("%%EndFeature\n", fp) < 0)
8c1333e2 311 {
312 free(choices);
313 return (-1);
314 }
96831d7f 315
316 if (fputs("} stopped cleartomark\n", fp) < 0)
317 {
318 free(choices);
319 return (-1);
320 }
8c1333e2 321 }
d23a857a 322 else if (fputs(choices[i]->code, fp) < 0)
8c1333e2 323 {
324 free(choices);
325 return (-1);
326 }
327
328 free(choices);
2b85e375 329 return (0);
330}
331
332
333/*
334 * 'ppdEmitFd()' - Emit code for marked options to a file.
ea930040 335 */
336
2b85e375 337int /* O - 0 on success, -1 on failure */
338ppdEmitFd(ppd_file_t *ppd, /* I - PPD file record */
339 int fd, /* I - File to write to */
340 ppd_section_t section) /* I - Section to write */
341{
8c1333e2 342 int i, /* Looping var */
8c5f90ff 343 count, /* Number of choices */
344 custom_size; /* Non-zero if this option is a custom size */
8c1333e2 345 ppd_choice_t **choices; /* Choices */
ed6078a4 346 ppd_size_t *size; /* Custom page size */
8c1333e2 347 char buf[1024]; /* Output buffer for feature */
348
349
ed6078a4 350 /*
351 * Use PageSize or PageRegion as required...
352 */
353
354 ppd_handle_media(ppd);
355
356 /*
357 * Collect the options we need to emit and emit them!
358 */
359
cbcf8057 360 if ((count = ppdCollect(ppd, section, &choices)) == 0)
8c1333e2 361 return (0);
362
363 for (i = 0; i < count; i ++)
364 if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
365 {
96831d7f 366 /*
367 * Send wrapper commands to prevent printer errors for unsupported
368 * options...
369 */
370
371 if (write(fd, "[{\n", 3) < 1)
372 {
373 free(choices);
374 return (-1);
375 }
376
8c1333e2 377 /*
378 * Send DSC comments with option...
379 */
380
8c5f90ff 381 if ((strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageSize") == 0 ||
382 strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageRegion") == 0) &&
383 strcasecmp(choices[i]->choice, "Custom") == 0)
384 {
385 custom_size = 1;
386
387 strcpy(buf, "%%BeginFeature: *CustomPageSize True\n");
388 }
389 else
390 {
391 custom_size = 0;
392
393 snprintf(buf, sizeof(buf), "%%%%BeginFeature: *%s %s\n",
394 ((ppd_option_t *)choices[i]->option)->keyword,
395 choices[i]->choice);
396 }
8c1333e2 397
398 if (write(fd, buf, strlen(buf)) < 1)
399 {
400 free(choices);
401 return (-1);
402 }
403
8c5f90ff 404 if (custom_size)
8c1333e2 405 {
ed6078a4 406 /*
8c5f90ff 407 * Variable size; write out standard size options, using the
408 * parameter positions defined in the PPD file...
ed6078a4 409 */
410
8c5f90ff 411 ppd_attr_t *attr; /* PPD attribute */
412 int pos, /* Position of custom value */
ae90e335 413 values[5], /* Values for custom command */
414 orientation; /* Orientation to use */
8c5f90ff 415
416
ed6078a4 417 size = ppdPageSize(ppd, "Custom");
8c5f90ff 418
419 memset(values, 0, sizeof(values));
420
421 if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL)
422 {
423 pos = atoi(attr->value) - 1;
424
425 if (pos < 0 || pos > 4)
426 pos = 0;
427 }
428 else
429 pos = 0;
430
431 values[pos] = (int)size->width;
432
433 if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL)
434 {
435 pos = atoi(attr->value) - 1;
436
437 if (pos < 0 || pos > 4)
438 pos = 1;
439 }
440 else
441 pos = 1;
442
443 values[pos] = (int)size->length;
444
ae90e335 445 if (size->width < size->length)
446 orientation = 1;
447 else
448 orientation = 0;
449
450 if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize",
451 "Orientation")) != NULL)
452 {
453 int min_orient, max_orient; /* Minimum and maximum orientations */
454
455
456 if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient,
457 &max_orient) != 3)
458 pos = 4;
459 else
460 {
5edf6841 461 pos --;
462
ae90e335 463 if (pos < 0 || pos > 4)
464 pos = 4;
465
466 if (orientation > max_orient)
467 orientation = max_orient;
468 else if (orientation < min_orient)
469 orientation = min_orient;
470 }
471 }
472 else
473 pos = 4;
474
475 values[pos] = orientation;
476
8c5f90ff 477 snprintf(buf, sizeof(buf), "%d %d %d %d %d\n", values[0], values[1],
478 values[2], values[3], values[4]);
ed6078a4 479
480 if (write(fd, buf, strlen(buf)) < 1)
481 {
482 free(choices);
483 return (-1);
484 }
485
486 if (choices[i]->code == NULL)
487 {
488 /*
489 * This can happen with certain buggy PPD files that don't include
490 * a CustomPageSize command sequence... We just use a generic
491 * Level 2 command sequence...
492 */
493
494 if (write(fd, ppd_custom_code, strlen(ppd_custom_code)) < 1)
495 {
496 free(choices);
497 return (-1);
498 }
499 }
500 }
501
502 if (choices[i]->code != NULL && choices[i]->code[0] != '\0')
503 {
504 if (write(fd, choices[i]->code, strlen(choices[i]->code)) < 1)
505 {
506 free(choices);
507 return (-1);
508 }
8c1333e2 509 }
510
511 if (write(fd, "%%EndFeature\n", 13) < 1)
512 {
513 free(choices);
514 return (-1);
515 }
96831d7f 516
517 if (write(fd, "} stopped cleartomark\n", 22) < 1)
518 {
519 free(choices);
520 return (-1);
521 }
8c1333e2 522 }
d23a857a 523 else if (write(fd, choices[i]->code, strlen(choices[i]->code)) < 1)
8c1333e2 524 {
525 free(choices);
526 return (-1);
527 }
528
529 free(choices);
2b85e375 530 return (0);
531}
ea930040 532
533
ee6a18b5 534/*
535 * 'ppdEmitJCL()' - Emit code for JCL options to a file.
536 */
537
538int /* O - 0 on success, -1 on failure */
539ppdEmitJCL(ppd_file_t *ppd, /* I - PPD file record */
540 FILE *fp, /* I - File to write to */
541 int job_id, /* I - Job ID */
542 const char *user, /* I - Username */
543 const char *title) /* I - Title */
544{
33b8a82d 545 char *ptr; /* Pointer into JCL string */
ae90e335 546 char temp[81]; /* Local title string */
ee6a18b5 547
548
549 if (ppd == NULL || ppd->jcl_begin == NULL || ppd->jcl_ps == NULL)
550 return (0);
551
552 if (strncmp(ppd->jcl_begin, "\033%-12345X@", 10) == 0)
553 {
554 /*
555 * This printer uses HP PJL commands for output; filter the output
556 * so that we only have a single "@PJL JOB" command in the header...
ae90e335 557 *
558 * To avoid bugs in the PJL implementation of certain vendors' products
559 * (Xerox in particular), we add a dummy "@PJL" command at the beginning
560 * of the PJL commands to initialize PJL processing.
ee6a18b5 561 */
562
ae90e335 563 fputs("\033%-12345X@PJL\n", fp);
ee6a18b5 564 for (ptr = ppd->jcl_begin + 9; *ptr;)
565 if (strncmp(ptr, "@PJL JOB", 8) == 0)
566 {
567 /*
568 * Skip job command...
569 */
570
571 for (;*ptr; ptr ++)
572 if (*ptr == '\n')
573 break;
574
575 if (*ptr)
576 ptr ++;
577 }
578 else
579 {
580 /*
581 * Copy line...
582 */
583
584 for (;*ptr; ptr ++)
585 {
586 putc(*ptr, fp);
587 if (*ptr == '\n')
588 break;
589 }
590
591 if (*ptr)
592 ptr ++;
593 }
594
ae90e335 595 /*
596 * Replace double quotes with single quotes so that the title
597 * does not cause a PJL syntax error.
598 */
599
600 strlcpy(temp, title, sizeof(temp));
601
602 for (ptr = temp; *ptr; ptr ++)
603 if (*ptr == '\"')
604 *ptr = '\'';
605
ee6a18b5 606 /*
607 * Send PJL JOB command before we enter PostScript mode...
608 */
609
ae90e335 610 fprintf(fp, "@PJL JOB NAME = \"%s\" DISPLAY = \"%d %s %s\"\n", temp,
611 job_id, user, temp);
ee6a18b5 612 }
613 else
af50faa7 614 fputs(ppd->jcl_begin, fp);
ee6a18b5 615
af50faa7 616 ppdEmit(ppd, fp, PPD_ORDER_JCL);
617 fputs(ppd->jcl_ps, fp);
37ac5c5e 618
619 return (0);
ee6a18b5 620}
621
622
ed6078a4 623/*
624 * 'ppd_handle_media()' - Handle media selection...
625 */
626
627static void
628ppd_handle_media(ppd_file_t *ppd)
629{
630 ppd_choice_t *manual_feed, /* ManualFeed choice, if any */
b3291c5a 631 *input_slot, /* InputSlot choice, if any */
632 *page; /* PageSize/PageRegion */
ed6078a4 633 ppd_size_t *size; /* Current media size */
1b98ab76 634 ppd_attr_t *rpr; /* RequiresPageRegion value */
ed6078a4 635
636
637 /*
638 * This function determines if the user has selected a media source
639 * via the InputSlot or ManualFeed options; if so, it marks the
640 * PageRegion option corresponding to the current media size.
641 * Otherwise it marks the PageSize option.
642 */
643
644 if ((size = ppdPageSize(ppd, NULL)) == NULL)
645 return;
646
647 manual_feed = ppdFindMarkedChoice(ppd, "ManualFeed");
648 input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
649
b3291c5a 650 if (input_slot != NULL)
651 rpr = ppdFindAttr(ppd, "RequiresPageRegion", input_slot->choice);
652 else
653 rpr = NULL;
654
655 if (!rpr)
656 rpr = ppdFindAttr(ppd, "RequiresPageRegion", "All");
657
ed6078a4 658 if (strcasecmp(size->name, "Custom") == 0 ||
659 (manual_feed == NULL && input_slot == NULL) ||
660 (manual_feed != NULL && strcasecmp(manual_feed->choice, "False") == 0) ||
661 (input_slot != NULL && (input_slot->code == NULL || !input_slot->code[0])))
662 {
663 /*
664 * Manual feed was not selected and/or the input slot selection does
665 * not contain any PostScript code. Use the PageSize option...
666 */
667
668 ppdMarkOption(ppd, "PageSize", size->name);
669 }
670 else
671 {
672 /*
673 * Manual feed was selected and/or the input slot selection contains
674 * PostScript code. Use the PageRegion option...
675 */
676
677 ppdMarkOption(ppd, "PageRegion", size->name);
b3291c5a 678
6f83172d 679 /*
680 * RequiresPageRegion does not apply to manual feed so we need to
681 * check that we are not doing manual feed before unmarking PageRegion.
682 */
683
684 if (!(manual_feed && !strcasecmp(manual_feed->choice, "True")) &&
685 ((rpr && rpr->value && !strcmp(rpr->value, "False")) ||
686 (!rpr && !ppd->num_filters)))
b3291c5a 687 {
688 /*
689 * Either the PPD file specifies no PageRegion code or the PPD file
690 * not for a CUPS raster driver and thus defaults to no PageRegion
691 * code... Unmark the PageRegion choice so that we don't output the
692 * code...
693 */
694
695 page = ppdFindMarkedChoice(ppd, "PageRegion");
696
697 if (page)
698 page->marked = 0;
699 }
ed6078a4 700 }
701}
702
703
ea930040 704/*
8c1333e2 705 * 'ppd_sort()' - Sort options by ordering numbers...
706 */
707
708static int /* O - -1 if c1 < c2, 0 if equal, 1 otherwise */
709ppd_sort(ppd_choice_t **c1, /* I - First choice */
710 ppd_choice_t **c2) /* I - Second choice */
711{
712 if (((ppd_option_t *)(*c1)->option)->order < ((ppd_option_t *)(*c2)->option)->order)
713 return (-1);
714 else if (((ppd_option_t *)(*c1)->option)->order > ((ppd_option_t *)(*c2)->option)->order)
715 return (1);
716 else
717 return (0);
718}
719
720
721/*
6f83172d 722 * End of "$Id: emit.c,v 1.23.2.13 2004/02/03 04:08:18 mike Exp $".
ea930040 723 */