]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/options.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / options.c
CommitLineData
ef416fc2 1/*
f7deaa1a 2 * "$Id: options.c 6310 2007-02-27 14:20:39Z mike $"
ef416fc2 3 *
4 * Option routines for the Common UNIX Printing System (CUPS).
5 *
f7deaa1a 6 * Copyright 1997-2007 by Easy Software Products.
ef416fc2 7 *
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
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
b423cd4c 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.
ef416fc2 34 */
35
36/*
37 * Include necessary headers...
38 */
39
40#include "cups.h"
41#include <stdlib.h>
42#include <ctype.h>
43#include "string.h"
44#include "debug.h"
45
46
47/*
48 * 'cupsAddOption()' - Add an option to an option array.
49 */
50
51int /* O - Number of options */
52cupsAddOption(const char *name, /* I - Name of option */
53 const char *value, /* I - Value of option */
54 int num_options,/* I - Number of options */
55 cups_option_t **options) /* IO - Pointer to options */
56{
57 int i; /* Looping var */
58 cups_option_t *temp; /* Pointer to new option */
59
60
61 if (name == NULL || !name[0] || value == NULL ||
62 options == NULL || num_options < 0)
63 return (num_options);
64
65 /*
66 * Look for an existing option with the same name...
67 */
68
69 for (i = 0, temp = *options; i < num_options; i ++, temp ++)
70 if (strcasecmp(temp->name, name) == 0)
71 break;
72
73 if (i >= num_options)
74 {
75 /*
76 * No matching option name...
77 */
78
79 if (num_options == 0)
80 temp = (cups_option_t *)malloc(sizeof(cups_option_t));
81 else
82 temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) *
83 (num_options + 1));
84
85 if (temp == NULL)
86 return (0);
87
88 *options = temp;
89 temp += num_options;
90 temp->name = strdup(name);
91 num_options ++;
92 }
93 else
94 {
95 /*
96 * Match found; free the old value...
97 */
98
99 free(temp->value);
100 }
101
102 temp->value = strdup(value);
103
104 return (num_options);
105}
106
107
108/*
109 * 'cupsFreeOptions()' - Free all memory used by options.
110 */
111
112void
113cupsFreeOptions(
114 int num_options, /* I - Number of options */
115 cups_option_t *options) /* I - Pointer to options */
116{
117 int i; /* Looping var */
118
119
120 if (num_options <= 0 || options == NULL)
121 return;
122
123 for (i = 0; i < num_options; i ++)
124 {
125 free(options[i].name);
126 free(options[i].value);
127 }
128
129 free(options);
130}
131
132
133/*
134 * 'cupsGetOption()' - Get an option value.
135 */
136
137const char * /* O - Option value or NULL */
138cupsGetOption(const char *name, /* I - Name of option */
139 int num_options,/* I - Number of options */
140 cups_option_t *options) /* I - Options */
141{
142 int i; /* Looping var */
143
144
145 if (name == NULL || num_options <= 0 || options == NULL)
146 return (NULL);
147
148 for (i = 0; i < num_options; i ++)
149 if (strcasecmp(options[i].name, name) == 0)
150 return (options[i].value);
151
152 return (NULL);
153}
154
155
ef416fc2 156/*
157 * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
158 */
159
160int /* O - 1 if conflicting */
161cupsMarkOptions(
162 ppd_file_t *ppd, /* I - PPD file */
163 int num_options, /* I - Number of options */
164 cups_option_t *options) /* I - Options */
165{
166 int i, j, k; /* Looping vars */
167 int conflict; /* Option conflicts */
168 char *val, /* Pointer into value */
169 *ptr, /* Pointer into string */
170 s[255]; /* Temporary string */
fa73b229 171 const char *page_size; /* PageSize option */
ef416fc2 172 cups_option_t *optptr; /* Current option */
173 ppd_option_t *option; /* PPD option */
174 static const char * const duplex_options[] =
175 { /* Duplex option names */
176 "Duplex", /* Adobe */
177 "EFDuplex", /* EFI */
178 "EFDuplexing", /* EFI */
179 "KD03Duplex", /* Kodak */
180 "JCLDuplex" /* Samsung */
181 };
182 static const char * const duplex_one[] =
183 { /* one-sided names */
184 "None",
185 "False"
186 };
187 static const char * const duplex_two_long[] =
188 { /* two-sided-long-edge names */
189 "DuplexNoTumble", /* Adobe */
190 "LongEdge", /* EFI */
191 "Top" /* EFI */
192 };
193 static const char * const duplex_two_short[] =
194 { /* two-sided-long-edge names */
195 "DuplexTumble", /* Adobe */
196 "ShortEdge", /* EFI */
197 "Bottom" /* EFI */
198 };
199
200
201 /*
202 * Check arguments...
203 */
204
205 if (ppd == NULL || num_options <= 0 || options == NULL)
206 return (0);
207
208 /*
209 * Mark options...
210 */
211
fa73b229 212 conflict = 0;
ef416fc2 213
214 for (i = num_options, optptr = options; i > 0; i --, optptr ++)
215 if (!strcasecmp(optptr->name, "media"))
216 {
217 /*
218 * Loop through the option string, separating it at commas and
fa73b229 219 * marking each individual option as long as the corresponding
220 * PPD option (PageSize, InputSlot, etc.) is not also set.
221 *
222 * For PageSize, we also check for an empty option value since
223 * some versions of MacOS X use it to specify auto-selection
224 * of the media based solely on the size.
ef416fc2 225 */
226
fa73b229 227 page_size = cupsGetOption("PageSize", num_options, options);
228
ef416fc2 229 for (val = optptr->value; *val;)
230 {
231 /*
232 * Extract the sub-option from the string...
233 */
234
235 for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
236 *ptr++ = *val++;
237 *ptr++ = '\0';
238
239 if (*val == ',')
240 val ++;
241
242 /*
243 * Mark it...
244 */
245
fa73b229 246 if (!page_size || !page_size[0])
ef416fc2 247 if (ppdMarkOption(ppd, "PageSize", s))
248 conflict = 1;
249
250 if (cupsGetOption("InputSlot", num_options, options) == NULL)
251 if (ppdMarkOption(ppd, "InputSlot", s))
252 conflict = 1;
253
254 if (cupsGetOption("MediaType", num_options, options) == NULL)
255 if (ppdMarkOption(ppd, "MediaType", s))
256 conflict = 1;
257
258 if (cupsGetOption("EFMediaType", num_options, options) == NULL)
259 if (ppdMarkOption(ppd, "EFMediaType", s))
260 conflict = 1;
261
262 if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL)
263 if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */
264 conflict = 1;
265
266 if (strcasecmp(s, "manual") == 0 &&
267 cupsGetOption("ManualFeed", num_options, options) == NULL)
268 if (ppdMarkOption(ppd, "ManualFeed", "True"))
269 conflict = 1;
270 }
271 }
272 else if (!strcasecmp(optptr->name, "sides"))
273 {
274 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
275 if (cupsGetOption(duplex_options[j], num_options, options) != NULL)
276 break;
277
278 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
279 {
280 /*
281 * Don't override the PPD option with the IPP attribute...
282 */
283
284 continue;
285 }
286
287 if (!strcasecmp(optptr->value, "one-sided"))
288 {
289 /*
290 * Mark the appropriate duplex option for one-sided output...
291 */
292
293 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
294 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
295 break;
296
297 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
298 {
299 for (k = 0; k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); k ++)
300 if (ppdFindChoice(option, duplex_one[k]))
301 {
302 if (ppdMarkOption(ppd, duplex_options[j], duplex_one[k]))
303 conflict = 1;
304
305 break;
306 }
307 }
308 }
309 else if (!strcasecmp(optptr->value, "two-sided-long-edge"))
310 {
311 /*
312 * Mark the appropriate duplex option for two-sided-long-edge output...
313 */
314
315 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
316 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
317 break;
318
319 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
320 {
321 for (k = 0; k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); k ++)
322 if (ppdFindChoice(option, duplex_two_long[k]))
323 {
324 if (ppdMarkOption(ppd, duplex_options[j], duplex_two_long[k]))
325 conflict = 1;
326
327 break;
328 }
329 }
330 }
331 else if (!strcasecmp(optptr->value, "two-sided-short-edge"))
332 {
333 /*
334 * Mark the appropriate duplex option for two-sided-short-edge output...
335 */
336
337 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
338 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
339 break;
340
341 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
342 {
343 for (k = 0; k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); k ++)
344 if (ppdFindChoice(option, duplex_two_short[k]))
345 {
346 if (ppdMarkOption(ppd, duplex_options[j], duplex_two_short[k]))
347 conflict = 1;
348
349 break;
350 }
351 }
352 }
353 }
354 else if (!strcasecmp(optptr->name, "resolution") ||
355 !strcasecmp(optptr->name, "printer-resolution"))
356 {
357 if (ppdMarkOption(ppd, "Resolution", optptr->value))
358 conflict = 1;
359 if (ppdMarkOption(ppd, "SetResolution", optptr->value))
360 /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
361 conflict = 1;
362 if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */
363 conflict = 1;
364 if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */
365 conflict = 1;
366 }
367 else if (!strcasecmp(optptr->name, "output-bin"))
368 {
f7deaa1a 369 if (!cupsGetOption("OutputBin", num_options, options))
ef416fc2 370 if (ppdMarkOption(ppd, "OutputBin", optptr->value))
371 conflict = 1;
372 }
f7deaa1a 373 else if (!strcasecmp(optptr->name, "multiple-document-handling"))
374 {
375 if (!cupsGetOption("Collate", num_options, options) &&
376 ppdFindOption(ppd, "Collate"))
377 {
378 if (strcasecmp(optptr->value, "separate-documents-uncollated-copies"))
379 {
380 if (ppdMarkOption(ppd, "Collate", "True"))
381 conflict = 1;
382 }
383 else
384 {
385 if (ppdMarkOption(ppd, "Collate", "False"))
386 conflict = 1;
387 }
388 }
389 }
ef416fc2 390 else if (ppdMarkOption(ppd, optptr->name, optptr->value))
391 conflict = 1;
392
393 return (conflict);
394}
395
396
397/*
b423cd4c 398 * 'cupsParseOptions()' - Parse options from a command-line argument.
399 *
400 * This function converts space-delimited name/value pairs according
401 * to the PAPI text option ABNF specification. Collection values
402 * ("name={a=... b=... c=...}") are stored with the curley brackets
403 * intact - use cupsParseOptions() on the value to extract the collection
404 * attributes.
405 */
406
407int /* O - Number of options found */
408cupsParseOptions(
409 const char *arg, /* I - Argument to parse */
410 int num_options, /* I - Number of options */
411 cups_option_t **options) /* O - Options found */
412{
413 char *copyarg, /* Copy of input string */
414 *ptr, /* Pointer into string */
415 *name, /* Pointer to name */
416 *value; /* Pointer to value */
417
418
419 if (arg == NULL || options == NULL || num_options < 0)
420 return (0);
421
422 /*
423 * Make a copy of the argument string and then divide it up...
424 */
425
426 copyarg = strdup(arg);
427 ptr = copyarg;
428
429 /*
430 * Skip leading spaces...
431 */
432
433 while (isspace(*ptr & 255))
434 ptr ++;
435
436 /*
437 * Loop through the string...
438 */
439
440 while (*ptr != '\0')
441 {
442 /*
443 * Get the name up to a SPACE, =, or end-of-string...
444 */
445
446 name = ptr;
447 while (!isspace(*ptr & 255) && *ptr != '=' && *ptr != '\0')
448 ptr ++;
449
450 /*
451 * Avoid an empty name...
452 */
453
454 if (ptr == name)
455 break;
456
457 /*
458 * Skip trailing spaces...
459 */
460
461 while (isspace(*ptr & 255))
462 *ptr++ = '\0';
463
464 if (*ptr != '=')
465 {
466 /*
467 * Start of another option...
468 */
469
470 if (strncasecmp(name, "no", 2) == 0)
471 num_options = cupsAddOption(name + 2, "false", num_options,
472 options);
473 else
474 num_options = cupsAddOption(name, "true", num_options, options);
475
476 continue;
477 }
478
479 /*
480 * Remove = and parse the value...
481 */
482
483 *ptr++ = '\0';
484
485 if (*ptr == '\'')
486 {
487 /*
488 * Quoted string constant...
489 */
490
491 ptr ++;
492 value = ptr;
493
494 while (*ptr != '\'' && *ptr != '\0')
495 {
496 if (*ptr == '\\')
497 _cups_strcpy(ptr, ptr + 1);
498
499 ptr ++;
500 }
501
502 if (*ptr != '\0')
503 *ptr++ = '\0';
504 }
505 else if (*ptr == '\"')
506 {
507 /*
508 * Double-quoted string constant...
509 */
510
511 ptr ++;
512 value = ptr;
513
514 while (*ptr != '\"' && *ptr != '\0')
515 {
516 if (*ptr == '\\')
517 _cups_strcpy(ptr, ptr + 1);
518
519 ptr ++;
520 }
521
522 if (*ptr != '\0')
523 *ptr++ = '\0';
524 }
525 else if (*ptr == '{')
526 {
527 /*
528 * Collection value...
529 */
530
531 int depth;
532
533 value = ptr;
534
535 for (depth = 1; *ptr; ptr ++)
536 if (*ptr == '{')
537 depth ++;
538 else if (*ptr == '}')
539 {
540 depth --;
541 if (!depth)
542 {
543 ptr ++;
544
545 if (*ptr != ',')
546 break;
547 }
548 }
549 else if (*ptr == '\\')
550 _cups_strcpy(ptr, ptr + 1);
551
552 if (*ptr != '\0')
553 *ptr++ = '\0';
554 }
555 else
556 {
557 /*
558 * Normal space-delimited string...
559 */
560
561 value = ptr;
562
563 while (!isspace(*ptr & 255) && *ptr != '\0')
564 {
565 if (*ptr == '\\')
566 _cups_strcpy(ptr, ptr + 1);
567
568 ptr ++;
569 }
570 }
571
572 /*
573 * Skip trailing whitespace...
574 */
575
576 while (isspace(*ptr & 255))
577 *ptr++ = '\0';
578
579 /*
580 * Add the string value...
581 */
582
583 num_options = cupsAddOption(name, value, num_options, options);
584 }
585
586 /*
587 * Free the copy of the argument we made and return the number of options
588 * found.
589 */
590
591 free(copyarg);
592
593 return (num_options);
594}
595
596
597/*
f7deaa1a 598 * 'cupsRemoveOption()' - Remove an option from an option array.
b423cd4c 599 *
600 * @since CUPS 1.2@
601 */
602
603int /* O - New number of options */
604cupsRemoveOption(
605 const char *name, /* I - Option name */
606 int num_options, /* I - Current number of options */
607 cups_option_t **options) /* IO - Options */
608{
609 int i; /* Looping var */
610 cups_option_t *option; /* Current option */
611
612
613 /*
614 * Range check input...
615 */
616
617 if (!name || num_options < 1 || !options)
618 return (num_options);
619
620 /*
621 * Loop for the option...
622 */
623
624 for (i = num_options, option = *options; i > 0; i --, option ++)
625 if (!strcasecmp(name, option->name))
626 break;
627
628 if (i)
629 {
630 /*
631 * Remove this option from the array...
632 */
633
634 num_options --;
635 i --;
636
637 free(option->name);
638 if (option->value)
639 free(option->value);
640
641 if (i > 0)
f7deaa1a 642 memmove(option, option + 1, i * sizeof(cups_option_t));
b423cd4c 643 }
644
645 /*
646 * Return the new number of options...
647 */
648
649 return (num_options);
650}
651
652
653/*
f7deaa1a 654 * End of "$Id: options.c 6310 2007-02-27 14:20:39Z mike $".
ef416fc2 655 */