]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/options.c
55159efb493b00129357467cd2f75c3ada35bb63
[thirdparty/cups.git] / cups / options.c
1 /*
2 * "$Id: options.c,v 1.33 2004/02/25 20:14:51 mike Exp $"
3 *
4 * Option routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2004 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-3111 USA
19 *
20 * Voice: (301) 373-9603
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
50 int /* O - Number of options */
51 cupsAddOption(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
111 void
112 cupsFreeOptions(int num_options, /* I - Number of options */
113 cups_option_t *options) /* I - Pointer to options */
114 {
115 int i; /* Looping var */
116
117
118 if (num_options <= 0 || options == NULL)
119 return;
120
121 for (i = 0; i < num_options; i ++)
122 {
123 free(options[i].name);
124 free(options[i].value);
125 }
126
127 free(options);
128 }
129
130
131 /*
132 * 'cupsGetOption()' - Get an option value.
133 */
134
135 const char * /* O - Option value or NULL */
136 cupsGetOption(const char *name, /* I - Name of option */
137 int num_options,/* I - Number of options */
138 cups_option_t *options) /* I - Options */
139 {
140 int i; /* Looping var */
141
142
143 if (name == NULL || num_options <= 0 || options == NULL)
144 return (NULL);
145
146 for (i = 0; i < num_options; i ++)
147 if (strcasecmp(options[i].name, name) == 0)
148 return (options[i].value);
149
150 return (NULL);
151 }
152
153
154 /*
155 * 'cupsParseOptions()' - Parse options from a command-line argument.
156 */
157
158 int /* O - Number of options found */
159 cupsParseOptions(const char *arg, /* I - Argument to parse */
160 int num_options, /* I - Number of options */
161 cups_option_t **options) /* O - Options found */
162 {
163 char *copyarg, /* Copy of input string */
164 *ptr, /* Pointer into string */
165 *name, /* Pointer to name */
166 *value; /* Pointer to value */
167
168
169 if (arg == NULL || options == NULL || num_options < 0)
170 return (0);
171
172 /*
173 * Make a copy of the argument string and then divide it up...
174 */
175
176 copyarg = strdup(arg);
177 ptr = copyarg;
178
179 /*
180 * Skip leading spaces...
181 */
182
183 while (isspace(*ptr & 255))
184 ptr ++;
185
186 /*
187 * Loop through the string...
188 */
189
190 while (*ptr != '\0')
191 {
192 /*
193 * Get the name up to a SPACE, =, or end-of-string...
194 */
195
196 name = ptr;
197 while (!isspace(*ptr & 255) && *ptr != '=' && *ptr != '\0')
198 ptr ++;
199
200 /*
201 * Avoid an empty name...
202 */
203
204 if (ptr == name)
205 break;
206
207 /*
208 * Skip trailing spaces...
209 */
210
211 while (isspace(*ptr & 255))
212 *ptr++ = '\0';
213
214 if (*ptr != '=')
215 {
216 /*
217 * Start of another option...
218 */
219
220 if (strncasecmp(name, "no", 2) == 0)
221 num_options = cupsAddOption(name + 2, "false", num_options,
222 options);
223 else
224 num_options = cupsAddOption(name, "true", num_options, options);
225
226 continue;
227 }
228
229 /*
230 * Remove = and parse the value...
231 */
232
233 *ptr++ = '\0';
234
235 if (*ptr == '\'')
236 {
237 /*
238 * Quoted string constant...
239 */
240
241 ptr ++;
242 value = ptr;
243
244 while (*ptr != '\'' && *ptr != '\0')
245 {
246 if (*ptr == '\\')
247 cups_strcpy(ptr, ptr + 1);
248
249 ptr ++;
250 }
251
252 if (*ptr != '\0')
253 *ptr++ = '\0';
254 }
255 else if (*ptr == '\"')
256 {
257 /*
258 * Double-quoted string constant...
259 */
260
261 ptr ++;
262 value = ptr;
263
264 while (*ptr != '\"' && *ptr != '\0')
265 {
266 if (*ptr == '\\')
267 cups_strcpy(ptr, ptr + 1);
268
269 ptr ++;
270 }
271
272 if (*ptr != '\0')
273 *ptr++ = '\0';
274 }
275 else if (*ptr == '{')
276 {
277 /*
278 * Collection value...
279 */
280
281 int depth;
282
283 value = ptr;
284
285 for (depth = 1; *ptr; ptr ++)
286 if (*ptr == '{')
287 depth ++;
288 else if (*ptr == '}')
289 {
290 depth --;
291 if (!depth)
292 {
293 ptr ++;
294
295 if (*ptr != ',')
296 break;
297 }
298 }
299 else if (*ptr == '\\')
300 cups_strcpy(ptr, ptr + 1);
301
302 if (*ptr != '\0')
303 *ptr++ = '\0';
304 }
305 else
306 {
307 /*
308 * Normal space-delimited string...
309 */
310
311 value = ptr;
312
313 while (!isspace(*ptr & 255) && *ptr != '\0')
314 {
315 if (*ptr == '\\')
316 cups_strcpy(ptr, ptr + 1);
317
318 ptr ++;
319 }
320 }
321
322 /*
323 * Skip trailing whitespace...
324 */
325
326 while (isspace(*ptr & 255))
327 *ptr++ = '\0';
328
329 /*
330 * Add the string value...
331 */
332
333 num_options = cupsAddOption(name, value, num_options, options);
334 }
335
336 /*
337 * Free the copy of the argument we made and return the number of options
338 * found.
339 */
340
341 free(copyarg);
342
343 return (num_options);
344 }
345
346
347 /*
348 * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
349 */
350
351 int /* O - 1 if conflicting */
352 cupsMarkOptions(ppd_file_t *ppd, /* I - PPD file */
353 int num_options, /* I - Number of options */
354 cups_option_t *options) /* I - Options */
355 {
356 int i; /* Looping var */
357 int conflict; /* Option conflicts */
358 char *val, /* Pointer into value */
359 *ptr, /* Pointer into string */
360 s[255]; /* Temporary string */
361 cups_option_t *optptr; /* Current option */
362
363
364 /*
365 * Check arguments...
366 */
367
368 if (ppd == NULL || num_options <= 0 || options == NULL)
369 return (0);
370
371 /*
372 * Mark options...
373 */
374
375 conflict = 0;
376
377 for (i = num_options, optptr = options; i > 0; i --, optptr ++)
378 if (strcasecmp(optptr->name, "media") == 0)
379 {
380 /*
381 * Loop through the option string, separating it at commas and
382 * marking each individual option.
383 */
384
385 for (val = optptr->value; *val;)
386 {
387 /*
388 * Extract the sub-option from the string...
389 */
390
391 for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
392 *ptr++ = *val++;
393 *ptr++ = '\0';
394
395 if (*val == ',')
396 val ++;
397
398 /*
399 * Mark it...
400 */
401
402 if (cupsGetOption("PageSize", num_options, options) == NULL)
403 if (ppdMarkOption(ppd, "PageSize", s))
404 conflict = 1;
405
406 if (cupsGetOption("InputSlot", num_options, options) == NULL)
407 if (ppdMarkOption(ppd, "InputSlot", s))
408 conflict = 1;
409
410 if (cupsGetOption("MediaType", num_options, options) == NULL)
411 if (ppdMarkOption(ppd, "MediaType", s))
412 conflict = 1;
413
414 if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL)
415 if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */
416 conflict = 1;
417
418 if (strcasecmp(s, "manual") == 0 &&
419 cupsGetOption("ManualFeed", num_options, options) == NULL)
420 if (ppdMarkOption(ppd, "ManualFeed", "True"))
421 conflict = 1;
422 }
423 }
424 else if (strcasecmp(optptr->name, "sides") == 0)
425 {
426 if (cupsGetOption("Duplex", num_options, options) != NULL ||
427 cupsGetOption("JCLDuplex", num_options, options) != NULL ||
428 cupsGetOption("EFDuplex", num_options, options) != NULL ||
429 cupsGetOption("KD03Duplex", num_options, options) != NULL)
430 {
431 /*
432 * Don't override the PPD option with the IPP attribute...
433 */
434
435 continue;
436 }
437 else if (strcasecmp(optptr->value, "one-sided") == 0)
438 {
439 if (ppdMarkOption(ppd, "Duplex", "None"))
440 conflict = 1;
441 if (ppdMarkOption(ppd, "JCLDuplex", "None")) /* Samsung */
442 conflict = 1;
443 if (ppdMarkOption(ppd, "EFDuplex", "None")) /* EFI */
444 conflict = 1;
445 if (ppdMarkOption(ppd, "KD03Duplex", "None")) /* Kodak */
446 conflict = 1;
447 }
448 else if (strcasecmp(optptr->value, "two-sided-long-edge") == 0)
449 {
450 if (ppdMarkOption(ppd, "Duplex", "DuplexNoTumble"))
451 conflict = 1;
452 if (ppdMarkOption(ppd, "JCLDuplex", "DuplexNoTumble")) /* Samsung */
453 conflict = 1;
454 if (ppdMarkOption(ppd, "EFDuplex", "DuplexNoTumble")) /* EFI */
455 conflict = 1;
456 if (ppdMarkOption(ppd, "KD03Duplex", "DuplexNoTumble")) /* Kodak */
457 conflict = 1;
458 }
459 else if (strcasecmp(optptr->value, "two-sided-short-edge") == 0)
460 {
461 if (ppdMarkOption(ppd, "Duplex", "DuplexTumble"))
462 conflict = 1;
463 if (ppdMarkOption(ppd, "JCLDuplex", "DuplexTumble")) /* Samsung */
464 conflict = 1;
465 if (ppdMarkOption(ppd, "EFDuplex", "DuplexTumble")) /* EFI */
466 conflict = 1;
467 if (ppdMarkOption(ppd, "KD03Duplex", "DuplexTumble")) /* Kodak */
468 conflict = 1;
469 }
470 }
471 else if (strcasecmp(optptr->name, "resolution") == 0 ||
472 strcasecmp(optptr->name, "printer-resolution") == 0)
473 {
474 if (ppdMarkOption(ppd, "Resolution", optptr->value))
475 conflict = 1;
476 if (ppdMarkOption(ppd, "SetResolution", optptr->value))
477 /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
478 conflict = 1;
479 if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */
480 conflict = 1;
481 if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */
482 conflict = 1;
483 }
484 else if (strcasecmp(optptr->name, "output-bin") == 0)
485 {
486 if (cupsGetOption("OutputBin", num_options, options) == NULL)
487 if (ppdMarkOption(ppd, "OutputBin", optptr->value))
488 conflict = 1;
489 }
490 else if (ppdMarkOption(ppd, optptr->name, optptr->value))
491 conflict = 1;
492
493 return (conflict);
494 }
495
496
497 /*
498 * End of "$Id: options.c,v 1.33 2004/02/25 20:14:51 mike Exp $".
499 */