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