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