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