]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/lpoptions.c
Fix .PHONY declaration
[thirdparty/cups.git] / systemv / lpoptions.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * Printer option program for CUPS.
ef416fc2 3 *
bdbfacc7 4 * Copyright 2007-2016 by Apple Inc.
7e86f2f6 5 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 6 *
7e86f2f6
MS
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
57b7b66b 11 * missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 12 */
13
14/*
15 * Include necessary headers...
16 */
17
71e16022 18#include <cups/cups-private.h>
f787e1e3 19#include <cups/ppd-private.h>
ef416fc2 20
21
22/*
23 * Local functions...
24 */
25
dd1abb6b
MS
26static void list_group(ppd_file_t *ppd, ppd_group_t *group);
27static void list_options(cups_dest_t *dest);
85dda01c 28static void usage(void) __attribute__((noreturn));
ef416fc2 29
30
31/*
32 * 'main()' - Main entry.
33 */
34
35int /* O - Exit status */
36main(int argc, /* I - Number of command-line arguments */
37 char *argv[]) /* I - Command-line arguments */
38{
39 int i, j; /* Looping vars */
40 int changes; /* Did we make changes? */
41 int num_options; /* Number of options */
42 cups_option_t *options; /* Options */
43 int num_dests; /* Number of destinations */
44 cups_dest_t *dests; /* Destinations */
45 cups_dest_t *dest; /* Current destination */
bdbfacc7
MS
46 char *opt, /* Option pointer */
47 *printer, /* Printer name */
88f9aafc 48 *instance, /* Instance name */
ef416fc2 49 *option; /* Current option */
50
51
07725fee 52 _cupsSetLocale(argv);
d09495fa 53
ef416fc2 54 /*
55 * Loop through the command-line arguments...
56 */
57
58 dest = NULL;
59 num_dests = 0;
60 dests = NULL;
61 num_options = 0;
62 options = NULL;
63 changes = 0;
64
65 for (i = 1; i < argc; i ++)
bdbfacc7 66 {
ef416fc2 67 if (argv[i][0] == '-')
68 {
bdbfacc7 69 for (opt = argv[i] + 1; *opt; opt ++)
ef416fc2 70 {
bdbfacc7
MS
71 switch (*opt)
72 {
73 case 'd' : /* -d printer */
74 if (opt[1] != '\0')
75 {
76 printer = opt + 1;
77 opt += strlen(opt) - 1;
78 }
79 else
80 {
81 i ++;
82 if (i >= argc)
83 usage();
ef416fc2 84
bdbfacc7
MS
85 printer = argv[i];
86 }
ef416fc2 87
bdbfacc7
MS
88 if ((instance = strrchr(printer, '/')) != NULL)
89 *instance++ = '\0';
ef416fc2 90
8ca02f3c 91 if (num_dests == 0)
92 num_dests = cupsGetDests(&dests);
93
bdbfacc7
MS
94 if (num_dests == 0 || !dests || (dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
95 {
96 _cupsLangPuts(stderr, _("lpoptions: Unknown printer or class."));
97 return (1);
98 }
8ca02f3c 99
bdbfacc7
MS
100 /*
101 * Set the default destination...
102 */
103
104 for (j = 0; j < num_dests; j ++)
105 dests[j].is_default = 0;
106
107 dest->is_default = 1;
108
109 cupsSetDests(num_dests, dests);
7594b224 110
8ca02f3c 111 for (j = 0; j < dest->num_options; j ++)
bdbfacc7
MS
112 if (cupsGetOption(dest->options[j].name, num_options,
113 options) == NULL)
8ca02f3c 114 num_options = cupsAddOption(dest->options[j].name,
bdbfacc7
MS
115 dest->options[j].value,
116 num_options, &options);
117 break;
118
119 case 'h' : /* -h server */
120 if (opt[1] != '\0')
ef416fc2 121 {
bdbfacc7
MS
122 cupsSetServer(opt + 1);
123 opt += strlen(opt) - 1;
ef416fc2 124 }
bdbfacc7
MS
125 else
126 {
127 i ++;
128 if (i >= argc)
129 usage();
8ca02f3c 130
bdbfacc7
MS
131 cupsSetServer(argv[i]);
132 }
133 break;
134
135 case 'E' : /* Encrypt connection */
136 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
137 break;
138
139 case 'l' : /* -l (list options) */
140 if (dest == NULL)
141 {
142 if (num_dests == 0)
143 num_dests = cupsGetDests(&dests);
144
145 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
146 dest = dests;
147 }
8ca02f3c 148
7594b224 149 if (dest == NULL)
0837b7e8 150 _cupsLangPuts(stderr, _("lpoptions: No printers."));
bdbfacc7
MS
151 else
152 list_options(dest);
153
154 changes = -1;
155 break;
156
157 case 'o' : /* -o option[=value] */
158 if (dest == NULL)
159 {
160 if (num_dests == 0)
161 num_dests = cupsGetDests(&dests);
162
163 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
164 dest = dests;
165
166 if (dest == NULL)
167 {
168 _cupsLangPuts(stderr, _("lpoptions: No printers."));
169 return (1);
170 }
171
172 for (j = 0; j < dest->num_options; j ++)
173 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
174 num_options = cupsAddOption(dest->options[j].name,
175 dest->options[j].value,
176 num_options, &options);
177 }
178
179 if (opt[1] != '\0')
180 {
181 num_options = cupsParseOptions(opt + 1, num_options, &options);
182 opt += strlen(opt) - 1;
183 }
184 else
185 {
186 i ++;
187 if (i >= argc)
188 usage();
189
190 num_options = cupsParseOptions(argv[i], num_options, &options);
191 }
192
193 changes = 1;
194 break;
195
196 case 'p' : /* -p printer */
197 if (opt[1] != '\0')
198 {
199 printer = opt + 1;
200 opt += strlen(opt) - 1;
201 }
202 else
203 {
204 i ++;
205 if (i >= argc)
206 usage();
207
208 printer = argv[i];
209 }
210
211 if ((instance = strrchr(printer, '/')) != NULL)
212 *instance++ = '\0';
213
214 if (num_dests == 0)
215 num_dests = cupsGetDests(&dests);
216
217 if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
218 {
219 num_dests = cupsAddDest(printer, instance, num_dests, &dests);
220 dest = cupsGetDest(printer, instance, num_dests, dests);
221
222 if (dest == NULL)
223 {
224 _cupsLangPrintf(stderr, _("lpoptions: Unable to add printer or instance: %s"), strerror(errno));
225 return (1);
226 }
227 }
7594b224 228
8ca02f3c 229 for (j = 0; j < dest->num_options; j ++)
bdbfacc7 230 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
8ca02f3c 231 num_options = cupsAddOption(dest->options[j].name,
bdbfacc7
MS
232 dest->options[j].value,
233 num_options, &options);
234 break;
235
236 case 'r' : /* -r option (remove) */
237 if (dest == NULL)
ef416fc2 238 {
bdbfacc7
MS
239 if (num_dests == 0)
240 num_dests = cupsGetDests(&dests);
241
242 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
243 dest = dests;
244
245 if (dest == NULL)
246 {
247 _cupsLangPuts(stderr, _("lpoptions: No printers."));
248 return (1);
249 }
250
251 for (j = 0; j < dest->num_options; j ++)
252 if (cupsGetOption(dest->options[j].name, num_options,
253 options) == NULL)
254 num_options = cupsAddOption(dest->options[j].name,
255 dest->options[j].value,
256 num_options, &options);
257 }
ef416fc2 258
bdbfacc7 259 if (opt[1] != '\0')
ef416fc2 260 {
bdbfacc7
MS
261 option = opt + 1;
262 opt += strlen(opt) - 1;
ef416fc2 263 }
264 else
265 {
bdbfacc7
MS
266 i ++;
267 if (i >= argc)
268 usage();
ef416fc2 269
bdbfacc7 270 option = argv[i];
ef416fc2 271 }
ef416fc2 272
bdbfacc7
MS
273 num_options = cupsRemoveOption(option, num_options, &options);
274
275 changes = 1;
276 break;
ef416fc2 277
bdbfacc7
MS
278 case 'x' : /* -x printer */
279 if (opt[1] != '\0')
280 {
281 printer = opt + 1;
282 opt += strlen(opt) - 1;
283 }
284 else
285 {
286 i ++;
287 if (i >= argc)
288 usage();
289
290 printer = argv[i];
291 }
292
293 if ((instance = strrchr(printer, '/')) != NULL)
294 *instance++ = '\0';
295
296 if (num_dests == 0)
297 num_dests = cupsGetDests(&dests);
298
299 num_dests = cupsRemoveDest(printer, instance, num_dests, &dests);
300
301 cupsSetDests(num_dests, dests);
302 dest = NULL;
303 changes = -1;
304 break;
305
306 default :
307 usage();
308 }
ef416fc2 309 }
310 }
311 else
bdbfacc7 312 {
ef416fc2 313 usage();
bdbfacc7
MS
314 }
315 }
ef416fc2 316
317 if (num_dests == 0)
318 num_dests = cupsGetDests(&dests);
319
320 if (dest == NULL)
321 {
322 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL)
323 {
324 for (j = 0; j < dest->num_options; j ++)
325 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
326 num_options = cupsAddOption(dest->options[j].name,
327 dest->options[j].value,
328 num_options, &options);
329 }
330 }
331
332 if (dest == NULL)
333 return (0);
334
335 if (changes > 0)
336 {
337 /*
338 * Set printer options...
339 */
340
341 cupsFreeOptions(dest->num_options, dest->options);
342
343 dest->num_options = num_options;
344 dest->options = options;
345
346 cupsSetDests(num_dests, dests);
347 }
348 else if (changes == 0)
349 {
0837b7e8
MS
350 char buffer[10240], /* String for options */
351 *ptr; /* Pointer into string */
352
ef416fc2 353 num_options = dest->num_options;
354 options = dest->options;
355
0837b7e8
MS
356 for (i = 0, ptr = buffer;
357 ptr < (buffer + sizeof(buffer) - 1) && i < num_options;
358 i ++)
ef416fc2 359 {
360 if (i)
0837b7e8 361 *ptr++ = ' ';
ef416fc2 362
363 if (!options[i].value[0])
7e86f2f6 364 strlcpy(ptr, options[i].name, sizeof(buffer) - (size_t)(ptr - buffer));
ef416fc2 365 else if (strchr(options[i].value, ' ') != NULL ||
366 strchr(options[i].value, '\t') != NULL)
7e86f2f6 367 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=\'%s\'", options[i].name, options[i].value);
ef416fc2 368 else
7e86f2f6 369 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=%s", options[i].name, options[i].value);
0837b7e8
MS
370
371 ptr += strlen(ptr);
ef416fc2 372 }
373
0837b7e8 374 _cupsLangPuts(stdout, buffer);
ef416fc2 375 }
376
377 return (0);
378}
379
380/*
381 * 'list_group()' - List printer-specific options from the PPD group.
382 */
383
dd1abb6b
MS
384static void
385list_group(ppd_file_t *ppd, /* I - PPD file */
386 ppd_group_t *group) /* I - Group to show */
ef416fc2 387{
dd1abb6b
MS
388 int i, j; /* Looping vars */
389 ppd_option_t *option; /* Current option */
390 ppd_choice_t *choice; /* Current choice */
391 ppd_group_t *subgroup; /* Current subgroup */
0837b7e8
MS
392 char buffer[10240], /* Option string buffer */
393 *ptr; /* Pointer into option string */
ef416fc2 394
395
396 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
397 {
88f9aafc 398 if (!_cups_strcasecmp(option->keyword, "PageRegion"))
dd1abb6b
MS
399 continue;
400
0837b7e8 401 snprintf(buffer, sizeof(buffer), "%s/%s:", option->keyword, option->text);
ef416fc2 402
0837b7e8
MS
403 for (j = option->num_choices, choice = option->choices,
404 ptr = buffer + strlen(buffer);
405 j > 0 && ptr < (buffer + sizeof(buffer) - 1);
dd1abb6b 406 j --, choice ++)
0837b7e8 407 {
88f9aafc 408 if (!_cups_strcasecmp(choice->choice, "Custom"))
dd1abb6b
MS
409 {
410 ppd_coption_t *coption; /* Custom option */
411 ppd_cparam_t *cparam; /* Custom parameter */
412 static const char * const types[] =
413 { /* Parameter types */
414 "CURVE",
415 "INTEGER",
416 "INVCURVE",
417 "PASSCODE",
418 "PASSWORD",
419 "POINTS",
420 "REAL",
421 "STRING"
422 };
423
424
425 if ((coption = ppdFindCustomOption(ppd, option->keyword)) == NULL ||
426 cupsArrayCount(coption->params) == 0)
7e86f2f6 427 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom", choice->marked ? "*" : "");
88f9aafc
MS
428 else if (!_cups_strcasecmp(option->keyword, "PageSize") ||
429 !_cups_strcasecmp(option->keyword, "PageRegion"))
7e86f2f6 430 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.WIDTHxHEIGHT", choice->marked ? "*" : "");
dd1abb6b
MS
431 else
432 {
433 cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
434
435 if (cupsArrayCount(coption->params) == 1)
7e86f2f6 436 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.%s", choice->marked ? "*" : "", types[cparam->type]);
dd1abb6b
MS
437 else
438 {
439 const char *prefix; /* Prefix string */
440
441
442 if (choice->marked)
443 prefix = " *{";
444 else
445 prefix = " {";
446
447 while (cparam)
448 {
7e86f2f6 449 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s%s=%s", prefix, cparam->name, types[cparam->type]);
dd1abb6b
MS
450 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params);
451 prefix = " ";
0837b7e8 452 ptr += strlen(ptr);
dd1abb6b
MS
453 }
454
0837b7e8 455 if (ptr < (buffer + sizeof(buffer) - 1))
7e86f2f6 456 strlcpy(ptr, "}", sizeof(buffer) - (size_t)(ptr - buffer));
dd1abb6b
MS
457 }
458 }
459 }
460 else if (choice->marked)
7e86f2f6 461 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " *%s", choice->choice);
ef416fc2 462 else
7e86f2f6 463 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %s", choice->choice);
0837b7e8
MS
464
465 ptr += strlen(ptr);
466 }
ef416fc2 467
0837b7e8 468 _cupsLangPuts(stdout, buffer);
ef416fc2 469 }
470
471 for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++)
dd1abb6b 472 list_group(ppd, subgroup);
ef416fc2 473}
474
475
476/*
477 * 'list_options()' - List printer-specific options from the PPD file.
478 */
479
dd1abb6b
MS
480static void
481list_options(cups_dest_t *dest) /* I - Destination to list */
ef416fc2 482{
dd1abb6b
MS
483 int i; /* Looping var */
484 const char *filename; /* PPD filename */
485 ppd_file_t *ppd; /* PPD data */
486 ppd_group_t *group; /* Current group */
ef416fc2 487
488
489 if ((filename = cupsGetPPD(dest->name)) == NULL)
490 {
0837b7e8 491 _cupsLangPrintf(stderr, _("lpoptions: Unable to get PPD file for %s: %s"),
b86bc4cf 492 dest->name, cupsLastErrorString());
ef416fc2 493 return;
494 }
495
496 if ((ppd = ppdOpenFile(filename)) == NULL)
497 {
498 unlink(filename);
0837b7e8 499 _cupsLangPrintf(stderr, _("lpoptions: Unable to open PPD file for %s."),
ef416fc2 500 dest->name);
501 return;
502 }
503
504 ppdMarkDefaults(ppd);
505 cupsMarkOptions(ppd, dest->num_options, dest->options);
506
507 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
dd1abb6b 508 list_group(ppd, group);
ef416fc2 509
510 ppdClose(ppd);
511 unlink(filename);
512}
513
514
515/*
516 * 'usage()' - Show program usage and exit.
517 */
518
dd1abb6b 519static void
ef416fc2 520usage(void)
521{
fa73b229 522 _cupsLangPuts(stdout,
ef416fc2 523 _("Usage: lpoptions [-h server] [-E] -d printer\n"
524 " lpoptions [-h server] [-E] [-p printer] -l\n"
525 " lpoptions [-h server] [-E] -p printer -o "
526 "option[=value] ...\n"
0837b7e8 527 " lpoptions [-h server] [-E] -x printer"));
ef416fc2 528
529 exit(1);
530}