1 //
2 // Source class for the CUPS PPD Compiler.
3 //
4 // Copyright © 2020-2024 by OpenPrinting.
5 // Copyright 2007-2018 by Apple Inc.
6 // Copyright 2002-2007 by Easy Software Products.
7 //
8 // Licensed under Apache License v2.0. See the file "LICENSE" for more
9 // information.
10 //
11
12 //
13 // Include necessary headers...
14 //
15
16 #include "ppdc-private.h"
17 #include <limits.h>
18 #include <math.h>
19 #include <unistd.h>
20 #include <cups/raster.h>
21 #include "data/epson.h"
22 #include "data/hp.h"
23 #include "data/label.h"
24 #ifndef _WIN32
25 # include <sys/utsname.h>
26 #endif // !_WIN32
27
28
29 //
30 // Class globals...
31 //
32
33 ppdcArray *ppdcSource::includes = 0;
34 const char *ppdcSource::driver_types[] =
35 {
36 "custom",
37 "ps",
38 "escp",
39 "pcl",
40 "label",
41 "epson",
42 "hp"
43 };
44
45
46 //
47 // 'ppdcSource::ppdcSource()' - Load a driver source file.
48 //
49
ppdcSource(const char * f,cups_file_t * ffp)50 ppdcSource::ppdcSource(const char *f, // I - File to read
51 cups_file_t *ffp)// I - File pointer to use
52 : ppdcShared()
53 {
54 PPDC_NEW;
55
56 filename = new ppdcString(f);
57 base_fonts = new ppdcArray();
58 drivers = new ppdcArray();
59 po_files = new ppdcArray();
60 sizes = new ppdcArray();
61 vars = new ppdcArray();
62 cond_state = PPDC_COND_NORMAL;
63 cond_current = cond_stack;
64 cond_stack[0] = PPDC_COND_NORMAL;
65
66 // Add standard #define variables...
67 #define MAKE_STRING(x) #x
68
69 vars->add(new ppdcVariable("CUPS_VERSION", MAKE_STRING(CUPS_VERSION)));
70 vars->add(new ppdcVariable("CUPS_VERSION_MAJOR", MAKE_STRING(CUPS_VERSION_MAJOR)));
71 vars->add(new ppdcVariable("CUPS_VERSION_MINOR", MAKE_STRING(CUPS_VERSION_MINOR)));
72 vars->add(new ppdcVariable("CUPS_VERSION_PATCH", MAKE_STRING(CUPS_VERSION_PATCH)));
73
74 #ifdef _WIN32
75 vars->add(new ppdcVariable("PLATFORM_NAME", "Windows"));
76 vars->add(new ppdcVariable("PLATFORM_ARCH", "X86"));
77
78 #else
79 struct utsname name; // uname information
80
81 if (!uname(&name))
82 {
83 vars->add(new ppdcVariable("PLATFORM_NAME", name.sysname));
84 vars->add(new ppdcVariable("PLATFORM_ARCH", name.machine));
85 }
86 else
87 {
88 vars->add(new ppdcVariable("PLATFORM_NAME", "unknown"));
89 vars->add(new ppdcVariable("PLATFORM_ARCH", "unknown"));
90 }
91 #endif // _WIN32
92
93 if (f)
94 read_file(f, ffp);
95 }
96
97
98 //
99 // 'ppdcSource::~ppdcSource()' - Free a driver source file.
100 //
101
~ppdcSource()102 ppdcSource::~ppdcSource()
103 {
104 PPDC_DELETE;
105
106 filename->release();
107 base_fonts->release();
108 drivers->release();
109 po_files->release();
110 sizes->release();
111 vars->release();
112 }
113
114
115 //
116 // 'ppdcSource::add_include()' - Add an include directory.
117 //
118
119 void
add_include(const char * d)120 ppdcSource::add_include(const char *d) // I - Include directory
121 {
122 if (!d)
123 return;
124
125 if (!includes)
126 includes = new ppdcArray();
127
128 includes->add(new ppdcString(d));
129 }
130
131
132 //
133 // 'ppdcSource::find_driver()' - Find a driver.
134 //
135
136 ppdcDriver * // O - Driver
find_driver(const char * f)137 ppdcSource::find_driver(const char *f) // I - Driver file name
138 {
139 ppdcDriver *d; // Current driver
140
141
142 for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
143 if (!_cups_strcasecmp(f, d->pc_file_name->value))
144 return (d);
145
146 return (NULL);
147 }
148
149
150 //
151 // 'ppdcSource::find_include()' - Find an include file.
152 //
153
154 char * // O - Found path or NULL
find_include(const char * f,const char * base,char * n,int nlen)155 ppdcSource::find_include(
156 const char *f, // I - Include filename
157 const char *base, // I - Current directory
158 char *n, // I - Path buffer
159 int nlen) // I - Path buffer length
160 {
161 ppdcString *dir; // Include directory
162 char temp[1024], // Temporary path
163 *ptr; // Pointer to end of path
164
165
166 // Range check input...
167 if (!f || !*f || !n || nlen < 2)
168 return (0);
169
170 // Check the first character to see if we have <name> or "name"...
171 if (*f == '<')
172 {
173 // Remove the surrounding <> from the name...
174 strlcpy(temp, f + 1, sizeof(temp));
175 ptr = temp + strlen(temp) - 1;
176
177 if (*ptr != '>')
178 {
179 _cupsLangPrintf(stderr,
180 _("ppdc: Invalid #include/#po filename \"%s\"."), n);
181 return (0);
182 }
183
184 *ptr = '\0';
185 f = temp;
186 }
187 else
188 {
189 // Check for the local file relative to the current directory...
190 if (base && *base && f[0] != '/')
191 snprintf(n, (size_t)nlen, "%s/%s", base, f);
192 else
193 strlcpy(n, f, (size_t)nlen);
194
195 if (!access(n, 0))
196 return (n);
197 else if (*f == '/')
198 {
199 // Absolute path that doesn't exist...
200 return (0);
201 }
202 }
203
204 // Search the include directories, if any...
205 if (includes)
206 {
207 for (dir = (ppdcString *)includes->first(); dir; dir = (ppdcString *)includes->next())
208 {
209 snprintf(n, (size_t)nlen, "%s/%s", dir->value, f);
210 if (!access(n, 0))
211 return (n);
212 }
213 }
214
215 // Search the standard include directories...
216 _cups_globals_t *cg = _cupsGlobals(); // Global data
217
218 snprintf(n, (size_t)nlen, "%s/ppdc/%s", cg->cups_datadir, f);
219 if (!access(n, 0))
220 return (n);
221
222 snprintf(n, (size_t)nlen, "%s/po/%s", cg->cups_datadir, f);
223 if (!access(n, 0))
224 return (n);
225 else
226 return (0);
227 }
228
229
230 //
231 // 'ppdcSource::find_po()' - Find a message catalog for the given locale.
232 //
233
234 ppdcCatalog * // O - Message catalog or NULL
find_po(const char * l)235 ppdcSource::find_po(const char *l) // I - Locale name
236 {
237 ppdcCatalog *cat; // Current message catalog
238
239
240 for (cat = (ppdcCatalog *)po_files->first();
241 cat;
242 cat = (ppdcCatalog *)po_files->next())
243 if (!_cups_strcasecmp(l, cat->locale->value))
244 return (cat);
245
246 return (NULL);
247 }
248
249
250 //
251 // 'ppdcSource::find_size()' - Find a media size.
252 //
253
254 ppdcMediaSize * // O - Size
find_size(const char * s)255 ppdcSource::find_size(const char *s) // I - Size name
256 {
257 ppdcMediaSize *m; // Current media size
258
259
260 for (m = (ppdcMediaSize *)sizes->first(); m; m = (ppdcMediaSize *)sizes->next())
261 if (!_cups_strcasecmp(s, m->name->value))
262 return (m);
263
264 return (NULL);
265 }
266
267
268 //
269 // 'ppdcSource::find_variable()' - Find a variable.
270 //
271
272 ppdcVariable * // O - Variable
find_variable(const char * n)273 ppdcSource::find_variable(const char *n)// I - Variable name
274 {
275 ppdcVariable *v; // Current variable
276
277
278 for (v = (ppdcVariable *)vars->first(); v; v = (ppdcVariable *)vars->next())
279 if (!_cups_strcasecmp(n, v->name->value))
280 return (v);
281
282 return (NULL);
283 }
284
285
286 //
287 // 'ppdcSource::get_attr()' - Get an attribute.
288 //
289
290 ppdcAttr * // O - Attribute
get_attr(ppdcFile * fp,bool loc)291 ppdcSource::get_attr(ppdcFile *fp, // I - File to read
292 bool loc) // I - Localize this attribute?
293 {
294 char name[1024], // Name string
295 selector[1024], // Selector string
296 *text, // Text string
297 value[1024]; // Value string
298
299
300 // Get the attribute parameters:
301 //
302 // Attribute name selector value
303 if (!get_token(fp, name, sizeof(name)))
304 {
305 _cupsLangPrintf(stderr,
306 _("ppdc: Expected name after %s on line %d of %s."),
307 loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
308 return (0);
309 }
310
311 if (!get_token(fp, selector, sizeof(selector)))
312 {
313 _cupsLangPrintf(stderr,
314 _("ppdc: Expected selector after %s on line %d of %s."),
315 loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
316 return (0);
317 }
318
319 if ((text = strchr(selector, '/')) != NULL)
320 *text++ = '\0';
321
322 if (!get_token(fp, value, sizeof(value)))
323 {
324 _cupsLangPrintf(stderr,
325 _("ppdc: Expected value after %s on line %d of %s."),
326 loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
327 return (0);
328 }
329
330 return (new ppdcAttr(name, selector, text, value, loc));
331 }
332
333
334 //
335 // 'ppdcSource::get_boolean()' - Get a boolean value.
336 //
337
338 int // O - Boolean value
get_boolean(ppdcFile * fp)339 ppdcSource::get_boolean(ppdcFile *fp) // I - File to read
340 {
341 char buffer[256]; // String buffer
342
343
344 if (!get_token(fp, buffer, sizeof(buffer)))
345 {
346 _cupsLangPrintf(stderr,
347 _("ppdc: Expected boolean value on line %d of %s."),
348 fp->line, fp->filename);
349 return (-1);
350 }
351
352 if (!_cups_strcasecmp(buffer, "on") ||
353 !_cups_strcasecmp(buffer, "yes") ||
354 !_cups_strcasecmp(buffer, "true"))
355 return (1);
356 else if (!_cups_strcasecmp(buffer, "off") ||
357 !_cups_strcasecmp(buffer, "no") ||
358 !_cups_strcasecmp(buffer, "false"))
359 return (0);
360 else
361 {
362 _cupsLangPrintf(stderr,
363 _("ppdc: Bad boolean value (%s) on line %d of %s."),
364 buffer, fp->line, fp->filename);
365 return (-1);
366 }
367 }
368
369
370 //
371 // 'ppdcSource::get_choice()' - Get a choice.
372 //
373
374 ppdcChoice * // O - Choice data
get_choice(ppdcFile * fp)375 ppdcSource::get_choice(ppdcFile *fp) // I - File to read
376 {
377 char name[1024], // Name
378 *text, // Text
379 code[10240]; // Code
380
381
382 // Read a choice from the file:
383 //
384 // Choice name/text code
385 if (!get_token(fp, name, sizeof(name)))
386 {
387 _cupsLangPrintf(stderr,
388 _("ppdc: Expected choice name/text on line %d of %s."),
389 fp->line, fp->filename);
390 return (NULL);
391 }
392
393 if ((text = strchr(name, '/')) != NULL)
394 *text++ = '\0';
395 else
396 text = name;
397
398 if (!get_token(fp, code, sizeof(code)))
399 {
400 _cupsLangPrintf(stderr, _("ppdc: Expected choice code on line %d of %s."),
401 fp->line, fp->filename);
402 return (NULL);
403 }
404
405 // Return the new choice
406 return (new ppdcChoice(name, text, code));
407 }
408
409
410 //
411 // 'ppdcSource::get_color_model()' - Get an old-style color model option.
412 //
413
414 ppdcChoice * // O - Choice data
get_color_model(ppdcFile * fp)415 ppdcSource::get_color_model(ppdcFile *fp)
416 // I - File to read
417 {
418 char name[1024], // Option name
419 *text, // Text option
420 temp[256]; // Temporary string
421 int color_space, // Colorspace
422 color_order, // Color order
423 compression; // Compression mode
424
425
426 // Get the ColorModel parameters:
427 //
428 // ColorModel name/text colorspace colororder compression
429 if (!get_token(fp, name, sizeof(name)))
430 {
431 _cupsLangPrintf(stderr,
432 _("ppdc: Expected name/text combination for ColorModel on "
433 "line %d of %s."), fp->line, fp->filename);
434 return (NULL);
435 }
436
437 if ((text = strchr(name, '/')) != NULL)
438 *text++ = '\0';
439 else
440 text = name;
441
442 if (!get_token(fp, temp, sizeof(temp)))
443 {
444 _cupsLangPrintf(stderr,
445 _("ppdc: Expected colorspace for ColorModel on line %d of "
446 "%s."), fp->line, fp->filename);
447 return (NULL);
448 }
449
450 if ((color_space = get_color_space(temp)) < 0)
451 color_space = get_integer(temp);
452
453 if (!get_token(fp, temp, sizeof(temp)))
454 {
455 _cupsLangPrintf(stderr,
456 _("ppdc: Expected color order for ColorModel on line %d of "
457 "%s."), fp->line, fp->filename);
458 return (NULL);
459 }
460
461 if ((color_order = get_color_order(temp)) < 0)
462 color_order = get_integer(temp);
463
464 if (!get_token(fp, temp, sizeof(temp)))
465 {
466 _cupsLangPrintf(stderr,
467 _("ppdc: Expected compression for ColorModel on line %d of "
468 "%s."), fp->line, fp->filename);
469 return (NULL);
470 }
471
472 compression = get_integer(temp);
473
474 snprintf(temp, sizeof(temp),
475 "<</cupsColorSpace %d/cupsColorOrder %d/cupsCompression %d>>"
476 "setpagedevice",
477 color_space, color_order, compression);
478
479 return (new ppdcChoice(name, text, temp));
480 }
481
482
483 //
484 // 'ppdcSource::get_color_order()' - Get an old-style color order value.
485 //
486
487 int // O - Color order value
get_color_order(const char * co)488 ppdcSource::get_color_order(
489 const char *co) // I - Color order string
490 {
491 if (!_cups_strcasecmp(co, "chunked") ||
492 !_cups_strcasecmp(co, "chunky"))
493 return (CUPS_ORDER_CHUNKED);
494 else if (!_cups_strcasecmp(co, "banded"))
495 return (CUPS_ORDER_BANDED);
496 else if (!_cups_strcasecmp(co, "planar"))
497 return (CUPS_ORDER_PLANAR);
498 else
499 return (-1);
500 }
501
502
503 //
504 // 'ppdcSource::get_color_profile()' - Get a color profile definition.
505 //
506
507 ppdcProfile * // O - Color profile
get_color_profile(ppdcFile * fp)508 ppdcSource::get_color_profile(
509 ppdcFile *fp) // I - File to read
510 {
511 char resolution[1024], // Resolution/media type
512 *media_type; // Media type
513 int i; // Looping var
514 float g, // Gamma value
515 d, // Density value
516 m[9]; // Transform matrix
517
518
519 // Get the ColorProfile parameters:
520 //
521 // ColorProfile resolution/mediatype gamma density m00 m01 m02 ... m22
522 if (!get_token(fp, resolution, sizeof(resolution)))
523 {
524 _cupsLangPrintf(stderr,
525 _("ppdc: Expected resolution/mediatype following "
526 "ColorProfile on line %d of %s."),
527 fp->line, fp->filename);
528 return (NULL);
529 }
530
531 if ((media_type = strchr(resolution, '/')) != NULL)
532 *media_type++ = '\0';
533 else
534 media_type = resolution;
535
536 g = get_float(fp);
537 d = get_float(fp);
538 for (i = 0; i < 9; i ++)
539 m[i] = get_float(fp);
540
541 return (new ppdcProfile(resolution, media_type, d, g, m));
542 }
543
544
545 //
546 // 'ppdcSource::get_color_space()' - Get an old-style colorspace value.
547 //
548
549 int // O - Colorspace value
get_color_space(const char * cs)550 ppdcSource::get_color_space(
551 const char *cs) // I - Colorspace string
552 {
553 if (!_cups_strcasecmp(cs, "w"))
554 return (CUPS_CSPACE_W);
555 else if (!_cups_strcasecmp(cs, "rgb"))
556 return (CUPS_CSPACE_RGB);
557 else if (!_cups_strcasecmp(cs, "rgba"))
558 return (CUPS_CSPACE_RGBA);
559 else if (!_cups_strcasecmp(cs, "k"))
560 return (CUPS_CSPACE_K);
561 else if (!_cups_strcasecmp(cs, "cmy"))
562 return (CUPS_CSPACE_CMY);
563 else if (!_cups_strcasecmp(cs, "ymc"))
564 return (CUPS_CSPACE_YMC);
565 else if (!_cups_strcasecmp(cs, "cmyk"))
566 return (CUPS_CSPACE_CMYK);
567 else if (!_cups_strcasecmp(cs, "ymck"))
568 return (CUPS_CSPACE_YMCK);
569 else if (!_cups_strcasecmp(cs, "kcmy"))
570 return (CUPS_CSPACE_KCMY);
571 else if (!_cups_strcasecmp(cs, "kcmycm"))
572 return (CUPS_CSPACE_KCMYcm);
573 else if (!_cups_strcasecmp(cs, "gmck"))
574 return (CUPS_CSPACE_GMCK);
575 else if (!_cups_strcasecmp(cs, "gmcs"))
576 return (CUPS_CSPACE_GMCS);
577 else if (!_cups_strcasecmp(cs, "white"))
578 return (CUPS_CSPACE_WHITE);
579 else if (!_cups_strcasecmp(cs, "gold"))
580 return (CUPS_CSPACE_GOLD);
581 else if (!_cups_strcasecmp(cs, "silver"))
582 return (CUPS_CSPACE_SILVER);
583 else if (!_cups_strcasecmp(cs, "CIEXYZ"))
584 return (CUPS_CSPACE_CIEXYZ);
585 else if (!_cups_strcasecmp(cs, "CIELab"))
586 return (CUPS_CSPACE_CIELab);
587 else if (!_cups_strcasecmp(cs, "RGBW"))
588 return (CUPS_CSPACE_RGBW);
589 else if (!_cups_strcasecmp(cs, "ICC1"))
590 return (CUPS_CSPACE_ICC1);
591 else if (!_cups_strcasecmp(cs, "ICC2"))
592 return (CUPS_CSPACE_ICC2);
593 else if (!_cups_strcasecmp(cs, "ICC3"))
594 return (CUPS_CSPACE_ICC3);
595 else if (!_cups_strcasecmp(cs, "ICC4"))
596 return (CUPS_CSPACE_ICC4);
597 else if (!_cups_strcasecmp(cs, "ICC5"))
598 return (CUPS_CSPACE_ICC5);
599 else if (!_cups_strcasecmp(cs, "ICC6"))
600 return (CUPS_CSPACE_ICC6);
601 else if (!_cups_strcasecmp(cs, "ICC7"))
602 return (CUPS_CSPACE_ICC7);
603 else if (!_cups_strcasecmp(cs, "ICC8"))
604 return (CUPS_CSPACE_ICC8);
605 else if (!_cups_strcasecmp(cs, "ICC9"))
606 return (CUPS_CSPACE_ICC9);
607 else if (!_cups_strcasecmp(cs, "ICCA"))
608 return (CUPS_CSPACE_ICCA);
609 else if (!_cups_strcasecmp(cs, "ICCB"))
610 return (CUPS_CSPACE_ICCB);
611 else if (!_cups_strcasecmp(cs, "ICCC"))
612 return (CUPS_CSPACE_ICCC);
613 else if (!_cups_strcasecmp(cs, "ICCD"))
614 return (CUPS_CSPACE_ICCD);
615 else if (!_cups_strcasecmp(cs, "ICCE"))
616 return (CUPS_CSPACE_ICCE);
617 else if (!_cups_strcasecmp(cs, "ICCF"))
618 return (CUPS_CSPACE_ICCF);
619 else
620 return (-1);
621 }
622
623
624 //
625 // 'ppdcSource::get_constraint()' - Get a constraint.
626 //
627
628 ppdcConstraint * // O - Constraint
get_constraint(ppdcFile * fp)629 ppdcSource::get_constraint(ppdcFile *fp)// I - File to read
630 {
631 char temp[1024], // One string to rule them all
632 *ptr, // Pointer into string
633 *option1, // Constraint option 1
634 *choice1, // Constraint choice 1
635 *option2, // Constraint option 2
636 *choice2; // Constraint choice 2
637
638
639 // Read the UIConstaints parameter in one of the following forms:
640 //
641 // UIConstraints "*Option1 *Option2"
642 // UIConstraints "*Option1 Choice1 *Option2"
643 // UIConstraints "*Option1 *Option2 Choice2"
644 // UIConstraints "*Option1 Choice1 *Option2 Choice2"
645 if (!get_token(fp, temp, sizeof(temp)))
646 {
647 _cupsLangPrintf(stderr,
648 _("ppdc: Expected constraints string for UIConstraints on "
649 "line %d of %s."), fp->line, fp->filename);
650 return (NULL);
651 }
652
653 for (ptr = temp; isspace(*ptr); ptr ++);
654
655 if (*ptr != '*')
656 {
657 _cupsLangPrintf(stderr,
658 _("ppdc: Option constraint must *name on line %d of %s."),
659 fp->line, fp->filename);
660 return (NULL);
661 }
662
663 option1 = ptr;
664
665 for (; *ptr && !isspace(*ptr); ptr ++);
666 for (; isspace(*ptr); *ptr++ = '\0');
667
668 if (*ptr != '*')
669 {
670 choice1 = ptr;
671
672 for (; *ptr && !isspace(*ptr); ptr ++);
673 for (; isspace(*ptr); *ptr++ = '\0');
674 }
675 else
676 choice1 = NULL;
677
678 if (*ptr != '*')
679 {
680 _cupsLangPrintf(stderr,
681 _("ppdc: Expected two option names on line %d of %s."),
682 fp->line, fp->filename);
683 return (NULL);
684 }
685
686 option2 = ptr;
687
688 for (; *ptr && !isspace(*ptr); ptr ++);
689 for (; isspace(*ptr); *ptr++ = '\0');
690
691 if (*ptr)
692 choice2 = ptr;
693 else
694 choice2 = NULL;
695
696 return (new ppdcConstraint(option1, choice1, option2, choice2));
697 }
698
699
700 //
701 // 'ppdcSource::get_custom_size()' - Get a custom media size definition from a file.
702 //
703
704 ppdcMediaSize * // O - Media size
get_custom_size(ppdcFile * fp)705 ppdcSource::get_custom_size(ppdcFile *fp)
706 // I - File to read
707 {
708 char name[1024], // Name
709 *text, // Text
710 size_code[10240], // PageSize code
711 region_code[10240]; // PageRegion
712 float width, // Width
713 length, // Length
714 left, // Left margin
715 bottom, // Bottom margin
716 right, // Right margin
717 top; // Top margin
718
719
720 // Get the name, text, width, length, margins, and code:
721 //
722 // CustomMedia name/text width length left bottom right top size-code region-code
723 if (!get_token(fp, name, sizeof(name)))
724 return (NULL);
725
726 if ((text = strchr(name, '/')) != NULL)
727 *text++ = '\0';
728 else
729 text = name;
730
731 if ((width = get_measurement(fp)) < 0.0f)
732 return (NULL);
733
734 if ((length = get_measurement(fp)) < 0.0f)
735 return (NULL);
736
737 if ((left = get_measurement(fp)) < 0.0f)
738 return (NULL);
739
740 if ((bottom = get_measurement(fp)) < 0.0f)
741 return (NULL);
742
743 if ((right = get_measurement(fp)) < 0.0f)
744 return (NULL);
745
746 if ((top = get_measurement(fp)) < 0.0f)
747 return (NULL);
748
749 if (!get_token(fp, size_code, sizeof(size_code)))
750 return (NULL);
751
752 if (!get_token(fp, region_code, sizeof(region_code)))
753 return (NULL);
754
755 // Return the new media size...
756 return (new ppdcMediaSize(name, text, width, length, left, bottom,
757 right, top, size_code, region_code));
758 }
759
760
761 //
762 // 'ppdcSource::get_duplex()' - Get a duplex option.
763 //
764
765 void
get_duplex(ppdcFile * fp,ppdcDriver * d)766 ppdcSource::get_duplex(ppdcFile *fp, // I - File to read from
767 ppdcDriver *d) // I - Current driver
768 {
769 char temp[256]; // Duplex keyword
770 ppdcAttr *attr; // cupsFlipDuplex attribute
771 ppdcGroup *g; // Current group
772 ppdcOption *o; // Duplex option
773
774
775 // Duplex {boolean|none|normal|flip}
776 if (!get_token(fp, temp, sizeof(temp)))
777 {
778 _cupsLangPrintf(stderr,
779 _("ppdc: Expected duplex type after Duplex on line %d of "
780 "%s."), fp->line, fp->filename);
781 return;
782 }
783
784 if (cond_state)
785 return;
786
787 if (!_cups_strcasecmp(temp, "none") || !_cups_strcasecmp(temp, "false") ||
788 !_cups_strcasecmp(temp, "no") || !_cups_strcasecmp(temp, "off"))
789 {
790 g = d->find_group("General");
791 if ((o = g->find_option("Duplex")) != NULL)
792 g->options->remove(o);
793
794 for (attr = (ppdcAttr *)d->attrs->first();
795 attr;
796 attr = (ppdcAttr *)d->attrs->next())
797 if (!strcmp(attr->name->value, "cupsFlipDuplex"))
798 {
799 d->attrs->remove(attr);
800 break;
801 }
802 }
803 else if (!_cups_strcasecmp(temp, "normal") || !_cups_strcasecmp(temp, "true") ||
804 !_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "on") ||
805 !_cups_strcasecmp(temp, "flip") || !_cups_strcasecmp(temp, "rotated") ||
806 !_cups_strcasecmp(temp, "manualtumble"))
807 {
808 g = d->find_group("General");
809 o = g->find_option("Duplex");
810
811 if (!o)
812 {
813 o = new ppdcOption(PPDC_PICKONE, "Duplex", "2-Sided Printing",
814 !_cups_strcasecmp(temp, "flip") ? PPDC_SECTION_PAGE :
815 PPDC_SECTION_ANY, 10.0f);
816 o->add_choice(new ppdcChoice("None", "Off (1-Sided)",
817 "<</Duplex false>>setpagedevice"));
818 o->add_choice(new ppdcChoice("DuplexNoTumble", "Long-Edge (Portrait)",
819 "<</Duplex true/Tumble false>>setpagedevice"));
820 o->add_choice(new ppdcChoice("DuplexTumble", "Short-Edge (Landscape)",
821 "<</Duplex true/Tumble true>>setpagedevice"));
822
823 g->add_option(o);
824 }
825
826 for (attr = (ppdcAttr *)d->attrs->first();
827 attr;
828 attr = (ppdcAttr *)d->attrs->next())
829 if (!strcmp(attr->name->value, "cupsFlipDuplex"))
830 {
831 if (_cups_strcasecmp(temp, "flip"))
832 d->attrs->remove(attr);
833 break;
834 }
835
836 if (!_cups_strcasecmp(temp, "flip") && !attr)
837 d->add_attr(new ppdcAttr("cupsFlipDuplex", NULL, NULL, "true"));
838
839 for (attr = (ppdcAttr *)d->attrs->first();
840 attr;
841 attr = (ppdcAttr *)d->attrs->next())
842 if (!strcmp(attr->name->value, "cupsBackSide"))
843 {
844 d->attrs->remove(attr);
845 break;
846 }
847
848 if (!_cups_strcasecmp(temp, "flip"))
849 d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Flipped"));
850 else if (!_cups_strcasecmp(temp, "rotated"))
851 d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Rotated"));
852 else if (!_cups_strcasecmp(temp, "manualtumble"))
853 d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "ManualTumble"));
854 else
855 d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Normal"));
856 }
857 else
858 _cupsLangPrintf(stderr,
859 _("ppdc: Unknown duplex type \"%s\" on line %d of %s."),
860 temp, fp->line, fp->filename);
861 }
862
863
864 //
865 // 'ppdcSource::get_filter()' - Get a filter.
866 //
867
868 ppdcFilter * // O - Filter
get_filter(ppdcFile * fp)869 ppdcSource::get_filter(ppdcFile *fp) // I - File to read
870 {
871 char type[1024], // MIME type
872 program[1024], // Filter program
873 *ptr; // Pointer into MIME type
874 int cost; // Relative cost
875
876
877 // Read filter parameters in one of the following formats:
878 //
879 // Filter "type cost program"
880 // Filter type cost program
881
882 if (!get_token(fp, type, sizeof(type)))
883 {
884 _cupsLangPrintf(stderr,
885 _("ppdc: Expected a filter definition on line %d of %s."),
886 fp->line, fp->filename);
887 return (NULL);
888 }
889
890 if ((ptr = strchr(type, ' ')) != NULL)
891 {
892 // Old-style filter definition in one string...
893 *ptr++ = '\0';
894 cost = strtol(ptr, &ptr, 10);
895
896 while (isspace(*ptr))
897 ptr ++;
898
899 strlcpy(program, ptr, sizeof(program));
900 }
901 else
902 {
903 cost = get_integer(fp);
904
905 if (!get_token(fp, program, sizeof(program)))
906 {
907 _cupsLangPrintf(stderr,
908 _("ppdc: Expected a program name on line %d of %s."),
909 fp->line, fp->filename);
910 return (NULL);
911 }
912 }
913
914 if (!type[0])
915 {
916 _cupsLangPrintf(stderr,
917 _("ppdc: Invalid empty MIME type for filter on line %d of "
918 "%s."), fp->line, fp->filename);
919 return (NULL);
920 }
921
922 if (cost < 0 || cost > 200)
923 {
924 _cupsLangPrintf(stderr,
925 _("ppdc: Invalid cost for filter on line %d of %s."),
926 fp->line, fp->filename);
927 return (NULL);
928 }
929
930 if (!program[0])
931 {
932 _cupsLangPrintf(stderr,
933 _("ppdc: Invalid empty program name for filter on line %d "
934 "of %s."), fp->line, fp->filename);
935 return (NULL);
936 }
937
938 return (new ppdcFilter(type, program, cost));
939 }
940
941
942 //
943 // 'ppdcSource::get_float()' - Get a single floating-point number.
944 //
945
946 float // O - Number
get_float(ppdcFile * fp)947 ppdcSource::get_float(ppdcFile *fp) // I - File to read
948 {
949 char temp[256], // String buffer
950 *ptr; // Pointer into buffer
951 float val; // Floating point value
952
953
954 // Get the number from the file and range-check...
955 if (!get_token(fp, temp, sizeof(temp)))
956 {
957 _cupsLangPrintf(stderr, _("ppdc: Expected real number on line %d of %s."),
958 fp->line, fp->filename);
959 return (-1.0f);
960 }
961
962 val = (float)strtod(temp, &ptr);
963
964 if (*ptr)
965 {
966 _cupsLangPrintf(stderr,
967 _("ppdc: Unknown trailing characters in real number \"%s\" "
968 "on line %d of %s."), temp, fp->line, fp->filename);
969 return (-1.0f);
970 }
971 else
972 return (val);
973 }
974
975
976 //
977 // 'ppdcSource::get_font()' - Get a font definition.
978 //
979
980 ppdcFont * // O - Font data
get_font(ppdcFile * fp)981 ppdcSource::get_font(ppdcFile *fp) // I - File to read
982 {
983 char name[256], // Font name
984 encoding[256], // Font encoding
985 version[256], // Font version
986 charset[256], // Font charset
987 temp[256]; // Font status string
988 ppdcFontStatus status; // Font status enumeration
989
990
991 // Read font parameters as follows:
992 //
993 // Font *
994 // Font name encoding version charset status
995 // %font name encoding version charset status
996 //
997 // "Name" is the PostScript font name.
998 //
999 // "Encoding" is the default encoding of the font: Standard, ISOLatin1,
1000 // Special, Expert, ExpertSubset, etc.
1001 //
1002 // "Version" is the version number string.
1003 //
1004 // "Charset" specifies the characters that are included in the font:
1005 // Standard, Special, Expert, Adobe-Identity, etc.
1006 //
1007 // "Status" is the keyword ROM or Disk.
1008 if (!get_token(fp, name, sizeof(name)))
1009 {
1010 _cupsLangPrintf(stderr,
1011 _("ppdc: Expected name after Font on line %d of %s."),
1012 fp->line, fp->filename);
1013 return (0);
1014 }
1015
1016 if (!strcmp(name, "*"))
1017 {
1018 // Include all base fonts...
1019 encoding[0] = '\0';
1020 version[0] = '\0';
1021 charset[0] = '\0';
1022 status = PPDC_FONT_ROM;
1023 }
1024 else
1025 {
1026 // Load a full font definition...
1027 if (!get_token(fp, encoding, sizeof(encoding)))
1028 {
1029 _cupsLangPrintf(stderr,
1030 _("ppdc: Expected encoding after Font on line %d of "
1031 "%s."), fp->line, fp->filename);
1032 return (0);
1033 }
1034
1035 if (!get_token(fp, version, sizeof(version)))
1036 {
1037 _cupsLangPrintf(stderr,
1038 _("ppdc: Expected version after Font on line %d of "
1039 "%s."), fp->line, fp->filename);
1040 return (0);
1041 }
1042
1043 if (!get_token(fp, charset, sizeof(charset)))
1044 {
1045 _cupsLangPrintf(stderr,
1046 _("ppdc: Expected charset after Font on line %d of "
1047 "%s."), fp->line, fp->filename);
1048 return (0);
1049 }
1050
1051 if (!get_token(fp, temp, sizeof(temp)))
1052 {
1053 _cupsLangPrintf(stderr,
1054 _("ppdc: Expected status after Font on line %d of %s."),
1055 fp->line, fp->filename);
1056 return (0);
1057 }
1058
1059 if (!_cups_strcasecmp(temp, "ROM"))
1060 status = PPDC_FONT_ROM;
1061 else if (!_cups_strcasecmp(temp, "Disk"))
1062 status = PPDC_FONT_DISK;
1063 else
1064 {
1065 _cupsLangPrintf(stderr,
1066 _("ppdc: Bad status keyword %s on line %d of %s."),
1067 temp, fp->line, fp->filename);
1068 return (0);
1069 }
1070 }
1071
1072 // printf("Font %s %s %s %s %s\n", name, encoding, version, charset, temp);
1073
1074 return (new ppdcFont(name, encoding, version, charset, status));
1075 }
1076
1077
1078 //
1079 // 'ppdcSource::get_generic()' - Get a generic old-style option.
1080 //
1081
1082 ppdcChoice * // O - Choice data
get_generic(ppdcFile * fp,const char * keyword,const char * tattr,const char * nattr)1083 ppdcSource::get_generic(ppdcFile *fp, // I - File to read
1084 const char *keyword,
1085 // I - Keyword name
1086 const char *tattr,
1087 // I - Text attribute
1088 const char *nattr)
1089 // I - Numeric attribute
1090 {
1091 char name[1024], // Name
1092 *text, // Text
1093 command[256]; // Command string
1094 int val; // Numeric value
1095
1096
1097 // Read one of the following parameters:
1098 //
1099 // Foo name/text
1100 // Foo integer name/text
1101 if (nattr)
1102 val = get_integer(fp);
1103 else
1104 val = 0;
1105
1106 if (!get_token(fp, name, sizeof(name)))
1107 {
1108 _cupsLangPrintf(stderr,
1109 _("ppdc: Expected name/text after %s on line %d of %s."),
1110 keyword, fp->line, fp->filename);
1111 return (NULL);
1112 }
1113
1114 if ((text = strchr(name, '/')) != NULL)
1115 *text++ = '\0';
1116 else
1117 text = name;
1118
1119 if (nattr)
1120 {
1121 if (tattr)
1122 snprintf(command, sizeof(command),
1123 "<</%s(%s)/%s %d>>setpagedevice",
1124 tattr, name, nattr, val);
1125 else
1126 snprintf(command, sizeof(command),
1127 "<</%s %d>>setpagedevice",
1128 nattr, val);
1129 }
1130 else
1131 snprintf(command, sizeof(command),
1132 "<</%s(%s)>>setpagedevice",
1133 tattr, name);
1134
1135 return (new ppdcChoice(name, text, command));
1136 }
1137
1138
1139 //
1140 // 'ppdcSource::get_group()' - Get an option group.
1141 //
1142
1143 ppdcGroup * // O - Group
get_group(ppdcFile * fp,ppdcDriver * d)1144 ppdcSource::get_group(ppdcFile *fp, // I - File to read
1145 ppdcDriver *d) // I - Printer driver
1146 {
1147 char name[1024], // UI name
1148 *text; // UI text
1149 ppdcGroup *g; // Group
1150
1151
1152 // Read the Group parameters:
1153 //
1154 // Group name/text
1155 if (!get_token(fp, name, sizeof(name)))
1156 {
1157 _cupsLangPrintf(stderr,
1158 _("ppdc: Expected group name/text on line %d of %s."),
1159 fp->line, fp->filename);
1160 return (NULL);
1161 }
1162
1163 if ((text = strchr(name, '/')) != NULL)
1164 *text++ = '\0';
1165 else
1166 text = name;
1167
1168 // See if the group already exists...
1169 if ((g = d->find_group(name)) == NULL)
1170 {
1171 // Nope, add a new one...
1172 g = new ppdcGroup(name, text);
1173 }
1174
1175 return (g);
1176 }
1177
1178
1179 //
1180 // 'ppdcSource::get_installable()' - Get an installable option.
1181 //
1182
1183 ppdcOption * // O - Option
get_installable(ppdcFile * fp)1184 ppdcSource::get_installable(ppdcFile *fp)
1185 // I - File to read
1186 {
1187 char name[1024], // Name for installable option
1188 *text; // Text for installable option
1189 ppdcOption *o; // Option
1190
1191
1192 // Read the parameter for an installable option:
1193 //
1194 // Installable name/text
1195 if (!get_token(fp, name, sizeof(name)))
1196 {
1197 _cupsLangPrintf(stderr,
1198 _("ppdc: Expected name/text after Installable on line %d "
1199 "of %s."), fp->line, fp->filename);
1200 return (NULL);
1201 }
1202
1203 if ((text = strchr(name, '/')) != NULL)
1204 *text++ = '\0';
1205 else
1206 text = name;
1207
1208 // Create the option...
1209 o = new ppdcOption(PPDC_BOOLEAN, name, text, PPDC_SECTION_ANY, 10.0f);
1210
1211 // Add the false and true choices...
1212 o->add_choice(new ppdcChoice("False", "Not Installed", ""));
1213 o->add_choice(new ppdcChoice("True", "Installed", ""));
1214
1215 return (o);
1216 }
1217
1218
1219 //
1220 // 'ppdcSource::get_integer()' - Get an integer value from a string.
1221 //
1222
1223 #define PPDC_XX -1 // Bad
1224 #define PPDC_EQ 0 // ==
1225 #define PPDC_NE 1 // !=
1226 #define PPDC_LT 2 // <
1227 #define PPDC_LE 3 // <=
1228 #define PPDC_GT 4 // >
1229 #define PPDC_GE 5 // >=
1230
1231 int // O - Integer value
get_integer(const char * v)1232 ppdcSource::get_integer(const char *v) // I - Value string
1233 {
1234 long val; // Value
1235 long temp, // Temporary value
1236 temp2; // Second temporary value
1237 char *newv, // New value string pointer
1238 ch; // Temporary character
1239 ppdcVariable *var; // #define variable
1240 int compop; // Comparison operator
1241
1242
1243 // Parse the value string...
1244 if (!v)
1245 return (-1);
1246
1247 if (isdigit(*v & 255) || *v == '-' || *v == '+')
1248 {
1249 // Return a simple integer value
1250 val = strtol(v, (char **)&v, 0);
1251 if (*v || val == LONG_MIN)
1252 return (-1);
1253 else
1254 return ((int)val);
1255 }
1256 else if (*v == '(')
1257 {
1258 // Evaluate and expression in any of the following formats:
1259 //
1260 // (number number ... number) Bitwise OR of all numbers
1261 // (NAME == value) 1 if equal, 0 otherwise
1262 // (NAME != value) 1 if not equal, 0 otherwise
1263 // (NAME < value) 1 if less than, 0 otherwise
1264 // (NAME <= value) 1 if less than or equal, 0 otherwise
1265 // (NAME > value) 1 if greater than, 0 otherwise
1266 // (NAME >= value) 1 if greater than or equal, 0 otherwise
1267
1268 v ++;
1269 val = 0;
1270
1271 while (*v && *v != ')')
1272 {
1273 // Skip leading whitespace...
1274 while (*v && isspace(*v & 255))
1275 v ++;
1276
1277 if (!*v || *v == ')')
1278 break;
1279
1280 if (isdigit(*v & 255) || *v == '-' || *v == '+')
1281 {
1282 // Bitwise OR a number...
1283 temp = strtol(v, &newv, 0);
1284
1285 if (!*newv || newv == v || !(isspace(*newv) || *newv == ')') ||
1286 temp == LONG_MIN)
1287 return (-1);
1288 }
1289 else
1290 {
1291 // NAME logicop value
1292 for (newv = (char *)v + 1;
1293 *newv && (isalnum(*newv & 255) || *newv == '_');
1294 newv ++)
1295 /* do nothing */;
1296
1297 ch = *newv;
1298 *newv = '\0';
1299
1300 if ((var = find_variable(v)) != NULL)
1301 {
1302 if (!var->value || !var->value->value || !var->value->value[0])
1303 temp = 0;
1304 else if (isdigit(var->value->value[0] & 255) ||
1305 var->value->value[0] == '-' ||
1306 var->value->value[0] == '+')
1307 temp = strtol(var->value->value, NULL, 0);
1308 else
1309 temp = 1;
1310 }
1311 else
1312 temp = 0;
1313
1314 *newv = ch;
1315 while (isspace(*newv & 255))
1316 newv ++;
1317
1318 if (!strncmp(newv, "==", 2))
1319 {
1320 compop = PPDC_EQ;
1321 newv += 2;
1322 }
1323 else if (!strncmp(newv, "!=", 2))
1324 {
1325 compop = PPDC_NE;
1326 newv += 2;
1327 }
1328 else if (!strncmp(newv, "<=", 2))
1329 {
1330 compop = PPDC_LE;
1331 newv += 2;
1332 }
1333 else if (*newv == '<')
1334 {
1335 compop = PPDC_LT;
1336 newv ++;
1337 }
1338 else if (!strncmp(newv, ">=", 2))
1339 {
1340 compop = PPDC_GE;
1341 newv += 2;
1342 }
1343 else if (*newv == '>')
1344 {
1345 compop = PPDC_GT;
1346 newv ++;
1347 }
1348 else
1349 compop = PPDC_XX;
1350
1351 if (compop != PPDC_XX)
1352 {
1353 while (isspace(*newv & 255))
1354 newv ++;
1355
1356 if (*newv == ')' || !*newv)
1357 return (-1);
1358
1359 if (isdigit(*newv & 255) || *newv == '-' || *newv == '+')
1360 {
1361 // Get the second number...
1362 temp2 = strtol(newv, &newv, 0);
1363 if (!*newv || newv == v || !(isspace(*newv) || *newv == ')') ||
1364 temp == LONG_MIN)
1365 return (-1);
1366 }
1367 else
1368 {
1369 // Lookup the second name...
1370 for (v = newv, newv ++;
1371 *newv && (isalnum(*newv & 255) || *newv == '_');
1372 newv ++);
1373
1374 ch = *newv;
1375 *newv = '\0';
1376
1377 if ((var = find_variable(v)) != NULL)
1378 {
1379 if (!var->value || !var->value->value || !var->value->value[0])
1380 temp2 = 0;
1381 else if (isdigit(var->value->value[0] & 255) ||
1382 var->value->value[0] == '-' ||
1383 var->value->value[0] == '+')
1384 temp2 = strtol(var->value->value, NULL, 0);
1385 else
1386 temp2 = 1;
1387 }
1388 else
1389 temp2 = 0;
1390
1391 *newv = ch;
1392 }
1393
1394 // Do the comparison...
1395 switch (compop)
1396 {
1397 case PPDC_EQ :
1398 temp = temp == temp2;
1399 break;
1400 case PPDC_NE :
1401 temp = temp != temp2;
1402 break;
1403 case PPDC_LT :
1404 temp = temp < temp2;
1405 break;
1406 case PPDC_LE :
1407 temp = temp <= temp2;
1408 break;
1409 case PPDC_GT :
1410 temp = temp > temp2;
1411 break;
1412 case PPDC_GE :
1413 temp = temp >= temp2;
1414 break;
1415 }
1416 }
1417 }
1418
1419 val |= temp;
1420 v = newv;
1421 }
1422
1423 if (*v == ')' && !v[1])
1424 return ((int)val);
1425 else
1426 return (-1);
1427 }
1428 else if ((var = find_variable(v)) != NULL)
1429 {
1430 // NAME by itself returns 1 if the #define variable is not blank and
1431 // not "0"...
1432 return (var->value->value && var->value->value[0] &&
1433 strcmp(var->value->value, "0"));
1434 }
1435 else
1436 {
1437 // Anything else is an error...
1438 return (-1);
1439 }
1440 }
1441
1442
1443 //
1444 // 'ppdcSource::get_integer()' - Get an integer value from a file.
1445 //
1446
1447 int // O - Integer value
get_integer(ppdcFile * fp)1448 ppdcSource::get_integer(ppdcFile *fp) // I - File to read
1449 {
1450 char temp[1024]; // String buffer
1451
1452
1453 if (!get_token(fp, temp, sizeof(temp)))
1454 {
1455 _cupsLangPrintf(stderr, _("ppdc: Expected integer on line %d of %s."),
1456 fp->line, fp->filename);
1457 return (-1);
1458 }
1459 else
1460 return (get_integer(temp));
1461 }
1462
1463
1464 //
1465 // 'ppdcSource::get_measurement()' - Get a measurement value.
1466 //
1467
1468 float // O - Measurement value in points
get_measurement(ppdcFile * fp)1469 ppdcSource::get_measurement(ppdcFile *fp)
1470 // I - File to read
1471 {
1472 char buffer[256], // Number buffer
1473 *ptr; // Pointer into buffer
1474 float val; // Measurement value
1475
1476
1477 // Grab a token from the file...
1478 if (!get_token(fp, buffer, sizeof(buffer)))
1479 return (-1.0f);
1480
1481 // Get the floating point value of "s" and skip all digits and decimal points.
1482 val = (float)strtod(buffer, &ptr);
1483
1484 // Check for a trailing unit specifier...
1485 if (!_cups_strcasecmp(ptr, "mm"))
1486 val *= 72.0f / 25.4f;
1487 else if (!_cups_strcasecmp(ptr, "cm"))
1488 val *= 72.0f / 2.54f;
1489 else if (!_cups_strcasecmp(ptr, "m"))
1490 val *= 72.0f / 0.0254f;
1491 else if (!_cups_strcasecmp(ptr, "in"))
1492 val *= 72.0f;
1493 else if (!_cups_strcasecmp(ptr, "ft"))
1494 val *= 72.0f * 12.0f;
1495 else if (_cups_strcasecmp(ptr, "pt") && *ptr)
1496 return (-1.0f);
1497
1498 return (val);
1499 }
1500
1501
1502 //
1503 // 'ppdcSource::get_option()' - Get an option definition.
1504 //
1505
1506 ppdcOption * // O - Option
get_option(ppdcFile * fp,ppdcDriver * d,ppdcGroup * g)1507 ppdcSource::get_option(ppdcFile *fp, // I - File to read
1508 ppdcDriver *d, // I - Printer driver
1509 ppdcGroup *g) // I - Current group
1510 {
1511 char name[1024], // UI name
1512 *text, // UI text
1513 type[256]; // UI type string
1514 ppdcOptType ot; // Option type value
1515 ppdcOptSection section; // Option section
1516 float order; // Option order
1517 ppdcOption *o; // Option
1518 ppdcGroup *mg; // Matching group, if any
1519
1520
1521 // Read the Option parameters:
1522 //
1523 // Option name/text type section order
1524 if (!get_token(fp, name, sizeof(name)))
1525 {
1526 _cupsLangPrintf(stderr,
1527 _("ppdc: Expected option name/text on line %d of %s."),
1528 fp->line, fp->filename);
1529 return (NULL);
1530 }
1531
1532 if ((text = strchr(name, '/')) != NULL)
1533 *text++ = '\0';
1534 else
1535 text = name;
1536
1537 if (!get_token(fp, type, sizeof(type)))
1538 {
1539 _cupsLangPrintf(stderr, _("ppdc: Expected option type on line %d of %s."),
1540 fp->line, fp->filename);
1541 return (NULL);
1542 }
1543
1544 if (!_cups_strcasecmp(type, "boolean"))
1545 ot = PPDC_BOOLEAN;
1546 else if (!_cups_strcasecmp(type, "pickone"))
1547 ot = PPDC_PICKONE;
1548 else if (!_cups_strcasecmp(type, "pickmany"))
1549 ot = PPDC_PICKMANY;
1550 else
1551 {
1552 _cupsLangPrintf(stderr,
1553 _("ppdc: Invalid option type \"%s\" on line %d of %s."),
1554 type, fp->line, fp->filename);
1555 return (NULL);
1556 }
1557
1558 if (!get_token(fp, type, sizeof(type)))
1559 {
1560 _cupsLangPrintf(stderr,
1561 _("ppdc: Expected option section on line %d of %s."),
1562 fp->line, fp->filename);
1563 return (NULL);
1564 }
1565
1566 if (!_cups_strcasecmp(type, "AnySetup"))
1567 section = PPDC_SECTION_ANY;
1568 else if (!_cups_strcasecmp(type, "DocumentSetup"))
1569 section = PPDC_SECTION_DOCUMENT;
1570 else if (!_cups_strcasecmp(type, "ExitServer"))
1571 section = PPDC_SECTION_EXIT;
1572 else if (!_cups_strcasecmp(type, "JCLSetup"))
1573 section = PPDC_SECTION_JCL;
1574 else if (!_cups_strcasecmp(type, "PageSetup"))
1575 section = PPDC_SECTION_PAGE;
1576 else if (!_cups_strcasecmp(type, "Prolog"))
1577 section = PPDC_SECTION_PROLOG;
1578 else
1579 {
1580 _cupsLangPrintf(stderr,
1581 _("ppdc: Invalid option section \"%s\" on line %d of "
1582 "%s."), type, fp->line, fp->filename);
1583 return (NULL);
1584 }
1585
1586 order = get_float(fp);
1587
1588 // See if the option already exists...
1589 if ((o = d->find_option_group(name, &mg)) == NULL)
1590 {
1591 // Nope, add a new one...
1592 o = new ppdcOption(ot, name, text, section, order);
1593 }
1594 else if (o->type != ot)
1595 {
1596 _cupsLangPrintf(stderr,
1597 _("ppdc: Option %s redefined with a different type on line "
1598 "%d of %s."), name, fp->line, fp->filename);
1599 return (NULL);
1600 }
1601 else if (g != mg)
1602 {
1603 _cupsLangPrintf(stderr,
1604 _("ppdc: Option %s defined in two different groups on line "
1605 "%d of %s."), name, fp->line, fp->filename);
1606 return (NULL);
1607 }
1608
1609 return (o);
1610 }
1611
1612
1613 //
1614 // 'ppdcSource::get_po()' - Get a message catalog.
1615 //
1616
1617 ppdcCatalog * // O - Message catalog
get_po(ppdcFile * fp)1618 ppdcSource::get_po(ppdcFile *fp) // I - File to read
1619 {
1620 char locale[32], // Locale name
1621 poname[1024], // Message catalog filename
1622 basedir[1024], // Base directory
1623 *baseptr, // Pointer into directory
1624 pofilename[1024]; // Full filename of message catalog
1625 ppdcCatalog *cat; // Message catalog
1626
1627
1628 // Read the #po parameters:
1629 //
1630 // #po locale "filename.po"
1631 if (!get_token(fp, locale, sizeof(locale)))
1632 {
1633 _cupsLangPrintf(stderr,
1634 _("ppdc: Expected locale after #po on line %d of %s."),
1635 fp->line, fp->filename);
1636 return (NULL);
1637 }
1638
1639 if (!get_token(fp, poname, sizeof(poname)))
1640 {
1641 _cupsLangPrintf(stderr,
1642 _("ppdc: Expected filename after #po %s on line %d of "
1643 "%s."), locale, fp->line, fp->filename);
1644 return (NULL);
1645 }
1646
1647 // See if the locale is already loaded...
1648 if (find_po(locale))
1649 {
1650 _cupsLangPrintf(stderr,
1651 _("ppdc: Duplicate #po for locale %s on line %d of %s."),
1652 locale, fp->line, fp->filename);
1653 return (NULL);
1654 }
1655
1656 // Figure out the current directory...
1657 strlcpy(basedir, fp->filename, sizeof(basedir));
1658
1659 if ((baseptr = strrchr(basedir, '/')) != NULL)
1660 *baseptr = '\0';
1661 else
1662 strlcpy(basedir, ".", sizeof(basedir));
1663
1664 // Find the po file...
1665 pofilename[0] = '\0';
1666
1667 if (!poname[0] ||
1668 find_include(poname, basedir, pofilename, sizeof(pofilename)))
1669 {
1670 // Found it, so load it...
1671 cat = new ppdcCatalog(locale, pofilename);
1672
1673 // Reset the filename to the name supplied by the user...
1674 cat->filename->release();
1675 cat->filename = new ppdcString(poname);
1676
1677 // Return the catalog...
1678 return (cat);
1679 }
1680 else
1681 {
1682 _cupsLangPrintf(stderr,
1683 _("ppdc: Unable to find #po file %s on line %d of %s."),
1684 poname, fp->line, fp->filename);
1685 return (NULL);
1686 }
1687 }
1688
1689
1690 //
1691 // 'ppdcSource::get_resolution()' - Get an old-style resolution option.
1692 //
1693
1694 ppdcChoice * // O - Choice data
get_resolution(ppdcFile * fp)1695 ppdcSource::get_resolution(ppdcFile *fp)// I - File to read
1696 {
1697 char name[1024], // Name
1698 *text, // Text
1699 temp[256], // Temporary string
1700 command[256], // Command string
1701 *commptr; // Pointer into command
1702 int xdpi, ydpi, // X + Y resolution
1703 color_order, // Color order
1704 color_space, // Colorspace
1705 compression, // Compression mode
1706 depth, // Bits per color
1707 row_count, // Row count
1708 row_feed, // Row feed
1709 row_step; // Row step/interval
1710
1711
1712 // Read the resolution parameters:
1713 //
1714 // Resolution colorspace bits row-count row-feed row-step name/text
1715 if (!get_token(fp, temp, sizeof(temp)))
1716 {
1717 _cupsLangPrintf(stderr,
1718 _("ppdc: Expected override field after Resolution on line "
1719 "%d of %s."), fp->line, fp->filename);
1720 return (NULL);
1721 }
1722
1723 color_order = get_color_order(temp);
1724 color_space = get_color_space(temp);
1725 compression = get_integer(temp);
1726
1727 depth = get_integer(fp);
1728 row_count = get_integer(fp);
1729 row_feed = get_integer(fp);
1730 row_step = get_integer(fp);
1731
1732 if (!get_token(fp, name, sizeof(name)))
1733 {
1734 _cupsLangPrintf(stderr,
1735 _("ppdc: Expected name/text after Resolution on line %d of "
1736 "%s."), fp->line, fp->filename);
1737 return (NULL);
1738 }
1739
1740 if ((text = strchr(name, '/')) != NULL)
1741 *text++ = '\0';
1742 else
1743 text = name;
1744
1745 switch (sscanf(name, "%dx%d", &xdpi, &ydpi))
1746 {
1747 case 1 :
1748 ydpi = xdpi;
1749 break;
1750 case 2 :
1751 break;
1752 default :
1753 _cupsLangPrintf(stderr,
1754 _("ppdc: Bad resolution name \"%s\" on line %d of "
1755 "%s."), name, fp->line, fp->filename);
1756 break;
1757 }
1758
1759 // Create the necessary PS commands...
1760 snprintf(command, sizeof(command),
1761 "<</HWResolution[%d %d]/cupsBitsPerColor %d/cupsRowCount %d"
1762 "/cupsRowFeed %d/cupsRowStep %d",
1763 xdpi, ydpi, depth, row_count, row_feed, row_step);
1764 commptr = command + strlen(command);
1765
1766 if (color_order >= 0)
1767 {
1768 snprintf(commptr, sizeof(command) - (size_t)(commptr - command),
1769 "/cupsColorOrder %d", color_order);
1770 commptr += strlen(commptr);
1771 }
1772
1773 if (color_space >= 0)
1774 {
1775 snprintf(commptr, sizeof(command) - (size_t)(commptr - command),
1776 "/cupsColorSpace %d", color_space);
1777 commptr += strlen(commptr);
1778 }
1779
1780 if (compression >= 0)
1781 {
1782 snprintf(commptr, sizeof(command) - (size_t)(commptr - command),
1783 "/cupsCompression %d", compression);
1784 commptr += strlen(commptr);
1785 }
1786
1787 snprintf(commptr, sizeof(command) - (size_t)(commptr - command), ">>setpagedevice");
1788
1789 // Return the new choice...
1790 return (new ppdcChoice(name, text, command));
1791 }
1792
1793
1794 //
1795 // 'ppdcSource::get_simple_profile()' - Get a simple color profile definition.
1796 //
1797
1798 ppdcProfile * // O - Color profile
get_simple_profile(ppdcFile * fp)1799 ppdcSource::get_simple_profile(ppdcFile *fp)
1800 // I - File to read
1801 {
1802 char resolution[1024], // Resolution/media type
1803 *media_type; // Media type
1804 float m[9]; // Transform matrix
1805 float kd, rd, g; // Densities and gamma
1806 float red, green, blue; // RGB adjustments
1807 float yellow; // Yellow density
1808 float color; // Color density values
1809
1810
1811 // Get the SimpleColorProfile parameters:
1812 //
1813 // SimpleColorProfile resolution/mediatype black-density yellow-density
1814 // red-density gamma red-adjust green-adjust blue-adjust
1815 if (!get_token(fp, resolution, sizeof(resolution)))
1816 {
1817 _cupsLangPrintf(stderr,
1818 _("ppdc: Expected resolution/mediatype following "
1819 "SimpleColorProfile on line %d of %s."),
1820 fp->line, fp->filename);
1821 return (NULL);
1822 }
1823
1824 if ((media_type = strchr(resolution, '/')) != NULL)
1825 *media_type++ = '\0';
1826 else
1827 media_type = resolution;
1828
1829 // Collect the profile parameters...
1830 kd = get_float(fp);
1831 yellow = get_float(fp);
1832 rd = get_float(fp);
1833 g = get_float(fp);
1834 red = get_float(fp);
1835 green = get_float(fp);
1836 blue = get_float(fp);
1837
1838 // Build the color profile...
1839 color = 0.5f * rd / kd - kd;
1840 m[0] = 1.0f; // C
1841 m[1] = color + blue; // C + M (blue)
1842 m[2] = color - green; // C + Y (green)
1843 m[3] = color - blue; // M + C (blue)
1844 m[4] = 1.0f; // M
1845 m[5] = color + red; // M + Y (red)
1846 m[6] = yellow * (color + green); // Y + C (green)
1847 m[7] = yellow * (color - red); // Y + M (red)
1848 m[8] = yellow; // Y
1849
1850 if (m[1] > 0.0f)
1851 {
1852 m[3] -= m[1];
1853 m[1] = 0.0f;
1854 }
1855 else if (m[3] > 0.0f)
1856 {
1857 m[1] -= m[3];
1858 m[3] = 0.0f;
1859 }
1860
1861 if (m[2] > 0.0f)
1862 {
1863 m[6] -= m[2];
1864 m[2] = 0.0f;
1865 }
1866 else if (m[6] > 0.0f)
1867 {
1868 m[2] -= m[6];
1869 m[6] = 0.0f;
1870 }
1871
1872 if (m[5] > 0.0f)
1873 {
1874 m[7] -= m[5];
1875 m[5] = 0.0f;
1876 }
1877 else if (m[7] > 0.0f)
1878 {
1879 m[5] -= m[7];
1880 m[7] = 0.0f;
1881 }
1882
1883 // Return the new profile...
1884 return (new ppdcProfile(resolution, media_type, kd, g, m));
1885 }
1886
1887
1888 //
1889 // 'ppdcSource::get_size()' - Get a media size definition from a file.
1890 //
1891
1892 ppdcMediaSize * // O - Media size
get_size(ppdcFile * fp)1893 ppdcSource::get_size(ppdcFile *fp) // I - File to read
1894 {
1895 char name[1024], // Name
1896 *text; // Text
1897 float width, // Width
1898 length; // Length
1899
1900
1901 // Get the name, text, width, and length:
1902 //
1903 // #media name/text width length
1904 if (!get_token(fp, name, sizeof(name)))
1905 return (NULL);
1906
1907 if ((text = strchr(name, '/')) != NULL)
1908 *text++ = '\0';
1909 else
1910 text = name;
1911
1912 if ((width = get_measurement(fp)) < 0.0f)
1913 return (NULL);
1914
1915 if ((length = get_measurement(fp)) < 0.0f)
1916 return (NULL);
1917
1918 // Return the new media size...
1919 return (new ppdcMediaSize(name, text, width, length, 0.0f, 0.0f, 0.0f, 0.0f));
1920 }
1921
1922
1923 //
1924 // 'ppdcSource::get_token()' - Get a token from a file.
1925 //
1926
1927 char * // O - Token string or NULL
get_token(ppdcFile * fp,char * buffer,int buflen)1928 ppdcSource::get_token(ppdcFile *fp, // I - File to read
1929 char *buffer, // I - Buffer
1930 int buflen) // I - Length of buffer
1931 {
1932 char *bufptr, // Pointer into string buffer
1933 *bufend; // End of string buffer
1934 int ch, // Character from file
1935 nextch, // Next char in file
1936 quote, // Quote character used...
1937 empty, // Empty input?
1938 startline; // Start line for quote
1939 char name[256], // Name string
1940 *nameptr; // Name pointer
1941 ppdcVariable *var; // Variable pointer
1942
1943
1944 // Mark the beginning and end of the buffer...
1945 bufptr = buffer;
1946 bufend = buffer + buflen - 1;
1947
1948 // Loop intil we've read a token...
1949 quote = 0;
1950 startline = 0;
1951 empty = 1;
1952
1953 while ((ch = fp->get()) != EOF)
1954 {
1955 if (isspace(ch) && !quote)
1956 {
1957 if (empty)
1958 continue;
1959 else
1960 break;
1961 }
1962 else if (ch == '$')
1963 {
1964 // Variable substitution
1965 empty = 0;
1966
1967 for (nameptr = name; (ch = fp->peek()) != EOF;)
1968 {
1969 if (!isalnum(ch) && ch != '_')
1970 break;
1971 else if (nameptr < (name + sizeof(name) - 1))
1972 *nameptr++ = (char)fp->get();
1973 }
1974
1975 if (nameptr == name)
1976 {
1977 // Just substitute this character...
1978 if (ch == '$')
1979 {
1980 // $$ = $
1981 if (bufptr < bufend)
1982 *bufptr++ = (char)fp->get();
1983 }
1984 else
1985 {
1986 // $ch = $ch
1987 _cupsLangPrintf(stderr,
1988 _("ppdc: Bad variable substitution ($%c) on line %d "
1989 "of %s."), ch, fp->line, fp->filename);
1990
1991 if (bufptr < bufend)
1992 *bufptr++ = '$';
1993 }
1994 }
1995 else
1996 {
1997 // Substitute the variable value...
1998 *nameptr = '\0';
1999 var = find_variable(name);
2000 if (var)
2001 {
2002 strlcpy(bufptr, var->value->value, (size_t)(bufend - bufptr + 1));
2003 bufptr += strlen(bufptr);
2004 }
2005 else
2006 {
2007 if (!(cond_state & PPDC_COND_SKIP))
2008 _cupsLangPrintf(stderr,
2009 _("ppdc: Undefined variable (%s) on line %d of "
2010 "%s."), name, fp->line, fp->filename);
2011
2012 snprintf(bufptr, (size_t)(bufend - bufptr + 1), "$%s", name);
2013 bufptr += strlen(bufptr);
2014 }
2015 }
2016 }
2017 else if (ch == '/' && !quote)
2018 {
2019 // Possibly a comment...
2020 nextch = fp->peek();
2021
2022 if (nextch == '*')
2023 {
2024 // C comment...
2025 fp->get();
2026 ch = fp->get();
2027 while ((nextch = fp->get()) != EOF)
2028 {
2029 if (ch == '*' && nextch == '/')
2030 break;
2031
2032 ch = nextch;
2033 }
2034
2035 if (nextch == EOF)
2036 break;
2037 }
2038 else if (nextch == '/')
2039 {
2040 // C++ comment...
2041 while ((nextch = fp->get()) != EOF)
2042 if (nextch == '\n')
2043 break;
2044
2045 if (nextch == EOF)
2046 break;
2047 }
2048 else
2049 {
2050 // Not a comment...
2051 empty = 0;
2052
2053 if (bufptr < bufend)
2054 *bufptr++ = (char)ch;
2055 }
2056 }
2057 else if (ch == '\'' || ch == '\"')
2058 {
2059 empty = 0;
2060
2061 if (quote == ch)
2062 {
2063 // Ending the current quoted string...
2064 quote = 0;
2065 }
2066 else if (quote)
2067 {
2068 // Insert the opposing quote char...
2069 if (bufptr < bufend)
2070 *bufptr++ = (char)ch;
2071 }
2072 else
2073 {
2074 // Start a new quoted string...
2075 startline = fp->line;
2076 quote = ch;
2077 }
2078 }
2079 else if ((ch == '(' || ch == '<') && !quote)
2080 {
2081 empty = 0;
2082 quote = ch;
2083 startline = fp->line;
2084
2085 if (bufptr < bufend)
2086 *bufptr++ = (char)ch;
2087 }
2088 else if ((ch == ')' && quote == '(') || (ch == '>' && quote == '<'))
2089 {
2090 quote = 0;
2091
2092 if (bufptr < bufend)
2093 *bufptr++ = (char)ch;
2094 }
2095 else if (ch == '\\')
2096 {
2097 empty = 0;
2098
2099 if ((ch = fp->get()) == EOF)
2100 break;
2101
2102 if (bufptr < bufend)
2103 *bufptr++ = (char)ch;
2104 }
2105 else if (bufptr < bufend)
2106 {
2107 empty = 0;
2108
2109 *bufptr++ = (char)ch;
2110
2111 if ((ch == '{' || ch == '}') && !quote)
2112 break;
2113 }
2114 }
2115
2116 if (quote)
2117 {
2118 _cupsLangPrintf(stderr,
2119 _("ppdc: Unterminated string starting with %c on line %d "
2120 "of %s."), quote, startline, fp->filename);
2121 return (NULL);
2122 }
2123
2124 if (empty)
2125 return (NULL);
2126 else
2127 {
2128 *bufptr = '\0';
2129 return (buffer);
2130 }
2131 }
2132
2133
2134 //
2135 // 'ppdcSource::get_variable()' - Get a variable definition.
2136 //
2137
2138 ppdcVariable * // O - Variable
get_variable(ppdcFile * fp)2139 ppdcSource::get_variable(ppdcFile *fp) // I - File to read
2140 {
2141 char name[1024], // Name
2142 value[1024]; // Value
2143
2144
2145 // Get the name and value:
2146 //
2147 // #define name value
2148 if (!get_token(fp, name, sizeof(name)))
2149 return (NULL);
2150
2151 if (!get_token(fp, value, sizeof(value)))
2152 return (NULL);
2153
2154 // Set the variable...
2155 return (set_variable(name, value));
2156 }
2157
2158
2159 //
2160 // 'ppdcSource::quotef()' - Write a formatted, quoted string...
2161 //
2162
2163 int // O - Number bytes on success, -1 on failure
quotef(cups_file_t * fp,const char * format,...)2164 ppdcSource::quotef(cups_file_t *fp, // I - File to write to
2165 const char *format, // I - Printf-style format string
2166 ...) // I - Additional args as needed
2167 {
2168 va_list ap; // Pointer to additional arguments
2169 int bytes; // Bytes written
2170 char sign, // Sign of format width
2171 size, // Size character (h, l, L)
2172 type; // Format type character
2173 const char *bufformat; // Start of format
2174 int width, // Width of field
2175 prec; // Number of characters of precision
2176 char tformat[100]; // Temporary format string for fprintf()
2177 char *s; // Pointer to string
2178 int slen; // Length of string
2179 int i; // Looping var
2180
2181
2182 // Range check input...
2183 if (!fp || !format)
2184 return (-1);
2185
2186 // Loop through the format string, formatting as needed...
2187 va_start(ap, format);
2188
2189 bytes = 0;
2190
2191 while (*format)
2192 {
2193 if (*format == '%')
2194 {
2195 bufformat = format;
2196 format ++;
2197
2198 if (*format == '%')
2199 {
2200 cupsFilePutChar(fp, *format++);
2201 bytes ++;
2202 continue;
2203 }
2204 else if (strchr(" -+#\'", *format))
2205 sign = *format++;
2206 else
2207 sign = 0;
2208
2209 width = 0;
2210 while (isdigit(*format))
2211 width = width * 10 + *format++ - '0';
2212
2213 if (*format == '.')
2214 {
2215 format ++;
2216 prec = 0;
2217
2218 while (isdigit(*format))
2219 prec = prec * 10 + *format++ - '0';
2220 }
2221 else
2222 prec = -1;
2223
2224 if (*format == 'l' && format[1] == 'l')
2225 {
2226 size = 'L';
2227 format += 2;
2228 }
2229 else if (*format == 'h' || *format == 'l' || *format == 'L')
2230 size = *format++;
2231 else
2232 size = '\0';
2233
2234 if (!*format)
2235 break;
2236
2237 type = *format++;
2238
2239 switch (type)
2240 {
2241 case 'E' : // Floating point formats
2242 case 'G' :
2243 case 'e' :
2244 case 'f' :
2245 case 'g' :
2246 if ((format - bufformat + 1) > (int)sizeof(tformat))
2247 break;
2248
2249 memcpy(tformat, bufformat, (size_t)(format - bufformat));
2250 tformat[format - bufformat] = '\0';
2251
2252 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, double));
2253 break;
2254
2255 case 'B' : // Integer formats
2256 case 'X' :
2257 case 'b' :
2258 case 'd' :
2259 case 'i' :
2260 case 'o' :
2261 case 'u' :
2262 case 'x' :
2263 if ((format - bufformat + 1) > (int)sizeof(tformat))
2264 break;
2265
2266 memcpy(tformat, bufformat, (size_t)(format - bufformat));
2267 tformat[format - bufformat] = '\0';
2268
2269 # ifdef HAVE_LONG_LONG
2270 if (size == 'L')
2271 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, long long));
2272 else
2273 # endif /* HAVE_LONG_LONG */
2274 if (size == 'l')
2275 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, long));
2276 else
2277 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, int));
2278 break;
2279
2280 case 'p' : // Pointer value
2281 if ((format - bufformat + 1) > (int)sizeof(tformat))
2282 break;
2283
2284 memcpy(tformat, bufformat, (size_t)(format - bufformat));
2285 tformat[format - bufformat] = '\0';
2286
2287 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, void *));
2288 break;
2289
2290 case 'c' : // Character or character array
2291 if (width <= 1)
2292 {
2293 bytes ++;
2294 cupsFilePutChar(fp, va_arg(ap, int));
2295 }
2296 else
2297 {
2298 cupsFileWrite(fp, va_arg(ap, char *), (size_t)width);
2299 bytes += width;
2300 }
2301 break;
2302
2303 case 's' : // String
2304 if ((s = va_arg(ap, char *)) == NULL)
2305 s = (char *)"(nil)";
2306
2307 slen = (int)strlen(s);
2308 if (slen > width && prec != width)
2309 width = slen;
2310
2311 if (slen > width)
2312 slen = width;
2313
2314 if (sign != '-')
2315 {
2316 for (i = width - slen; i > 0; i --, bytes ++)
2317 cupsFilePutChar(fp, ' ');
2318 }
2319
2320 for (i = slen; i > 0; i --, s ++, bytes ++)
2321 {
2322 if (*s == '\\' || *s == '\"')
2323 {
2324 cupsFilePutChar(fp, '\\');
2325 bytes ++;
2326 }
2327
2328 cupsFilePutChar(fp, *s);
2329 }
2330
2331 if (sign == '-')
2332 {
2333 for (i = width - slen; i > 0; i --, bytes ++)
2334 cupsFilePutChar(fp, ' ');
2335 }
2336 break;
2337 }
2338 }
2339 else
2340 {
2341 cupsFilePutChar(fp, *format++);
2342 bytes ++;
2343 }
2344 }
2345
2346 va_end(ap);
2347
2348 // Return the number of characters written.
2349 return (bytes);
2350 }
2351
2352
2353 //
2354 // 'ppdcSource::read_file()' - Read a driver source file.
2355 //
2356
2357 void
read_file(const char * f,cups_file_t * ffp)2358 ppdcSource::read_file(const char *f, // I - File to read
2359 cups_file_t *ffp) // I - File pointer to use
2360 {
2361 ppdcFile *fp = new ppdcFile(f, ffp);
2362 scan_file(fp);
2363 delete fp;
2364
2365 if (cond_current != cond_stack)
2366 _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"."), f);
2367 }
2368
2369
2370 //
2371 // 'ppdcSource::scan_file()' - Scan a driver source file.
2372 //
2373
2374 void
scan_file(ppdcFile * fp,ppdcDriver * td,bool inc)2375 ppdcSource::scan_file(ppdcFile *fp, // I - File to read
2376 ppdcDriver *td, // I - Driver template
2377 bool inc) // I - Including?
2378 {
2379 ppdcDriver *d; // Current driver
2380 ppdcGroup *g, // Current group
2381 *mg, // Matching group
2382 *general, // General options group
2383 *install; // Installable options group
2384 ppdcOption *o; // Current option
2385 ppdcChoice *c; // Current choice
2386 char temp[256], // Token from file...
2387 *ptr; // Pointer into token
2388 int isdefault; // Default option?
2389
2390
2391 // Initialize things as needed...
2392 if (inc && td)
2393 {
2394 d = td;
2395 d->retain();
2396 }
2397 else
2398 d = new ppdcDriver(td);
2399
2400 if ((general = d->find_group("General")) == NULL)
2401 {
2402 general = new ppdcGroup("General", NULL);
2403 d->add_group(general);
2404 }
2405
2406 if ((install = d->find_group("InstallableOptions")) == NULL)
2407 {
2408 install = new ppdcGroup("InstallableOptions", "Installable Options");
2409 d->add_group(install);
2410 }
2411
2412 // Loop until EOF or }
2413 o = 0;
2414 g = general;
2415
2416 while (get_token(fp, temp, sizeof(temp)))
2417 {
2418 if (temp[0] == '*')
2419 {
2420 // Mark the next choice as the default
2421 isdefault = 1;
2422
2423 for (ptr = temp; ptr[1]; ptr ++)
2424 *ptr = ptr[1];
2425
2426 *ptr = '\0';
2427 }
2428 else
2429 {
2430 // Don't mark the next choice as the default
2431 isdefault = 0;
2432 }
2433
2434 if (!_cups_strcasecmp(temp, "}"))
2435 {
2436 // Close this one out...
2437 break;
2438 }
2439 else if (!_cups_strcasecmp(temp, "{"))
2440 {
2441 // Open a new child...
2442 scan_file(fp, d);
2443 }
2444 else if (!_cups_strcasecmp(temp, "#if"))
2445 {
2446 if ((cond_current - cond_stack) >= 100)
2447 {
2448 _cupsLangPrintf(stderr,
2449 _("ppdc: Too many nested #if's on line %d of %s."),
2450 fp->line, fp->filename);
2451 break;
2452 }
2453
2454 cond_current ++;
2455 if (get_integer(fp) > 0)
2456 *cond_current = PPDC_COND_SATISFIED;
2457 else
2458 {
2459 *cond_current = PPDC_COND_SKIP;
2460 cond_state |= PPDC_COND_SKIP;
2461 }
2462 }
2463 else if (!_cups_strcasecmp(temp, "#elif"))
2464 {
2465 if (cond_current == cond_stack)
2466 {
2467 _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
2468 fp->line, fp->filename);
2469 break;
2470 }
2471
2472 if (*cond_current & PPDC_COND_SATISFIED)
2473 {
2474 get_integer(fp);
2475 *cond_current |= PPDC_COND_SKIP;
2476 }
2477 else if (get_integer(fp) > 0)
2478 {
2479 *cond_current |= PPDC_COND_SATISFIED;
2480 *cond_current &= ~PPDC_COND_SKIP;
2481 }
2482 else
2483 *cond_current |= PPDC_COND_SKIP;
2484
2485 // Update the current state
2486 int *cond_temp = cond_current; // Temporary stack pointer
2487
2488 cond_state = PPDC_COND_NORMAL;
2489 while (cond_temp > cond_stack)
2490 if (*cond_temp & PPDC_COND_SKIP)
2491 {
2492 cond_state = PPDC_COND_SKIP;
2493 break;
2494 }
2495 else
2496 cond_temp --;
2497 }
2498 else if (!_cups_strcasecmp(temp, "#else"))
2499 {
2500 if (cond_current == cond_stack)
2501 {
2502 _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
2503 fp->line, fp->filename);
2504 break;
2505 }
2506
2507 if (*cond_current & PPDC_COND_SATISFIED)
2508 *cond_current |= PPDC_COND_SKIP;
2509 else
2510 {
2511 *cond_current |= PPDC_COND_SATISFIED;
2512 *cond_current &= ~PPDC_COND_SKIP;
2513 }
2514
2515 // Update the current state
2516 int *cond_temp = cond_current; // Temporary stack pointer
2517
2518 cond_state = PPDC_COND_NORMAL;
2519 while (cond_temp > cond_stack)
2520 if (*cond_temp & PPDC_COND_SKIP)
2521 {
2522 cond_state = PPDC_COND_SKIP;
2523 break;
2524 }
2525 else
2526 cond_temp --;
2527 }
2528 else if (!_cups_strcasecmp(temp, "#endif"))
2529 {
2530 if (cond_current == cond_stack)
2531 {
2532 _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
2533 fp->line, fp->filename);
2534 break;
2535 }
2536
2537 cond_current --;
2538
2539 // Update the current state
2540 int *cond_temp = cond_current; // Temporary stack pointer
2541
2542 cond_state = PPDC_COND_NORMAL;
2543 while (cond_temp > cond_stack)
2544 if (*cond_temp & PPDC_COND_SKIP)
2545 {
2546 cond_state = PPDC_COND_SKIP;
2547 break;
2548 }
2549 else
2550 cond_temp --;
2551 }
2552 else if (!_cups_strcasecmp(temp, "#define"))
2553 {
2554 // Get the variable...
2555 get_variable(fp);
2556 }
2557 else if (!_cups_strcasecmp(temp, "#include"))
2558 {
2559 // #include filename
2560 char basedir[1024], // Base directory
2561 *baseptr, // Pointer into directory
2562 inctemp[1024], // Initial filename
2563 incname[1024]; // Include filename
2564 ppdcFile *incfile; // Include file
2565 int *old_current = cond_current;
2566 // Previous current stack
2567
2568
2569 // Get the include name...
2570 if (!get_token(fp, inctemp, sizeof(inctemp)))
2571 {
2572 _cupsLangPrintf(stderr,
2573 _("ppdc: Expected include filename on line %d of "
2574 "%s."), fp->line, fp->filename);
2575 break;
2576 }
2577
2578 if (cond_state)
2579 continue;
2580
2581 // Figure out the current directory...
2582 strlcpy(basedir, fp->filename, sizeof(basedir));
2583
2584 if ((baseptr = strrchr(basedir, '/')) != NULL)
2585 *baseptr = '\0';
2586 else
2587 strlcpy(basedir, ".", sizeof(basedir));
2588
2589 // Find the include file...
2590 if (find_include(inctemp, basedir, incname, sizeof(incname)))
2591 {
2592 // Open the include file, scan it, and then close it...
2593 incfile = new ppdcFile(incname);
2594 scan_file(incfile, d, true);
2595 delete incfile;
2596
2597 if (cond_current != old_current)
2598 _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"."),
2599 incname);
2600 }
2601 else
2602 {
2603 // Can't find it!
2604 _cupsLangPrintf(stderr,
2605 _("ppdc: Unable to find include file \"%s\" on line %d "
2606 "of %s."), inctemp, fp->line, fp->filename);
2607 break;
2608 }
2609 }
2610 else if (!_cups_strcasecmp(temp, "#media"))
2611 {
2612 ppdcMediaSize *m; // Media size
2613
2614
2615 // Get a media size...
2616 m = get_size(fp);
2617 if (m)
2618 {
2619 if (cond_state)
2620 m->release();
2621 else
2622 sizes->add(m);
2623 }
2624 }
2625 else if (!_cups_strcasecmp(temp, "#po"))
2626 {
2627 ppdcCatalog *cat; // Message catalog
2628
2629
2630 // Get a message catalog...
2631 cat = get_po(fp);
2632 if (cat)
2633 {
2634 if (cond_state)
2635 cat->release();
2636 else
2637 po_files->add(cat);
2638 }
2639 }
2640 else if (!_cups_strcasecmp(temp, "Attribute") ||
2641 !_cups_strcasecmp(temp, "LocAttribute"))
2642 {
2643 ppdcAttr *a; // Attribute
2644
2645
2646 // Get an attribute...
2647 a = get_attr(fp, !_cups_strcasecmp(temp, "LocAttribute"));
2648 if (a)
2649 {
2650 if (cond_state)
2651 a->release();
2652 else
2653 d->add_attr(a);
2654 }
2655 }
2656 else if (!_cups_strcasecmp(temp, "Choice"))
2657 {
2658 // Get a choice...
2659 c = get_choice(fp);
2660 if (!c)
2661 break;
2662
2663 if (cond_state)
2664 {
2665 c->release();
2666 continue;
2667 }
2668
2669 // Add it to the current option...
2670 if (!o)
2671 {
2672 c->release();
2673 _cupsLangPrintf(stderr,
2674 _("ppdc: Choice found on line %d of %s with no "
2675 "Option."), fp->line, fp->filename);
2676 break;
2677 }
2678
2679 o->add_choice(c);
2680
2681 if (isdefault)
2682 o->set_defchoice(c);
2683 }
2684 else if (!_cups_strcasecmp(temp, "ColorDevice"))
2685 {
2686 // ColorDevice boolean
2687 if (cond_state)
2688 get_boolean(fp);
2689 else
2690 d->color_device = get_boolean(fp);
2691 }
2692 else if (!_cups_strcasecmp(temp, "ColorModel"))
2693 {
2694 // Get the color model
2695 c = get_color_model(fp);
2696 if (!c)
2697 continue;
2698
2699 if (cond_state)
2700 {
2701 c->release();
2702 continue;
2703 }
2704
2705 // Add the choice to the ColorModel option...
2706 if ((o = d->find_option("ColorModel")) == NULL)
2707 {
2708 // Create the ColorModel option...
2709 o = new ppdcOption(PPDC_PICKONE, "ColorModel", "Color Mode", PPDC_SECTION_ANY, 10.0f);
2710 g = general;
2711 g->add_option(o);
2712 }
2713
2714 o->add_choice(c);
2715
2716 if (isdefault)
2717 o->set_defchoice(c);
2718
2719 o = NULL;
2720 }
2721 else if (!_cups_strcasecmp(temp, "ColorProfile"))
2722 {
2723 ppdcProfile *p; // Color profile
2724
2725
2726 // Get the color profile...
2727 p = get_color_profile(fp);
2728
2729 if (p)
2730 {
2731 if (cond_state)
2732 p->release();
2733 else
2734 d->profiles->add(p);
2735 }
2736 }
2737 else if (!_cups_strcasecmp(temp, "Copyright"))
2738 {
2739 // Copyright string
2740 char copytemp[8192], // Copyright string
2741 *copyptr, // Pointer into string
2742 *copyend; // Pointer to end of string
2743
2744
2745 // Get the copyright string...
2746 if (!get_token(fp, copytemp, sizeof(temp)))
2747 {
2748 _cupsLangPrintf(stderr,
2749 _("ppdc: Expected string after Copyright on line %d "
2750 "of %s."), fp->line, fp->filename);
2751 break;
2752 }
2753
2754 if (cond_state)
2755 continue;
2756
2757 // Break it up into individual lines...
2758 for (copyptr = copytemp; copyptr; copyptr = copyend)
2759 {
2760 if ((copyend = strchr(copyptr, '\n')) != NULL)
2761 *copyend++ = '\0';
2762
2763 d->copyright->add(new ppdcString(copyptr));
2764 }
2765 }
2766 else if (!_cups_strcasecmp(temp, "CustomMedia"))
2767 {
2768 ppdcMediaSize *m; // Media size
2769
2770
2771 // Get a custom media size...
2772 m = get_custom_size(fp);
2773
2774 if (cond_state)
2775 {
2776 m->release();
2777 continue;
2778 }
2779
2780 if (m)
2781 d->sizes->add(m);
2782
2783 if (isdefault)
2784 d->set_default_size(m);
2785 }
2786 else if (!_cups_strcasecmp(temp, "Cutter"))
2787 {
2788 // Cutter boolean
2789 int have_cutter; // Have a paper cutter?
2790
2791
2792 have_cutter = get_boolean(fp);
2793 if (have_cutter <= 0 || cond_state)
2794 continue;
2795
2796 if (!d->find_option("CutMedia"))
2797 {
2798 o = new ppdcOption(PPDC_BOOLEAN, "CutMedia", "Cut Media", PPDC_SECTION_ANY, 10.0f);
2799
2800 g = general;
2801 g->add_option(o);
2802
2803 c = new ppdcChoice("False", NULL, "<</CutMedia 0>>setpagedevice");
2804 o->add_choice(c);
2805 o->set_defchoice(c);
2806
2807 c = new ppdcChoice("True", NULL, "<</CutMedia 4>>setpagedevice");
2808 o->add_choice(c);
2809 o = NULL;
2810 }
2811 }
2812 else if (!_cups_strcasecmp(temp, "Darkness"))
2813 {
2814 // Get the darkness choice...
2815 c = get_generic(fp, "Darkness", NULL, "cupsCompression");
2816 if (!c)
2817 continue;
2818
2819 if (cond_state)
2820 {
2821 c->release();
2822 continue;
2823 }
2824
2825 // Add the choice to the cupsDarkness option...
2826 if ((o = d->find_option_group("cupsDarkness", &mg)) == NULL)
2827 {
2828 // Create the cupsDarkness option...
2829 o = new ppdcOption(PPDC_PICKONE, "cupsDarkness", "Darkness", PPDC_SECTION_ANY, 10.0f);
2830 g = general;
2831 g->add_option(o);
2832 }
2833 else if (mg != general)
2834 {
2835 _cupsLangPrintf(stderr,
2836 _("ppdc: Option %s defined in two different groups on "
2837 "line %d of %s."), "cupsDarkness", fp->line,
2838 fp->filename);
2839 c->release();
2840 continue;
2841 }
2842
2843 o->add_choice(c);
2844
2845 if (isdefault)
2846 o->set_defchoice(c);
2847
2848 o = NULL;
2849 }
2850 else if (!_cups_strcasecmp(temp, "DriverType"))
2851 {
2852 int i; // Looping var
2853
2854
2855 // DriverType keyword
2856 if (!get_token(fp, temp, sizeof(temp)))
2857 {
2858 _cupsLangPrintf(stderr,
2859 _("ppdc: Expected driver type keyword following "
2860 "DriverType on line %d of %s."),
2861 fp->line, fp->filename);
2862 continue;
2863 }
2864
2865 if (cond_state)
2866 continue;
2867
2868 for (i = 0; i < (int)(sizeof(driver_types) / sizeof(driver_types[0])); i ++)
2869 if (!_cups_strcasecmp(temp, driver_types[i]))
2870 break;
2871
2872 if (i < (int)(sizeof(driver_types) / sizeof(driver_types[0])))
2873 d->type = (ppdcDrvType)i;
2874 else if (!_cups_strcasecmp(temp, "dymo"))
2875 d->type = PPDC_DRIVER_LABEL;
2876 else
2877 _cupsLangPrintf(stderr,
2878 _("ppdc: Unknown driver type %s on line %d of %s."),
2879 temp, fp->line, fp->filename);
2880 }
2881 else if (!_cups_strcasecmp(temp, "Duplex"))
2882 get_duplex(fp, d);
2883 else if (!_cups_strcasecmp(temp, "Filter"))
2884 {
2885 ppdcFilter *f; // Filter
2886
2887
2888 // Get the filter value...
2889 f = get_filter(fp);
2890 if (f)
2891 {
2892 if (cond_state)
2893 f->release();
2894 else
2895 d->filters->add(f);
2896 }
2897 }
2898 else if (!_cups_strcasecmp(temp, "Finishing"))
2899 {
2900 // Get the finishing choice...
2901 c = get_generic(fp, "Finishing", "OutputType", NULL);
2902 if (!c)
2903 continue;
2904
2905 if (cond_state)
2906 {
2907 c->release();
2908 continue;
2909 }
2910
2911 // Add the choice to the cupsFinishing option...
2912 if ((o = d->find_option_group("cupsFinishing", &mg)) == NULL)
2913 {
2914 // Create the cupsFinishing option...
2915 o = new ppdcOption(PPDC_PICKONE, "cupsFinishing", "Finishing", PPDC_SECTION_ANY, 10.0f);
2916 g = general;
2917 g->add_option(o);
2918 }
2919 else if (mg != general)
2920 {
2921 _cupsLangPrintf(stderr,
2922 _("ppdc: Option %s defined in two different groups on "
2923 "line %d of %s."), "cupsFinishing", fp->line,
2924 fp->filename);
2925 c->release();
2926 continue;
2927 }
2928
2929 o->add_choice(c);
2930
2931 if (isdefault)
2932 o->set_defchoice(c);
2933
2934 o = NULL;
2935 }
2936 else if (!_cups_strcasecmp(temp, "Font") ||
2937 !_cups_strcasecmp(temp, "#font"))
2938 {
2939 ppdcFont *f; // Font
2940
2941
2942 // Get a font...
2943 f = get_font(fp);
2944 if (f)
2945 {
2946 if (cond_state)
2947 f->release();
2948 else
2949 {
2950 if (!_cups_strcasecmp(temp, "#font"))
2951 base_fonts->add(f);
2952 else
2953 d->add_font(f);
2954
2955 if (isdefault)
2956 d->set_default_font(f);
2957 }
2958 }
2959 }
2960 else if (!_cups_strcasecmp(temp, "Group"))
2961 {
2962 // Get a group...
2963 ppdcGroup *tempg = get_group(fp, d);
2964
2965 if (!tempg)
2966 break;
2967
2968 if (cond_state)
2969 {
2970 if (!d->find_group(tempg->name->value))
2971 tempg->release();
2972 }
2973 else
2974 {
2975 if (!d->find_group(tempg->name->value))
2976 d->add_group(tempg);
2977
2978 g = tempg;
2979 }
2980 }
2981 else if (!_cups_strcasecmp(temp, "HWMargins"))
2982 {
2983 // HWMargins left bottom right top
2984 d->left_margin = get_measurement(fp);
2985 d->bottom_margin = get_measurement(fp);
2986 d->right_margin = get_measurement(fp);
2987 d->top_margin = get_measurement(fp);
2988 }
2989 else if (!_cups_strcasecmp(temp, "InputSlot"))
2990 {
2991 // Get the input slot choice...
2992 c = get_generic(fp, "InputSlot", NULL, "MediaPosition");
2993 if (!c)
2994 continue;
2995
2996 if (cond_state)
2997 {
2998 c->release();
2999 continue;
3000 }
3001
3002 // Add the choice to the InputSlot option...
3003
3004 if ((o = d->find_option_group("InputSlot", &mg)) == NULL)
3005 {
3006 // Create the InputSlot option...
3007 o = new ppdcOption(PPDC_PICKONE, "InputSlot", "Media Source",
3008 PPDC_SECTION_ANY, 10.0f);
3009 g = general;
3010 g->add_option(o);
3011 }
3012 else if (mg != general)
3013 {
3014 _cupsLangPrintf(stderr,
3015 _("ppdc: Option %s defined in two different groups on "
3016 "line %d of %s."), "InputSlot", fp->line,
3017 fp->filename);
3018 c->release();
3019 continue;
3020 }
3021
3022 o->add_choice(c);
3023
3024 if (isdefault)
3025 o->set_defchoice(c);
3026
3027 o = NULL;
3028 }
3029 else if (!_cups_strcasecmp(temp, "Installable"))
3030 {
3031 // Get the installable option...
3032 o = get_installable(fp);
3033
3034 // Add it as needed...
3035 if (o)
3036 {
3037 if (cond_state)
3038 o->release();
3039 else
3040 install->add_option(o);
3041
3042 o = NULL;
3043 }
3044 }
3045 else if (!_cups_strcasecmp(temp, "ManualCopies"))
3046 {
3047 // ManualCopies boolean
3048 if (cond_state)
3049 get_boolean(fp);
3050 else
3051 d->manual_copies = get_boolean(fp);
3052 }
3053 else if (!_cups_strcasecmp(temp, "Manufacturer"))
3054 {
3055 // Manufacturer name
3056 char name[256]; // Model name string
3057
3058
3059 if (!get_token(fp, name, sizeof(name)))
3060 {
3061 _cupsLangPrintf(stderr,
3062 _("ppdc: Expected name after Manufacturer on line %d "
3063 "of %s."), fp->line, fp->filename);
3064 break;
3065 }
3066
3067 if (!cond_state)
3068 d->set_manufacturer(name);
3069 }
3070 else if (!_cups_strcasecmp(temp, "MaxSize"))
3071 {
3072 // MaxSize width length
3073 if (cond_state)
3074 {
3075 get_measurement(fp);
3076 get_measurement(fp);
3077 }
3078 else
3079 {
3080 d->max_width = get_measurement(fp);
3081 d->max_length = get_measurement(fp);
3082 }
3083 }
3084 else if (!_cups_strcasecmp(temp, "MediaSize"))
3085 {
3086 // MediaSize keyword
3087 char name[41]; // Media size name
3088 ppdcMediaSize *m, // Matching media size...
3089 *dm; // Driver media size...
3090
3091
3092 if (get_token(fp, name, sizeof(name)) == NULL)
3093 {
3094 _cupsLangPrintf(stderr,
3095 _("ppdc: Expected name after MediaSize on line %d of "
3096 "%s."), fp->line, fp->filename);
3097 break;
3098 }
3099
3100 if (cond_state)
3101 continue;
3102
3103 m = find_size(name);
3104
3105 if (!m)
3106 {
3107 _cupsLangPrintf(stderr,
3108 _("ppdc: Unknown media size \"%s\" on line %d of "
3109 "%s."), name, fp->line, fp->filename);
3110 break;
3111 }
3112
3113 // Add this size to the driver...
3114 dm = new ppdcMediaSize(m->name->value, m->text->value,
3115 m->width, m->length, d->left_margin,
3116 d->bottom_margin, d->right_margin,
3117 d->top_margin);
3118 d->sizes->add(dm);
3119
3120 if (isdefault)
3121 d->set_default_size(dm);
3122 }
3123 else if (!_cups_strcasecmp(temp, "MediaType"))
3124 {
3125 // Get the media type choice...
3126 c = get_generic(fp, "MediaType", "MediaType", "cupsMediaType");
3127 if (!c)
3128 continue;
3129
3130 if (cond_state)
3131 {
3132 c->release();
3133 continue;
3134 }
3135
3136 // Add the choice to the MediaType option...
3137 if ((o = d->find_option_group("MediaType", &mg)) == NULL)
3138 {
3139 // Create the MediaType option...
3140 o = new ppdcOption(PPDC_PICKONE, "MediaType", "Media Type",
3141 PPDC_SECTION_ANY, 10.0f);
3142 g = general;
3143 g->add_option(o);
3144 }
3145 else if (mg != general)
3146 {
3147 _cupsLangPrintf(stderr,
3148 _("ppdc: Option %s defined in two different groups on "
3149 "line %d of %s."), "MediaType", fp->line,
3150 fp->filename);
3151 c->release();
3152 continue;
3153 }
3154
3155 o->add_choice(c);
3156
3157 if (isdefault)
3158 o->set_defchoice(c);
3159
3160 o = NULL;
3161 }
3162 else if (!_cups_strcasecmp(temp, "MinSize"))
3163 {
3164 // MinSize width length
3165 if (cond_state)
3166 {
3167 get_measurement(fp);
3168 get_measurement(fp);
3169 }
3170 else
3171 {
3172 d->min_width = get_measurement(fp);
3173 d->min_length = get_measurement(fp);
3174 }
3175 }
3176 else if (!_cups_strcasecmp(temp, "ModelName"))
3177 {
3178 // ModelName name
3179 char name[256]; // Model name string
3180
3181
3182 if (!get_token(fp, name, sizeof(name)))
3183 {
3184 _cupsLangPrintf(stderr,
3185 _("ppdc: Expected name after ModelName on line %d of "
3186 "%s."), fp->line, fp->filename);
3187 break;
3188 }
3189
3190 if (!cond_state)
3191 d->set_model_name(name);
3192 }
3193 else if (!_cups_strcasecmp(temp, "ModelNumber"))
3194 {
3195 // ModelNumber number
3196 if (cond_state)
3197 get_integer(fp);
3198 else
3199 d->model_number = get_integer(fp);
3200 }
3201 else if (!_cups_strcasecmp(temp, "Option"))
3202 {
3203 // Get an option...
3204 ppdcOption *tempo = get_option(fp, d, g);
3205
3206 if (!tempo)
3207 break;
3208
3209 if (cond_state)
3210 {
3211 if (!g->find_option(tempo->name->value))
3212 tempo->release();
3213 }
3214 else
3215 {
3216 if (!g->find_option(tempo->name->value))
3217 g->add_option(tempo);
3218
3219 o = tempo;
3220 }
3221 }
3222 else if (!_cups_strcasecmp(temp, "FileName"))
3223 {
3224 // FileName name
3225 char name[256]; // Filename string
3226
3227
3228 if (!get_token(fp, name, sizeof(name)))
3229 {
3230 _cupsLangPrintf(stderr,
3231 _("ppdc: Expected name after FileName on line %d of "
3232 "%s."), fp->line, fp->filename);
3233 break;
3234 }
3235
3236 if (!cond_state)
3237 d->set_file_name(name);
3238 }
3239 else if (!_cups_strcasecmp(temp, "PCFileName"))
3240 {
3241 // PCFileName name
3242 char name[256]; // PC filename string
3243
3244
3245 if (!get_token(fp, name, sizeof(name)))
3246 {
3247 _cupsLangPrintf(stderr,
3248 _("ppdc: Expected name after PCFileName on line %d of "
3249 "%s."), fp->line, fp->filename);
3250 break;
3251 }
3252
3253 if (!cond_state)
3254 d->set_pc_file_name(name);
3255 }
3256 else if (!_cups_strcasecmp(temp, "Resolution"))
3257 {
3258 // Get the resolution choice...
3259 c = get_resolution(fp);
3260 if (!c)
3261 continue;
3262
3263 if (cond_state)
3264 {
3265 c->release();
3266 continue;
3267 }
3268
3269 // Add the choice to the Resolution option...
3270 if ((o = d->find_option_group("Resolution", &mg)) == NULL)
3271 {
3272 // Create the Resolution option...
3273 o = new ppdcOption(PPDC_PICKONE, "Resolution", NULL, PPDC_SECTION_ANY,
3274 10.0f);
3275 g = general;
3276 g->add_option(o);
3277 }
3278 else if (mg != general)
3279 {
3280 _cupsLangPrintf(stderr,
3281 _("ppdc: Option %s defined in two different groups on "
3282 "line %d of %s."), "Resolution", fp->line,
3283 fp->filename);
3284 c->release();
3285 continue;
3286 }
3287
3288 o->add_choice(c);
3289
3290 if (isdefault)
3291 o->set_defchoice(c);
3292
3293 o = NULL;
3294 }
3295 else if (!_cups_strcasecmp(temp, "SimpleColorProfile"))
3296 {
3297 ppdcProfile *p; // Color profile
3298
3299
3300 // Get the color profile...
3301 p = get_simple_profile(fp);
3302
3303 if (p)
3304 {
3305 if (cond_state)
3306 p->release();
3307 else
3308 d->profiles->add(p);
3309 }
3310 }
3311 else if (!_cups_strcasecmp(temp, "Throughput"))
3312 {
3313 // Throughput number
3314 if (cond_state)
3315 get_integer(fp);
3316 else
3317 d->throughput = get_integer(fp);
3318 }
3319 else if (!_cups_strcasecmp(temp, "UIConstraints"))
3320 {
3321 ppdcConstraint *con; // Constraint
3322
3323
3324 con = get_constraint(fp);
3325
3326 if (con)
3327 {
3328 if (cond_state)
3329 con->release();
3330 else
3331 d->constraints->add(con);
3332 }
3333 }
3334 else if (!_cups_strcasecmp(temp, "VariablePaperSize"))
3335 {
3336 // VariablePaperSize boolean
3337 if (cond_state)
3338 get_boolean(fp);
3339 else
3340 d->variable_paper_size = get_boolean(fp);
3341 }
3342 else if (!_cups_strcasecmp(temp, "Version"))
3343 {
3344 // Version string
3345 char name[256]; // Model name string
3346
3347
3348 if (!get_token(fp, name, sizeof(name)))
3349 {
3350 _cupsLangPrintf(stderr,
3351 _("ppdc: Expected string after Version on line %d of "
3352 "%s."), fp->line, fp->filename);
3353 break;
3354 }
3355
3356 if (!cond_state)
3357 d->set_version(name);
3358 }
3359 else
3360 {
3361 _cupsLangPrintf(stderr,
3362 _("ppdc: Unknown token \"%s\" seen on line %d of %s."),
3363 temp, fp->line, fp->filename);
3364 break;
3365 }
3366 }
3367
3368 // Done processing this block, is there anything to save?
3369 if (!inc)
3370 {
3371 if (!d->pc_file_name || !d->model_name || !d->manufacturer || !d->version ||
3372 !d->sizes->count)
3373 {
3374 // Nothing to save...
3375 d->release();
3376 }
3377 else
3378 {
3379 // Got a driver, save it...
3380 drivers->add(d);
3381 }
3382 }
3383 else if (inc && td)
3384 td->release();
3385 }
3386
3387
3388 //
3389 // 'ppdcSource::set_variable()' - Set a variable.
3390 //
3391
3392 ppdcVariable * // O - Variable
set_variable(const char * name,const char * value)3393 ppdcSource::set_variable(
3394 const char *name, // I - Name
3395 const char *value) // I - Value
3396 {
3397 ppdcVariable *v; // Variable
3398
3399
3400 // See if the variable exists already...
3401 v = find_variable(name);
3402 if (v)
3403 {
3404 // Change the variable value...
3405 v->set_value(value);
3406 }
3407 else
3408 {
3409 // Create a new variable and add it...
3410 v = new ppdcVariable(name, value);
3411 vars->add(v);
3412 }
3413
3414 return (v);
3415 }
3416
3417
3418 //
3419 // 'ppdcSource::write_file()' - Write the current source data to a file.
3420 //
3421
3422 int // O - 0 on success, -1 on error
write_file(const char * f)3423 ppdcSource::write_file(const char *f) // I - File to write
3424 {
3425 cups_file_t *fp; // Output file
3426 char bckname[1024]; // Backup file
3427 ppdcDriver *d; // Current driver
3428 ppdcString *st; // Current string
3429 ppdcAttr *a; // Current attribute
3430 ppdcConstraint *co; // Current constraint
3431 ppdcFilter *fi; // Current filter
3432 ppdcFont *fo; // Current font
3433 ppdcGroup *g; // Current group
3434 ppdcOption *o; // Current option
3435 ppdcChoice *ch; // Current choice
3436 ppdcProfile *p; // Current color profile
3437 ppdcMediaSize *si; // Current media size
3438 float left, // Current left margin
3439 bottom, // Current bottom margin
3440 right, // Current right margin
3441 top; // Current top margin
3442 int dtused[PPDC_DRIVER_MAX];// Driver type usage...
3443
3444
3445 // Rename the current file, if any, to .bck...
3446 snprintf(bckname, sizeof(bckname), "%s.bck", f);
3447 rename(f, bckname);
3448
3449 // Open the output file...
3450 fp = cupsFileOpen(f, "w");
3451
3452 if (!fp)
3453 {
3454 // Can't create file; restore backup and return...
3455 rename(bckname, f);
3456 return (-1);
3457 }
3458
3459 cupsFilePuts(fp, "// CUPS PPD Compiler " CUPS_SVERSION "\n\n");
3460
3461 // Include standard files...
3462 cupsFilePuts(fp, "// Include necessary files...\n");
3463 cupsFilePuts(fp, "#include <font.defs>\n");
3464 cupsFilePuts(fp, "#include <media.defs>\n");
3465
3466 memset(dtused, 0, sizeof(dtused));
3467
3468 for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
3469 if (d->type > PPDC_DRIVER_PS && !dtused[d->type])
3470 {
3471 cupsFilePrintf(fp, "#include <%s.h>\n", driver_types[d->type]);
3472 dtused[d->type] = 1;
3473 }
3474
3475 // Output each driver...
3476 for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
3477 {
3478 // Start the driver...
3479 cupsFilePrintf(fp, "\n// %s %s\n", d->manufacturer->value,
3480 d->model_name->value);
3481 cupsFilePuts(fp, "{\n");
3482
3483 // Write the copyright strings...
3484 for (st = (ppdcString *)d->copyright->first();
3485 st;
3486 st = (ppdcString *)d->copyright->next())
3487 quotef(fp, " Copyright \"%s\"\n", st->value);
3488
3489 // Write other strings and values...
3490 if (d->manufacturer && d->manufacturer->value)
3491 quotef(fp, " Manufacturer \"%s\"\n", d->manufacturer->value);
3492 if (d->model_name->value)
3493 quotef(fp, " ModelName \"%s\"\n", d->model_name->value);
3494 if (d->file_name && d->file_name->value)
3495 quotef(fp, " FileName \"%s\"\n", d->file_name->value);
3496 if (d->pc_file_name && d->pc_file_name->value)
3497 quotef(fp, " PCFileName \"%s\"\n", d->pc_file_name->value);
3498 if (d->version && d->version->value)
3499 quotef(fp, " Version \"%s\"\n", d->version->value);
3500
3501 cupsFilePrintf(fp, " DriverType %s\n", driver_types[d->type]);
3502
3503 if (d->model_number)
3504 {
3505 switch (d->type)
3506 {
3507 case PPDC_DRIVER_LABEL :
3508 cupsFilePuts(fp, " ModelNumber ");
3509
3510 switch (d->model_number)
3511 {
3512 case DYMO_3x0 :
3513 cupsFilePuts(fp, "$DYMO_3x0\n");
3514 break;
3515
3516 case ZEBRA_EPL_LINE :
3517 cupsFilePuts(fp, "$ZEBRA_EPL_LINE\n");
3518 break;
3519
3520 case ZEBRA_EPL_PAGE :
3521 cupsFilePuts(fp, "$ZEBRA_EPL_PAGE\n");
3522 break;
3523
3524 case ZEBRA_ZPL :
3525 cupsFilePuts(fp, "$ZEBRA_ZPL\n");
3526 break;
3527
3528 case ZEBRA_CPCL :
3529 cupsFilePuts(fp, "$ZEBRA_CPCL\n");
3530 break;
3531
3532 case INTELLITECH_PCL :
3533 cupsFilePuts(fp, "$INTELLITECH_PCL\n");
3534 break;
3535
3536 default :
3537 cupsFilePrintf(fp, "%d\n", d->model_number);
3538 break;
3539 }
3540 break;
3541
3542 case PPDC_DRIVER_EPSON :
3543 cupsFilePuts(fp, " ModelNumber ");
3544
3545 switch (d->model_number)
3546 {
3547 case EPSON_9PIN :
3548 cupsFilePuts(fp, "$EPSON_9PIN\n");
3549 break;
3550
3551 case EPSON_24PIN :
3552 cupsFilePuts(fp, "$EPSON_24PIN\n");
3553 break;
3554
3555 case EPSON_COLOR :
3556 cupsFilePuts(fp, "$EPSON_COLOR\n");
3557 break;
3558
3559 case EPSON_PHOTO :
3560 cupsFilePuts(fp, "$EPSON_PHOTO\n");
3561 break;
3562
3563 case EPSON_ICOLOR :
3564 cupsFilePuts(fp, "$EPSON_ICOLOR\n");
3565 break;
3566
3567 case EPSON_IPHOTO :
3568 cupsFilePuts(fp, "$EPSON_IPHOTO\n");
3569 break;
3570
3571 default :
3572 cupsFilePrintf(fp, "%d\n", d->model_number);
3573 break;
3574 }
3575 break;
3576
3577 case PPDC_DRIVER_HP :
3578 cupsFilePuts(fp, " ModelNumber ");
3579 switch (d->model_number)
3580 {
3581 case HP_LASERJET :
3582 cupsFilePuts(fp, "$HP_LASERJET\n");
3583 break;
3584
3585 case HP_DESKJET :
3586 cupsFilePuts(fp, "$HP_DESKJET\n");
3587 break;
3588
3589 case HP_DESKJET2 :
3590 cupsFilePuts(fp, "$HP_DESKJET2\n");
3591 break;
3592
3593 default :
3594 cupsFilePrintf(fp, "%d\n", d->model_number);
3595 break;
3596 }
3597
3598 cupsFilePuts(fp, ")\n");
3599 break;
3600
3601 default :
3602 cupsFilePrintf(fp, " ModelNumber %d\n", d->model_number);
3603 break;
3604 }
3605 }
3606
3607 if (d->manual_copies)
3608 cupsFilePuts(fp, " ManualCopies Yes\n");
3609
3610 if (d->color_device)
3611 cupsFilePuts(fp, " ColorDevice Yes\n");
3612
3613 if (d->throughput)
3614 cupsFilePrintf(fp, " Throughput %d\n", d->throughput);
3615
3616 // Output all of the attributes...
3617 for (a = (ppdcAttr *)d->attrs->first();
3618 a;
3619 a = (ppdcAttr *)d->attrs->next())
3620 if (a->text->value && a->text->value[0])
3621 quotef(fp, " Attribute \"%s\" \"%s/%s\" \"%s\"\n",
3622 a->name->value, a->selector->value ? a->selector->value : "",
3623 a->text->value, a->value->value ? a->value->value : "");
3624 else
3625 quotef(fp, " Attribute \"%s\" \"%s\" \"%s\"\n",
3626 a->name->value, a->selector->value ? a->selector->value : "",
3627 a->value->value ? a->value->value : "");
3628
3629 // Output all of the constraints...
3630 for (co = (ppdcConstraint *)d->constraints->first();
3631 co;
3632 co = (ppdcConstraint *)d->constraints->next())
3633 {
3634 if (co->option1->value[0] == '*')
3635 cupsFilePrintf(fp, " UIConstraints \"%s %s", co->option1->value,
3636 co->choice1->value ? co->choice1->value : "");
3637 else
3638 cupsFilePrintf(fp, " UIConstraints \"*%s %s", co->option1->value,
3639 co->choice1->value ? co->choice1->value : "");
3640
3641 if (co->option2->value[0] == '*')
3642 cupsFilePrintf(fp, " %s %s\"\n", co->option2->value,
3643 co->choice2->value ? co->choice2->value : "");
3644 else
3645 cupsFilePrintf(fp, " *%s %s\"\n", co->option2->value,
3646 co->choice2->value ? co->choice2->value : "");
3647 }
3648
3649 // Output all of the filters...
3650 for (fi = (ppdcFilter *)d->filters->first();
3651 fi;
3652 fi = (ppdcFilter *)d->filters->next())
3653 cupsFilePrintf(fp, " Filter \"%s %d %s\"\n",
3654 fi->mime_type->value, fi->cost, fi->program->value);
3655
3656 // Output all of the fonts...
3657 for (fo = (ppdcFont *)d->fonts->first();
3658 fo;
3659 fo = (ppdcFont *)d->fonts->next())
3660 if (!strcmp(fo->name->value, "*"))
3661 cupsFilePuts(fp, " Font *\n");
3662 else
3663 cupsFilePrintf(fp, " Font \"%s\" \"%s\" \"%s\" \"%s\" %s\n",
3664 fo->name->value, fo->encoding->value,
3665 fo->version->value, fo->charset->value,
3666 fo->status == PPDC_FONT_ROM ? "ROM" : "Disk");
3667
3668 // Output all options...
3669 for (g = (ppdcGroup *)d->groups->first();
3670 g;
3671 g = (ppdcGroup *)d->groups->next())
3672 {
3673 if (g->options->count == 0)
3674 continue;
3675
3676 if (g->text->value && g->text->value[0])
3677 quotef(fp, " Group \"%s/%s\"\n", g->name->value, g->text->value);
3678 else
3679 cupsFilePrintf(fp, " Group \"%s\"\n", g->name->value);
3680
3681 for (o = (ppdcOption *)g->options->first();
3682 o;
3683 o = (ppdcOption *)g->options->next())
3684 {
3685 if (o->choices->count == 0)
3686 continue;
3687
3688 if (o->text->value && o->text->value[0])
3689 quotef(fp, " Option \"%s/%s\"", o->name->value, o->text->value);
3690 else
3691 cupsFilePrintf(fp, " Option \"%s\"", o->name->value);
3692
3693 cupsFilePrintf(fp, " %s %s %.1f\n",
3694 o->type == PPDC_BOOLEAN ? "Boolean" :
3695 o->type == PPDC_PICKONE ? "PickOne" : "PickMany",
3696 o->section == PPDC_SECTION_ANY ? "AnySetup" :
3697 o->section == PPDC_SECTION_DOCUMENT ? "DocumentSetup" :
3698 o->section == PPDC_SECTION_EXIT ? "ExitServer" :
3699 o->section == PPDC_SECTION_JCL ? "JCLSetup" :
3700 o->section == PPDC_SECTION_PAGE ? "PageSetup" :
3701 "Prolog",
3702 o->order);
3703
3704 for (ch = (ppdcChoice *)o->choices->first();
3705 ch;
3706 ch = (ppdcChoice *)o->choices->next())
3707 {
3708 if (ch->text->value && ch->text->value[0])
3709 quotef(fp, " %sChoice \"%s/%s\" \"%s\"\n",
3710 o->defchoice == ch->name ? "*" : "",
3711 ch->name->value, ch->text->value,
3712 ch->code->value ? ch->code->value : "");
3713 else
3714 quotef(fp, " %sChoice \"%s\" \"%s\"\n",
3715 o->defchoice == ch->name ? "*" : "",
3716 ch->name->value,
3717 ch->code->value ? ch->code->value : "");
3718 }
3719 }
3720 }
3721
3722 // Output all of the color profiles...
3723 for (p = (ppdcProfile *)d->profiles->first();
3724 p;
3725 p = (ppdcProfile *)d->profiles->next())
3726 cupsFilePrintf(fp, " ColorProfile \"%s/%s\" %.3f %.3f "
3727 "%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n",
3728 p->resolution->value, p->media_type->value,
3729 p->density, p->gamma,
3730 p->profile[0], p->profile[1], p->profile[2],
3731 p->profile[3], p->profile[4], p->profile[5],
3732 p->profile[6], p->profile[7], p->profile[8]);
3733
3734 // Output all of the media sizes...
3735 left = 0.0;
3736 bottom = 0.0;
3737 right = 0.0;
3738 top = 0.0;
3739
3740 for (si = (ppdcMediaSize *)d->sizes->first();
3741 si;
3742 si = (ppdcMediaSize *)d->sizes->next())
3743 if (si->size_code->value && si->region_code->value)
3744 {
3745 // Output a custom media size...
3746 quotef(fp, " %sCustomMedia \"%s/%s\" %.2f %.2f %.2f %.2f %.2f %.2f \"%s\" \"%s\"\n",
3747 si->name == d->default_size ? "*" : "", si->name->value,
3748 si->text->value, si->width, si->length, si->left, si->bottom,
3749 si->right, si->top, si->size_code->value,
3750 si->region_code->value);
3751 }
3752 else
3753 {
3754 // Output a standard media size...
3755 if (fabs(left - si->left) > 0.1 ||
3756 fabs(bottom - si->bottom) > 0.1 ||
3757 fabs(right - si->right) > 0.1 ||
3758 fabs(top - si->top) > 0.1)
3759 {
3760 cupsFilePrintf(fp, " HWMargins %.2f %.2f %.2f %.2f\n",
3761 si->left, si->bottom, si->right, si->top);
3762
3763 left = si->left;
3764 bottom = si->bottom;
3765 right = si->right;
3766 top = si->top;
3767 }
3768
3769 cupsFilePrintf(fp, " %sMediaSize %s\n",
3770 si->name == d->default_size ? "*" : "",
3771 si->name->value);
3772 }
3773
3774 if (d->variable_paper_size)
3775 {
3776 cupsFilePuts(fp, " VariablePaperSize Yes\n");
3777
3778 if (fabs(left - d->left_margin) > 0.1 ||
3779 fabs(bottom - d->bottom_margin) > 0.1 ||
3780 fabs(right - d->right_margin) > 0.1 ||
3781 fabs(top - d->top_margin) > 0.1)
3782 {
3783 cupsFilePrintf(fp, " HWMargins %.2f %.2f %.2f %.2f\n",
3784 d->left_margin, d->bottom_margin, d->right_margin,
3785 d->top_margin);
3786 }
3787
3788 cupsFilePrintf(fp, " MinSize %.2f %.2f\n", d->min_width, d->min_length);
3789 cupsFilePrintf(fp, " MaxSize %.2f %.2f\n", d->max_width, d->max_length);
3790 }
3791
3792 // End the driver...
3793 cupsFilePuts(fp, "}\n");
3794 }
3795
3796 // Close the file and return...
3797 cupsFileClose(fp);
3798
3799 return (0);
3800 }
3801