]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
5a738aea | 2 | * "$Id: mark.c 7278 2008-01-31 01:23:09Z mike $" |
ef416fc2 | 3 | * |
4 | * Option marking routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
5a738aea | 6 | * Copyright 2007-2008 by Apple Inc. |
b86bc4cf | 7 | * Copyright 1997-2007 by Easy Software Products, all rights reserved. |
ef416fc2 | 8 | * |
9 | * These coded instructions, statements, and computer programs are the | |
bc44d920 | 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/". | |
ef416fc2 | 14 | * |
15 | * PostScript is a trademark of Adobe Systems, Inc. | |
16 | * | |
17 | * This file is subject to the Apple OS-Developed Software exception. | |
18 | * | |
19 | * Contents: | |
20 | * | |
5a738aea MS |
21 | * cupsMarkOptions() - Mark command-line options in a PPD file. |
22 | * ppdConflicts() - Check to see if there are any conflicts among the | |
23 | * marked option choices. | |
ef416fc2 | 24 | * ppdFindChoice() - Return a pointer to an option choice. |
25 | * ppdFindMarkedChoice() - Return the marked choice for the specified option. | |
26 | * ppdFindOption() - Return a pointer to the specified option. | |
5a738aea | 27 | * ppdIsMarked() - Check to see if an option is marked. |
ef416fc2 | 28 | * ppdMarkDefaults() - Mark all default options in the PPD file. |
29 | * ppdMarkOption() - Mark an option in a PPD file. | |
5a738aea MS |
30 | * ppdFirstOption() - Return the first option in the PPD file. |
31 | * ppdNextOption() - Return the next option in the PPD file. | |
32 | * debug_marked() - Output the marked array to stdout... | |
ef416fc2 | 33 | * ppd_defaults() - Set the defaults for this group and all sub-groups. |
5a738aea | 34 | * ppd_mark_choices() - Mark one or more option choices from a string. |
ef416fc2 | 35 | */ |
36 | ||
37 | /* | |
38 | * Include necessary headers... | |
39 | */ | |
40 | ||
b423cd4c | 41 | #include "cups.h" |
ef416fc2 | 42 | #include "string.h" |
43 | #include "debug.h" | |
44 | ||
45 | ||
46 | /* | |
47 | * Local functions... | |
48 | */ | |
49 | ||
5a738aea MS |
50 | #ifdef DEBUG |
51 | static void debug_marked(ppd_file_t *ppd, const char *title); | |
52 | #else | |
53 | # define debug_marked(ppd,title) | |
54 | #endif /* DEBUG */ | |
ef416fc2 | 55 | static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g); |
5a738aea | 56 | static int ppd_mark_choices(ppd_file_t *ppd, const char *options); |
ef416fc2 | 57 | |
58 | ||
59 | /* | |
5a738aea MS |
60 | * 'cupsMarkOptions()' - Mark command-line options in a PPD file. |
61 | * | |
62 | * This function maps the IPP "finishings", "media", "mirror", | |
63 | * "multiple-document-handling", "output-bin", "printer-resolution", and | |
64 | * "sides" attributes to their corresponding PPD options and choices. | |
65 | */ | |
66 | ||
67 | int /* O - 1 if conflicting */ | |
68 | cupsMarkOptions( | |
69 | ppd_file_t *ppd, /* I - PPD file */ | |
70 | int num_options, /* I - Number of options */ | |
71 | cups_option_t *options) /* I - Options */ | |
72 | { | |
73 | int i, j, k; /* Looping vars */ | |
74 | int conflict; /* Option conflicts */ | |
75 | char *val, /* Pointer into value */ | |
76 | *ptr, /* Pointer into string */ | |
77 | s[255]; /* Temporary string */ | |
78 | const char *page_size; /* PageSize option */ | |
79 | cups_option_t *optptr; /* Current option */ | |
80 | ppd_option_t *option; /* PPD option */ | |
81 | ppd_attr_t *attr; /* PPD attribute */ | |
82 | static const char * const duplex_options[] = | |
83 | { /* Duplex option names */ | |
84 | "Duplex", /* Adobe */ | |
85 | "EFDuplex", /* EFI */ | |
86 | "EFDuplexing", /* EFI */ | |
87 | "KD03Duplex", /* Kodak */ | |
88 | "JCLDuplex" /* Samsung */ | |
89 | }; | |
90 | static const char * const duplex_one[] = | |
91 | { /* one-sided names */ | |
92 | "None", | |
93 | "False" | |
94 | }; | |
95 | static const char * const duplex_two_long[] = | |
96 | { /* two-sided-long-edge names */ | |
97 | "DuplexNoTumble", /* Adobe */ | |
98 | "LongEdge", /* EFI */ | |
99 | "Top" /* EFI */ | |
100 | }; | |
101 | static const char * const duplex_two_short[] = | |
102 | { /* two-sided-long-edge names */ | |
103 | "DuplexTumble", /* Adobe */ | |
104 | "ShortEdge", /* EFI */ | |
105 | "Bottom" /* EFI */ | |
106 | }; | |
107 | ||
108 | ||
109 | /* | |
110 | * Check arguments... | |
111 | */ | |
112 | ||
113 | if (!ppd || num_options <= 0 || !options) | |
114 | return (0); | |
115 | ||
116 | debug_marked(ppd, "Before..."); | |
117 | ||
118 | /* | |
119 | * Mark options... | |
120 | */ | |
121 | ||
122 | conflict = 0; | |
123 | ||
124 | for (i = num_options, optptr = options; i > 0; i --, optptr ++) | |
125 | if (!strcasecmp(optptr->name, "media")) | |
126 | { | |
127 | /* | |
128 | * Loop through the option string, separating it at commas and | |
129 | * marking each individual option as long as the corresponding | |
130 | * PPD option (PageSize, InputSlot, etc.) is not also set. | |
131 | * | |
132 | * For PageSize, we also check for an empty option value since | |
133 | * some versions of MacOS X use it to specify auto-selection | |
134 | * of the media based solely on the size. | |
135 | */ | |
136 | ||
137 | page_size = cupsGetOption("PageSize", num_options, options); | |
138 | ||
139 | for (val = optptr->value; *val;) | |
140 | { | |
141 | /* | |
142 | * Extract the sub-option from the string... | |
143 | */ | |
144 | ||
145 | for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);) | |
146 | *ptr++ = *val++; | |
147 | *ptr++ = '\0'; | |
148 | ||
149 | if (*val == ',') | |
150 | val ++; | |
151 | ||
152 | /* | |
153 | * Mark it... | |
154 | */ | |
155 | ||
156 | if (!page_size || !page_size[0]) | |
157 | if (ppdMarkOption(ppd, "PageSize", s)) | |
158 | conflict = 1; | |
159 | ||
160 | if (cupsGetOption("InputSlot", num_options, options) == NULL) | |
161 | if (ppdMarkOption(ppd, "InputSlot", s)) | |
162 | conflict = 1; | |
163 | ||
164 | if (cupsGetOption("MediaType", num_options, options) == NULL) | |
165 | if (ppdMarkOption(ppd, "MediaType", s)) | |
166 | conflict = 1; | |
167 | ||
168 | if (cupsGetOption("EFMediaType", num_options, options) == NULL) | |
169 | if (ppdMarkOption(ppd, "EFMediaType", s)) /* EFI */ | |
170 | conflict = 1; | |
171 | ||
172 | if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL) | |
173 | if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */ | |
174 | conflict = 1; | |
175 | ||
176 | if (strcasecmp(s, "manual") == 0 && | |
177 | cupsGetOption("ManualFeed", num_options, options) == NULL) | |
178 | if (ppdMarkOption(ppd, "ManualFeed", "True")) | |
179 | conflict = 1; | |
180 | } | |
181 | } | |
182 | else if (!strcasecmp(optptr->name, "sides")) | |
183 | { | |
184 | for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) | |
185 | if (cupsGetOption(duplex_options[j], num_options, options) != NULL) | |
186 | break; | |
187 | ||
188 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
189 | { | |
190 | /* | |
191 | * Don't override the PPD option with the IPP attribute... | |
192 | */ | |
193 | ||
194 | continue; | |
195 | } | |
196 | ||
197 | if (!strcasecmp(optptr->value, "one-sided")) | |
198 | { | |
199 | /* | |
200 | * Mark the appropriate duplex option for one-sided output... | |
201 | */ | |
202 | ||
203 | for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) | |
204 | if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) | |
205 | break; | |
206 | ||
207 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
208 | { | |
209 | for (k = 0; k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); k ++) | |
210 | if (ppdFindChoice(option, duplex_one[k])) | |
211 | { | |
212 | if (ppdMarkOption(ppd, duplex_options[j], duplex_one[k])) | |
213 | conflict = 1; | |
214 | ||
215 | break; | |
216 | } | |
217 | } | |
218 | } | |
219 | else if (!strcasecmp(optptr->value, "two-sided-long-edge")) | |
220 | { | |
221 | /* | |
222 | * Mark the appropriate duplex option for two-sided-long-edge output... | |
223 | */ | |
224 | ||
225 | for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) | |
226 | if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) | |
227 | break; | |
228 | ||
229 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
230 | { | |
231 | for (k = 0; k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); k ++) | |
232 | if (ppdFindChoice(option, duplex_two_long[k])) | |
233 | { | |
234 | if (ppdMarkOption(ppd, duplex_options[j], duplex_two_long[k])) | |
235 | conflict = 1; | |
236 | ||
237 | break; | |
238 | } | |
239 | } | |
240 | } | |
241 | else if (!strcasecmp(optptr->value, "two-sided-short-edge")) | |
242 | { | |
243 | /* | |
244 | * Mark the appropriate duplex option for two-sided-short-edge output... | |
245 | */ | |
246 | ||
247 | for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) | |
248 | if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) | |
249 | break; | |
250 | ||
251 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
252 | { | |
253 | for (k = 0; k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); k ++) | |
254 | if (ppdFindChoice(option, duplex_two_short[k])) | |
255 | { | |
256 | if (ppdMarkOption(ppd, duplex_options[j], duplex_two_short[k])) | |
257 | conflict = 1; | |
258 | ||
259 | break; | |
260 | } | |
261 | } | |
262 | } | |
263 | } | |
264 | else if (!strcasecmp(optptr->name, "resolution") || | |
265 | !strcasecmp(optptr->name, "printer-resolution")) | |
266 | { | |
267 | if (ppdMarkOption(ppd, "Resolution", optptr->value)) | |
268 | conflict = 1; | |
269 | if (ppdMarkOption(ppd, "SetResolution", optptr->value)) | |
270 | /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */ | |
271 | conflict = 1; | |
272 | if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */ | |
273 | conflict = 1; | |
274 | if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */ | |
275 | conflict = 1; | |
276 | } | |
277 | else if (!strcasecmp(optptr->name, "output-bin")) | |
278 | { | |
279 | if (!cupsGetOption("OutputBin", num_options, options)) | |
280 | if (ppdMarkOption(ppd, "OutputBin", optptr->value)) | |
281 | conflict = 1; | |
282 | } | |
283 | else if (!strcasecmp(optptr->name, "multiple-document-handling")) | |
284 | { | |
285 | if (!cupsGetOption("Collate", num_options, options) && | |
286 | ppdFindOption(ppd, "Collate")) | |
287 | { | |
288 | if (strcasecmp(optptr->value, "separate-documents-uncollated-copies")) | |
289 | { | |
290 | if (ppdMarkOption(ppd, "Collate", "True")) | |
291 | conflict = 1; | |
292 | } | |
293 | else | |
294 | { | |
295 | if (ppdMarkOption(ppd, "Collate", "False")) | |
296 | conflict = 1; | |
297 | } | |
298 | } | |
299 | } | |
300 | else if (!strcasecmp(optptr->name, "finishings")) | |
301 | { | |
302 | /* | |
303 | * Lookup cupsIPPFinishings attributes for each value... | |
304 | */ | |
305 | ||
306 | for (ptr = optptr->value; *ptr;) | |
307 | { | |
308 | /* | |
309 | * Get the next finishings number... | |
310 | */ | |
311 | ||
312 | if (!isdigit(*ptr & 255)) | |
313 | break; | |
314 | ||
315 | if ((j = strtol(ptr, &ptr, 10)) < 3) | |
316 | break; | |
317 | ||
318 | /* | |
319 | * Skip separator as needed... | |
320 | */ | |
321 | ||
322 | if (*ptr == ',') | |
323 | ptr ++; | |
324 | ||
325 | /* | |
326 | * Look it up in the PPD file... | |
327 | */ | |
328 | ||
329 | sprintf(s, "%d", j); | |
330 | ||
331 | if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL) | |
332 | continue; | |
333 | ||
334 | /* | |
335 | * Apply "*Option Choice" settings from the attribute value... | |
336 | */ | |
337 | ||
338 | if (ppd_mark_choices(ppd, attr->value)) | |
339 | conflict = 1; | |
340 | } | |
341 | } | |
342 | else if (!strcasecmp(optptr->name, "mirror")) | |
343 | { | |
344 | if (ppdMarkOption(ppd, "MirrorPrint", optptr->value)) | |
345 | conflict = 1; | |
346 | } | |
347 | else if (ppdMarkOption(ppd, optptr->name, optptr->value)) | |
348 | conflict = 1; | |
349 | ||
350 | debug_marked(ppd, "After..."); | |
351 | ||
352 | return (conflict); | |
353 | } | |
354 | ||
355 | ||
356 | /* | |
357 | * 'ppdConflicts()' - Check to see if there are any conflicts among the | |
358 | * marked option choices. | |
359 | * | |
360 | * The returned value is the same as returned by @link ppdMarkOption@. | |
ef416fc2 | 361 | */ |
362 | ||
b94498cf | 363 | int /* O - Number of conflicts found */ |
364 | ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */ | |
ef416fc2 | 365 | { |
b94498cf | 366 | int i, /* Looping variable */ |
367 | conflicts; /* Number of conflicts */ | |
368 | ppd_const_t *c; /* Current constraint */ | |
369 | ppd_option_t *o1, *o2; /* Options */ | |
370 | ppd_choice_t *c1, *c2; /* Choices */ | |
371 | ppd_choice_t key; /* Search key */ | |
ef416fc2 | 372 | |
373 | ||
2abf387c | 374 | if (!ppd) |
ef416fc2 | 375 | return (0); |
376 | ||
377 | /* | |
378 | * Clear all conflicts... | |
379 | */ | |
380 | ||
381 | conflicts = 0; | |
382 | ||
2abf387c | 383 | for (o1 = ppdFirstOption(ppd); o1; o1 = ppdNextOption(ppd)) |
384 | o1->conflicted = 0; | |
ef416fc2 | 385 | |
355e94dc MS |
386 | cupsArraySave(ppd->marked); |
387 | ||
ef416fc2 | 388 | /* |
389 | * Loop through all of the UI constraints and flag any options | |
390 | * that conflict... | |
391 | */ | |
392 | ||
b94498cf | 393 | for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL; |
394 | i > 0; | |
395 | i --, c ++) | |
ef416fc2 | 396 | { |
397 | /* | |
398 | * Grab pointers to the first option... | |
399 | */ | |
400 | ||
b94498cf | 401 | if (!o1 || strcmp(c->option1, o1->keyword)) |
402 | { | |
403 | o1 = ppdFindOption(ppd, c->option1); | |
404 | c1 = NULL; | |
405 | } | |
ef416fc2 | 406 | |
2abf387c | 407 | if (!o1) |
ef416fc2 | 408 | continue; |
b94498cf | 409 | else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice))) |
ef416fc2 | 410 | { |
411 | /* | |
412 | * This constraint maps to a specific choice. | |
413 | */ | |
414 | ||
b94498cf | 415 | key.option = o1; |
416 | ||
417 | if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL && | |
09a101d6 | 418 | (!c1->marked || strcmp(c->choice1, c1->choice))) |
b94498cf | 419 | c1 = NULL; |
ef416fc2 | 420 | } |
b94498cf | 421 | else if (!c1) |
ef416fc2 | 422 | { |
423 | /* | |
424 | * This constraint applies to any choice for this option. | |
425 | */ | |
426 | ||
b94498cf | 427 | key.option = o1; |
ef416fc2 | 428 | |
b94498cf | 429 | if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL && |
430 | (!strcasecmp(c1->choice, "None") || !strcasecmp(c1->choice, "Off") || | |
431 | !strcasecmp(c1->choice, "False"))) | |
ef416fc2 | 432 | c1 = NULL; |
433 | } | |
434 | ||
435 | /* | |
436 | * Grab pointers to the second option... | |
437 | */ | |
438 | ||
b94498cf | 439 | if (!o2 || strcmp(c->option2, o2->keyword)) |
440 | { | |
441 | o2 = ppdFindOption(ppd, c->option2); | |
442 | c2 = NULL; | |
443 | } | |
ef416fc2 | 444 | |
2abf387c | 445 | if (!o2) |
ef416fc2 | 446 | continue; |
b94498cf | 447 | else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice))) |
ef416fc2 | 448 | { |
449 | /* | |
450 | * This constraint maps to a specific choice. | |
451 | */ | |
452 | ||
b94498cf | 453 | key.option = o2; |
454 | ||
455 | if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL && | |
09a101d6 | 456 | (!c2->marked || strcmp(c->choice2, c2->choice))) |
b94498cf | 457 | c2 = NULL; |
ef416fc2 | 458 | } |
b94498cf | 459 | else if (!c2) |
ef416fc2 | 460 | { |
461 | /* | |
462 | * This constraint applies to any choice for this option. | |
463 | */ | |
464 | ||
b94498cf | 465 | key.option = o2; |
ef416fc2 | 466 | |
b94498cf | 467 | if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL && |
468 | (!strcasecmp(c2->choice, "None") || !strcasecmp(c2->choice, "Off") || | |
469 | !strcasecmp(c2->choice, "False"))) | |
ef416fc2 | 470 | c2 = NULL; |
471 | } | |
472 | ||
473 | /* | |
474 | * If both options are marked then there is a conflict... | |
475 | */ | |
476 | ||
2abf387c | 477 | if (c1 && c1->marked && c2 && c2->marked) |
ef416fc2 | 478 | { |
479 | DEBUG_printf(("%s->%s conflicts with %s->%s (%s %s %s %s)\n", | |
480 | o1->keyword, c1->choice, o2->keyword, c2->choice, | |
481 | c->option1, c->choice1, c->option2, c->choice2)); | |
482 | conflicts ++; | |
483 | o1->conflicted = 1; | |
484 | o2->conflicted = 1; | |
485 | } | |
486 | } | |
487 | ||
355e94dc MS |
488 | cupsArrayRestore(ppd->marked); |
489 | ||
ef416fc2 | 490 | /* |
491 | * Return the number of conflicts found... | |
492 | */ | |
493 | ||
494 | return (conflicts); | |
495 | } | |
496 | ||
497 | ||
498 | /* | |
499 | * 'ppdFindChoice()' - Return a pointer to an option choice. | |
500 | */ | |
501 | ||
5a738aea | 502 | ppd_choice_t * /* O - Choice pointer or @code NULL@ */ |
ef416fc2 | 503 | ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */ |
504 | const char *choice) /* I - Name of choice */ | |
505 | { | |
b94498cf | 506 | int i; /* Looping var */ |
507 | ppd_choice_t *c; /* Current choice */ | |
ef416fc2 | 508 | |
509 | ||
bdd6c45b | 510 | if (!o || !choice) |
ef416fc2 | 511 | return (NULL); |
512 | ||
bdd6c45b MS |
513 | if (choice[0] == '{' || !strncasecmp(choice, "Custom.", 7)) |
514 | choice = "Custom"; | |
515 | ||
ef416fc2 | 516 | for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) |
bdd6c45b | 517 | if (!strcasecmp(c->choice, choice)) |
ef416fc2 | 518 | return (c); |
519 | ||
520 | return (NULL); | |
521 | } | |
522 | ||
523 | ||
524 | /* | |
525 | * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option. | |
526 | */ | |
527 | ||
5a738aea | 528 | ppd_choice_t * /* O - Pointer to choice or @code NULL@ */ |
ef416fc2 | 529 | ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */ |
530 | const char *option) /* I - Keyword/option name */ | |
531 | { | |
b94498cf | 532 | ppd_choice_t key; /* Search key for choice */ |
ef416fc2 | 533 | |
534 | ||
b94498cf | 535 | if ((key.option = ppdFindOption(ppd, option)) == NULL) |
ef416fc2 | 536 | return (NULL); |
537 | ||
b94498cf | 538 | return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key)); |
ef416fc2 | 539 | } |
540 | ||
541 | ||
542 | /* | |
543 | * 'ppdFindOption()' - Return a pointer to the specified option. | |
544 | */ | |
545 | ||
5a738aea | 546 | ppd_option_t * /* O - Pointer to option or @code NULL@ */ |
ef416fc2 | 547 | ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */ |
548 | const char *option) /* I - Option/Keyword name */ | |
549 | { | |
fa73b229 | 550 | /* |
551 | * Range check input... | |
552 | */ | |
ef416fc2 | 553 | |
fa73b229 | 554 | if (!ppd || !option) |
ef416fc2 | 555 | return (NULL); |
556 | ||
f301802f | 557 | if (ppd->options) |
558 | { | |
559 | /* | |
560 | * Search in the array... | |
561 | */ | |
562 | ||
563 | ppd_option_t key; /* Option search key */ | |
564 | ||
565 | ||
566 | strlcpy(key.keyword, option, sizeof(key.keyword)); | |
ef416fc2 | 567 | |
f301802f | 568 | return ((ppd_option_t *)cupsArrayFind(ppd->options, &key)); |
569 | } | |
570 | else | |
571 | { | |
572 | /* | |
573 | * Search in each group... | |
574 | */ | |
ef416fc2 | 575 | |
f301802f | 576 | int i, j; /* Looping vars */ |
577 | ppd_group_t *group; /* Current group */ | |
578 | ppd_option_t *optptr; /* Current option */ | |
579 | ||
580 | ||
581 | for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) | |
582 | for (j = group->num_options, optptr = group->options; | |
583 | j > 0; | |
584 | j --, optptr ++) | |
585 | if (!strcasecmp(optptr->keyword, option)) | |
586 | return (optptr); | |
587 | ||
588 | return (NULL); | |
589 | } | |
ef416fc2 | 590 | } |
591 | ||
592 | ||
593 | /* | |
5a738aea | 594 | * 'ppdIsMarked()' - Check to see if an option is marked. |
ef416fc2 | 595 | */ |
596 | ||
b94498cf | 597 | int /* O - Non-zero if option is marked */ |
598 | ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */ | |
599 | const char *option, /* I - Option/Keyword name */ | |
600 | const char *choice) /* I - Choice name */ | |
ef416fc2 | 601 | { |
b94498cf | 602 | ppd_choice_t key, /* Search key */ |
603 | *c; /* Choice pointer */ | |
ef416fc2 | 604 | |
605 | ||
b94498cf | 606 | if (!ppd) |
ef416fc2 | 607 | return (0); |
608 | ||
b94498cf | 609 | if ((key.option = ppdFindOption(ppd, option)) == NULL) |
ef416fc2 | 610 | return (0); |
611 | ||
b94498cf | 612 | if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL) |
ef416fc2 | 613 | return (0); |
614 | ||
b94498cf | 615 | return (!strcmp(c->choice, choice)); |
ef416fc2 | 616 | } |
617 | ||
618 | ||
619 | /* | |
620 | * 'ppdMarkDefaults()' - Mark all default options in the PPD file. | |
621 | */ | |
622 | ||
623 | void | |
b94498cf | 624 | ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */ |
ef416fc2 | 625 | { |
b94498cf | 626 | int i; /* Looping variables */ |
627 | ppd_group_t *g; /* Current group */ | |
628 | ppd_choice_t *c; /* Current choice */ | |
ef416fc2 | 629 | |
630 | ||
b94498cf | 631 | if (!ppd) |
ef416fc2 | 632 | return; |
633 | ||
b94498cf | 634 | /* |
635 | * Clean out the marked array... | |
636 | */ | |
637 | ||
638 | for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked); | |
639 | c; | |
640 | c = (ppd_choice_t *)cupsArrayNext(ppd->marked)) | |
641 | cupsArrayRemove(ppd->marked, c); | |
642 | ||
643 | /* | |
644 | * Then repopulate it with the defaults... | |
645 | */ | |
646 | ||
ef416fc2 | 647 | for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) |
648 | ppd_defaults(ppd, g); | |
649 | } | |
650 | ||
651 | ||
652 | /* | |
653 | * 'ppdMarkOption()' - Mark an option in a PPD file. | |
ef416fc2 | 654 | */ |
655 | ||
656 | int /* O - Number of conflicts */ | |
657 | ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */ | |
658 | const char *option, /* I - Keyword */ | |
659 | const char *choice) /* I - Option name */ | |
660 | { | |
fa73b229 | 661 | int i, j; /* Looping vars */ |
662 | ppd_option_t *o; /* Option pointer */ | |
b94498cf | 663 | ppd_choice_t *c, /* Choice pointer */ |
664 | *oldc, /* Old choice pointer */ | |
665 | key; /* Search key for choice */ | |
757d2cad | 666 | struct lconv *loc; /* Locale data */ |
ef416fc2 | 667 | |
668 | ||
bd7854cb | 669 | DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n", |
670 | ppd, option, choice)); | |
671 | ||
fa73b229 | 672 | /* |
673 | * Range check input... | |
674 | */ | |
675 | ||
676 | if (!ppd || !option || !choice) | |
ef416fc2 | 677 | return (0); |
678 | ||
fa73b229 | 679 | /* |
680 | * AP_D_InputSlot is the "default input slot" on MacOS X, and setting | |
681 | * it clears the regular InputSlot choices... | |
682 | */ | |
ef416fc2 | 683 | |
fa73b229 | 684 | if (!strcasecmp(option, "AP_D_InputSlot")) |
685 | { | |
686 | if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) | |
b94498cf | 687 | { |
688 | key.option = o; | |
689 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
690 | { | |
691 | oldc->marked = 0; | |
692 | cupsArrayRemove(ppd->marked, oldc); | |
693 | } | |
694 | } | |
ef416fc2 | 695 | } |
696 | ||
fa73b229 | 697 | /* |
698 | * Check for custom options... | |
699 | */ | |
700 | ||
ef416fc2 | 701 | if ((o = ppdFindOption(ppd, option)) == NULL) |
702 | return (0); | |
703 | ||
757d2cad | 704 | loc = localeconv(); |
ef416fc2 | 705 | |
b423cd4c | 706 | if (!strncasecmp(choice, "Custom.", 7)) |
ef416fc2 | 707 | { |
708 | /* | |
fa73b229 | 709 | * Handle a custom option... |
ef416fc2 | 710 | */ |
711 | ||
fa73b229 | 712 | if ((c = ppdFindChoice(o, "Custom")) == NULL) |
713 | return (0); | |
ef416fc2 | 714 | |
fa73b229 | 715 | if (!strcasecmp(option, "PageSize")) |
716 | { | |
717 | /* | |
718 | * Handle custom page sizes... | |
719 | */ | |
ef416fc2 | 720 | |
fa73b229 | 721 | ppdPageSize(ppd, choice); |
722 | } | |
723 | else | |
ef416fc2 | 724 | { |
725 | /* | |
fa73b229 | 726 | * Handle other custom options... |
ef416fc2 | 727 | */ |
728 | ||
fa73b229 | 729 | ppd_coption_t *coption; /* Custom option */ |
730 | ppd_cparam_t *cparam; /* Custom parameter */ | |
757d2cad | 731 | char *units; /* Custom points units */ |
fa73b229 | 732 | |
8ca02f3c | 733 | |
fa73b229 | 734 | if ((coption = ppdFindCustomOption(ppd, option)) != NULL) |
ef416fc2 | 735 | { |
fa73b229 | 736 | if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL) |
737 | return (0); | |
738 | ||
739 | switch (cparam->type) | |
740 | { | |
741 | case PPD_CUSTOM_CURVE : | |
742 | case PPD_CUSTOM_INVCURVE : | |
743 | case PPD_CUSTOM_REAL : | |
b86bc4cf | 744 | cparam->current.custom_real = (float)_cupsStrScand(choice + 7, |
745 | NULL, loc); | |
fa73b229 | 746 | break; |
747 | ||
748 | case PPD_CUSTOM_POINTS : | |
b86bc4cf | 749 | cparam->current.custom_points = (float)_cupsStrScand(choice + 7, |
750 | &units, | |
751 | loc); | |
757d2cad | 752 | |
753 | if (units) | |
754 | { | |
755 | if (!strcasecmp(units, "cm")) | |
b86bc4cf | 756 | cparam->current.custom_points *= 72.0f / 2.54f; |
757d2cad | 757 | else if (!strcasecmp(units, "mm")) |
b86bc4cf | 758 | cparam->current.custom_points *= 72.0f / 25.4f; |
757d2cad | 759 | else if (!strcasecmp(units, "m")) |
b86bc4cf | 760 | cparam->current.custom_points *= 72.0f / 0.0254f; |
757d2cad | 761 | else if (!strcasecmp(units, "in")) |
b86bc4cf | 762 | cparam->current.custom_points *= 72.0f; |
757d2cad | 763 | else if (!strcasecmp(units, "ft")) |
b86bc4cf | 764 | cparam->current.custom_points *= 12.0f * 72.0f; |
757d2cad | 765 | } |
fa73b229 | 766 | break; |
767 | ||
768 | case PPD_CUSTOM_INT : | |
769 | cparam->current.custom_int = atoi(choice + 7); | |
770 | break; | |
771 | ||
772 | case PPD_CUSTOM_PASSCODE : | |
773 | case PPD_CUSTOM_PASSWORD : | |
774 | case PPD_CUSTOM_STRING : | |
775 | if (cparam->current.custom_string) | |
2e4ff8af | 776 | _cupsStrFree(cparam->current.custom_string); |
fa73b229 | 777 | |
2e4ff8af | 778 | cparam->current.custom_string = _cupsStrAlloc(choice + 7); |
fa73b229 | 779 | break; |
780 | } | |
ef416fc2 | 781 | } |
782 | } | |
8ca02f3c | 783 | |
784 | /* | |
785 | * Make sure that we keep the option marked below... | |
786 | */ | |
787 | ||
788 | choice = "Custom"; | |
fa73b229 | 789 | } |
b423cd4c | 790 | else if (choice[0] == '{') |
791 | { | |
792 | /* | |
793 | * Handle multi-value custom options... | |
794 | */ | |
795 | ||
796 | ppd_coption_t *coption; /* Custom option */ | |
797 | ppd_cparam_t *cparam; /* Custom parameter */ | |
757d2cad | 798 | char *units; /* Custom points units */ |
b423cd4c | 799 | int num_vals; /* Number of values */ |
800 | cups_option_t *vals, /* Values */ | |
801 | *val; /* Value */ | |
802 | ||
803 | ||
804 | if ((c = ppdFindChoice(o, "Custom")) == NULL) | |
805 | return (0); | |
806 | ||
807 | if ((coption = ppdFindCustomOption(ppd, option)) != NULL) | |
808 | { | |
809 | num_vals = cupsParseOptions(choice + 1, 0, &vals); | |
810 | ||
811 | for (i = 0, val = vals; i < num_vals; i ++, val ++) | |
812 | { | |
813 | if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL) | |
814 | continue; | |
815 | ||
816 | switch (cparam->type) | |
817 | { | |
818 | case PPD_CUSTOM_CURVE : | |
819 | case PPD_CUSTOM_INVCURVE : | |
820 | case PPD_CUSTOM_REAL : | |
b86bc4cf | 821 | cparam->current.custom_real = (float)_cupsStrScand(val->value, |
822 | NULL, loc); | |
b423cd4c | 823 | break; |
824 | ||
825 | case PPD_CUSTOM_POINTS : | |
b86bc4cf | 826 | cparam->current.custom_points = (float)_cupsStrScand(val->value, |
827 | &units, | |
828 | loc); | |
757d2cad | 829 | |
830 | if (units) | |
831 | { | |
832 | if (!strcasecmp(units, "cm")) | |
b86bc4cf | 833 | cparam->current.custom_points *= 72.0f / 2.54f; |
757d2cad | 834 | else if (!strcasecmp(units, "mm")) |
b86bc4cf | 835 | cparam->current.custom_points *= 72.0f / 25.4f; |
757d2cad | 836 | else if (!strcasecmp(units, "m")) |
b86bc4cf | 837 | cparam->current.custom_points *= 72.0f / 0.0254f; |
757d2cad | 838 | else if (!strcasecmp(units, "in")) |
b86bc4cf | 839 | cparam->current.custom_points *= 72.0f; |
757d2cad | 840 | else if (!strcasecmp(units, "ft")) |
b86bc4cf | 841 | cparam->current.custom_points *= 12.0f * 72.0f; |
757d2cad | 842 | } |
b423cd4c | 843 | break; |
844 | ||
845 | case PPD_CUSTOM_INT : | |
846 | cparam->current.custom_int = atoi(val->value); | |
847 | break; | |
848 | ||
849 | case PPD_CUSTOM_PASSCODE : | |
850 | case PPD_CUSTOM_PASSWORD : | |
851 | case PPD_CUSTOM_STRING : | |
852 | if (cparam->current.custom_string) | |
2e4ff8af | 853 | _cupsStrFree(cparam->current.custom_string); |
b423cd4c | 854 | |
2e4ff8af | 855 | cparam->current.custom_string = _cupsStrAlloc(val->value); |
b423cd4c | 856 | break; |
857 | } | |
858 | } | |
859 | ||
860 | cupsFreeOptions(num_vals, vals); | |
861 | } | |
862 | } | |
fa73b229 | 863 | else |
864 | { | |
865 | for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) | |
866 | if (!strcasecmp(c->choice, choice)) | |
867 | break; | |
ef416fc2 | 868 | |
fa73b229 | 869 | if (!i) |
870 | return (0); | |
871 | } | |
ef416fc2 | 872 | |
fa73b229 | 873 | /* |
874 | * Option found; mark it and then handle unmarking any other options. | |
875 | */ | |
876 | ||
fa73b229 | 877 | if (o->ui != PPD_UI_PICKMANY) |
878 | { | |
879 | /* | |
880 | * Unmark all other choices... | |
881 | */ | |
882 | ||
b94498cf | 883 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL) |
884 | { | |
885 | oldc->marked = 0; | |
886 | cupsArrayRemove(ppd->marked, oldc); | |
887 | } | |
888 | ||
889 | if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion")) | |
890 | { | |
891 | /* | |
892 | * Mark current page size... | |
893 | */ | |
894 | ||
895 | for (j = 0; j < ppd->num_sizes; j ++) | |
896 | ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name, | |
897 | choice); | |
898 | ||
899 | /* | |
900 | * Unmark the current PageSize or PageRegion setting, as | |
901 | * appropriate... | |
902 | */ | |
903 | ||
904 | if (!strcasecmp(option, "PageSize")) | |
fa73b229 | 905 | { |
b94498cf | 906 | if ((o = ppdFindOption(ppd, "PageRegion")) != NULL) |
907 | { | |
908 | key.option = o; | |
909 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
910 | { | |
911 | oldc->marked = 0; | |
912 | cupsArrayRemove(ppd->marked, oldc); | |
913 | } | |
914 | } | |
915 | } | |
916 | else | |
917 | { | |
918 | if ((o = ppdFindOption(ppd, "PageSize")) != NULL) | |
919 | { | |
920 | key.option = o; | |
921 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
922 | { | |
923 | oldc->marked = 0; | |
924 | cupsArrayRemove(ppd->marked, oldc); | |
925 | } | |
926 | } | |
927 | } | |
928 | } | |
929 | else if (!strcasecmp(option, "InputSlot")) | |
930 | { | |
931 | /* | |
355e94dc | 932 | * Unmark ManualFeed option... |
b94498cf | 933 | */ |
fa73b229 | 934 | |
b94498cf | 935 | if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL) |
936 | { | |
937 | key.option = o; | |
938 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
939 | { | |
940 | oldc->marked = 0; | |
941 | cupsArrayRemove(ppd->marked, oldc); | |
942 | } | |
943 | } | |
944 | } | |
945 | else if (!strcasecmp(option, "ManualFeed") && | |
946 | !strcasecmp(choice, "True")) | |
947 | { | |
948 | /* | |
949 | * Unmark InputSlot option... | |
950 | */ | |
fa73b229 | 951 | |
b94498cf | 952 | if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) |
953 | { | |
954 | key.option = o; | |
955 | if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL) | |
956 | { | |
957 | oldc->marked = 0; | |
958 | cupsArrayRemove(ppd->marked, oldc); | |
959 | } | |
fa73b229 | 960 | } |
b94498cf | 961 | } |
ef416fc2 | 962 | } |
963 | ||
b94498cf | 964 | c->marked = 1; |
965 | ||
966 | cupsArrayAdd(ppd->marked, c); | |
967 | ||
fa73b229 | 968 | /* |
969 | * Return the number of conflicts... | |
970 | */ | |
971 | ||
ef416fc2 | 972 | return (ppdConflicts(ppd)); |
973 | } | |
974 | ||
975 | ||
bd7854cb | 976 | /* |
977 | * 'ppdFirstOption()' - Return the first option in the PPD file. | |
978 | * | |
5a738aea | 979 | * Options are returned from all groups in ascending alphanumeric order. |
bd7854cb | 980 | * |
981 | * @since CUPS 1.2@ | |
982 | */ | |
983 | ||
5a738aea | 984 | ppd_option_t * /* O - First option or @code NULL@ */ |
bd7854cb | 985 | ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */ |
986 | { | |
987 | if (!ppd) | |
988 | return (NULL); | |
989 | else | |
990 | return ((ppd_option_t *)cupsArrayFirst(ppd->options)); | |
991 | } | |
992 | ||
993 | ||
994 | /* | |
995 | * 'ppdNextOption()' - Return the next option in the PPD file. | |
996 | * | |
5a738aea | 997 | * Options are returned from all groups in ascending alphanumeric order. |
bd7854cb | 998 | * |
999 | * @since CUPS 1.2@ | |
1000 | */ | |
1001 | ||
5a738aea | 1002 | ppd_option_t * /* O - Next option or @code NULL@ */ |
bd7854cb | 1003 | ppdNextOption(ppd_file_t *ppd) /* I - PPD file */ |
1004 | { | |
1005 | if (!ppd) | |
1006 | return (NULL); | |
1007 | else | |
1008 | return ((ppd_option_t *)cupsArrayNext(ppd->options)); | |
1009 | } | |
1010 | ||
1011 | ||
5a738aea MS |
1012 | #ifdef DEBUG |
1013 | /* | |
1014 | * 'debug_marked()' - Output the marked array to stdout... | |
1015 | */ | |
1016 | ||
1017 | static void | |
1018 | debug_marked(ppd_file_t *ppd, /* I - PPD file data */ | |
1019 | const char *title) /* I - Title for list */ | |
1020 | { | |
1021 | ppd_choice_t *c; /* Current choice */ | |
1022 | ||
1023 | ||
ae71f5de | 1024 | DEBUG_printf(("cupsMarkOptions: %s\n", title)); |
5a738aea MS |
1025 | |
1026 | for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked); | |
1027 | c; | |
1028 | c = (ppd_choice_t *)cupsArrayNext(ppd->marked)) | |
ae71f5de | 1029 | DEBUG_printf(("cupsMarkOptions: %s=%s\n", c->option->keyword, c->choice)); |
5a738aea MS |
1030 | } |
1031 | #endif /* DEBUG */ | |
1032 | ||
1033 | ||
ef416fc2 | 1034 | /* |
1035 | * 'ppd_defaults()' - Set the defaults for this group and all sub-groups. | |
1036 | */ | |
1037 | ||
1038 | static void | |
5a738aea MS |
1039 | ppd_defaults(ppd_file_t *ppd, /* I - PPD file */ |
1040 | ppd_group_t *g) /* I - Group to default */ | |
ef416fc2 | 1041 | { |
5a738aea MS |
1042 | int i; /* Looping var */ |
1043 | ppd_option_t *o; /* Current option */ | |
1044 | ppd_group_t *sg; /* Current sub-group */ | |
ef416fc2 | 1045 | |
1046 | ||
ef416fc2 | 1047 | for (i = g->num_options, o = g->options; i > 0; i --, o ++) |
1048 | if (strcasecmp(o->keyword, "PageRegion") != 0) | |
1049 | ppdMarkOption(ppd, o->keyword, o->defchoice); | |
1050 | ||
1051 | for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++) | |
1052 | ppd_defaults(ppd, sg); | |
1053 | } | |
1054 | ||
1055 | ||
1056 | /* | |
5a738aea MS |
1057 | * 'ppd_mark_choices()' - Mark one or more option choices from a string. |
1058 | */ | |
1059 | ||
1060 | static int /* O - 1 if there are conflicts, 0 otherwise */ | |
1061 | ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */ | |
1062 | const char *options) /* I - "*Option Choice ..." string */ | |
1063 | { | |
1064 | char option[PPD_MAX_NAME], /* Current option */ | |
1065 | choice[PPD_MAX_NAME], /* Current choice */ | |
1066 | *ptr; /* Pointer into option or choice */ | |
1067 | int conflict = 0; /* Do we have a conflict? */ | |
1068 | ||
1069 | ||
1070 | if (!options) | |
1071 | return (0); | |
1072 | ||
1073 | /* | |
1074 | * Read all of the "*Option Choice" pairs from the string, marking PPD | |
1075 | * options as we go... | |
1076 | */ | |
1077 | ||
1078 | while (*options) | |
1079 | { | |
1080 | /* | |
1081 | * Skip leading whitespace... | |
1082 | */ | |
1083 | ||
1084 | while (isspace(*options & 255)) | |
1085 | options ++; | |
1086 | ||
1087 | if (*options != '*') | |
1088 | break; | |
1089 | ||
1090 | /* | |
1091 | * Get the option name... | |
1092 | */ | |
1093 | ||
1094 | options ++; | |
1095 | ptr = option; | |
1096 | while (*options && !isspace(*options & 255) && | |
1097 | ptr < (option + sizeof(option) - 1)) | |
1098 | *ptr++ = *options++; | |
1099 | ||
1100 | if (ptr == option) | |
1101 | break; | |
1102 | ||
1103 | *ptr = '\0'; | |
1104 | ||
1105 | /* | |
1106 | * Get the choice... | |
1107 | */ | |
1108 | ||
1109 | while (isspace(*options & 255)) | |
1110 | options ++; | |
1111 | ||
1112 | if (!*options) | |
1113 | break; | |
1114 | ||
1115 | ptr = choice; | |
1116 | while (*options && !isspace(*options & 255) && | |
1117 | ptr < (choice + sizeof(choice) - 1)) | |
1118 | *ptr++ = *options++; | |
1119 | ||
1120 | *ptr = '\0'; | |
1121 | ||
1122 | /* | |
1123 | * Mark the option... | |
1124 | */ | |
1125 | ||
1126 | if (ppdMarkOption(ppd, option, choice)) | |
1127 | conflict = 1; | |
1128 | } | |
1129 | ||
1130 | /* | |
1131 | * Return whether we had any conflicts... | |
1132 | */ | |
1133 | ||
1134 | return (conflict); | |
1135 | } | |
1136 | ||
1137 | ||
1138 | /* | |
1139 | * End of "$Id: mark.c 7278 2008-01-31 01:23:09Z mike $". | |
ef416fc2 | 1140 | */ |