]>
git.ipfire.org Git - thirdparty/cups.git/blob - cups/options.c
2 * "$Id: options.c 6601 2007-06-22 21:27:22Z mike $"
4 * Option routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2007 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * cupsAddOption() - Add an option to an option array.
29 * cupsFreeOptions() - Free all memory used by options.
30 * cupsGetOption() - Get an option value.
31 * cupsMarkOptions() - Mark command-line options in a PPD file.
32 * cupsParseOptions() - Parse options from a command-line argument.
33 * cupsRemoveOptions() - Remove an option from an option array.
34 * ppd_mark_choices() - Mark one or more option choices from a string.
38 * Include necessary headers...
52 static int ppd_mark_choices(ppd_file_t
*ppd
, const char *options
);
56 * 'cupsAddOption()' - Add an option to an option array.
59 int /* O - Number of options */
60 cupsAddOption(const char *name
, /* I - Name of option */
61 const char *value
, /* I - Value of option */
62 int num_options
,/* I - Number of options */
63 cups_option_t
**options
) /* IO - Pointer to options */
65 int i
; /* Looping var */
66 cups_option_t
*temp
; /* Pointer to new option */
69 if (name
== NULL
|| !name
[0] || value
== NULL
||
70 options
== NULL
|| num_options
< 0)
74 * Look for an existing option with the same name...
77 for (i
= 0, temp
= *options
; i
< num_options
; i
++, temp
++)
78 if (strcasecmp(temp
->name
, name
) == 0)
84 * No matching option name...
88 temp
= (cups_option_t
*)malloc(sizeof(cups_option_t
));
90 temp
= (cups_option_t
*)realloc(*options
, sizeof(cups_option_t
) *
98 temp
->name
= strdup(name
);
104 * Match found; free the old value...
110 temp
->value
= strdup(value
);
112 return (num_options
);
117 * 'cupsFreeOptions()' - Free all memory used by options.
122 int num_options
, /* I - Number of options */
123 cups_option_t
*options
) /* I - Pointer to options */
125 int i
; /* Looping var */
128 if (num_options
<= 0 || options
== NULL
)
131 for (i
= 0; i
< num_options
; i
++)
133 free(options
[i
].name
);
134 free(options
[i
].value
);
142 * 'cupsGetOption()' - Get an option value.
145 const char * /* O - Option value or NULL */
146 cupsGetOption(const char *name
, /* I - Name of option */
147 int num_options
,/* I - Number of options */
148 cups_option_t
*options
) /* I - Options */
150 int i
; /* Looping var */
153 if (name
== NULL
|| num_options
<= 0 || options
== NULL
)
156 for (i
= 0; i
< num_options
; i
++)
157 if (strcasecmp(options
[i
].name
, name
) == 0)
158 return (options
[i
].value
);
165 * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
168 int /* O - 1 if conflicting */
170 ppd_file_t
*ppd
, /* I - PPD file */
171 int num_options
, /* I - Number of options */
172 cups_option_t
*options
) /* I - Options */
174 int i
, j
, k
; /* Looping vars */
175 int conflict
; /* Option conflicts */
176 char *val
, /* Pointer into value */
177 *ptr
, /* Pointer into string */
178 s
[255]; /* Temporary string */
179 const char *page_size
; /* PageSize option */
180 cups_option_t
*optptr
; /* Current option */
181 ppd_option_t
*option
; /* PPD option */
182 ppd_attr_t
*attr
; /* PPD attribute */
183 static const char * const duplex_options
[] =
184 { /* Duplex option names */
185 "Duplex", /* Adobe */
186 "EFDuplex", /* EFI */
187 "EFDuplexing", /* EFI */
188 "KD03Duplex", /* Kodak */
189 "JCLDuplex" /* Samsung */
191 static const char * const duplex_one
[] =
192 { /* one-sided names */
196 static const char * const duplex_two_long
[] =
197 { /* two-sided-long-edge names */
198 "DuplexNoTumble", /* Adobe */
199 "LongEdge", /* EFI */
202 static const char * const duplex_two_short
[] =
203 { /* two-sided-long-edge names */
204 "DuplexTumble", /* Adobe */
205 "ShortEdge", /* EFI */
214 if (ppd
== NULL
|| num_options
<= 0 || options
== NULL
)
223 for (i
= num_options
, optptr
= options
; i
> 0; i
--, optptr
++)
224 if (!strcasecmp(optptr
->name
, "media"))
227 * Loop through the option string, separating it at commas and
228 * marking each individual option as long as the corresponding
229 * PPD option (PageSize, InputSlot, etc.) is not also set.
231 * For PageSize, we also check for an empty option value since
232 * some versions of MacOS X use it to specify auto-selection
233 * of the media based solely on the size.
236 page_size
= cupsGetOption("PageSize", num_options
, options
);
238 for (val
= optptr
->value
; *val
;)
241 * Extract the sub-option from the string...
244 for (ptr
= s
; *val
&& *val
!= ',' && (ptr
- s
) < (sizeof(s
) - 1);)
255 if (!page_size
|| !page_size
[0])
256 if (ppdMarkOption(ppd
, "PageSize", s
))
259 if (cupsGetOption("InputSlot", num_options
, options
) == NULL
)
260 if (ppdMarkOption(ppd
, "InputSlot", s
))
263 if (cupsGetOption("MediaType", num_options
, options
) == NULL
)
264 if (ppdMarkOption(ppd
, "MediaType", s
))
267 if (cupsGetOption("EFMediaType", num_options
, options
) == NULL
)
268 if (ppdMarkOption(ppd
, "EFMediaType", s
))
271 if (cupsGetOption("EFMediaQualityMode", num_options
, options
) == NULL
)
272 if (ppdMarkOption(ppd
, "EFMediaQualityMode", s
)) /* EFI */
275 if (strcasecmp(s
, "manual") == 0 &&
276 cupsGetOption("ManualFeed", num_options
, options
) == NULL
)
277 if (ppdMarkOption(ppd
, "ManualFeed", "True"))
281 else if (!strcasecmp(optptr
->name
, "sides"))
283 for (j
= 0; j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])); j
++)
284 if (cupsGetOption(duplex_options
[j
], num_options
, options
) != NULL
)
287 if (j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])))
290 * Don't override the PPD option with the IPP attribute...
296 if (!strcasecmp(optptr
->value
, "one-sided"))
299 * Mark the appropriate duplex option for one-sided output...
302 for (j
= 0; j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])); j
++)
303 if ((option
= ppdFindOption(ppd
, duplex_options
[j
])) != NULL
)
306 if (j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])))
308 for (k
= 0; k
< (int)(sizeof(duplex_one
) / sizeof(duplex_one
[0])); k
++)
309 if (ppdFindChoice(option
, duplex_one
[k
]))
311 if (ppdMarkOption(ppd
, duplex_options
[j
], duplex_one
[k
]))
318 else if (!strcasecmp(optptr
->value
, "two-sided-long-edge"))
321 * Mark the appropriate duplex option for two-sided-long-edge output...
324 for (j
= 0; j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])); j
++)
325 if ((option
= ppdFindOption(ppd
, duplex_options
[j
])) != NULL
)
328 if (j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])))
330 for (k
= 0; k
< (int)(sizeof(duplex_two_long
) / sizeof(duplex_two_long
[0])); k
++)
331 if (ppdFindChoice(option
, duplex_two_long
[k
]))
333 if (ppdMarkOption(ppd
, duplex_options
[j
], duplex_two_long
[k
]))
340 else if (!strcasecmp(optptr
->value
, "two-sided-short-edge"))
343 * Mark the appropriate duplex option for two-sided-short-edge output...
346 for (j
= 0; j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])); j
++)
347 if ((option
= ppdFindOption(ppd
, duplex_options
[j
])) != NULL
)
350 if (j
< (int)(sizeof(duplex_options
) / sizeof(duplex_options
[0])))
352 for (k
= 0; k
< (int)(sizeof(duplex_two_short
) / sizeof(duplex_two_short
[0])); k
++)
353 if (ppdFindChoice(option
, duplex_two_short
[k
]))
355 if (ppdMarkOption(ppd
, duplex_options
[j
], duplex_two_short
[k
]))
363 else if (!strcasecmp(optptr
->name
, "resolution") ||
364 !strcasecmp(optptr
->name
, "printer-resolution"))
366 if (ppdMarkOption(ppd
, "Resolution", optptr
->value
))
368 if (ppdMarkOption(ppd
, "SetResolution", optptr
->value
))
369 /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
371 if (ppdMarkOption(ppd
, "JCLResolution", optptr
->value
)) /* HP */
373 if (ppdMarkOption(ppd
, "CNRes_PGP", optptr
->value
)) /* Canon */
376 else if (!strcasecmp(optptr
->name
, "output-bin"))
378 if (!cupsGetOption("OutputBin", num_options
, options
))
379 if (ppdMarkOption(ppd
, "OutputBin", optptr
->value
))
382 else if (!strcasecmp(optptr
->name
, "multiple-document-handling"))
384 if (!cupsGetOption("Collate", num_options
, options
) &&
385 ppdFindOption(ppd
, "Collate"))
387 if (strcasecmp(optptr
->value
, "separate-documents-uncollated-copies"))
389 if (ppdMarkOption(ppd
, "Collate", "True"))
394 if (ppdMarkOption(ppd
, "Collate", "False"))
399 else if (!strcasecmp(optptr
->name
, "finishings"))
402 * Lookup cupsIPPFinishings attributes for each value...
405 for (ptr
= optptr
->value
; *ptr
;)
408 * Get the next finishings number...
411 if (!isdigit(*ptr
& 255))
414 if ((j
= strtol(ptr
, &ptr
, 10)) < 3)
418 * Skip separator as needed...
425 * Look it up in the PPD file...
430 if ((attr
= ppdFindAttr(ppd
, "cupsIPPFinishings", s
)) == NULL
)
434 * Apply "*Option Choice" settings from the attribute value...
437 if (ppd_mark_choices(ppd
, attr
->value
))
441 else if (!strcasecmp(optptr
->name
, "mirror") &&
442 ppdMarkOption(ppd
, "MirrorPrint", optptr
->value
))
444 else if (ppdMarkOption(ppd
, optptr
->name
, optptr
->value
))
452 * 'cupsParseOptions()' - Parse options from a command-line argument.
454 * This function converts space-delimited name/value pairs according
455 * to the PAPI text option ABNF specification. Collection values
456 * ("name={a=... b=... c=...}") are stored with the curley brackets
457 * intact - use cupsParseOptions() on the value to extract the collection
461 int /* O - Number of options found */
463 const char *arg
, /* I - Argument to parse */
464 int num_options
, /* I - Number of options */
465 cups_option_t
**options
) /* O - Options found */
467 char *copyarg
, /* Copy of input string */
468 *ptr
, /* Pointer into string */
469 *name
, /* Pointer to name */
470 *value
; /* Pointer to value */
473 if (arg
== NULL
|| options
== NULL
|| num_options
< 0)
477 * Make a copy of the argument string and then divide it up...
480 copyarg
= strdup(arg
);
484 * Skip leading spaces...
487 while (isspace(*ptr
& 255))
491 * Loop through the string...
497 * Get the name up to a SPACE, =, or end-of-string...
501 while (!isspace(*ptr
& 255) && *ptr
!= '=' && *ptr
!= '\0')
505 * Avoid an empty name...
512 * Skip trailing spaces...
515 while (isspace(*ptr
& 255))
521 * Start of another option...
524 if (strncasecmp(name
, "no", 2) == 0)
525 num_options
= cupsAddOption(name
+ 2, "false", num_options
,
528 num_options
= cupsAddOption(name
, "true", num_options
, options
);
534 * Remove = and parse the value...
542 * Quoted string constant...
548 while (*ptr
!= '\'' && *ptr
!= '\0')
551 _cups_strcpy(ptr
, ptr
+ 1);
559 else if (*ptr
== '\"')
562 * Double-quoted string constant...
568 while (*ptr
!= '\"' && *ptr
!= '\0')
571 _cups_strcpy(ptr
, ptr
+ 1);
579 else if (*ptr
== '{')
582 * Collection value...
589 for (depth
= 1; *ptr
; ptr
++)
592 else if (*ptr
== '}')
603 else if (*ptr
== '\\')
604 _cups_strcpy(ptr
, ptr
+ 1);
612 * Normal space-delimited string...
617 while (!isspace(*ptr
& 255) && *ptr
!= '\0')
620 _cups_strcpy(ptr
, ptr
+ 1);
627 * Skip trailing whitespace...
630 while (isspace(*ptr
& 255))
634 * Add the string value...
637 num_options
= cupsAddOption(name
, value
, num_options
, options
);
641 * Free the copy of the argument we made and return the number of options
647 return (num_options
);
652 * 'cupsRemoveOption()' - Remove an option from an option array.
657 int /* O - New number of options */
659 const char *name
, /* I - Option name */
660 int num_options
, /* I - Current number of options */
661 cups_option_t
**options
) /* IO - Options */
663 int i
; /* Looping var */
664 cups_option_t
*option
; /* Current option */
668 * Range check input...
671 if (!name
|| num_options
< 1 || !options
)
672 return (num_options
);
675 * Loop for the option...
678 for (i
= num_options
, option
= *options
; i
> 0; i
--, option
++)
679 if (!strcasecmp(name
, option
->name
))
685 * Remove this option from the array...
696 memmove(option
, option
+ 1, i
* sizeof(cups_option_t
));
700 * Return the new number of options...
703 return (num_options
);
708 * 'ppd_mark_choices()' - Mark one or more option choices from a string.
711 static int /* O - 1 if there are conflicts, 0 otherwise */
712 ppd_mark_choices(ppd_file_t
*ppd
, /* I - PPD file */
713 const char *options
) /* I - "*Option Choice ..." string */
715 char option
[PPD_MAX_NAME
], /* Current option */
716 choice
[PPD_MAX_NAME
], /* Current choice */
717 *ptr
; /* Pointer into option or choice */
718 int conflict
= 0; /* Do we have a conflict? */
725 * Read all of the "*Option Choice" pairs from the string, marking PPD
726 * options as we go...
732 * Skip leading whitespace...
735 while (isspace(*options
& 255))
742 * Get the option name...
747 while (*options
&& !isspace(*options
& 255) &&
748 ptr
< (option
+ sizeof(option
) - 1))
760 while (isspace(*options
& 255))
767 while (*options
&& !isspace(*options
& 255) &&
768 ptr
< (choice
+ sizeof(choice
) - 1))
777 if (ppdMarkOption(ppd
, option
, choice
))
782 * Return whether we had any conflicts...
790 * End of "$Id: options.c 6601 2007-06-22 21:27:22Z mike $".