]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
355e94dc | 2 | * "$Id: options.c 6703 2007-07-20 21:28:10Z mike $" |
ef416fc2 | 3 | * |
4 | * Option routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
bc44d920 | 6 | * Copyright 2007 by Apple Inc. |
f7deaa1a | 7 | * Copyright 1997-2007 by Easy Software Products. |
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 | * This file is subject to the Apple OS-Developed Software exception. | |
16 | * | |
17 | * Contents: | |
18 | * | |
b423cd4c | 19 | * cupsAddOption() - Add an option to an option array. |
20 | * cupsFreeOptions() - Free all memory used by options. | |
21 | * cupsGetOption() - Get an option value. | |
22 | * cupsMarkOptions() - Mark command-line options in a PPD file. | |
23 | * cupsParseOptions() - Parse options from a command-line argument. | |
24 | * cupsRemoveOptions() - Remove an option from an option array. | |
355e94dc | 25 | * debug_marked() - Output the marked array to stdout... |
09a101d6 | 26 | * ppd_mark_choices() - Mark one or more option choices from a string. |
ef416fc2 | 27 | */ |
28 | ||
29 | /* | |
30 | * Include necessary headers... | |
31 | */ | |
32 | ||
33 | #include "cups.h" | |
34 | #include <stdlib.h> | |
35 | #include <ctype.h> | |
36 | #include "string.h" | |
37 | #include "debug.h" | |
38 | ||
39 | ||
09a101d6 | 40 | /* |
41 | * Local functions... | |
42 | */ | |
43 | ||
355e94dc MS |
44 | #ifdef DEBUG |
45 | static void debug_marked(ppd_file_t *ppd, const char *title); | |
46 | #else | |
47 | # define debug_marked(ppd,title) | |
48 | #endif /* DEBUG */ | |
09a101d6 | 49 | static int ppd_mark_choices(ppd_file_t *ppd, const char *options); |
50 | ||
51 | ||
ef416fc2 | 52 | /* |
53 | * 'cupsAddOption()' - Add an option to an option array. | |
54 | */ | |
55 | ||
56 | int /* O - Number of options */ | |
57 | cupsAddOption(const char *name, /* I - Name of option */ | |
58 | const char *value, /* I - Value of option */ | |
59 | int num_options,/* I - Number of options */ | |
60 | cups_option_t **options) /* IO - Pointer to options */ | |
61 | { | |
62 | int i; /* Looping var */ | |
63 | cups_option_t *temp; /* Pointer to new option */ | |
64 | ||
65 | ||
66 | if (name == NULL || !name[0] || value == NULL || | |
67 | options == NULL || num_options < 0) | |
68 | return (num_options); | |
69 | ||
70 | /* | |
71 | * Look for an existing option with the same name... | |
72 | */ | |
73 | ||
74 | for (i = 0, temp = *options; i < num_options; i ++, temp ++) | |
75 | if (strcasecmp(temp->name, name) == 0) | |
76 | break; | |
77 | ||
78 | if (i >= num_options) | |
79 | { | |
80 | /* | |
81 | * No matching option name... | |
82 | */ | |
83 | ||
84 | if (num_options == 0) | |
85 | temp = (cups_option_t *)malloc(sizeof(cups_option_t)); | |
86 | else | |
87 | temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) * | |
88 | (num_options + 1)); | |
89 | ||
90 | if (temp == NULL) | |
91 | return (0); | |
92 | ||
93 | *options = temp; | |
94 | temp += num_options; | |
95 | temp->name = strdup(name); | |
96 | num_options ++; | |
97 | } | |
98 | else | |
99 | { | |
100 | /* | |
101 | * Match found; free the old value... | |
102 | */ | |
103 | ||
104 | free(temp->value); | |
105 | } | |
106 | ||
107 | temp->value = strdup(value); | |
108 | ||
109 | return (num_options); | |
110 | } | |
111 | ||
112 | ||
113 | /* | |
114 | * 'cupsFreeOptions()' - Free all memory used by options. | |
115 | */ | |
116 | ||
117 | void | |
118 | cupsFreeOptions( | |
119 | int num_options, /* I - Number of options */ | |
120 | cups_option_t *options) /* I - Pointer to options */ | |
121 | { | |
122 | int i; /* Looping var */ | |
123 | ||
124 | ||
125 | if (num_options <= 0 || options == NULL) | |
126 | return; | |
127 | ||
128 | for (i = 0; i < num_options; i ++) | |
129 | { | |
130 | free(options[i].name); | |
131 | free(options[i].value); | |
132 | } | |
133 | ||
134 | free(options); | |
135 | } | |
136 | ||
137 | ||
138 | /* | |
139 | * 'cupsGetOption()' - Get an option value. | |
140 | */ | |
141 | ||
142 | const char * /* O - Option value or NULL */ | |
143 | cupsGetOption(const char *name, /* I - Name of option */ | |
144 | int num_options,/* I - Number of options */ | |
145 | cups_option_t *options) /* I - Options */ | |
146 | { | |
147 | int i; /* Looping var */ | |
148 | ||
149 | ||
150 | if (name == NULL || num_options <= 0 || options == NULL) | |
151 | return (NULL); | |
152 | ||
153 | for (i = 0; i < num_options; i ++) | |
154 | if (strcasecmp(options[i].name, name) == 0) | |
155 | return (options[i].value); | |
156 | ||
157 | return (NULL); | |
158 | } | |
159 | ||
160 | ||
ef416fc2 | 161 | /* |
162 | * 'cupsMarkOptions()' - Mark command-line options in a PPD file. | |
163 | */ | |
164 | ||
165 | int /* O - 1 if conflicting */ | |
166 | cupsMarkOptions( | |
167 | ppd_file_t *ppd, /* I - PPD file */ | |
168 | int num_options, /* I - Number of options */ | |
169 | cups_option_t *options) /* I - Options */ | |
170 | { | |
171 | int i, j, k; /* Looping vars */ | |
172 | int conflict; /* Option conflicts */ | |
173 | char *val, /* Pointer into value */ | |
174 | *ptr, /* Pointer into string */ | |
175 | s[255]; /* Temporary string */ | |
fa73b229 | 176 | const char *page_size; /* PageSize option */ |
ef416fc2 | 177 | cups_option_t *optptr; /* Current option */ |
178 | ppd_option_t *option; /* PPD option */ | |
09a101d6 | 179 | ppd_attr_t *attr; /* PPD attribute */ |
ef416fc2 | 180 | static const char * const duplex_options[] = |
181 | { /* Duplex option names */ | |
182 | "Duplex", /* Adobe */ | |
183 | "EFDuplex", /* EFI */ | |
184 | "EFDuplexing", /* EFI */ | |
185 | "KD03Duplex", /* Kodak */ | |
186 | "JCLDuplex" /* Samsung */ | |
187 | }; | |
188 | static const char * const duplex_one[] = | |
189 | { /* one-sided names */ | |
190 | "None", | |
191 | "False" | |
192 | }; | |
193 | static const char * const duplex_two_long[] = | |
194 | { /* two-sided-long-edge names */ | |
195 | "DuplexNoTumble", /* Adobe */ | |
196 | "LongEdge", /* EFI */ | |
197 | "Top" /* EFI */ | |
198 | }; | |
199 | static const char * const duplex_two_short[] = | |
200 | { /* two-sided-long-edge names */ | |
201 | "DuplexTumble", /* Adobe */ | |
202 | "ShortEdge", /* EFI */ | |
203 | "Bottom" /* EFI */ | |
204 | }; | |
205 | ||
206 | ||
207 | /* | |
208 | * Check arguments... | |
209 | */ | |
210 | ||
211 | if (ppd == NULL || num_options <= 0 || options == NULL) | |
212 | return (0); | |
213 | ||
355e94dc MS |
214 | debug_marked(ppd, "Before..."); |
215 | ||
ef416fc2 | 216 | /* |
217 | * Mark options... | |
218 | */ | |
219 | ||
fa73b229 | 220 | conflict = 0; |
ef416fc2 | 221 | |
222 | for (i = num_options, optptr = options; i > 0; i --, optptr ++) | |
223 | if (!strcasecmp(optptr->name, "media")) | |
224 | { | |
225 | /* | |
226 | * Loop through the option string, separating it at commas and | |
fa73b229 | 227 | * marking each individual option as long as the corresponding |
228 | * PPD option (PageSize, InputSlot, etc.) is not also set. | |
229 | * | |
230 | * For PageSize, we also check for an empty option value since | |
231 | * some versions of MacOS X use it to specify auto-selection | |
232 | * of the media based solely on the size. | |
ef416fc2 | 233 | */ |
234 | ||
fa73b229 | 235 | page_size = cupsGetOption("PageSize", num_options, options); |
236 | ||
ef416fc2 | 237 | for (val = optptr->value; *val;) |
238 | { | |
239 | /* | |
240 | * Extract the sub-option from the string... | |
241 | */ | |
242 | ||
243 | for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);) | |
244 | *ptr++ = *val++; | |
245 | *ptr++ = '\0'; | |
246 | ||
247 | if (*val == ',') | |
248 | val ++; | |
249 | ||
250 | /* | |
251 | * Mark it... | |
252 | */ | |
253 | ||
fa73b229 | 254 | if (!page_size || !page_size[0]) |
ef416fc2 | 255 | if (ppdMarkOption(ppd, "PageSize", s)) |
256 | conflict = 1; | |
257 | ||
258 | if (cupsGetOption("InputSlot", num_options, options) == NULL) | |
259 | if (ppdMarkOption(ppd, "InputSlot", s)) | |
260 | conflict = 1; | |
261 | ||
262 | if (cupsGetOption("MediaType", num_options, options) == NULL) | |
263 | if (ppdMarkOption(ppd, "MediaType", s)) | |
264 | conflict = 1; | |
265 | ||
266 | if (cupsGetOption("EFMediaType", num_options, options) == NULL) | |
355e94dc | 267 | if (ppdMarkOption(ppd, "EFMediaType", s)) /* EFI */ |
ef416fc2 | 268 | conflict = 1; |
269 | ||
270 | if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL) | |
271 | if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */ | |
272 | conflict = 1; | |
273 | ||
274 | if (strcasecmp(s, "manual") == 0 && | |
275 | cupsGetOption("ManualFeed", num_options, options) == NULL) | |
276 | if (ppdMarkOption(ppd, "ManualFeed", "True")) | |
277 | conflict = 1; | |
278 | } | |
279 | } | |
280 | else if (!strcasecmp(optptr->name, "sides")) | |
281 | { | |
282 | for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) | |
283 | if (cupsGetOption(duplex_options[j], num_options, options) != NULL) | |
284 | break; | |
285 | ||
286 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
287 | { | |
288 | /* | |
289 | * Don't override the PPD option with the IPP attribute... | |
290 | */ | |
291 | ||
292 | continue; | |
293 | } | |
294 | ||
295 | if (!strcasecmp(optptr->value, "one-sided")) | |
296 | { | |
297 | /* | |
298 | * Mark the appropriate duplex option for one-sided output... | |
299 | */ | |
300 | ||
301 | for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) | |
302 | if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) | |
303 | break; | |
304 | ||
305 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
306 | { | |
307 | for (k = 0; k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); k ++) | |
308 | if (ppdFindChoice(option, duplex_one[k])) | |
309 | { | |
310 | if (ppdMarkOption(ppd, duplex_options[j], duplex_one[k])) | |
311 | conflict = 1; | |
312 | ||
313 | break; | |
314 | } | |
315 | } | |
316 | } | |
317 | else if (!strcasecmp(optptr->value, "two-sided-long-edge")) | |
318 | { | |
319 | /* | |
320 | * Mark the appropriate duplex option for two-sided-long-edge output... | |
321 | */ | |
322 | ||
323 | for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) | |
324 | if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) | |
325 | break; | |
326 | ||
327 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
328 | { | |
329 | for (k = 0; k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); k ++) | |
330 | if (ppdFindChoice(option, duplex_two_long[k])) | |
331 | { | |
332 | if (ppdMarkOption(ppd, duplex_options[j], duplex_two_long[k])) | |
333 | conflict = 1; | |
334 | ||
335 | break; | |
336 | } | |
337 | } | |
338 | } | |
339 | else if (!strcasecmp(optptr->value, "two-sided-short-edge")) | |
340 | { | |
341 | /* | |
342 | * Mark the appropriate duplex option for two-sided-short-edge output... | |
343 | */ | |
344 | ||
345 | for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) | |
346 | if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) | |
347 | break; | |
348 | ||
349 | if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) | |
350 | { | |
351 | for (k = 0; k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); k ++) | |
352 | if (ppdFindChoice(option, duplex_two_short[k])) | |
353 | { | |
354 | if (ppdMarkOption(ppd, duplex_options[j], duplex_two_short[k])) | |
355 | conflict = 1; | |
356 | ||
357 | break; | |
358 | } | |
359 | } | |
360 | } | |
361 | } | |
362 | else if (!strcasecmp(optptr->name, "resolution") || | |
363 | !strcasecmp(optptr->name, "printer-resolution")) | |
364 | { | |
365 | if (ppdMarkOption(ppd, "Resolution", optptr->value)) | |
366 | conflict = 1; | |
367 | if (ppdMarkOption(ppd, "SetResolution", optptr->value)) | |
368 | /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */ | |
369 | conflict = 1; | |
370 | if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */ | |
371 | conflict = 1; | |
372 | if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */ | |
373 | conflict = 1; | |
374 | } | |
375 | else if (!strcasecmp(optptr->name, "output-bin")) | |
376 | { | |
f7deaa1a | 377 | if (!cupsGetOption("OutputBin", num_options, options)) |
ef416fc2 | 378 | if (ppdMarkOption(ppd, "OutputBin", optptr->value)) |
379 | conflict = 1; | |
380 | } | |
f7deaa1a | 381 | else if (!strcasecmp(optptr->name, "multiple-document-handling")) |
382 | { | |
383 | if (!cupsGetOption("Collate", num_options, options) && | |
384 | ppdFindOption(ppd, "Collate")) | |
385 | { | |
386 | if (strcasecmp(optptr->value, "separate-documents-uncollated-copies")) | |
387 | { | |
388 | if (ppdMarkOption(ppd, "Collate", "True")) | |
389 | conflict = 1; | |
390 | } | |
391 | else | |
392 | { | |
393 | if (ppdMarkOption(ppd, "Collate", "False")) | |
394 | conflict = 1; | |
395 | } | |
396 | } | |
397 | } | |
09a101d6 | 398 | else if (!strcasecmp(optptr->name, "finishings")) |
399 | { | |
400 | /* | |
401 | * Lookup cupsIPPFinishings attributes for each value... | |
402 | */ | |
403 | ||
404 | for (ptr = optptr->value; *ptr;) | |
405 | { | |
406 | /* | |
407 | * Get the next finishings number... | |
408 | */ | |
409 | ||
410 | if (!isdigit(*ptr & 255)) | |
411 | break; | |
412 | ||
413 | if ((j = strtol(ptr, &ptr, 10)) < 3) | |
414 | break; | |
415 | ||
416 | /* | |
417 | * Skip separator as needed... | |
418 | */ | |
419 | ||
420 | if (*ptr == ',') | |
421 | ptr ++; | |
422 | ||
423 | /* | |
424 | * Look it up in the PPD file... | |
425 | */ | |
426 | ||
427 | sprintf(s, "%d", j); | |
428 | ||
429 | if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL) | |
430 | continue; | |
431 | ||
432 | /* | |
433 | * Apply "*Option Choice" settings from the attribute value... | |
434 | */ | |
435 | ||
436 | if (ppd_mark_choices(ppd, attr->value)) | |
437 | conflict = 1; | |
438 | } | |
439 | } | |
355e94dc MS |
440 | else if (!strcasecmp(optptr->name, "mirror")) |
441 | { | |
442 | if (ppdMarkOption(ppd, "MirrorPrint", optptr->value)) | |
443 | conflict = 1; | |
444 | } | |
ef416fc2 | 445 | else if (ppdMarkOption(ppd, optptr->name, optptr->value)) |
446 | conflict = 1; | |
447 | ||
355e94dc MS |
448 | debug_marked(ppd, "After..."); |
449 | ||
ef416fc2 | 450 | return (conflict); |
451 | } | |
452 | ||
453 | ||
454 | /* | |
b423cd4c | 455 | * 'cupsParseOptions()' - Parse options from a command-line argument. |
456 | * | |
457 | * This function converts space-delimited name/value pairs according | |
458 | * to the PAPI text option ABNF specification. Collection values | |
459 | * ("name={a=... b=... c=...}") are stored with the curley brackets | |
460 | * intact - use cupsParseOptions() on the value to extract the collection | |
461 | * attributes. | |
462 | */ | |
463 | ||
464 | int /* O - Number of options found */ | |
465 | cupsParseOptions( | |
466 | const char *arg, /* I - Argument to parse */ | |
467 | int num_options, /* I - Number of options */ | |
468 | cups_option_t **options) /* O - Options found */ | |
469 | { | |
470 | char *copyarg, /* Copy of input string */ | |
471 | *ptr, /* Pointer into string */ | |
472 | *name, /* Pointer to name */ | |
473 | *value; /* Pointer to value */ | |
474 | ||
475 | ||
476 | if (arg == NULL || options == NULL || num_options < 0) | |
477 | return (0); | |
478 | ||
479 | /* | |
480 | * Make a copy of the argument string and then divide it up... | |
481 | */ | |
482 | ||
483 | copyarg = strdup(arg); | |
484 | ptr = copyarg; | |
485 | ||
486 | /* | |
487 | * Skip leading spaces... | |
488 | */ | |
489 | ||
490 | while (isspace(*ptr & 255)) | |
491 | ptr ++; | |
492 | ||
493 | /* | |
494 | * Loop through the string... | |
495 | */ | |
496 | ||
497 | while (*ptr != '\0') | |
498 | { | |
499 | /* | |
500 | * Get the name up to a SPACE, =, or end-of-string... | |
501 | */ | |
502 | ||
503 | name = ptr; | |
504 | while (!isspace(*ptr & 255) && *ptr != '=' && *ptr != '\0') | |
505 | ptr ++; | |
506 | ||
507 | /* | |
508 | * Avoid an empty name... | |
509 | */ | |
510 | ||
511 | if (ptr == name) | |
512 | break; | |
513 | ||
514 | /* | |
515 | * Skip trailing spaces... | |
516 | */ | |
517 | ||
518 | while (isspace(*ptr & 255)) | |
519 | *ptr++ = '\0'; | |
520 | ||
521 | if (*ptr != '=') | |
522 | { | |
523 | /* | |
524 | * Start of another option... | |
525 | */ | |
526 | ||
527 | if (strncasecmp(name, "no", 2) == 0) | |
528 | num_options = cupsAddOption(name + 2, "false", num_options, | |
529 | options); | |
530 | else | |
531 | num_options = cupsAddOption(name, "true", num_options, options); | |
532 | ||
533 | continue; | |
534 | } | |
535 | ||
536 | /* | |
537 | * Remove = and parse the value... | |
538 | */ | |
539 | ||
540 | *ptr++ = '\0'; | |
541 | ||
542 | if (*ptr == '\'') | |
543 | { | |
544 | /* | |
545 | * Quoted string constant... | |
546 | */ | |
547 | ||
548 | ptr ++; | |
549 | value = ptr; | |
550 | ||
551 | while (*ptr != '\'' && *ptr != '\0') | |
552 | { | |
553 | if (*ptr == '\\') | |
554 | _cups_strcpy(ptr, ptr + 1); | |
555 | ||
556 | ptr ++; | |
557 | } | |
558 | ||
559 | if (*ptr != '\0') | |
560 | *ptr++ = '\0'; | |
561 | } | |
562 | else if (*ptr == '\"') | |
563 | { | |
564 | /* | |
565 | * Double-quoted string constant... | |
566 | */ | |
567 | ||
568 | ptr ++; | |
569 | value = ptr; | |
570 | ||
571 | while (*ptr != '\"' && *ptr != '\0') | |
572 | { | |
573 | if (*ptr == '\\') | |
574 | _cups_strcpy(ptr, ptr + 1); | |
575 | ||
576 | ptr ++; | |
577 | } | |
578 | ||
579 | if (*ptr != '\0') | |
580 | *ptr++ = '\0'; | |
581 | } | |
582 | else if (*ptr == '{') | |
583 | { | |
584 | /* | |
585 | * Collection value... | |
586 | */ | |
587 | ||
588 | int depth; | |
589 | ||
590 | value = ptr; | |
591 | ||
592 | for (depth = 1; *ptr; ptr ++) | |
593 | if (*ptr == '{') | |
594 | depth ++; | |
595 | else if (*ptr == '}') | |
596 | { | |
597 | depth --; | |
598 | if (!depth) | |
599 | { | |
600 | ptr ++; | |
601 | ||
602 | if (*ptr != ',') | |
603 | break; | |
604 | } | |
605 | } | |
606 | else if (*ptr == '\\') | |
607 | _cups_strcpy(ptr, ptr + 1); | |
608 | ||
609 | if (*ptr != '\0') | |
610 | *ptr++ = '\0'; | |
611 | } | |
612 | else | |
613 | { | |
614 | /* | |
615 | * Normal space-delimited string... | |
616 | */ | |
617 | ||
618 | value = ptr; | |
619 | ||
620 | while (!isspace(*ptr & 255) && *ptr != '\0') | |
621 | { | |
622 | if (*ptr == '\\') | |
623 | _cups_strcpy(ptr, ptr + 1); | |
624 | ||
625 | ptr ++; | |
626 | } | |
627 | } | |
628 | ||
629 | /* | |
630 | * Skip trailing whitespace... | |
631 | */ | |
632 | ||
633 | while (isspace(*ptr & 255)) | |
634 | *ptr++ = '\0'; | |
635 | ||
636 | /* | |
637 | * Add the string value... | |
638 | */ | |
639 | ||
640 | num_options = cupsAddOption(name, value, num_options, options); | |
641 | } | |
642 | ||
643 | /* | |
644 | * Free the copy of the argument we made and return the number of options | |
645 | * found. | |
646 | */ | |
647 | ||
648 | free(copyarg); | |
649 | ||
650 | return (num_options); | |
651 | } | |
652 | ||
653 | ||
654 | /* | |
f7deaa1a | 655 | * 'cupsRemoveOption()' - Remove an option from an option array. |
b423cd4c | 656 | * |
657 | * @since CUPS 1.2@ | |
658 | */ | |
659 | ||
660 | int /* O - New number of options */ | |
661 | cupsRemoveOption( | |
662 | const char *name, /* I - Option name */ | |
663 | int num_options, /* I - Current number of options */ | |
664 | cups_option_t **options) /* IO - Options */ | |
665 | { | |
666 | int i; /* Looping var */ | |
667 | cups_option_t *option; /* Current option */ | |
668 | ||
669 | ||
670 | /* | |
671 | * Range check input... | |
672 | */ | |
673 | ||
674 | if (!name || num_options < 1 || !options) | |
675 | return (num_options); | |
676 | ||
677 | /* | |
678 | * Loop for the option... | |
679 | */ | |
680 | ||
681 | for (i = num_options, option = *options; i > 0; i --, option ++) | |
682 | if (!strcasecmp(name, option->name)) | |
683 | break; | |
684 | ||
685 | if (i) | |
686 | { | |
687 | /* | |
688 | * Remove this option from the array... | |
689 | */ | |
690 | ||
691 | num_options --; | |
692 | i --; | |
693 | ||
694 | free(option->name); | |
695 | if (option->value) | |
696 | free(option->value); | |
697 | ||
698 | if (i > 0) | |
f7deaa1a | 699 | memmove(option, option + 1, i * sizeof(cups_option_t)); |
b423cd4c | 700 | } |
701 | ||
702 | /* | |
703 | * Return the new number of options... | |
704 | */ | |
705 | ||
706 | return (num_options); | |
707 | } | |
708 | ||
709 | ||
355e94dc MS |
710 | #ifdef DEBUG |
711 | /* | |
712 | * 'debug_marked()' - Output the marked array to stdout... | |
713 | */ | |
714 | ||
715 | static void | |
716 | debug_marked(ppd_file_t *ppd, /* I - PPD file data */ | |
717 | const char *title) /* I - Title for list */ | |
718 | { | |
719 | ppd_choice_t *c; /* Current choice */ | |
720 | ||
721 | ||
722 | printf("cupsMarkOptions: %s\n", title); | |
723 | ||
724 | for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked); | |
725 | c; | |
726 | c = (ppd_choice_t *)cupsArrayNext(ppd->marked)) | |
727 | printf("cupsMarkOptions: %s=%s\n", c->option->keyword, c->choice); | |
728 | } | |
729 | #endif /* DEBUG */ | |
730 | ||
731 | ||
b423cd4c | 732 | /* |
09a101d6 | 733 | * 'ppd_mark_choices()' - Mark one or more option choices from a string. |
734 | */ | |
735 | ||
736 | static int /* O - 1 if there are conflicts, 0 otherwise */ | |
737 | ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */ | |
738 | const char *options) /* I - "*Option Choice ..." string */ | |
739 | { | |
740 | char option[PPD_MAX_NAME], /* Current option */ | |
741 | choice[PPD_MAX_NAME], /* Current choice */ | |
742 | *ptr; /* Pointer into option or choice */ | |
743 | int conflict = 0; /* Do we have a conflict? */ | |
744 | ||
745 | ||
746 | if (!options) | |
747 | return (0); | |
748 | ||
749 | /* | |
750 | * Read all of the "*Option Choice" pairs from the string, marking PPD | |
751 | * options as we go... | |
752 | */ | |
753 | ||
754 | while (*options) | |
755 | { | |
756 | /* | |
757 | * Skip leading whitespace... | |
758 | */ | |
759 | ||
760 | while (isspace(*options & 255)) | |
761 | options ++; | |
762 | ||
763 | if (*options != '*') | |
764 | break; | |
765 | ||
766 | /* | |
767 | * Get the option name... | |
768 | */ | |
769 | ||
770 | options ++; | |
771 | ptr = option; | |
772 | while (*options && !isspace(*options & 255) && | |
773 | ptr < (option + sizeof(option) - 1)) | |
774 | *ptr++ = *options++; | |
775 | ||
776 | if (ptr == option) | |
777 | break; | |
778 | ||
779 | *ptr = '\0'; | |
780 | ||
781 | /* | |
782 | * Get the choice... | |
783 | */ | |
784 | ||
785 | while (isspace(*options & 255)) | |
786 | options ++; | |
787 | ||
788 | if (!*options) | |
789 | break; | |
790 | ||
791 | ptr = choice; | |
792 | while (*options && !isspace(*options & 255) && | |
793 | ptr < (choice + sizeof(choice) - 1)) | |
794 | *ptr++ = *options++; | |
795 | ||
796 | *ptr = '\0'; | |
797 | ||
798 | /* | |
799 | * Mark the option... | |
800 | */ | |
801 | ||
802 | if (ppdMarkOption(ppd, option, choice)) | |
803 | conflict = 1; | |
804 | } | |
805 | ||
806 | /* | |
807 | * Return whether we had any conflicts... | |
808 | */ | |
809 | ||
810 | return (conflict); | |
811 | } | |
812 | ||
813 | ||
814 | /* | |
355e94dc | 815 | * End of "$Id: options.c 6703 2007-07-20 21:28:10Z mike $". |
ef416fc2 | 816 | */ |