]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/options.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / options.c
1 /*
2 * "$Id: options.c 5151 2006-02-22 22:43:17Z mike $"
3 *
4 * Option routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
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 *
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 */
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
51 int /* O - Number of options */
52 cupsAddOption(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
112 void
113 cupsFreeOptions(
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
137 const char * /* O - Option value or NULL */
138 cupsGetOption(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
156 /*
157 * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
158 */
159
160 int /* O - 1 if conflicting */
161 cupsMarkOptions(
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 */
171 const char *page_size; /* PageSize option */
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
212 conflict = 0;
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
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.
225 */
226
227 page_size = cupsGetOption("PageSize", num_options, options);
228
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
246 if (!page_size || !page_size[0])
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 {
369 if (cupsGetOption("OutputBin", num_options, options) == NULL)
370 if (ppdMarkOption(ppd, "OutputBin", optptr->value))
371 conflict = 1;
372 }
373 else if (ppdMarkOption(ppd, optptr->name, optptr->value))
374 conflict = 1;
375
376 return (conflict);
377 }
378
379
380 /*
381 * 'cupsParseOptions()' - Parse options from a command-line argument.
382 *
383 * This function converts space-delimited name/value pairs according
384 * to the PAPI text option ABNF specification. Collection values
385 * ("name={a=... b=... c=...}") are stored with the curley brackets
386 * intact - use cupsParseOptions() on the value to extract the collection
387 * attributes.
388 */
389
390 int /* O - Number of options found */
391 cupsParseOptions(
392 const char *arg, /* I - Argument to parse */
393 int num_options, /* I - Number of options */
394 cups_option_t **options) /* O - Options found */
395 {
396 char *copyarg, /* Copy of input string */
397 *ptr, /* Pointer into string */
398 *name, /* Pointer to name */
399 *value; /* Pointer to value */
400
401
402 if (arg == NULL || options == NULL || num_options < 0)
403 return (0);
404
405 /*
406 * Make a copy of the argument string and then divide it up...
407 */
408
409 copyarg = strdup(arg);
410 ptr = copyarg;
411
412 /*
413 * Skip leading spaces...
414 */
415
416 while (isspace(*ptr & 255))
417 ptr ++;
418
419 /*
420 * Loop through the string...
421 */
422
423 while (*ptr != '\0')
424 {
425 /*
426 * Get the name up to a SPACE, =, or end-of-string...
427 */
428
429 name = ptr;
430 while (!isspace(*ptr & 255) && *ptr != '=' && *ptr != '\0')
431 ptr ++;
432
433 /*
434 * Avoid an empty name...
435 */
436
437 if (ptr == name)
438 break;
439
440 /*
441 * Skip trailing spaces...
442 */
443
444 while (isspace(*ptr & 255))
445 *ptr++ = '\0';
446
447 if (*ptr != '=')
448 {
449 /*
450 * Start of another option...
451 */
452
453 if (strncasecmp(name, "no", 2) == 0)
454 num_options = cupsAddOption(name + 2, "false", num_options,
455 options);
456 else
457 num_options = cupsAddOption(name, "true", num_options, options);
458
459 continue;
460 }
461
462 /*
463 * Remove = and parse the value...
464 */
465
466 *ptr++ = '\0';
467
468 if (*ptr == '\'')
469 {
470 /*
471 * Quoted string constant...
472 */
473
474 ptr ++;
475 value = ptr;
476
477 while (*ptr != '\'' && *ptr != '\0')
478 {
479 if (*ptr == '\\')
480 _cups_strcpy(ptr, ptr + 1);
481
482 ptr ++;
483 }
484
485 if (*ptr != '\0')
486 *ptr++ = '\0';
487 }
488 else if (*ptr == '\"')
489 {
490 /*
491 * Double-quoted string constant...
492 */
493
494 ptr ++;
495 value = ptr;
496
497 while (*ptr != '\"' && *ptr != '\0')
498 {
499 if (*ptr == '\\')
500 _cups_strcpy(ptr, ptr + 1);
501
502 ptr ++;
503 }
504
505 if (*ptr != '\0')
506 *ptr++ = '\0';
507 }
508 else if (*ptr == '{')
509 {
510 /*
511 * Collection value...
512 */
513
514 int depth;
515
516 value = ptr;
517
518 for (depth = 1; *ptr; ptr ++)
519 if (*ptr == '{')
520 depth ++;
521 else if (*ptr == '}')
522 {
523 depth --;
524 if (!depth)
525 {
526 ptr ++;
527
528 if (*ptr != ',')
529 break;
530 }
531 }
532 else if (*ptr == '\\')
533 _cups_strcpy(ptr, ptr + 1);
534
535 if (*ptr != '\0')
536 *ptr++ = '\0';
537 }
538 else
539 {
540 /*
541 * Normal space-delimited string...
542 */
543
544 value = ptr;
545
546 while (!isspace(*ptr & 255) && *ptr != '\0')
547 {
548 if (*ptr == '\\')
549 _cups_strcpy(ptr, ptr + 1);
550
551 ptr ++;
552 }
553 }
554
555 /*
556 * Skip trailing whitespace...
557 */
558
559 while (isspace(*ptr & 255))
560 *ptr++ = '\0';
561
562 /*
563 * Add the string value...
564 */
565
566 num_options = cupsAddOption(name, value, num_options, options);
567 }
568
569 /*
570 * Free the copy of the argument we made and return the number of options
571 * found.
572 */
573
574 free(copyarg);
575
576 return (num_options);
577 }
578
579
580 /*
581 * 'cupsRemoveOptions()' - Remove an option from an option array.
582 *
583 * @since CUPS 1.2@
584 */
585
586 int /* O - New number of options */
587 cupsRemoveOption(
588 const char *name, /* I - Option name */
589 int num_options, /* I - Current number of options */
590 cups_option_t **options) /* IO - Options */
591 {
592 int i; /* Looping var */
593 cups_option_t *option; /* Current option */
594
595
596 /*
597 * Range check input...
598 */
599
600 if (!name || num_options < 1 || !options)
601 return (num_options);
602
603 /*
604 * Loop for the option...
605 */
606
607 for (i = num_options, option = *options; i > 0; i --, option ++)
608 if (!strcasecmp(name, option->name))
609 break;
610
611 if (i)
612 {
613 /*
614 * Remove this option from the array...
615 */
616
617 num_options --;
618 i --;
619
620 free(option->name);
621 if (option->value)
622 free(option->value);
623
624 if (i > 0)
625 memmove(option, option + 1, i * sizeof(cups_option_t *));
626 }
627
628 /*
629 * Return the new number of options...
630 */
631
632 return (num_options);
633 }
634
635
636 /*
637 * End of "$Id: options.c 5151 2006-02-22 22:43:17Z mike $".
638 */