1 //
2 // Source class for the CUPS PPD Compiler.
3 //
4 // Copyright 2007-2018 by Apple Inc.
5 // Copyright 2002-2007 by Easy Software Products.
6 //
7 // Licensed under Apache License v2.0. See the file "LICENSE" for more
8 // information.
9 //
10
11 //
12 // Include necessary headers...
13 //
14
15 #include "ppdc-private.h"
16 #include <limits.h>
17 #include <math.h>
18 #include <unistd.h>
19 #include <cups/raster.h>
20 #include "data/epson.h"
21 #include "data/hp.h"
22 #include "data/label.h"
23 #ifndef _WIN32
24 # include <sys/utsname.h>
25 #endif // !_WIN32
26
27
28 //
29 // Class globals...
30 //
31
32 ppdcArray *ppdcSource::includes = 0;
33 const char *ppdcSource::driver_types[] =
34 {
35 "custom",
36 "ps",
37 "escp",
38 "pcl",
39 "label",
40 "epson",
41 "hp"
42 };
43
44
45 //
46 // 'ppdcSource::ppdcSource()' - Load a driver source file.
47 //
48
ppdcSource(const char * f,cups_file_t * ffp)49 ppdcSource::ppdcSource(const char *f, // I - File to read
50 cups_file_t *ffp)// I - File pointer to use
51 : ppdcShared()
52 {
53 PPDC_NEW;
54
55 filename = new ppdcString(f);
56 base_fonts = new ppdcArray();
57 drivers = new ppdcArray();
58 po_files = new ppdcArray();
59 sizes = new ppdcArray();
60 vars = new ppdcArray();
61 cond_state = PPDC_COND_NORMAL;
62 cond_current = cond_stack;
63 cond_stack[0] = PPDC_COND_NORMAL;
64
65 // Add standard #define variables...
66 #define MAKE_STRING(x) #x
67
68 vars->add(new ppdcVariable("CUPS_VERSION", MAKE_STRING(CUPS_VERSION)));
69 vars->add(new ppdcVariable("CUPS_VERSION_MAJOR", MAKE_STRING(CUPS_VERSION_MAJOR)));
70 vars->add(new ppdcVariable("CUPS_VERSION_MINOR", MAKE_STRING(CUPS_VERSION_MINOR)));
71 vars->add(new ppdcVariable("CUPS_VERSION_PATCH", MAKE_STRING(CUPS_VERSION_PATCH)));
72
73 #ifdef _WIN32
74 vars->add(new ppdcVariable("PLATFORM_NAME", "Windows"));
75 vars->add(new ppdcVariable("PLATFORM_ARCH", "X86"));
76
77 #else
78 struct utsname name; // uname information
79
80 if (!uname(&name))
81 {
82 vars->add(new ppdcVariable("PLATFORM_NAME", name.sysname));
83 vars->add(new ppdcVariable("PLATFORM_ARCH", name.machine));
84 }
85 else
86 {
87 vars->add(new ppdcVariable("PLATFORM_NAME", "unknown"));
88 vars->add(new ppdcVariable("PLATFORM_ARCH", "unknown"));
89 }
90 #endif // _WIN32
91
92 if (f)
93 read_file(f, ffp);
94 }
95
96
97 //
98 // 'ppdcSource::~ppdcSource()' - Free a driver source file.
99 //
100
~ppdcSource()101 ppdcSource::~ppdcSource()
102 {
103 PPDC_DELETE;
104
105 filename->release();
106 base_fonts->release();
107 drivers->release();
108 po_files->release();
109 sizes->release();
110 vars->release();
111 }
112
113
114 //
115 // 'ppdcSource::add_include()' - Add an include directory.
116 //
117
118 void
add_include(const char * d)119 ppdcSource::add_include(const char *d) // I - Include directory
120 {
121 if (!d)
122 return;
123
124 if (!includes)
125 includes = new ppdcArray();
126
127 includes->add(new ppdcString(d));
128 }
129
130
131 //
132 // 'ppdcSource::find_driver()' - Find a driver.
133 //
134
135 ppdcDriver * // O - Driver
find_driver(const char * f)136 ppdcSource::find_driver(const char *f) // I - Driver file name
137 {
138 ppdcDriver *d; // Current driver
139
140
141 for (d = (ppdcDriver *)drivers->first(); d; d = (ppdcDriver *)drivers->next())
142 if (!_cups_strcasecmp(f, d->pc_file_name->value))
143 return (d);
144
145 return (NULL);
146 }
147
148
149 //
150 // 'ppdcSource::find_include()' - Find an include file.
151 //
152
153 char * // O - Found path or NULL
find_include(const char * f,const char * base,char * n,int nlen)154 ppdcSource::find_include(
155 const char *f, // I - Include filename
156 const char *base, // I - Current directory
157 char *n, // I - Path buffer
158 int nlen) // I - Path buffer length
159 {
160 ppdcString *dir; // Include directory
161 char temp[1024], // Temporary path
162 *ptr; // Pointer to end of path
163
164
165 // Range check input...
166 if (!f || !*f || !n || nlen < 2)
167 return (0);
168
169 // Check the first character to see if we have <name> or "name"...
170 if (*f == '<')
171 {
172 // Remove the surrounding <> from the name...
173 strlcpy(temp, f + 1, sizeof(temp));
174 ptr = temp + strlen(temp) - 1;
175
176 if (*ptr != '>')
177 {
178 _cupsLangPrintf(stderr,
179 _("ppdc: Invalid #include/#po filename \"%s\"."), n);
180 return (0);
181 }
182
183 *ptr = '\0';
184 f = temp;
185 }
186 else
187 {
188 // Check for the local file relative to the current directory...
189 if (base && *base && f[0] != '/')
190 snprintf(n, (size_t)nlen, "%s/%s", base, f);
191 else
192 strlcpy(n, f, (size_t)nlen);
193
194 if (!access(n, 0))
195 return (n);
196 else if (*f == '/')
197 {
198 // Absolute path that doesn't exist...
199 return (0);
200 }
201 }
202
203 // Search the include directories, if any...
204 if (includes)
205 {
206 for (dir = (ppdcString *)includes->first(); dir; dir = (ppdcString *)includes->next())
207 {
208 snprintf(n, (size_t)nlen, "%s/%s", dir->value, f);
209 if (!access(n, 0))
210 return (n);
211 }
212 }
213
214 // Search the standard include directories...
215 _cups_globals_t *cg = _cupsGlobals(); // Global data
216
217 snprintf(n, (size_t)nlen, "%s/ppdc/%s", cg->cups_datadir, f);
218 if (!access(n, 0))
219 return (n);
220
221 snprintf(n, (size_t)nlen, "%s/po/%s", cg->cups_datadir, f);
222 if (!access(n, 0))
223 return (n);
224 else
225 return (0);
226 }
227
228
229 //
230 // 'ppdcSource::find_po()' - Find a message catalog for the given locale.
231 //
232
233 ppdcCatalog * // O - Message catalog or NULL
find_po(const char * l)234 ppdcSource::find_po(const char *l) // I - Locale name
235 {
236 ppdcCatalog *cat; // Current message catalog
237
238
239 for (cat = (ppdcCatalog *)po_files->first();
240 cat;
241 cat = (ppdcCatalog *)po_files->next())
242 if (!_cups_strcasecmp(l, cat->locale->value))
243 return (cat);
244
245 return (NULL);
246 }
247
248
249 //
250 // 'ppdcSource::find_size()' - Find a media size.
251 //
252
253 ppdcMediaSize * // O - Size
find_size(const char * s)254 ppdcSource::find_size(const char *s) // I - Size name
255 {
256 ppdcMediaSize *m; // Current media size
257
258
259 for (m = (ppdcMediaSize *)sizes->first(); m; m = (ppdcMediaSize *)sizes->next())
260 if (!_cups_strcasecmp(s, m->name->value))
261 return (m);
262
263 return (NULL);
264 }
265
266
267 //
268 // 'ppdcSource::find_variable()' - Find a variable.
269 //
270
271 ppdcVariable * // O - Variable
find_variable(const char * n)272 ppdcSource::find_variable(const char *n)// I - Variable name
273 {
274 ppdcVariable *v; // Current variable
275
276
277 for (v = (ppdcVariable *)vars->first(); v; v = (ppdcVariable *)vars->next())
278 if (!_cups_strcasecmp(n, v->name->value))
279 return (v);
280
281 return (NULL);
282 }
283
284
285 //
286 // 'ppdcSource::get_attr()' - Get an attribute.
287 //
288
289 ppdcAttr * // O - Attribute
get_attr(ppdcFile * fp,bool loc)290 ppdcSource::get_attr(ppdcFile *fp, // I - File to read
291 bool loc) // I - Localize this attribute?
292 {
293 char name[1024], // Name string
294 selector[1024], // Selector string
295 *text, // Text string
296 value[1024]; // Value string
297
298
299 // Get the attribute parameters:
300 //
301 // Attribute name selector value
302 if (!get_token(fp, name, sizeof(name)))
303 {
304 _cupsLangPrintf(stderr,
305 _("ppdc: Expected name after %s on line %d of %s."),
306 loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
307 return (0);
308 }
309
310 if (!get_token(fp, selector, sizeof(selector)))
311 {
312 _cupsLangPrintf(stderr,
313 _("ppdc: Expected selector after %s on line %d of %s."),
314 loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
315 return (0);
316 }
317
318 if ((text = strchr(selector, '/')) != NULL)
319 *text++ = '\0';
320
321 if (!get_token(fp, value, sizeof(value)))
322 {
323 _cupsLangPrintf(stderr,
324 _("ppdc: Expected value after %s on line %d of %s."),
325 loc ? "LocAttribute" : "Attribute", fp->line, fp->filename);
326 return (0);
327 }
328
329 return (new ppdcAttr(name, selector, text, value, loc));
330 }
331
332
333 //
334 // 'ppdcSource::get_boolean()' - Get a boolean value.
335 //
336
337 int // O - Boolean value
get_boolean(ppdcFile * fp)338 ppdcSource::get_boolean(ppdcFile *fp) // I - File to read
339 {
340 char buffer[256]; // String buffer
341
342
343 if (!get_token(fp, buffer, sizeof(buffer)))
344 {
345 _cupsLangPrintf(stderr,
346 _("ppdc: Expected boolean value on line %d of %s."),
347 fp->line, fp->filename);
348 return (-1);
349 }
350
351 if (!_cups_strcasecmp(buffer, "on") ||
352 !_cups_strcasecmp(buffer, "yes") ||
353 !_cups_strcasecmp(buffer, "true"))
354 return (1);
355 else if (!_cups_strcasecmp(buffer, "off") ||
356 !_cups_strcasecmp(buffer, "no") ||
357 !_cups_strcasecmp(buffer, "false"))
358 return (0);
359 else
360 {
361 _cupsLangPrintf(stderr,
362 _("ppdc: Bad boolean value (%s) on line %d of %s."),
363 buffer, fp->line, fp->filename);
364 return (-1);
365 }
366 }
367
368
369 //
370 // 'ppdcSource::get_choice()' - Get a choice.
371 //
372
373 ppdcChoice * // O - Choice data
get_choice(ppdcFile * fp)374 ppdcSource::get_choice(ppdcFile *fp) // I - File to read
375 {
376 char name[1024], // Name
377 *text, // Text
378 code[10240]; // Code
379
380
381 // Read a choice from the file:
382 //
383 // Choice name/text code
384 if (!get_token(fp, name, sizeof(name)))
385 {
386 _cupsLangPrintf(stderr,
387 _("ppdc: Expected choice name/text on line %d of %s."),
388 fp->line, fp->filename);
389 return (NULL);
390 }
391
392 if ((text = strchr(name, '/')) != NULL)
393 *text++ = '\0';
394 else
395 text = name;
396
397 if (!get_token(fp, code, sizeof(code)))
398 {
399 _cupsLangPrintf(stderr, _("ppdc: Expected choice code on line %d of %s."),
400 fp->line, fp->filename);
401 return (NULL);
402 }
403
404 // Return the new choice
405 return (new ppdcChoice(name, text, code));
406 }
407
408
409 //
410 // 'ppdcSource::get_color_model()' - Get an old-style color model option.
411 //
412
413 ppdcChoice * // O - Choice data
get_color_model(ppdcFile * fp)414 ppdcSource::get_color_model(ppdcFile *fp)
415 // I - File to read
416 {
417 char name[1024], // Option name
418 *text, // Text option
419 temp[256]; // Temporary string
420 int color_space, // Colorspace
421 color_order, // Color order
422 compression; // Compression mode
423
424
425 // Get the ColorModel parameters:
426 //
427 // ColorModel name/text colorspace colororder compression
428 if (!get_token(fp, name, sizeof(name)))
429 {
430 _cupsLangPrintf(stderr,
431 _("ppdc: Expected name/text combination for ColorModel on "
432 "line %d of %s."), fp->line, fp->filename);
433 return (NULL);
434 }
435
436 if ((text = strchr(name, '/')) != NULL)
437 *text++ = '\0';
438 else
439 text = name;
440
441 if (!get_token(fp, temp, sizeof(temp)))
442 {
443 _cupsLangPrintf(stderr,
444 _("ppdc: Expected colorspace for ColorModel on line %d of "
445 "%s."), fp->line, fp->filename);
446 return (NULL);
447 }
448
449 if ((color_space = get_color_space(temp)) < 0)
450 color_space = get_integer(temp);
451
452 if (!get_token(fp, temp, sizeof(temp)))
453 {
454 _cupsLangPrintf(stderr,
455 _("ppdc: Expected color order for ColorModel on line %d of "
456 "%s."), fp->line, fp->filename);
457 return (NULL);
458 }
459
460 if ((color_order = get_color_order(temp)) < 0)
461 color_order = get_integer(temp);
462
463 if (!get_token(fp, temp, sizeof(temp)))
464 {
465 _cupsLangPrintf(stderr,
466 _("ppdc: Expected compression for ColorModel on line %d of "
467 "%s."), fp->line, fp->filename);
468 return (NULL);
469 }
470
471 compression = get_integer(temp);
472
473 snprintf(temp, sizeof(temp),
474 "<</cupsColorSpace %d/cupsColorOrder %d/cupsCompression %d>>"
475 "setpagedevice",
476 color_space, color_order, compression);
477
478 return (new ppdcChoice(name, text, temp));
479 }
480
481
482 //
483 // 'ppdcSource::get_color_order()' - Get an old-style color order value.
484 //
485
486 int // O - Color order value
get_color_order(const char * co)487 ppdcSource::get_color_order(
488 const char *co) // I - Color order string
489 {
490 if (!_cups_strcasecmp(co, "chunked") ||
491 !_cups_strcasecmp(co, "chunky"))
492 return (CUPS_ORDER_CHUNKED);
493 else if (!_cups_strcasecmp(co, "banded"))
494 return (CUPS_ORDER_BANDED);
495 else if (!_cups_strcasecmp(co, "planar"))
496 return (CUPS_ORDER_PLANAR);
497 else
498 return (-1);
499 }
500
501
502 //
503 // 'ppdcSource::get_color_profile()' - Get a color profile definition.
504 //
505
506 ppdcProfile * // O - Color profile
get_color_profile(ppdcFile * fp)507 ppdcSource::get_color_profile(
508 ppdcFile *fp) // I - File to read
509 {
510 char resolution[1024], // Resolution/media type
511 *media_type; // Media type
512 int i; // Looping var
513 float g, // Gamma value
514 d, // Density value
515 m[9]; // Transform matrix
516
517
518 // Get the ColorProfile parameters:
519 //
520 // ColorProfile resolution/mediatype gamma density m00 m01 m02 ... m22
521 if (!get_token(fp, resolution, sizeof(resolution)))
522 {
523 _cupsLangPrintf(stderr,
524 _("ppdc: Expected resolution/mediatype following "
525 "ColorProfile on line %d of %s."),
526 fp->line, fp->filename);
527 return (NULL);
528 }
529
530 if ((media_type = strchr(resolution, '/')) != NULL)
531 *media_type++ = '\0';
532 else
533 media_type = resolution;
534
535 g = get_float(fp);
536 d = get_float(fp);
537 for (i = 0; i < 9; i ++)
538 m[i] = get_float(fp);
539
540 return (new ppdcProfile(resolution, media_type, g, d, m));
541 }
542
543
544 //
545 // 'ppdcSource::get_color_space()' - Get an old-style colorspace value.
546 //
547
548 int // O - Colorspace value
get_color_space(const char * cs)549 ppdcSource::get_color_space(
550 const char *cs) // I - Colorspace string
551 {
552 if (!_cups_strcasecmp(cs, "w"))
553 return (CUPS_CSPACE_W);
554 else if (!_cups_strcasecmp(cs, "rgb"))
555 return (CUPS_CSPACE_RGB);
556 else if (!_cups_strcasecmp(cs, "rgba"))
557 return (CUPS_CSPACE_RGBA);
558 else if (!_cups_strcasecmp(cs, "k"))
559 return (CUPS_CSPACE_K);
560 else if (!_cups_strcasecmp(cs, "cmy"))
561 return (CUPS_CSPACE_CMY);
562 else if (!_cups_strcasecmp(cs, "ymc"))
563 return (CUPS_CSPACE_YMC);
564 else if (!_cups_strcasecmp(cs, "cmyk"))
565 return (CUPS_CSPACE_CMYK);
566 else if (!_cups_strcasecmp(cs, "ymck"))
567 return (CUPS_CSPACE_YMCK);
568 else if (!_cups_strcasecmp(cs, "kcmy"))
569 return (CUPS_CSPACE_KCMY);
570 else if (!_cups_strcasecmp(cs, "kcmycm"))
571 return (CUPS_CSPACE_KCMYcm);
572 else if (!_cups_strcasecmp(cs, "gmck"))
573 return (CUPS_CSPACE_GMCK);
574 else if (!_cups_strcasecmp(cs, "gmcs"))
575 return (CUPS_CSPACE_GMCS);
576 else if (!_cups_strcasecmp(cs, "white"))
577 return (CUPS_CSPACE_WHITE);
578 else if (!_cups_strcasecmp(cs, "gold"))
579 return (CUPS_CSPACE_GOLD);
580 else if (!_cups_strcasecmp(cs, "silver"))
581 return (CUPS_CSPACE_SILVER);
582 else if (!_cups_strcasecmp(cs, "CIEXYZ"))
583 return (CUPS_CSPACE_CIEXYZ);
584 else if (!_cups_strcasecmp(cs, "CIELab"))
585 return (CUPS_CSPACE_CIELab);
586 else if (!_cups_strcasecmp(cs, "RGBW"))
587 return (CUPS_CSPACE_RGBW);
588 else if (!_cups_strcasecmp(cs, "ICC1"))
589 return (CUPS_CSPACE_ICC1);
590 else if (!_cups_strcasecmp(cs, "ICC2"))
591 return (CUPS_CSPACE_ICC2);
592 else if (!_cups_strcasecmp(cs, "ICC3"))
593 return (CUPS_CSPACE_ICC3);
594 else if (!_cups_strcasecmp(cs, "ICC4"))
595 return (CUPS_CSPACE_ICC4);
596 else if (!_cups_strcasecmp(cs, "ICC5"))
597 return (CUPS_CSPACE_ICC5);
598 else if (!_cups_strcasecmp(cs, "ICC6"))
599 return (CUPS_CSPACE_ICC6);
600 else if (!_cups_strcasecmp(cs, "ICC7"))
601 return (CUPS_CSPACE_ICC7);
602 else if (!_cups_strcasecmp(cs, "ICC8"))
603 return (CUPS_CSPACE_ICC8);
604 else if (!_cups_strcasecmp(cs, "ICC9"))
605 return (CUPS_CSPACE_ICC9);
606 else if (!_cups_strcasecmp(cs, "ICCA"))
607 return (CUPS_CSPACE_ICCA);
608 else if (!_cups_strcasecmp(cs, "ICCB"))
609 return (CUPS_CSPACE_ICCB);
610 else if (!_cups_strcasecmp(cs, "ICCC"))
611 return (CUPS_CSPACE_ICCC);
612 else if (!_cups_strcasecmp(cs, "ICCD"))
613 return (CUPS_CSPACE_ICCD);
614 else if (!_cups_strcasecmp(cs, "ICCE"))
615 return (CUPS_CSPACE_ICCE);
616 else if (!_cups_strcasecmp(cs, "ICCF"))
617 return (CUPS_CSPACE_ICCF);
618 else
619 return (-1);
620 }
621
622
623 //
624 // 'ppdcSource::get_constraint()' - Get a constraint.
625 //
626
627 ppdcConstraint * // O - Constraint
get_constraint(ppdcFile * fp)628 ppdcSource::get_constraint(ppdcFile *fp)// I - File to read
629 {
630 char temp[1024], // One string to rule them all
631 *ptr, // Pointer into string
632 *option1, // Constraint option 1
633 *choice1, // Constraint choice 1
634 *option2, // Constraint option 2
635 *choice2; // Constraint choice 2
636
637
638 // Read the UIConstaints parameter in one of the following forms:
639 //
640 // UIConstraints "*Option1 *Option2"
641 // UIConstraints "*Option1 Choice1 *Option2"
642 // UIConstraints "*Option1 *Option2 Choice2"
643 // UIConstraints "*Option1 Choice1 *Option2 Choice2"
644 if (!get_token(fp, temp, sizeof(temp)))
645 {
646 _cupsLangPrintf(stderr,
647 _("ppdc: Expected constraints string for UIConstraints on "
648 "line %d of %s."), fp->line, fp->filename);
649 return (NULL);
650 }
651
652 for (ptr = temp; isspace(*ptr); ptr ++);
653
654 if (*ptr != '*')
655 {
656 _cupsLangPrintf(stderr,
657 _("ppdc: Option constraint must *name on line %d of %s."),
658 fp->line, fp->filename);
659 return (NULL);
660 }
661
662 option1 = ptr;
663
664 for (; *ptr && !isspace(*ptr); ptr ++);
665 for (; isspace(*ptr); *ptr++ = '\0');
666
667 if (*ptr != '*')
668 {
669 choice1 = ptr;
670
671 for (; *ptr && !isspace(*ptr); ptr ++);
672 for (; isspace(*ptr); *ptr++ = '\0');
673 }
674 else
675 choice1 = NULL;
676
677 if (*ptr != '*')
678 {
679 _cupsLangPrintf(stderr,
680 _("ppdc: Expected two option names on line %d of %s."),
681 fp->line, fp->filename);
682 return (NULL);
683 }
684
685 option2 = ptr;
686
687 for (; *ptr && !isspace(*ptr); ptr ++);
688 for (; isspace(*ptr); *ptr++ = '\0');
689
690 if (*ptr)
691 choice2 = ptr;
692 else
693 choice2 = NULL;
694
695 return (new ppdcConstraint(option1, choice1, option2, choice2));
696 }
697
698
699 //
700 // 'ppdcSource::get_custom_size()' - Get a custom media size definition from a file.
701 //
702
703 ppdcMediaSize * // O - Media size
get_custom_size(ppdcFile * fp)704 ppdcSource::get_custom_size(ppdcFile *fp)
705 // I - File to read
706 {
707 char name[1024], // Name
708 *text, // Text
709 size_code[10240], // PageSize code
710 region_code[10240]; // PageRegion
711 float width, // Width
712 length, // Length
713 left, // Left margin
714 bottom, // Bottom margin
715 right, // Right margin
716 top; // Top margin
717
718
719 // Get the name, text, width, length, margins, and code:
720 //
721 // CustomMedia name/text width length left bottom right top size-code region-code
722 if (!get_token(fp, name, sizeof(name)))
723 return (NULL);
724
725 if ((text = strchr(name, '/')) != NULL)
726 *text++ = '\0';
727 else
728 text = name;
729
730 if ((width = get_measurement(fp)) < 0.0f)
731 return (NULL);
732
733 if ((length = get_measurement(fp)) < 0.0f)
734 return (NULL);
735
736 if ((left = get_measurement(fp)) < 0.0f)
737 return (NULL);
738
739 if ((bottom = get_measurement(fp)) < 0.0f)
740 return (NULL);
741
742 if ((right = get_measurement(fp)) < 0.0f)
743 return (NULL);
744
745 if ((top = get_measurement(fp)) < 0.0f)
746 return (NULL);
747
748 if (!get_token(fp, size_code, sizeof(size_code)))
749 return (NULL);
750
751 if (!get_token(fp, region_code, sizeof(region_code)))
752 return (NULL);
753
754 // Return the new media size...
755 return (new ppdcMediaSize(name, text, width, length, left, bottom,
756 right, top, size_code, region_code));
757 }
758
759
760 //
761 // 'ppdcSource::get_duplex()' - Get a duplex option.
762 //
763
764 void
get_duplex(ppdcFile * fp,ppdcDriver * d)765 ppdcSource::get_duplex(ppdcFile *fp, // I - File to read from
766 ppdcDriver *d) // I - Current driver
767 {
768 char temp[256]; // Duplex keyword
769 ppdcAttr *attr; // cupsFlipDuplex attribute
770 ppdcGroup *g; // Current group
771 ppdcOption *o; // Duplex option
772
773
774 // Duplex {boolean|none|normal|flip}
775 if (!get_token(fp, temp, sizeof(temp)))
776 {
777 _cupsLangPrintf(stderr,
778 _("ppdc: Expected duplex type after Duplex on line %d of "
779 "%s."), fp->line, fp->filename);
780 return;
781 }
782
783 if (cond_state)
784 return;
785
786 if (!_cups_strcasecmp(temp, "none") || !_cups_strcasecmp(temp, "false") ||
787 !_cups_strcasecmp(temp, "no") || !_cups_strcasecmp(temp, "off"))
788 {
789 g = d->find_group("General");
790 if ((o = g->find_option("Duplex")) != NULL)
791 g->options->remove(o);
792
793 for (attr = (ppdcAttr *)d->attrs->first();
794 attr;
795 attr = (ppdcAttr *)d->attrs->next())
796 if (!strcmp(attr->name->value, "cupsFlipDuplex"))
797 {
798 d->attrs->remove(attr);
799 break;
800 }
801 }
802 else if (!_cups_strcasecmp(temp, "normal") || !_cups_strcasecmp(temp, "true") ||
803 !_cups_strcasecmp(temp, "yes") || !_cups_strcasecmp(temp, "on") ||
804 !_cups_strcasecmp(temp, "flip") || !_cups_strcasecmp(temp, "rotated") ||
805 !_cups_strcasecmp(temp, "manualtumble"))
806 {
807 g = d->find_group("General");
808 o = g->find_option("Duplex");
809
810 if (!o)
811 {
812 o = new ppdcOption(PPDC_PICKONE, "Duplex", "2-Sided Printing",
813 !_cups_strcasecmp(temp, "flip") ? PPDC_SECTION_PAGE :
814 PPDC_SECTION_ANY, 10.0f);
815 o->add_choice(new ppdcChoice("None", "Off (1-Sided)",
816 "<</Duplex false>>setpagedevice"));
817 o->add_choice(new ppdcChoice("DuplexNoTumble", "Long-Edge (Portrait)",
818 "<</Duplex true/Tumble false>>setpagedevice"));
819 o->add_choice(new ppdcChoice("DuplexTumble", "Short-Edge (Landscape)",
820 "<</Duplex true/Tumble true>>setpagedevice"));
821
822 g->add_option(o);
823 }
824
825 for (attr = (ppdcAttr *)d->attrs->first();
826 attr;
827 attr = (ppdcAttr *)d->attrs->next())
828 if (!strcmp(attr->name->value, "cupsFlipDuplex"))
829 {
830 if (_cups_strcasecmp(temp, "flip"))
831 d->attrs->remove(attr);
832 break;
833 }
834
835 if (!_cups_strcasecmp(temp, "flip") && !attr)
836 d->add_attr(new ppdcAttr("cupsFlipDuplex", NULL, NULL, "true"));
837
838 for (attr = (ppdcAttr *)d->attrs->first();
839 attr;
840 attr = (ppdcAttr *)d->attrs->next())
841 if (!strcmp(attr->name->value, "cupsBackSide"))
842 {
843 d->attrs->remove(attr);
844 break;
845 }
846
847 if (!_cups_strcasecmp(temp, "flip"))
848 d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Flipped"));
849 else if (!_cups_strcasecmp(temp, "rotated"))
850 d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Rotated"));
851 else if (!_cups_strcasecmp(temp, "manualtumble"))
852 d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "ManualTumble"));
853 else
854 d->add_attr(new ppdcAttr("cupsBackSide", NULL, NULL, "Normal"));
855 }
856 else
857 _cupsLangPrintf(stderr,
858 _("ppdc: Unknown duplex type \"%s\" on line %d of %s."),
859 temp, fp->line, fp->filename);
860 }
861
862
863 //
864 // 'ppdcSource::get_filter()' - Get a filter.
865 //
866
867 ppdcFilter * // O - Filter
get_filter(ppdcFile * fp)868 ppdcSource::get_filter(ppdcFile *fp) // I - File to read
869 {
870 char type[1024], // MIME type
871 program[1024], // Filter program
872 *ptr; // Pointer into MIME type
873 int cost; // Relative cost
874
875
876 // Read filter parameters in one of the following formats:
877 //
878 // Filter "type cost program"
879 // Filter type cost program
880
881 if (!get_token(fp, type, sizeof(type)))
882 {
883 _cupsLangPrintf(stderr,
884 _("ppdc: Expected a filter definition on line %d of %s."),
885 fp->line, fp->filename);
886 return (NULL);
887 }
888
889 if ((ptr = strchr(type, ' ')) != NULL)
890 {
891 // Old-style filter definition in one string...
892 *ptr++ = '\0';
893 cost = strtol(ptr, &ptr, 10);
894
895 while (isspace(*ptr))
896 ptr ++;
897
898 strlcpy(program, ptr, sizeof(program));
899 }
900 else
901 {
902 cost = get_integer(fp);
903
904 if (!get_token(fp, program, sizeof(program)))
905 {
906 _cupsLangPrintf(stderr,
907 _("ppdc: Expected a program name on line %d of %s."),
908 fp->line, fp->filename);
909 return (NULL);
910 }
911 }
912
913 if (!type[0])
914 {
915 _cupsLangPrintf(stderr,
916 _("ppdc: Invalid empty MIME type for filter on line %d of "
917 "%s."), fp->line, fp->filename);
918 return (NULL);
919 }
920
921 if (cost < 0 || cost > 200)
922 {
923 _cupsLangPrintf(stderr,
924 _("ppdc: Invalid cost for filter on line %d of %s."),
925 fp->line, fp->filename);
926 return (NULL);
927 }
928
929 if (!program[0])
930 {
931 _cupsLangPrintf(stderr,
932 _("ppdc: Invalid empty program name for filter on line %d "
933 "of %s."), fp->line, fp->filename);
934 return (NULL);
935 }
936
937 return (new ppdcFilter(type, program, cost));
938 }
939
940
941 //
942 // 'ppdcSource::get_float()' - Get a single floating-point number.
943 //
944
945 float // O - Number
get_float(ppdcFile * fp)946 ppdcSource::get_float(ppdcFile *fp) // I - File to read
947 {
948 char temp[256], // String buffer
949 *ptr; // Pointer into buffer
950 float val; // Floating point value
951
952
953 // Get the number from the file and range-check...
954 if (!get_token(fp, temp, sizeof(temp)))
955 {
956 _cupsLangPrintf(stderr, _("ppdc: Expected real number on line %d of %s."),
957 fp->line, fp->filename);
958 return (-1.0f);
959 }
960
961 val = (float)strtod(temp, &ptr);
962
963 if (*ptr)
964 {
965 _cupsLangPrintf(stderr,
966 _("ppdc: Unknown trailing characters in real number \"%s\" "
967 "on line %d of %s."), temp, fp->line, fp->filename);
968 return (-1.0f);
969 }
970 else
971 return (val);
972 }
973
974
975 //
976 // 'ppdcSource::get_font()' - Get a font definition.
977 //
978
979 ppdcFont * // O - Font data
get_font(ppdcFile * fp)980 ppdcSource::get_font(ppdcFile *fp) // I - File to read
981 {
982 char name[256], // Font name
983 encoding[256], // Font encoding
984 version[256], // Font version
985 charset[256], // Font charset
986 temp[256]; // Font status string
987 ppdcFontStatus status; // Font status enumeration
988
989
990 // Read font parameters as follows:
991 //
992 // Font *
993 // Font name encoding version charset status
994 // %font name encoding version charset status
995 //
996 // "Name" is the PostScript font name.
997 //
998 // "Encoding" is the default encoding of the font: Standard, ISOLatin1,
999 // Special, Expert, ExpertSubset, etc.
1000 //
1001 // "Version" is the version number string.
1002 //
1003 // "Charset" specifies the characters that are included in the font:
1004 // Standard, Special, Expert, Adobe-Identity, etc.
1005 //
1006 // "Status" is the keyword ROM or Disk.
1007 if (!get_token(fp, name, sizeof(name)))
1008 {
1009 _cupsLangPrintf(stderr,
1010 _("ppdc: Expected name after Font on line %d of %s."),
1011 fp->line, fp->filename);
1012 return (0);
1013 }
1014
1015 if (!strcmp(name, "*"))
1016 {
1017 // Include all base fonts...
1018 encoding[0] = '\0';
1019 version[0] = '\0';
1020 charset[0] = '\0';
1021 status = PPDC_FONT_ROM;
1022 }
1023 else
1024 {
1025 // Load a full font definition...
1026 if (!get_token(fp, encoding, sizeof(encoding)))
1027 {
1028 _cupsLangPrintf(stderr,
1029 _("ppdc: Expected encoding after Font on line %d of "
1030 "%s."), fp->line, fp->filename);
1031 return (0);
1032 }
1033
1034 if (!get_token(fp, version, sizeof(version)))
1035 {
1036 _cupsLangPrintf(stderr,
1037 _("ppdc: Expected version after Font on line %d of "
1038 "%s."), fp->line, fp->filename);
1039 return (0);
1040 }
1041
1042 if (!get_token(fp, charset, sizeof(charset)))
1043 {
1044 _cupsLangPrintf(stderr,
1045 _("ppdc: Expected charset after Font on line %d of "
1046 "%s."), fp->line, fp->filename);
1047 return (0);
1048 }
1049
1050 if (!get_token(fp, temp, sizeof(temp)))
1051 {
1052 _cupsLangPrintf(stderr,
1053 _("ppdc: Expected status after Font on line %d of %s."),
1054 fp->line, fp->filename);
1055 return (0);
1056 }
1057
1058 if (!_cups_strcasecmp(temp, "ROM"))
1059 status = PPDC_FONT_ROM;
1060 else if (!_cups_strcasecmp(temp, "Disk"))
1061 status = PPDC_FONT_DISK;
1062 else
1063 {
1064 _cupsLangPrintf(stderr,
1065 _("ppdc: Bad status keyword %s on line %d of %s."),
1066 temp, fp->line, fp->filename);
1067 return (0);
1068 }
1069 }
1070
1071 // printf("Font %s %s %s %s %s\n", name, encoding, version, charset, temp);
1072
1073 return (new ppdcFont(name, encoding, version, charset, status));
1074 }
1075
1076
1077 //
1078 // 'ppdcSource::get_generic()' - Get a generic old-style option.
1079 //
1080
1081 ppdcChoice * // O - Choice data
get_generic(ppdcFile * fp,const char * keyword,const char * tattr,const char * nattr)1082 ppdcSource::get_generic(ppdcFile *fp, // I - File to read
1083 const char *keyword,
1084 // I - Keyword name
1085 const char *tattr,
1086 // I - Text attribute
1087 const char *nattr)
1088 // I - Numeric attribute
1089 {
1090 char name[1024], // Name
1091 *text, // Text
1092 command[256]; // Command string
1093 int val; // Numeric value
1094
1095
1096 // Read one of the following parameters:
1097 //
1098 // Foo name/text
1099 // Foo integer name/text
1100 if (nattr)
1101 val = get_integer(fp);
1102 else
1103 val = 0;
1104
1105 if (!get_token(fp, name, sizeof(name)))
1106 {
1107 _cupsLangPrintf(stderr,
1108 _("ppdc: Expected name/text after %s on line %d of %s."),
1109 keyword, fp->line, fp->filename);
1110 return (NULL);
1111 }
1112
1113 if ((text = strchr(name, '/')) != NULL)
1114 *text++ = '\0';
1115 else
1116 text = name;
1117
1118 if (nattr)
1119 {
1120 if (tattr)
1121 snprintf(command, sizeof(command),
1122 "<</%s(%s)/%s %d>>setpagedevice",
1123 tattr, name, nattr, val);
1124 else
1125 snprintf(command, sizeof(command),
1126 "<</%s %d>>setpagedevice",
1127 nattr, val);
1128 }
1129 else
1130 snprintf(command, sizeof(command),
1131 "<</%s(%s)>>setpagedevice",
1132 tattr, name);
1133
1134 return (new ppdcChoice(name, text, command));
1135 }
1136
1137
1138 //
1139 // 'ppdcSource::get_group()' - Get an option group.
1140 //
1141
1142 ppdcGroup * // O - Group
get_group(ppdcFile * fp,ppdcDriver * d)1143 ppdcSource::get_group(ppdcFile *fp, // I - File to read
1144 ppdcDriver *d) // I - Printer driver
1145 {
1146 char name[1024], // UI name
1147 *text; // UI text
1148 ppdcGroup *g; // Group
1149
1150
1151 // Read the Group parameters:
1152 //
1153 // Group name/text
1154 if (!get_token(fp, name, sizeof(name)))
1155 {
1156 _cupsLangPrintf(stderr,
1157 _("ppdc: Expected group name/text on line %d of %s."),
1158 fp->line, fp->filename);
1159 return (NULL);
1160 }
1161
1162 if ((text = strchr(name, '/')) != NULL)
1163 *text++ = '\0';
1164 else
1165 text = name;
1166
1167 // See if the group already exists...
1168 if ((g = d->find_group(name)) == NULL)
1169 {
1170 // Nope, add a new one...
1171 g = new ppdcGroup(name, text);
1172 }
1173
1174 return (g);
1175 }
1176
1177
1178 //
1179 // 'ppdcSource::get_installable()' - Get an installable option.
1180 //
1181
1182 ppdcOption * // O - Option
get_installable(ppdcFile * fp)1183 ppdcSource::get_installable(ppdcFile *fp)
1184 // I - File to read
1185 {
1186 char name[1024], // Name for installable option
1187 *text; // Text for installable option
1188 ppdcOption *o; // Option
1189
1190
1191 // Read the parameter for an installable option:
1192 //
1193 // Installable name/text
1194 if (!get_token(fp, name, sizeof(name)))
1195 {
1196 _cupsLangPrintf(stderr,
1197 _("ppdc: Expected name/text after Installable on line %d "
1198 "of %s."), fp->line, fp->filename);
1199 return (NULL);
1200 }
1201
1202 if ((text = strchr(name, '/')) != NULL)
1203 *text++ = '\0';
1204 else
1205 text = name;
1206
1207 // Create the option...
1208 o = new ppdcOption(PPDC_BOOLEAN, name, text, PPDC_SECTION_ANY, 10.0f);
1209
1210 // Add the false and true choices...
1211 o->add_choice(new ppdcChoice("False", "Not Installed", ""));
1212 o->add_choice(new ppdcChoice("True", "Installed", ""));
1213
1214 return (o);
1215 }
1216
1217
1218 //
1219 // 'ppdcSource::get_integer()' - Get an integer value from a string.
1220 //
1221
1222 #define PPDC_XX -1 // Bad
1223 #define PPDC_EQ 0 // ==
1224 #define PPDC_NE 1 // !=
1225 #define PPDC_LT 2 // <
1226 #define PPDC_LE 3 // <=
1227 #define PPDC_GT 4 // >
1228 #define PPDC_GE 5 // >=
1229
1230 int // O - Integer value
get_integer(const char * v)1231 ppdcSource::get_integer(const char *v) // I - Value string
1232 {
1233 long val; // Value
1234 long temp, // Temporary value
1235 temp2; // Second temporary value
1236 char *newv, // New value string pointer
1237 ch; // Temporary character
1238 ppdcVariable *var; // #define variable
1239 int compop; // Comparison operator
1240
1241
1242 // Parse the value string...
1243 if (!v)
1244 return (-1);
1245
1246 if (isdigit(*v & 255) || *v == '-' || *v == '+')
1247 {
1248 // Return a simple integer value
1249 val = strtol(v, (char **)&v, 0);
1250 if (*v || val == LONG_MIN)
1251 return (-1);
1252 else
1253 return ((int)val);
1254 }
1255 else if (*v == '(')
1256 {
1257 // Evaluate and expression in any of the following formats:
1258 //
1259 // (number number ... number) Bitwise OR of all numbers
1260 // (NAME == value) 1 if equal, 0 otherwise
1261 // (NAME != value) 1 if not equal, 0 otherwise
1262 // (NAME < value) 1 if less than, 0 otherwise
1263 // (NAME <= value) 1 if less than or equal, 0 otherwise
1264 // (NAME > value) 1 if greater than, 0 otherwise
1265 // (NAME >= value) 1 if greater than or equal, 0 otherwise
1266
1267 v ++;
1268 val = 0;
1269
1270 while (*v && *v != ')')
1271 {
1272 // Skip leading whitespace...
1273 while (*v && isspace(*v & 255))
1274 v ++;
1275
1276 if (!*v || *v == ')')
1277 break;
1278
1279 if (isdigit(*v & 255) || *v == '-' || *v == '+')
1280 {
1281 // Bitwise OR a number...
1282 temp = strtol(v, &newv, 0);
1283
1284 if (!*newv || newv == v || !(isspace(*newv) || *newv == ')') ||
1285 temp == LONG_MIN)
1286 return (-1);
1287 }
1288 else
1289 {
1290 // NAME logicop value
1291 for (newv = (char *)v + 1;
1292 *newv && (isalnum(*newv & 255) || *newv == '_');
1293 newv ++)
1294 /* do nothing */;
1295
1296 ch = *newv;
1297 *newv = '\0';
1298
1299 if ((var = find_variable(v)) != NULL)
1300 {
1301 if (!var->value || !var->value->value || !var->value->value[0])
1302 temp = 0;
1303 else if (isdigit(var->value->value[0] & 255) ||
1304 var->value->value[0] == '-' ||
1305 var->value->value[0] == '+')
1306 temp = strtol(var->value->value, NULL, 0);
1307 else
1308 temp = 1;
1309 }
1310 else
1311 temp = 0;
1312
1313 *newv = ch;
1314 while (isspace(*newv & 255))
1315 newv ++;
1316
1317 if (!strncmp(newv, "==", 2))
1318 {
1319 compop = PPDC_EQ;
1320 newv += 2;
1321 }
1322 else if (!strncmp(newv, "!=", 2))
1323 {
1324 compop = PPDC_NE;
1325 newv += 2;
1326 }
1327 else if (!strncmp(newv, "<=", 2))
1328 {
1329 compop = PPDC_LE;
1330 newv += 2;
1331 }
1332 else if (*newv == '<')
1333 {
1334 compop = PPDC_LT;
1335 newv ++;
1336 }
1337 else if (!strncmp(newv, ">=", 2))
1338 {
1339 compop = PPDC_GE;
1340 newv += 2;
1341 }
1342 else if (*newv == '>')
1343 {
1344 compop = PPDC_GT;
1345 newv ++;
1346 }
1347 else
1348 compop = PPDC_XX;
1349
1350 if (compop != PPDC_XX)
1351 {
1352 while (isspace(*newv & 255))
1353 newv ++;
1354
1355 if (*newv == ')' || !*newv)
1356 return (-1);
1357
1358 if (isdigit(*newv & 255) || *newv == '-' || *newv == '+')
1359 {
1360 // Get the second number...
1361 temp2 = strtol(newv, &newv, 0);
1362 if (!*newv || newv == v || !(isspace(*newv) || *newv == ')') ||
1363 temp == LONG_MIN)
1364 return (-1);
1365 }
1366 else
1367 {
1368 // Lookup the second name...
1369 for (v = newv, newv ++;
1370 *newv && (isalnum(*newv & 255) || *newv == '_');
1371 newv ++);
1372
1373 ch = *newv;
1374 *newv = '\0';
1375
1376 if ((var = find_variable(v)) != NULL)
1377 {
1378 if (!var->value || !var->value->value || !var->value->value[0])
1379 temp2 = 0;
1380 else if (isdigit(var->value->value[0] & 255) ||
1381 var->value->value[0] == '-' ||
1382 var->value->value[0] == '+')
1383 temp2 = strtol(var->value->value, NULL, 0);
1384 else
1385 temp2 = 1;
1386 }
1387 else
1388 temp2 = 0;
1389
1390 *newv = ch;
1391 }
1392
1393 // Do the comparison...
1394 switch (compop)
1395 {
1396 case PPDC_EQ :
1397 temp = temp == temp2;
1398 break;
1399 case PPDC_NE :
1400 temp = temp != temp2;
1401 break;
1402 case PPDC_LT :
1403 temp = temp < temp2;
1404 break;
1405 case PPDC_LE :
1406 temp = temp <= temp2;
1407 break;
1408 case PPDC_GT :
1409 temp = temp > temp2;
1410 break;
1411 case PPDC_GE :
1412 temp = temp >= temp2;
1413 break;
1414 }
1415 }
1416 }
1417
1418 val |= temp;
1419 v = newv;
1420 }
1421
1422 if (*v == ')' && !v[1])
1423 return ((int)val);
1424 else
1425 return (-1);
1426 }
1427 else if ((var = find_variable(v)) != NULL)
1428 {
1429 // NAME by itself returns 1 if the #define variable is not blank and
1430 // not "0"...
1431 return (var->value->value && var->value->value[0] &&
1432 strcmp(var->value->value, "0"));
1433 }
1434 else
1435 {
1436 // Anything else is an error...
1437 return (-1);
1438 }
1439 }
1440
1441
1442 //
1443 // 'ppdcSource::get_integer()' - Get an integer value from a file.
1444 //
1445
1446 int // O - Integer value
get_integer(ppdcFile * fp)1447 ppdcSource::get_integer(ppdcFile *fp) // I - File to read
1448 {
1449 char temp[1024]; // String buffer
1450
1451
1452 if (!get_token(fp, temp, sizeof(temp)))
1453 {
1454 _cupsLangPrintf(stderr, _("ppdc: Expected integer on line %d of %s."),
1455 fp->line, fp->filename);
1456 return (-1);
1457 }
1458 else
1459 return (get_integer(temp));
1460 }
1461
1462
1463 //
1464 // 'ppdcSource::get_measurement()' - Get a measurement value.
1465 //
1466
1467 float // O - Measurement value in points
get_measurement(ppdcFile * fp)1468 ppdcSource::get_measurement(ppdcFile *fp)
1469 // I - File to read
1470 {
1471 char buffer[256], // Number buffer
1472 *ptr; // Pointer into buffer
1473 float val; // Measurement value
1474
1475
1476 // Grab a token from the file...
1477 if (!get_token(fp, buffer, sizeof(buffer)))
1478 return (-1.0f);
1479
1480 // Get the floating point value of "s" and skip all digits and decimal points.
1481 val = (float)strtod(buffer, &ptr);
1482
1483 // Check for a trailing unit specifier...
1484 if (!_cups_strcasecmp(ptr, "mm"))
1485 val *= 72.0f / 25.4f;
1486 else if (!_cups_strcasecmp(ptr, "cm"))
1487 val *= 72.0f / 2.54f;
1488 else if (!_cups_strcasecmp(ptr, "m"))
1489 val *= 72.0f / 0.0254f;
1490 else if (!_cups_strcasecmp(ptr, "in"))
1491 val *= 72.0f;
1492 else if (!_cups_strcasecmp(ptr, "ft"))
1493 val *= 72.0f * 12.0f;
1494 else if (_cups_strcasecmp(ptr, "pt") && *ptr)
1495 return (-1.0f);
1496
1497 return (val);
1498 }
1499
1500
1501 //
1502 // 'ppdcSource::get_option()' - Get an option definition.
1503 //
1504
1505 ppdcOption * // O - Option
get_option(ppdcFile * fp,ppdcDriver * d,ppdcGroup * g)1506 ppdcSource::get_option(ppdcFile *fp, // I - File to read
1507 ppdcDriver *d, // I - Printer driver
1508 ppdcGroup *g) // I - Current group
1509 {
1510 char name[1024], // UI name
1511 *text, // UI text
1512 type[256]; // UI type string
1513 ppdcOptType ot; // Option type value
1514 ppdcOptSection section; // Option section
1515 float order; // Option order
1516 ppdcOption *o; // Option
1517 ppdcGroup *mg; // Matching group, if any
1518
1519
1520 // Read the Option parameters:
1521 //
1522 // Option name/text type section order
1523 if (!get_token(fp, name, sizeof(name)))
1524 {
1525 _cupsLangPrintf(stderr,
1526 _("ppdc: Expected option name/text on line %d of %s."),
1527 fp->line, fp->filename);
1528 return (NULL);
1529 }
1530
1531 if ((text = strchr(name, '/')) != NULL)
1532 *text++ = '\0';
1533 else
1534 text = name;
1535
1536 if (!get_token(fp, type, sizeof(type)))
1537 {
1538 _cupsLangPrintf(stderr, _("ppdc: Expected option type on line %d of %s."),
1539 fp->line, fp->filename);
1540 return (NULL);
1541 }
1542
1543 if (!_cups_strcasecmp(type, "boolean"))
1544 ot = PPDC_BOOLEAN;
1545 else if (!_cups_strcasecmp(type, "pickone"))
1546 ot = PPDC_PICKONE;
1547 else if (!_cups_strcasecmp(type, "pickmany"))
1548 ot = PPDC_PICKMANY;
1549 else
1550 {
1551 _cupsLangPrintf(stderr,
1552 _("ppdc: Invalid option type \"%s\" on line %d of %s."),
1553 type, fp->line, fp->filename);
1554 return (NULL);
1555 }
1556
1557 if (!get_token(fp, type, sizeof(type)))
1558 {
1559 _cupsLangPrintf(stderr,
1560 _("ppdc: Expected option section on line %d of %s."),
1561 fp->line, fp->filename);
1562 return (NULL);
1563 }
1564
1565 if (!_cups_strcasecmp(type, "AnySetup"))
1566 section = PPDC_SECTION_ANY;
1567 else if (!_cups_strcasecmp(type, "DocumentSetup"))
1568 section = PPDC_SECTION_DOCUMENT;
1569 else if (!_cups_strcasecmp(type, "ExitServer"))
1570 section = PPDC_SECTION_EXIT;
1571 else if (!_cups_strcasecmp(type, "JCLSetup"))
1572 section = PPDC_SECTION_JCL;
1573 else if (!_cups_strcasecmp(type, "PageSetup"))
1574 section = PPDC_SECTION_PAGE;
1575 else if (!_cups_strcasecmp(type, "Prolog"))
1576 section = PPDC_SECTION_PROLOG;
1577 else
1578 {
1579 _cupsLangPrintf(stderr,
1580 _("ppdc: Invalid option section \"%s\" on line %d of "
1581 "%s."), type, fp->line, fp->filename);
1582 return (NULL);
1583 }
1584
1585 order = get_float(fp);
1586
1587 // See if the option already exists...
1588 if ((o = d->find_option_group(name, &mg)) == NULL)
1589 {
1590 // Nope, add a new one...
1591 o = new ppdcOption(ot, name, text, section, order);
1592 }
1593 else if (o->type != ot)
1594 {
1595 _cupsLangPrintf(stderr,
1596 _("ppdc: Option %s redefined with a different type on line "
1597 "%d of %s."), name, fp->line, fp->filename);
1598 return (NULL);
1599 }
1600 else if (g != mg)
1601 {
1602 _cupsLangPrintf(stderr,
1603 _("ppdc: Option %s defined in two different groups on line "
1604 "%d of %s."), name, fp->line, fp->filename);
1605 return (NULL);
1606 }
1607
1608 return (o);
1609 }
1610
1611
1612 //
1613 // 'ppdcSource::get_po()' - Get a message catalog.
1614 //
1615
1616 ppdcCatalog * // O - Message catalog
get_po(ppdcFile * fp)1617 ppdcSource::get_po(ppdcFile *fp) // I - File to read
1618 {
1619 char locale[32], // Locale name
1620 poname[1024], // Message catalog filename
1621 basedir[1024], // Base directory
1622 *baseptr, // Pointer into directory
1623 pofilename[1024]; // Full filename of message catalog
1624 ppdcCatalog *cat; // Message catalog
1625
1626
1627 // Read the #po parameters:
1628 //
1629 // #po locale "filename.po"
1630 if (!get_token(fp, locale, sizeof(locale)))
1631 {
1632 _cupsLangPrintf(stderr,
1633 _("ppdc: Expected locale after #po on line %d of %s."),
1634 fp->line, fp->filename);
1635 return (NULL);
1636 }
1637
1638 if (!get_token(fp, poname, sizeof(poname)))
1639 {
1640 _cupsLangPrintf(stderr,
1641 _("ppdc: Expected filename after #po %s on line %d of "
1642 "%s."), locale, fp->line, fp->filename);
1643 return (NULL);
1644 }
1645
1646 // See if the locale is already loaded...
1647 if (find_po(locale))
1648 {
1649 _cupsLangPrintf(stderr,
1650 _("ppdc: Duplicate #po for locale %s on line %d of %s."),
1651 locale, fp->line, fp->filename);
1652 return (NULL);
1653 }
1654
1655 // Figure out the current directory...
1656 strlcpy(basedir, fp->filename, sizeof(basedir));
1657
1658 if ((baseptr = strrchr(basedir, '/')) != NULL)
1659 *baseptr = '\0';
1660 else
1661 strlcpy(basedir, ".", sizeof(basedir));
1662
1663 // Find the po file...
1664 pofilename[0] = '\0';
1665
1666 if (!poname[0] ||
1667 find_include(poname, basedir, pofilename, sizeof(pofilename)))
1668 {
1669 // Found it, so load it...
1670 cat = new ppdcCatalog(locale, pofilename);
1671
1672 // Reset the filename to the name supplied by the user...
1673 cat->filename->release();
1674 cat->filename = new ppdcString(poname);
1675
1676 // Return the catalog...
1677 return (cat);
1678 }
1679 else
1680 {
1681 _cupsLangPrintf(stderr,
1682 _("ppdc: Unable to find #po file %s on line %d of %s."),
1683 poname, fp->line, fp->filename);
1684 return (NULL);
1685 }
1686 }
1687
1688
1689 //
1690 // 'ppdcSource::get_resolution()' - Get an old-style resolution option.
1691 //
1692
1693 ppdcChoice * // O - Choice data
get_resolution(ppdcFile * fp)1694 ppdcSource::get_resolution(ppdcFile *fp)// I - File to read
1695 {
1696 char name[1024], // Name
1697 *text, // Text
1698 temp[256], // Temporary string
1699 command[256], // Command string
1700 *commptr; // Pointer into command
1701 int xdpi, ydpi, // X + Y resolution
1702 color_order, // Color order
1703 color_space, // Colorspace
1704 compression, // Compression mode
1705 depth, // Bits per color
1706 row_count, // Row count
1707 row_feed, // Row feed
1708 row_step; // Row step/interval
1709
1710
1711 // Read the resolution parameters:
1712 //
1713 // Resolution colorspace bits row-count row-feed row-step name/text
1714 if (!get_token(fp, temp, sizeof(temp)))
1715 {
1716 _cupsLangPrintf(stderr,
1717 _("ppdc: Expected override field after Resolution on line "
1718 "%d of %s."), fp->line, fp->filename);
1719 return (NULL);
1720 }
1721
1722 color_order = get_color_order(temp);
1723 color_space = get_color_space(temp);
1724 compression = get_integer(temp);
1725
1726 depth = get_integer(fp);
1727 row_count = get_integer(fp);
1728 row_feed = get_integer(fp);
1729 row_step = get_integer(fp);
1730
1731 if (!get_token(fp, name, sizeof(name)))
1732 {
1733 _cupsLangPrintf(stderr,
1734 _("ppdc: Expected name/text after Resolution on line %d of "
1735 "%s."), fp->line, fp->filename);
1736 return (NULL);
1737 }
1738
1739 if ((text = strchr(name, '/')) != NULL)
1740 *text++ = '\0';
1741 else
1742 text = name;
1743
1744 switch (sscanf(name, "%dx%d", &xdpi, &ydpi))
1745 {
1746 case 1 :
1747 ydpi = xdpi;
1748 break;
1749 case 2 :
1750 break;
1751 default :
1752 _cupsLangPrintf(stderr,
1753 _("ppdc: Bad resolution name \"%s\" on line %d of "
1754 "%s."), name, fp->line, fp->filename);
1755 break;
1756 }
1757
1758 // Create the necessary PS commands...
1759 snprintf(command, sizeof(command),
1760 "<</HWResolution[%d %d]/cupsBitsPerColor %d/cupsRowCount %d"
1761 "/cupsRowFeed %d/cupsRowStep %d",
1762 xdpi, ydpi, depth, row_count, row_feed, row_step);
1763 commptr = command + strlen(command);
1764
1765 if (color_order >= 0)
1766 {
1767 snprintf(commptr, sizeof(command) - (size_t)(commptr - command),
1768 "/cupsColorOrder %d", color_order);
1769 commptr += strlen(commptr);
1770 }
1771
1772 if (color_space >= 0)
1773 {
1774 snprintf(commptr, sizeof(command) - (size_t)(commptr - command),
1775 "/cupsColorSpace %d", color_space);
1776 commptr += strlen(commptr);
1777 }
1778
1779 if (compression >= 0)
1780 {
1781 snprintf(commptr, sizeof(command) - (size_t)(commptr - command),
1782 "/cupsCompression %d", compression);
1783 commptr += strlen(commptr);
1784 }
1785
1786 snprintf(commptr, sizeof(command) - (size_t)(commptr - command), ">>setpagedevice");
1787
1788 // Return the new choice...
1789 return (new ppdcChoice(name, text, command));
1790 }
1791
1792
1793 //
1794 // 'ppdcSource::get_simple_profile()' - Get a simple color profile definition.
1795 //
1796
1797 ppdcProfile * // O - Color profile
get_simple_profile(ppdcFile * fp)1798 ppdcSource::get_simple_profile(ppdcFile *fp)
1799 // I - File to read
1800 {
1801 char resolution[1024], // Resolution/media type
1802 *media_type; // Media type
1803 float m[9]; // Transform matrix
1804 float kd, rd, g; // Densities and gamma
1805 float red, green, blue; // RGB adjustments
1806 float yellow; // Yellow density
1807 float color; // Color density values
1808
1809
1810 // Get the SimpleColorProfile parameters:
1811 //
1812 // SimpleColorProfile resolution/mediatype black-density yellow-density
1813 // red-density gamma red-adjust green-adjust blue-adjust
1814 if (!get_token(fp, resolution, sizeof(resolution)))
1815 {
1816 _cupsLangPrintf(stderr,
1817 _("ppdc: Expected resolution/mediatype following "
1818 "SimpleColorProfile on line %d of %s."),
1819 fp->line, fp->filename);
1820 return (NULL);
1821 }
1822
1823 if ((media_type = strchr(resolution, '/')) != NULL)
1824 *media_type++ = '\0';
1825 else
1826 media_type = resolution;
1827
1828 // Collect the profile parameters...
1829 kd = get_float(fp);
1830 yellow = get_float(fp);
1831 rd = get_float(fp);
1832 g = get_float(fp);
1833 red = get_float(fp);
1834 green = get_float(fp);
1835 blue = get_float(fp);
1836
1837 // Build the color profile...
1838 color = 0.5f * rd / kd - kd;
1839 m[0] = 1.0f; // C
1840 m[1] = color + blue; // C + M (blue)
1841 m[2] = color - green; // C + Y (green)
1842 m[3] = color - blue; // M + C (blue)
1843 m[4] = 1.0f; // M
1844 m[5] = color + red; // M + Y (red)
1845 m[6] = yellow * (color + green); // Y + C (green)
1846 m[7] = yellow * (color - red); // Y + M (red)
1847 m[8] = yellow; // Y
1848
1849 if (m[1] > 0.0f)
1850 {
1851 m[3] -= m[1];
1852 m[1] = 0.0f;
1853 }
1854 else if (m[3] > 0.0f)
1855 {
1856 m[1] -= m[3];
1857 m[3] = 0.0f;
1858 }
1859
1860 if (m[2] > 0.0f)
1861 {
1862 m[6] -= m[2];
1863 m[2] = 0.0f;
1864 }
1865 else if (m[6] > 0.0f)
1866 {
1867 m[2] -= m[6];
1868 m[6] = 0.0f;
1869 }
1870
1871 if (m[5] > 0.0f)
1872 {
1873 m[7] -= m[5];
1874 m[5] = 0.0f;
1875 }
1876 else if (m[7] > 0.0f)
1877 {
1878 m[5] -= m[7];
1879 m[7] = 0.0f;
1880 }
1881
1882 // Return the new profile...
1883 return (new ppdcProfile(resolution, media_type, g, kd, m));
1884 }
1885
1886
1887 //
1888 // 'ppdcSource::get_size()' - Get a media size definition from a file.
1889 //
1890
1891 ppdcMediaSize * // O - Media size
get_size(ppdcFile * fp)1892 ppdcSource::get_size(ppdcFile *fp) // I - File to read
1893 {
1894 char name[1024], // Name
1895 *text; // Text
1896 float width, // Width
1897 length; // Length
1898
1899
1900 // Get the name, text, width, and length:
1901 //
1902 // #media name/text width length
1903 if (!get_token(fp, name, sizeof(name)))
1904 return (NULL);
1905
1906 if ((text = strchr(name, '/')) != NULL)
1907 *text++ = '\0';
1908 else
1909 text = name;
1910
1911 if ((width = get_measurement(fp)) < 0.0f)
1912 return (NULL);
1913
1914 if ((length = get_measurement(fp)) < 0.0f)
1915 return (NULL);
1916
1917 // Return the new media size...
1918 return (new ppdcMediaSize(name, text, width, length, 0.0f, 0.0f, 0.0f, 0.0f));
1919 }
1920
1921
1922 //
1923 // 'ppdcSource::get_token()' - Get a token from a file.
1924 //
1925
1926 char * // O - Token string or NULL
get_token(ppdcFile * fp,char * buffer,int buflen)1927 ppdcSource::get_token(ppdcFile *fp, // I - File to read
1928 char *buffer, // I - Buffer
1929 int buflen) // I - Length of buffer
1930 {
1931 char *bufptr, // Pointer into string buffer
1932 *bufend; // End of string buffer
1933 int ch, // Character from file
1934 nextch, // Next char in file
1935 quote, // Quote character used...
1936 empty, // Empty input?
1937 startline; // Start line for quote
1938 char name[256], // Name string
1939 *nameptr; // Name pointer
1940 ppdcVariable *var; // Variable pointer
1941
1942
1943 // Mark the beginning and end of the buffer...
1944 bufptr = buffer;
1945 bufend = buffer + buflen - 1;
1946
1947 // Loop intil we've read a token...
1948 quote = 0;
1949 startline = 0;
1950 empty = 1;
1951
1952 while ((ch = fp->get()) != EOF)
1953 {
1954 if (isspace(ch) && !quote)
1955 {
1956 if (empty)
1957 continue;
1958 else
1959 break;
1960 }
1961 else if (ch == '$')
1962 {
1963 // Variable substitution
1964 empty = 0;
1965
1966 for (nameptr = name; (ch = fp->peek()) != EOF;)
1967 {
1968 if (!isalnum(ch) && ch != '_')
1969 break;
1970 else if (nameptr < (name + sizeof(name) - 1))
1971 *nameptr++ = (char)fp->get();
1972 }
1973
1974 if (nameptr == name)
1975 {
1976 // Just substitute this character...
1977 if (ch == '$')
1978 {
1979 // $$ = $
1980 if (bufptr < bufend)
1981 *bufptr++ = (char)fp->get();
1982 }
1983 else
1984 {
1985 // $ch = $ch
1986 _cupsLangPrintf(stderr,
1987 _("ppdc: Bad variable substitution ($%c) on line %d "
1988 "of %s."), ch, fp->line, fp->filename);
1989
1990 if (bufptr < bufend)
1991 *bufptr++ = '$';
1992 }
1993 }
1994 else
1995 {
1996 // Substitute the variable value...
1997 *nameptr = '\0';
1998 var = find_variable(name);
1999 if (var)
2000 {
2001 strlcpy(bufptr, var->value->value, (size_t)(bufend - bufptr + 1));
2002 bufptr += strlen(bufptr);
2003 }
2004 else
2005 {
2006 if (!(cond_state & PPDC_COND_SKIP))
2007 _cupsLangPrintf(stderr,
2008 _("ppdc: Undefined variable (%s) on line %d of "
2009 "%s."), name, fp->line, fp->filename);
2010
2011 snprintf(bufptr, (size_t)(bufend - bufptr + 1), "$%s", name);
2012 bufptr += strlen(bufptr);
2013 }
2014 }
2015 }
2016 else if (ch == '/' && !quote)
2017 {
2018 // Possibly a comment...
2019 nextch = fp->peek();
2020
2021 if (nextch == '*')
2022 {
2023 // C comment...
2024 fp->get();
2025 ch = fp->get();
2026 while ((nextch = fp->get()) != EOF)
2027 {
2028 if (ch == '*' && nextch == '/')
2029 break;
2030
2031 ch = nextch;
2032 }
2033
2034 if (nextch == EOF)
2035 break;
2036 }
2037 else if (nextch == '/')
2038 {
2039 // C++ comment...
2040 while ((nextch = fp->get()) != EOF)
2041 if (nextch == '\n')
2042 break;
2043
2044 if (nextch == EOF)
2045 break;
2046 }
2047 else
2048 {
2049 // Not a comment...
2050 empty = 0;
2051
2052 if (bufptr < bufend)
2053 *bufptr++ = (char)ch;
2054 }
2055 }
2056 else if (ch == '\'' || ch == '\"')
2057 {
2058 empty = 0;
2059
2060 if (quote == ch)
2061 {
2062 // Ending the current quoted string...
2063 quote = 0;
2064 }
2065 else if (quote)
2066 {
2067 // Insert the opposing quote char...
2068 if (bufptr < bufend)
2069 *bufptr++ = (char)ch;
2070 }
2071 else
2072 {
2073 // Start a new quoted string...
2074 startline = fp->line;
2075 quote = ch;
2076 }
2077 }
2078 else if ((ch == '(' || ch == '<') && !quote)
2079 {
2080 empty = 0;
2081 quote = ch;
2082 startline = fp->line;
2083
2084 if (bufptr < bufend)
2085 *bufptr++ = (char)ch;
2086 }
2087 else if ((ch == ')' && quote == '(') || (ch == '>' && quote == '<'))
2088 {
2089 quote = 0;
2090
2091 if (bufptr < bufend)
2092 *bufptr++ = (char)ch;
2093 }
2094 else if (ch == '\\')
2095 {
2096 empty = 0;
2097
2098 if ((ch = fp->get()) == EOF)
2099 break;
2100
2101 if (bufptr < bufend)
2102 *bufptr++ = (char)ch;
2103 }
2104 else if (bufptr < bufend)
2105 {
2106 empty = 0;
2107
2108 *bufptr++ = (char)ch;
2109
2110 if ((ch == '{' || ch == '}') && !quote)
2111 break;
2112 }
2113 }
2114
2115 if (quote)
2116 {
2117 _cupsLangPrintf(stderr,
2118 _("ppdc: Unterminated string starting with %c on line %d "
2119 "of %s."), quote, startline, fp->filename);
2120 return (NULL);
2121 }
2122
2123 if (empty)
2124 return (NULL);
2125 else
2126 {
2127 *bufptr = '\0';
2128 return (buffer);
2129 }
2130 }
2131
2132
2133 //
2134 // 'ppdcSource::get_variable()' - Get a variable definition.
2135 //
2136
2137 ppdcVariable * // O - Variable
get_variable(ppdcFile * fp)2138 ppdcSource::get_variable(ppdcFile *fp) // I - File to read
2139 {
2140 char name[1024], // Name
2141 value[1024]; // Value
2142
2143
2144 // Get the name and value:
2145 //
2146 // #define name value
2147 if (!get_token(fp, name, sizeof(name)))
2148 return (NULL);
2149
2150 if (!get_token(fp, value, sizeof(value)))
2151 return (NULL);
2152
2153 // Set the variable...
2154 return (set_variable(name, value));
2155 }
2156
2157
2158 //
2159 // 'ppdcSource::quotef()' - Write a formatted, quoted string...
2160 //
2161
2162 int // O - Number bytes on success, -1 on failure
quotef(cups_file_t * fp,const char * format,...)2163 ppdcSource::quotef(cups_file_t *fp, // I - File to write to
2164 const char *format, // I - Printf-style format string
2165 ...) // I - Additional args as needed
2166 {
2167 va_list ap; // Pointer to additional arguments
2168 int bytes; // Bytes written
2169 char sign, // Sign of format width
2170 size, // Size character (h, l, L)
2171 type; // Format type character
2172 const char *bufformat; // Start of format
2173 int width, // Width of field
2174 prec; // Number of characters of precision
2175 char tformat[100]; // Temporary format string for fprintf()
2176 char *s; // Pointer to string
2177 int slen; // Length of string
2178 int i; // Looping var
2179
2180
2181 // Range check input...
2182 if (!fp || !format)
2183 return (-1);
2184
2185 // Loop through the format string, formatting as needed...
2186 va_start(ap, format);
2187
2188 bytes = 0;
2189
2190 while (*format)
2191 {
2192 if (*format == '%')
2193 {
2194 bufformat = format;
2195 format ++;
2196
2197 if (*format == '%')
2198 {
2199 cupsFilePutChar(fp, *format++);
2200 bytes ++;
2201 continue;
2202 }
2203 else if (strchr(" -+#\'", *format))
2204 sign = *format++;
2205 else
2206 sign = 0;
2207
2208 width = 0;
2209 while (isdigit(*format))
2210 width = width * 10 + *format++ - '0';
2211
2212 if (*format == '.')
2213 {
2214 format ++;
2215 prec = 0;
2216
2217 while (isdigit(*format))
2218 prec = prec * 10 + *format++ - '0';
2219 }
2220 else
2221 prec = -1;
2222
2223 if (*format == 'l' && format[1] == 'l')
2224 {
2225 size = 'L';
2226 format += 2;
2227 }
2228 else if (*format == 'h' || *format == 'l' || *format == 'L')
2229 size = *format++;
2230 else
2231 size = '\0';
2232
2233 if (!*format)
2234 break;
2235
2236 type = *format++;
2237
2238 switch (type)
2239 {
2240 case 'E' : // Floating point formats
2241 case 'G' :
2242 case 'e' :
2243 case 'f' :
2244 case 'g' :
2245 if ((format - bufformat + 1) > (int)sizeof(tformat))
2246 break;
2247
2248 memcpy(tformat, bufformat, (size_t)(format - bufformat));
2249 tformat[format - bufformat] = '\0';
2250
2251 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, double));
2252 break;
2253
2254 case 'B' : // Integer formats
2255 case 'X' :
2256 case 'b' :
2257 case 'd' :
2258 case 'i' :
2259 case 'o' :
2260 case 'u' :
2261 case 'x' :
2262 if ((format - bufformat + 1) > (int)sizeof(tformat))
2263 break;
2264
2265 memcpy(tformat, bufformat, (size_t)(format - bufformat));
2266 tformat[format - bufformat] = '\0';
2267
2268 # ifdef HAVE_LONG_LONG
2269 if (size == 'L')
2270 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, long long));
2271 else
2272 # endif /* HAVE_LONG_LONG */
2273 if (size == 'l')
2274 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, long));
2275 else
2276 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, int));
2277 break;
2278
2279 case 'p' : // Pointer value
2280 if ((format - bufformat + 1) > (int)sizeof(tformat))
2281 break;
2282
2283 memcpy(tformat, bufformat, (size_t)(format - bufformat));
2284 tformat[format - bufformat] = '\0';
2285
2286 bytes += cupsFilePrintf(fp, tformat, va_arg(ap, void *));
2287 break;
2288
2289 case 'c' : // Character or character array
2290 if (width <= 1)
2291 {
2292 bytes ++;
2293 cupsFilePutChar(fp, va_arg(ap, int));
2294 }
2295 else
2296 {
2297 cupsFileWrite(fp, va_arg(ap, char *), (size_t)width);
2298 bytes += width;
2299 }
2300 break;
2301
2302 case 's' : // String
2303 if ((s = va_arg(ap, char *)) == NULL)
2304 s = (char *)"(nil)";
2305
2306 slen = (int)strlen(s);
2307 if (slen > width && prec != width)
2308 width = slen;
2309
2310 if (slen > width)
2311 slen = width;
2312
2313 if (sign != '-')
2314 {
2315 for (i = width - slen; i > 0; i --, bytes ++)
2316 cupsFilePutChar(fp, ' ');
2317 }
2318
2319 for (i = slen; i > 0; i --, s ++, bytes ++)
2320 {
2321 if (*s == '\\' || *s == '\"')
2322 {
2323 cupsFilePutChar(fp, '\\');
2324 bytes ++;
2325 }
2326
2327 cupsFilePutChar(fp, *s);
2328 }
2329
2330 if (sign == '-')
2331 {
2332 for (i = width - slen; i > 0; i --, bytes ++)
2333 cupsFilePutChar(fp, ' ');
2334 }
2335 break;
2336 }
2337 }
2338 else
2339 {
2340 cupsFilePutChar(fp, *format++);
2341 bytes ++;
2342 }
2343 }
2344
2345 va_end(ap);
2346
2347 // Return the number of characters written.
2348 return (bytes);
2349 }
2350
2351
2352 //
2353 // 'ppdcSource::read_file()' - Read a driver source file.
2354 //
2355
2356 void
read_file(const char * f,cups_file_t * ffp)2357 ppdcSource::read_file(const char *f, // I - File to read
2358 cups_file_t *ffp) // I - File pointer to use
2359 {
2360 ppdcFile *fp = new ppdcFile(f, ffp);
2361 scan_file(fp);
2362 delete fp;
2363
2364 if (cond_current != cond_stack)
2365 _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"."), f);
2366 }
2367
2368
2369 //
2370 // 'ppdcSource::scan_file()' - Scan a driver source file.
2371 //
2372
2373 void
scan_file(ppdcFile * fp,ppdcDriver * td,bool inc)2374 ppdcSource::scan_file(ppdcFile *fp, // I - File to read
2375 ppdcDriver *td, // I - Driver template
2376 bool inc) // I - Including?
2377 {
2378 ppdcDriver *d; // Current driver
2379 ppdcGroup *g, // Current group
2380 *mg, // Matching group
2381 *general, // General options group
2382 *install; // Installable options group
2383 ppdcOption *o; // Current option
2384 ppdcChoice *c; // Current choice
2385 char temp[256], // Token from file...
2386 *ptr; // Pointer into token
2387 int isdefault; // Default option?
2388
2389
2390 // Initialize things as needed...
2391 if (inc && td)
2392 {
2393 d = td;
2394 d->retain();
2395 }
2396 else
2397 d = new ppdcDriver(td);
2398
2399 if ((general = d->find_group("General")) == NULL)
2400 {
2401 general = new ppdcGroup("General", NULL);
2402 d->add_group(general);
2403 }
2404
2405 if ((install = d->find_group("InstallableOptions")) == NULL)
2406 {
2407 install = new ppdcGroup("InstallableOptions", "Installable Options");
2408 d->add_group(install);
2409 }
2410
2411 // Loop until EOF or }
2412 o = 0;
2413 g = general;
2414
2415 while (get_token(fp, temp, sizeof(temp)))
2416 {
2417 if (temp[0] == '*')
2418 {
2419 // Mark the next choice as the default
2420 isdefault = 1;
2421
2422 for (ptr = temp; ptr[1]; ptr ++)
2423 *ptr = ptr[1];
2424
2425 *ptr = '\0';
2426 }
2427 else
2428 {
2429 // Don't mark the next choice as the default
2430 isdefault = 0;
2431 }
2432
2433 if (!_cups_strcasecmp(temp, "}"))
2434 {
2435 // Close this one out...
2436 break;
2437 }
2438 else if (!_cups_strcasecmp(temp, "{"))
2439 {
2440 // Open a new child...
2441 scan_file(fp, d);
2442 }
2443 else if (!_cups_strcasecmp(temp, "#if"))
2444 {
2445 if ((cond_current - cond_stack) >= 100)
2446 {
2447 _cupsLangPrintf(stderr,
2448 _("ppdc: Too many nested #if's on line %d of %s."),
2449 fp->line, fp->filename);
2450 break;
2451 }
2452
2453 cond_current ++;
2454 if (get_integer(fp) > 0)
2455 *cond_current = PPDC_COND_SATISFIED;
2456 else
2457 {
2458 *cond_current = PPDC_COND_SKIP;
2459 cond_state |= PPDC_COND_SKIP;
2460 }
2461 }
2462 else if (!_cups_strcasecmp(temp, "#elif"))
2463 {
2464 if (cond_current == cond_stack)
2465 {
2466 _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
2467 fp->line, fp->filename);
2468 break;
2469 }
2470
2471 if (*cond_current & PPDC_COND_SATISFIED)
2472 {
2473 get_integer(fp);
2474 *cond_current |= PPDC_COND_SKIP;
2475 }
2476 else if (get_integer(fp) > 0)
2477 {
2478 *cond_current |= PPDC_COND_SATISFIED;
2479 *cond_current &= ~PPDC_COND_SKIP;
2480 }
2481 else
2482 *cond_current |= PPDC_COND_SKIP;
2483
2484 // Update the current state
2485 int *cond_temp = cond_current; // Temporary stack pointer
2486
2487 cond_state = PPDC_COND_NORMAL;
2488 while (cond_temp > cond_stack)
2489 if (*cond_temp & PPDC_COND_SKIP)
2490 {
2491 cond_state = PPDC_COND_SKIP;
2492 break;
2493 }
2494 else
2495 cond_temp --;
2496 }
2497 else if (!_cups_strcasecmp(temp, "#else"))
2498 {
2499 if (cond_current == cond_stack)
2500 {
2501 _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
2502 fp->line, fp->filename);
2503 break;
2504 }
2505
2506 if (*cond_current & PPDC_COND_SATISFIED)
2507 *cond_current |= PPDC_COND_SKIP;
2508 else
2509 {
2510 *cond_current |= PPDC_COND_SATISFIED;
2511 *cond_current &= ~PPDC_COND_SKIP;
2512 }
2513
2514 // Update the current state
2515 int *cond_temp = cond_current; // Temporary stack pointer
2516
2517 cond_state = PPDC_COND_NORMAL;
2518 while (cond_temp > cond_stack)
2519 if (*cond_temp & PPDC_COND_SKIP)
2520 {
2521 cond_state = PPDC_COND_SKIP;
2522 break;
2523 }
2524 else
2525 cond_temp --;
2526 }
2527 else if (!_cups_strcasecmp(temp, "#endif"))
2528 {
2529 if (cond_current == cond_stack)
2530 {
2531 _cupsLangPrintf(stderr, _("ppdc: Missing #if on line %d of %s."),
2532 fp->line, fp->filename);
2533 break;
2534 }
2535
2536 cond_current --;
2537
2538 // Update the current state
2539 int *cond_temp = cond_current; // Temporary stack pointer
2540
2541 cond_state = PPDC_COND_NORMAL;
2542 while (cond_temp > cond_stack)
2543 if (*cond_temp & PPDC_COND_SKIP)
2544 {
2545 cond_state = PPDC_COND_SKIP;
2546 break;
2547 }
2548 else
2549 cond_temp --;
2550 }
2551 else if (!_cups_strcasecmp(temp, "#define"))
2552 {
2553 // Get the variable...
2554 get_variable(fp);
2555 }
2556 else if (!_cups_strcasecmp(temp, "#include"))
2557 {
2558 // #include filename
2559 char basedir[1024], // Base directory
2560 *baseptr, // Pointer into directory
2561 inctemp[1024], // Initial filename
2562 incname[1024]; // Include filename
2563 ppdcFile *incfile; // Include file
2564 int *old_current = cond_current;
2565 // Previous current stack
2566
2567
2568 // Get the include name...
2569 if (!get_token(fp, inctemp, sizeof(inctemp)))
2570 {
2571 _cupsLangPrintf(stderr,
2572 _("ppdc: Expected include filename on line %d of "
2573 "%s."), fp->line, fp->filename);
2574 break;
2575 }
2576
2577 if (cond_state)
2578 continue;
2579
2580 // Figure out the current directory...
2581 strlcpy(basedir, fp->filename, sizeof(basedir));
2582
2583 if ((baseptr = strrchr(basedir, '/')) != NULL)
2584 *baseptr = '\0';
2585 else
2586 strlcpy(basedir, ".", sizeof(basedir));
2587
2588 // Find the include file...
2589 if (find_include(inctemp, basedir, incname, sizeof(incname)))
2590 {
2591 // Open the include file, scan it, and then close it...
2592 incfile = new ppdcFile(incname);
2593 scan_file(incfile, d, true);
2594 delete incfile;
2595
2596 if (cond_current != old_current)
2597 _cupsLangPrintf(stderr, _("ppdc: Missing #endif at end of \"%s\"."),
2598 incname);
2599 }
2600 else
2601 {
2602 // Can't find it!
2603 _cupsLangPrintf(stderr,
2604 _("ppdc: Unable to find include file \"%s\" on line %d "
2605 "of %s."), inctemp, fp->line, fp->filename);
2606 break;
2607 }
2608 }
2609 else if (!_cups_strcasecmp(temp, "#media"))
2610 {
2611 ppdcMediaSize *m; // Media size
2612
2613
2614 // Get a media size...
2615 m = get_size(fp);
2616 if (m)
2617 {
2618 if (cond_state)
2619 m->release();
2620 else
2621 sizes->add(m);
2622 }
2623 }
2624 else if (!_cups_strcasecmp(temp, "#po"))
2625 {
2626 ppdcCatalog *cat; // Message catalog
2627
2628
2629 // Get a message catalog...
2630 cat = get_po(fp);
2631 if (cat)
2632 {
2633 if (cond_state)
2634 cat->release();
2635 else
2636 po_files->add(cat);
2637 }
2638 }
2639 else if (!_cups_strcasecmp(temp, "Attribute") ||
2640 !_cups_strcasecmp(temp, "LocAttribute"))
2641 {
2642 ppdcAttr *a; // Attribute
2643
2644
2645 // Get an attribute...
2646 a = get_attr(fp, !_cups_strcasecmp(temp, "LocAttribute"));
2647 if (a)
2648 {
2649 if (cond_state)
2650 a->release();
2651 else
2652 d->add_attr(a);
2653 }
2654 }
2655 else if (!_cups_strcasecmp(temp, "Choice"))
2656 {
2657 // Get a choice...
2658 c = get_choice(fp);
2659 if (!c)
2660 break;
2661
2662 if (cond_state)
2663 {
2664 c->release();
2665 continue;
2666 }
2667
2668 // Add it to the current option...
2669 if (!o)
2670 {
2671 c->release();
2672 _cupsLangPrintf(stderr,
2673 _("ppdc: Choice found on line %d of %s with no "
2674 "Option."), fp->line, fp->filename);
2675 break;
2676 }
2677
2678 o->add_choice(c);
2679
2680 if (isdefault)
2681 o->set_defchoice(c);
2682 }
2683 else if (!_cups_strcasecmp(temp, "ColorDevice"))
2684 {
2685 // ColorDevice boolean
2686 if (cond_state)
2687 get_boolean(fp);
2688 else
2689 d->color_device = get_boolean(fp);
2690 }
2691 else if (!_cups_strcasecmp(temp, "ColorModel"))
2692 {
2693 // Get the color model
2694 c = get_color_model(fp);
2695 if (!c)
2696 continue;
2697
2698 if (cond_state)
2699 {
2700 c->release();
2701 continue;
2702 }
2703
2704 // Add the choice to the ColorModel option...
2705 if ((o = d->find_option("ColorModel")) == NULL)
2706 {
2707 // Create the ColorModel option...
2708 o = new ppdcOption(PPDC_PICKONE, "ColorModel", "Color Mode", PPDC_SECTION_ANY, 10.0f);
2709 g = general;
2710 g->add_option(o);
2711 }
2712
2713 o->add_choice(c);
2714
2715 if (isdefault)
2716 o->set_defchoice(c);
2717
2718 o = NULL;
2719 }
2720 else if (!_cups_strcasecmp(temp, "ColorProfile"))
2721 {
2722 ppdcProfile *p; // Color profile
2723
2724
2725 // Get the color profile...
2726 p = get_color_profile(fp);
2727
2728 if (p)
2729 {
2730 if (cond_state)
2731 p->release();
2732 else
2733 d->profiles->add(p);
2734 }
2735 }
2736 else if (!_cups_strcasecmp(temp, "Copyright"))
2737 {
2738 // Copyright string
2739 char copytemp[8192], // Copyright string
2740 *copyptr, // Pointer into string
2741 *copyend; // Pointer to end of string
2742
2743
2744 // Get the copyright string...
2745 if (!get_token(fp, copytemp, sizeof(temp)))
2746 {
2747 _cupsLangPrintf(stderr,
2748 _("ppdc: Expected string after Copyright on line %d "
2749 "of %s."), fp->line, fp->filename);
2750 break;
2751 }
2752
2753 if (cond_state)
2754 continue;
2755
2756 // Break it up into individual lines...
2757 for (copyptr = copytemp; copyptr; copyptr = copyend)
2758 {
2759 if ((copyend = strchr(copyptr, '\n')) != NULL)
2760 *copyend++ = '\0';
2761
2762 d->copyright->add(new ppdcString(copyptr));
2763 }
2764 }
2765 else if (!_cups_strcasecmp(temp, "CustomMedia"))
2766 {
2767 ppdcMediaSize *m; // Media size
2768
2769
2770 // Get a custom media size...
2771 m = get_custom_size(fp);
2772
2773 if (cond_state)
2774 {
2775 m->release();
2776 continue;
2777 }
2778
2779 if (m)
2780 d->sizes->add(m);
2781
2782 if (isdefault)
2783 d->set_default_size(m);
2784 }
2785 else if (!_cups_strcasecmp(temp, "Cutter"))
2786 {
2787 // Cutter boolean
2788 int have_cutter; // Have a paper cutter?
2789
2790
2791 have_cutter = get_boolean(fp);
2792 if (have_cutter <= 0 || cond_state)
2793 continue;
2794
2795 if ((o = d->find_option("CutMedia")) == NULL)
2796 {
2797 o = new ppdcOption(PPDC_BOOLEAN, "CutMedia", "Cut Media", PPDC_SECTION_ANY, 10.0f);
2798
2799 g = general;
2800 g->add_option(o);
2801
2802 c = new ppdcChoice("False", NULL, "<</CutMedia 0>>setpagedevice");
2803 o->add_choice(c);
2804 o->set_defchoice(c);
2805
2806 c = new ppdcChoice("True", NULL, "<</CutMedia 4>>setpagedevice");
2807 o->add_choice(c);
2808 }
2809
2810 o = NULL;
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 stings...
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