]> 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/*
2 * "$Id: options.c 4918 2006-01-12 05:14:40Z mike $"
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 */
370 cups_option_t *optptr; /* Current option */
371 ppd_option_t *option; /* PPD option */
372 static const char * const duplex_options[] =
373 { /* Duplex option names */
374 "Duplex", /* Adobe */
375 "EFDuplex", /* EFI */
376 "EFDuplexing", /* EFI */
377 "KD03Duplex", /* Kodak */
378 "JCLDuplex" /* Samsung */
379 };
380 static const char * const duplex_one[] =
381 { /* one-sided names */
382 "None",
383 "False"
384 };
385 static const char * const duplex_two_long[] =
386 { /* two-sided-long-edge names */
387 "DuplexNoTumble", /* Adobe */
388 "LongEdge", /* EFI */
389 "Top" /* EFI */
390 };
391 static const char * const duplex_two_short[] =
392 { /* two-sided-long-edge names */
393 "DuplexTumble", /* Adobe */
394 "ShortEdge", /* EFI */
395 "Bottom" /* EFI */
396 };
397
398
399 /*
400 * Check arguments...
401 */
402
403 if (ppd == NULL || num_options <= 0 || options == NULL)
404 return (0);
405
406 /*
407 * Mark options...
408 */
409
410 conflict = 0;
411
412 for (i = num_options, optptr = options; i > 0; i --, optptr ++)
413 if (!strcasecmp(optptr->name, "media"))
414 {
415 /*
416 * Loop through the option string, separating it at commas and
417 * marking each individual option.
418 */
419
420 for (val = optptr->value; *val;)
421 {
422 /*
423 * Extract the sub-option from the string...
424 */
425
426 for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
427 *ptr++ = *val++;
428 *ptr++ = '\0';
429
430 if (*val == ',')
431 val ++;
432
433 /*
434 * Mark it...
435 */
436
437 if (cupsGetOption("PageSize", num_options, options) == NULL)
438 if (ppdMarkOption(ppd, "PageSize", s))
439 conflict = 1;
440
441 if (cupsGetOption("InputSlot", num_options, options) == NULL)
442 if (ppdMarkOption(ppd, "InputSlot", s))
443 conflict = 1;
444
445 if (cupsGetOption("MediaType", num_options, options) == NULL)
446 if (ppdMarkOption(ppd, "MediaType", s))
447 conflict = 1;
448
449 if (cupsGetOption("EFMediaType", num_options, options) == NULL)
450 if (ppdMarkOption(ppd, "EFMediaType", s))
451 conflict = 1;
452
453 if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL)
454 if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */
455 conflict = 1;
456
457 if (strcasecmp(s, "manual") == 0 &&
458 cupsGetOption("ManualFeed", num_options, options) == NULL)
459 if (ppdMarkOption(ppd, "ManualFeed", "True"))
460 conflict = 1;
461 }
462 }
463 else if (!strcasecmp(optptr->name, "sides"))
464 {
465 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
466 if (cupsGetOption(duplex_options[j], num_options, options) != NULL)
467 break;
468
469 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
470 {
471 /*
472 * Don't override the PPD option with the IPP attribute...
473 */
474
475 continue;
476 }
477
478 if (!strcasecmp(optptr->value, "one-sided"))
479 {
480 /*
481 * Mark the appropriate duplex option for one-sided output...
482 */
483
484 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
485 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
486 break;
487
488 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
489 {
490 for (k = 0; k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); k ++)
491 if (ppdFindChoice(option, duplex_one[k]))
492 {
493 if (ppdMarkOption(ppd, duplex_options[j], duplex_one[k]))
494 conflict = 1;
495
496 break;
497 }
498 }
499 }
500 else if (!strcasecmp(optptr->value, "two-sided-long-edge"))
501 {
502 /*
503 * Mark the appropriate duplex option for two-sided-long-edge output...
504 */
505
506 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
507 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
508 break;
509
510 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
511 {
512 for (k = 0; k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); k ++)
513 if (ppdFindChoice(option, duplex_two_long[k]))
514 {
515 if (ppdMarkOption(ppd, duplex_options[j], duplex_two_long[k]))
516 conflict = 1;
517
518 break;
519 }
520 }
521 }
522 else if (!strcasecmp(optptr->value, "two-sided-short-edge"))
523 {
524 /*
525 * Mark the appropriate duplex option for two-sided-short-edge output...
526 */
527
528 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
529 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
530 break;
531
532 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
533 {
534 for (k = 0; k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); k ++)
535 if (ppdFindChoice(option, duplex_two_short[k]))
536 {
537 if (ppdMarkOption(ppd, duplex_options[j], duplex_two_short[k]))
538 conflict = 1;
539
540 break;
541 }
542 }
543 }
544 }
545 else if (!strcasecmp(optptr->name, "resolution") ||
546 !strcasecmp(optptr->name, "printer-resolution"))
547 {
548 if (ppdMarkOption(ppd, "Resolution", optptr->value))
549 conflict = 1;
550 if (ppdMarkOption(ppd, "SetResolution", optptr->value))
551 /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
552 conflict = 1;
553 if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */
554 conflict = 1;
555 if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */
556 conflict = 1;
557 }
558 else if (!strcasecmp(optptr->name, "output-bin"))
559 {
560 if (cupsGetOption("OutputBin", num_options, options) == NULL)
561 if (ppdMarkOption(ppd, "OutputBin", optptr->value))
562 conflict = 1;
563 }
564 else if (ppdMarkOption(ppd, optptr->name, optptr->value))
565 conflict = 1;
566
567 return (conflict);
568}
569
570
571/*
572 * End of "$Id: options.c 4918 2006-01-12 05:14:40Z mike $".
573 */