]> git.ipfire.org Git - thirdparty/cups.git/blame - test/ipptest.c
Load cups into easysw/current.
[thirdparty/cups.git] / test / ipptest.c
CommitLineData
ef416fc2 1/*
bd7854cb 2 * "$Id: ipptest.c 5090 2006-02-08 17:08:01Z mike $"
ef416fc2 3 *
4 * IPP test command for the Common UNIX Printing System (CUPS).
5 *
fa73b229 6 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 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 * Contents:
25 *
e00b005a 26 * main() - Parse options and do tests.
27 * do_tests() - Do tests as specified in the test file.
28 * get_tag() - Get an IPP value or group tag from a name...
29 * get_token() - Get a token from a file.
30 * print_attr() - Print an attribute on the screen.
31 * usage() - Show program usage.
ef416fc2 32 */
33
34/*
35 * Include necessary headers...
36 */
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <cups/string.h>
41#include <errno.h>
42#include <ctype.h>
43
44#include <cups/cups.h>
45#include <cups/language.h>
46
47
e00b005a 48/*
49 * Globals...
50 */
51
52int Verbosity = 0; /* Show all attributes? */
53
54
ef416fc2 55/*
56 * Local functions...
57 */
58
59int do_tests(const char *, const char *);
60ipp_op_t ippOpValue(const char *);
61ipp_status_t ippErrorValue(const char *);
62ipp_tag_t get_tag(const char *);
63char *get_token(FILE *, char *, int, int *linenum);
64void print_attr(ipp_attribute_t *);
e00b005a 65void usage(const char *option);
ef416fc2 66
67
68/*
69 * 'main()' - Parse options and do tests.
70 */
71
72int /* O - Exit status */
73main(int argc, /* I - Number of command-line arguments */
74 char *argv[]) /* I - Command-line arguments */
75{
76 int i; /* Looping var */
77 int status; /* Status of tests... */
e00b005a 78 const char *uri; /* URI to use */
79 const char *testfile; /* Test file to use */
ef416fc2 80
81
82 /*
83 * We need at least:
84 *
85 * testipp URL testfile
86 */
87
e00b005a 88 uri = NULL;
89 testfile = NULL;
90 status = 0;
91
92 for (i = 1; i < argc; i ++)
ef416fc2 93 {
e00b005a 94 if (argv[i][0] == '-')
95 {
96 if (!strcmp(argv[i], "-v"))
97 Verbosity ++;
98 else
99 usage(argv[i]);
100 }
101 else if (!strncmp(argv[i], "ipp://", 6) ||
102 !strncmp(argv[i], "http://", 7) ||
103 !strncmp(argv[i], "https://", 8))
104 {
105 /*
106 * Set URI...
107 */
ef416fc2 108
e00b005a 109 if (!testfile && uri)
110 usage(NULL);
111
112 uri = argv[i];
113 testfile = NULL;
114 }
115 else
116 {
117 /*
118 * Run test...
119 */
120
121 testfile = argv[i];
122
123 if (!do_tests(uri, testfile))
124 status ++;
125 }
126 }
ef416fc2 127
e00b005a 128 if (!uri || !testfile)
129 usage(NULL);
ef416fc2 130
131 /*
132 * Exit...
133 */
134
e00b005a 135 return (status);
ef416fc2 136}
137
138
139/*
140 * 'do_tests()' - Do tests as specified in the test file.
141 */
142
143int /* 1 = success, 0 = failure */
144do_tests(const char *uri, /* I - URI to connect on */
145 const char *testfile) /* I - Test file to use */
146{
147 int i; /* Looping var */
148 int linenum; /* Current line number */
149 int version; /* IPP version number to use */
150 http_t *http; /* HTTP connection to server */
151 char method[HTTP_MAX_URI], /* URI method */
152 userpass[HTTP_MAX_URI], /* username:password */
153 server[HTTP_MAX_URI], /* Server */
154 resource[HTTP_MAX_URI]; /* Resource path */
155 int port; /* Port number */
156 FILE *fp; /* Test file */
157 char token[1024], /* Token from file */
158 *tokenptr, /* Pointer into token */
159 temp[1024], /* Temporary string */
160 *tempptr; /* Pointer into temp string */
161 ipp_t *request; /* IPP request */
162 ipp_t *response; /* IPP response */
163 ipp_op_t op; /* Operation */
164 ipp_tag_t group; /* Current group */
165 ipp_tag_t value; /* Current value type */
166 ipp_attribute_t *attrptr; /* Attribute pointer */
167 char attr[128]; /* Attribute name */
168 int num_statuses; /* Number of valid status codes */
169 ipp_status_t statuses[100]; /* Valid status codes */
170 int num_expects; /* Number of expected attributes */
171 char *expects[100]; /* Expected attributes */
172 int num_displayed; /* Number of displayed attributes */
173 char *displayed[100]; /* Displayed attributes */
174 char name[1024]; /* Name of test */
175 char filename[1024]; /* Filename */
176 int pass; /* Did we pass the test? */
177 int job_id; /* Job ID from last operation */
178 int subscription_id; /* Subscription ID from last operation */
179
180
181 /*
182 * Open the test file...
183 */
184
185 if ((fp = fopen(testfile, "r")) == NULL)
186 {
187 printf("Unable to open test file %s - %s\n", testfile, strerror(errno));
188 return (0);
189 }
190
191 /*
192 * Connect to the server...
193 */
194
a4d04587 195 httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), userpass,
196 sizeof(userpass), server, sizeof(server), &port, resource,
197 sizeof(resource));
ef416fc2 198 if ((http = httpConnect(server, port)) == NULL)
199 {
200 printf("Unable to connect to %s on port %d - %s\n", server, port,
201 strerror(errno));
202 return (0);
203 }
204
205 /*
206 * Loop on tests...
207 */
208
209 printf("\"%s\":\n", testfile);
210 pass = 1;
211 job_id = 0;
212 subscription_id = 0;
213 version = 1;
214 linenum = 1;
215
216 while (get_token(fp, token, sizeof(token), &linenum) != NULL)
217 {
218 /*
219 * Expect an open brace...
220 */
221
222 if (strcmp(token, "{"))
223 {
224 printf("Unexpected token %s seen on line %d - aborting test!\n", token,
225 linenum);
226 httpClose(http);
227 return (0);
228 }
229
230 /*
231 * Initialize things...
232 */
233
a4d04587 234 httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), userpass,
235 sizeof(userpass), server, sizeof(server), &port, resource,
236 sizeof(resource));
ef416fc2 237
238 request = ippNew();
239 op = (ipp_op_t)0;
240 group = IPP_TAG_ZERO;
241 value = IPP_TAG_ZERO;
242 num_statuses = 0;
243 num_expects = 0;
244 num_displayed = 0;
245 filename[0] = '\0';
246
247 strcpy(name, testfile);
248 if (strrchr(name, '.') != NULL)
249 *strrchr(name, '.') = '\0';
250
251 /*
252 * Parse until we see a close brace...
253 */
254
255 while (get_token(fp, token, sizeof(token), &linenum) != NULL)
256 {
257 if (!strcmp(token, "}"))
258 break;
259 else if (!strcasecmp(token, "NAME"))
260 {
261 /*
262 * Name of test...
263 */
264
265 get_token(fp, name, sizeof(name), &linenum);
266 }
267 else if (!strcasecmp(token, "VERSION"))
268 {
269 /*
270 * IPP version number for test...
271 */
272
273 get_token(fp, temp, sizeof(temp), &linenum);
274 sscanf(temp, "%*d.%d", &version);
275 }
276 else if (!strcasecmp(token, "RESOURCE"))
277 {
278 /*
279 * Resource name...
280 */
281
282 get_token(fp, resource, sizeof(resource), &linenum);
283 }
284 else if (!strcasecmp(token, "OPERATION"))
285 {
286 /*
287 * Operation...
288 */
289
290 get_token(fp, token, sizeof(token), &linenum);
291 op = ippOpValue(token);
292 }
293 else if (!strcasecmp(token, "GROUP"))
294 {
295 /*
296 * Attribute group...
297 */
298
299 get_token(fp, token, sizeof(token), &linenum);
300 value = get_tag(token);
301
302 if (value == group)
303 ippAddSeparator(request);
304
305 group = value;
306 }
307 else if (!strcasecmp(token, "DELAY"))
308 {
309 /*
310 * Delay before operation...
311 */
312
313 int delay;
314
315 get_token(fp, token, sizeof(token), &linenum);
316 if ((delay = atoi(token)) > 0)
317 sleep(delay);
318 }
319 else if (!strcasecmp(token, "ATTR"))
320 {
321 /*
322 * Attribute...
323 */
324
325 get_token(fp, token, sizeof(token), &linenum);
326 value = get_tag(token);
327 get_token(fp, attr, sizeof(attr), &linenum);
328 get_token(fp, temp, sizeof(temp), &linenum);
329
330 token[sizeof(token) - 1] = '\0';
331
332 for (tempptr = temp, tokenptr = token;
333 *tempptr && tokenptr < (token + sizeof(token) - 1);)
334 if (*tempptr == '$')
335 {
336 /*
337 * Substitute a string/number...
338 */
339
340 if (!strncasecmp(tempptr + 1, "uri", 3))
341 {
342 strlcpy(tokenptr, uri, sizeof(token) - (tokenptr - token));
343 tempptr += 4;
344 }
345 else if (!strncasecmp(tempptr + 1, "method", 6))
346 {
347 strlcpy(tokenptr, method, sizeof(token) - (tokenptr - token));
348 tempptr += 7;
349 }
350 else if (!strncasecmp(tempptr + 1, "username", 8))
351 {
352 strlcpy(tokenptr, userpass, sizeof(token) - (tokenptr - token));
353 tempptr += 9;
354 }
355 else if (!strncasecmp(tempptr + 1, "hostname", 8))
356 {
357 strlcpy(tokenptr, server, sizeof(token) - (tokenptr - token));
358 tempptr += 9;
359 }
360 else if (!strncasecmp(tempptr + 1, "port", 4))
361 {
362 snprintf(tokenptr, sizeof(token) - (tokenptr - token),
363 "%d", port);
364 tempptr += 5;
365 }
366 else if (!strncasecmp(tempptr + 1, "resource", 8))
367 {
368 strlcpy(tokenptr, resource, sizeof(token) - (tokenptr - token));
369 tempptr += 9;
370 }
371 else if (!strncasecmp(tempptr + 1, "job-id", 6))
372 {
373 snprintf(tokenptr, sizeof(token) - (tokenptr - token),
374 "%d", job_id);
375 tempptr += 7;
376 }
377 else if (!strncasecmp(tempptr + 1, "notify-subscription-id", 22))
378 {
379 snprintf(tokenptr, sizeof(token) - (tokenptr - token),
380 "%d", subscription_id);
381 tempptr += 23;
382 }
383 else if (!strncasecmp(tempptr + 1, "user", 4))
384 {
385 strlcpy(tokenptr, cupsUser(), sizeof(token) - (tokenptr - token));
386 tempptr += 5;
387 }
388 else
389 {
390 *tokenptr++ = *tempptr ++;
391 *tokenptr = '\0';
392 }
393
394 tokenptr += strlen(tokenptr);
395 }
396 else
397 {
398 *tokenptr++ = *tempptr++;
399 *tokenptr = '\0';
400 }
401
402 switch (value)
403 {
404 case IPP_TAG_BOOLEAN :
405 if (!strcasecmp(token, "true"))
406 ippAddBoolean(request, group, attr, 1);
407 else
408 ippAddBoolean(request, group, attr, atoi(token));
409 break;
410
411 case IPP_TAG_INTEGER :
412 case IPP_TAG_ENUM :
413 ippAddInteger(request, group, value, attr, atoi(token));
414 break;
415
416 case IPP_TAG_RESOLUTION :
417 puts(" ERROR: resolution tag not yet supported!");
418 break;
419
420 case IPP_TAG_RANGE :
421 puts(" ERROR: range tag not yet supported!");
422 break;
423
424 default :
425 if (!strchr(token, ','))
426 ippAddString(request, group, value, attr, NULL, token);
427 else
428 {
429 /*
430 * Multiple string values...
431 */
432
433 int num_values; /* Number of values */
434 char *values[100], /* Values */
435 *ptr; /* Pointer to next value */
436
437
438 values[0] = token;
439 num_values = 1;
440
441 for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ','))
442 {
443 *ptr++ = '\0';
444 values[num_values] = ptr;
445 num_values ++;
446 }
447
448 ippAddStrings(request, group, value, attr, num_values,
449 NULL, (const char **)values);
450 }
451 break;
452 }
453 }
454 else if (!strcasecmp(token, "FILE"))
455 {
456 /*
457 * File...
458 */
459
460 get_token(fp, filename, sizeof(filename), &linenum);
461 }
462 else if (!strcasecmp(token, "STATUS") &&
463 num_statuses < (int)(sizeof(statuses) / sizeof(statuses[0])))
464 {
465 /*
466 * Status...
467 */
468
469 get_token(fp, token, sizeof(token), &linenum);
470 statuses[num_statuses] = ippErrorValue(token);
471 num_statuses ++;
472 }
473 else if (!strcasecmp(token, "EXPECT") &&
474 num_expects < (int)(sizeof(expects) / sizeof(expects[0])))
475 {
476 /*
477 * Expected attributes...
478 */
479
480 get_token(fp, token, sizeof(token), &linenum);
481 expects[num_expects] = strdup(token);
482 num_expects ++;
483 }
484 else if (!strcasecmp(token, "DISPLAY") &&
485 num_displayed < (int)(sizeof(displayed) / sizeof(displayed[0])))
486 {
487 /*
488 * Display attributes...
489 */
490
491 get_token(fp, token, sizeof(token), &linenum);
492 displayed[num_displayed] = strdup(token);
493 num_displayed ++;
494 }
495 else
496 {
497 printf("Unexpected token %s seen on line %d - aborting test!\n", token,
498 linenum);
499 httpClose(http);
500 ippDelete(request);
501 return (0);
502 }
503 }
504
505 /*
506 * Submit the IPP request...
507 */
508
509 request->request.op.version[1] = version;
510 request->request.op.operation_id = op;
511 request->request.op.request_id = 1;
512
bd7854cb 513 if (Verbosity)
514 {
515 printf("%s:\n", ippOpString(op));
516
517 for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
518 print_attr(attrptr);
519 }
ef416fc2 520
521 printf(" %-60.60s [", name);
522 fflush(stdout);
523
524 if (filename[0])
525 response = cupsDoFileRequest(http, request, resource, filename);
526 else
527 response = cupsDoRequest(http, request, resource);
528
529 if (response == NULL)
530 {
531 time_t curtime;
532
533 curtime = time(NULL);
534
535 puts("FAIL]");
536 printf(" ERROR %04x (%s) @ %s\n", cupsLastError(),
bd7854cb 537 cupsLastErrorString(), ctime(&curtime));
ef416fc2 538 pass = 0;
539 }
540 else
541 {
542 if ((attrptr = ippFindAttribute(response, "job-id",
543 IPP_TAG_INTEGER)) != NULL)
544 job_id = attrptr->values[0].integer;
545
546 if ((attrptr = ippFindAttribute(response, "notify-subscription-id",
547 IPP_TAG_INTEGER)) != NULL)
548 subscription_id = attrptr->values[0].integer;
549
550 for (i = 0; i < num_statuses; i ++)
551 if (response->request.status.status_code == statuses[i])
552 break;
553
554 if (i == num_statuses && num_statuses > 0)
555 pass = 0;
556 else
557 {
558 for (i = 0; i < num_expects; i ++)
559 if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
560 {
561 pass = 0;
562 break;
563 }
564 }
565
566 if (pass)
567 {
568 puts("PASS]");
569 printf(" RECEIVED: %lu bytes in response\n",
570 (unsigned long)ippLength(response));
571
e00b005a 572 if (Verbosity)
573 {
574 for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
575 print_attr(attrptr);
576 }
577 else if (num_displayed > 0)
ef416fc2 578 {
579 for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
580 if (attrptr->name)
581 {
582 for (i = 0; i < num_displayed; i ++)
583 if (!strcmp(displayed[i], attrptr->name))
584 {
585 print_attr(attrptr);
586 break;
587 }
588 }
589 }
590 }
591 else
592 {
593 puts("FAIL]");
594 printf(" RECEIVED: %lu bytes in response\n",
595 (unsigned long)ippLength(response));
596
597 for (i = 0; i < num_statuses; i ++)
598 if (response->request.status.status_code == statuses[i])
599 break;
600
601 if (i == num_statuses && num_statuses > 0)
602 puts(" BAD STATUS");
603
604 printf(" status-code = %04x (%s)\n",
bd7854cb 605 cupsLastError(), cupsLastErrorString());
ef416fc2 606
607 for (i = 0; i < num_expects; i ++)
608 if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
609 printf(" EXPECTED: %s\n", expects[i]);
610
611 for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
612 print_attr(attrptr);
613 }
614
615 ippDelete(response);
616 }
617
618 for (i = 0; i < num_expects; i ++)
619 free(expects[i]);
620
621 if (!pass)
622 break;
623 }
624
625 fclose(fp);
626 httpClose(http);
627
628 return (pass);
629}
630
631
632/*
633 * 'get_tag()' - Get an IPP value or group tag from a name...
634 */
635
636ipp_tag_t /* O - Value/group tag */
637get_tag(const char *name) /* I - Name of value/group tag */
638{
639 int i; /* Looping var */
640 static const char * const names[] =
641 { /* Value/group tag names */
bd7854cb 642 "zero", /* 0x00 */
643 "operation", /* 0x01 */
644 "job", /* 0x02 */
645 "end", /* 0x03 */
646 "printer", /* 0x04 */
647 "unsupported-group", /* 0x05 */
648 "subscription", /* 0x06 */
649 "event-notification", /* 0x07 */
650 "", "", "", "", "", "", "", "",
651 "unsupported-value", /* 0x10 */
652 "default", /* 0x11 */
653 "unknown", /* 0x12 */
654 "novalue", /* 0x13 */
655 "",
656 "notsettable", /* 0x15 */
657 "deleteattr", /* 0x16 */
658 "anyvalue", /* 0x17 */
659 "", "", "", "", "", "", "", "", "",
660 "integer", /* 0x21 */
661 "boolean", /* 0x22 */
662 "enum", /* 0x23 */
663 "", "", "", "", "", "", "", "", "", "", "", "",
664 "string", /* 0x30 */
665 "date", /* 0x31 */
666 "resolution", /* 0x32 */
667 "range", /* 0x33 */
668 "collection", /* 0x34 */
669 "textlang", /* 0x35 */
670 "namelang", /* 0x36 */
671 "", "", "", "", "", "", "", "", "", "",
672 "text", /* 0x41 */
673 "name", /* 0x42 */
674 "",
675 "keyword", /* 0x44 */
676 "uri", /* 0x45 */
677 "urischeme", /* 0x46 */
678 "charset", /* 0x47 */
679 "language", /* 0x48 */
680 "mimetype" /* 0x49 */
ef416fc2 681 };
682
683
684 for (i = 0; i < (sizeof(names) / sizeof(names[0])); i ++)
685 if (!strcasecmp(name, names[i]))
686 return ((ipp_tag_t)i);
687
688 return (IPP_TAG_ZERO);
689}
690
691
692/*
693 * 'get_token()' - Get a token from a file.
694 */
695
696char * /* O - Token from file or NULL on EOF */
697get_token(FILE *fp, /* I - File to read from */
698 char *buf, /* I - Buffer to read into */
699 int buflen, /* I - Length of buffer */
700 int *linenum) /* IO - Current line number */
701{
702 int ch, /* Character from file */
703 quote; /* Quoting character */
704 char *bufptr, /* Pointer into buffer */
705 *bufend; /* End of buffer */
706
707
708 for (;;)
709 {
710 /*
711 * Skip whitespace...
712 */
713
714 while (isspace(ch = getc(fp)))
715 {
716 if (ch == '\n')
717 (*linenum) ++;
718 }
719
720 /*
721 * Read a token...
722 */
723
724 if (ch == EOF)
725 return (NULL);
726 else if (ch == '\'' || ch == '\"')
727 {
728 /*
729 * Quoted text...
730 */
731
732 quote = ch;
733 bufptr = buf;
734 bufend = buf + buflen - 1;
735
736 while ((ch = getc(fp)) != EOF)
737 if (ch == quote)
738 break;
739 else if (bufptr < bufend)
740 *bufptr++ = ch;
741
742 *bufptr = '\0';
743 return (buf);
744 }
745 else if (ch == '#')
746 {
747 /*
748 * Comment...
749 */
750
751 while ((ch = getc(fp)) != EOF)
752 if (ch == '\n')
753 break;
754
755 (*linenum) ++;
756 }
757 else
758 {
759 /*
760 * Whitespace delimited text...
761 */
762
763 ungetc(ch, fp);
764
765 bufptr = buf;
766 bufend = buf + buflen - 1;
767
768 while ((ch = getc(fp)) != EOF)
769 if (isspace(ch) || ch == '#')
770 break;
771 else if (bufptr < bufend)
772 *bufptr++ = ch;
773
774 if (ch == '#')
775 ungetc(ch, fp);
776
777 *bufptr = '\0';
778 return (buf);
779 }
780 }
781}
782
783
784/*
785 * 'print_attr()' - Print an attribute on the screen.
786 */
787
788void
789print_attr(ipp_attribute_t *attr) /* I - Attribute to print */
790{
791 int i; /* Looping var */
792
793
794 if (attr->name == NULL)
795 {
796 puts(" -- separator --");
797 return;
798 }
799
800 printf(" %s = ", attr->name);
801
802 switch (attr->value_tag)
803 {
804 case IPP_TAG_INTEGER :
805 case IPP_TAG_ENUM :
806 for (i = 0; i < attr->num_values; i ++)
807 printf("%d ", attr->values[i].integer);
808 break;
809
810 case IPP_TAG_BOOLEAN :
811 for (i = 0; i < attr->num_values; i ++)
812 if (attr->values[i].boolean)
813 printf("true ");
814 else
815 printf("false ");
816 break;
817
818 case IPP_TAG_NOVALUE :
819 printf("novalue");
820 break;
821
822 case IPP_TAG_RANGE :
823 for (i = 0; i < attr->num_values; i ++)
824 printf("%d-%d ", attr->values[i].range.lower,
825 attr->values[i].range.upper);
826 break;
827
828 case IPP_TAG_RESOLUTION :
829 for (i = 0; i < attr->num_values; i ++)
830 printf("%dx%d%s ", attr->values[i].resolution.xres,
831 attr->values[i].resolution.yres,
832 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
833 "dpi" : "dpc");
834 break;
835
836 case IPP_TAG_STRING :
837 case IPP_TAG_TEXT :
838 case IPP_TAG_NAME :
839 case IPP_TAG_KEYWORD :
840 case IPP_TAG_CHARSET :
841 case IPP_TAG_URI :
842 case IPP_TAG_MIMETYPE :
843 case IPP_TAG_LANGUAGE :
844 for (i = 0; i < attr->num_values; i ++)
845 printf("\"%s\" ", attr->values[i].string.text);
846 break;
847
848 case IPP_TAG_TEXTLANG :
849 case IPP_TAG_NAMELANG :
850 for (i = 0; i < attr->num_values; i ++)
851 printf("\"%s\",%s ", attr->values[i].string.text,
852 attr->values[i].string.charset);
853 break;
854
855 default :
856 break; /* anti-compiler-warning-code */
857 }
858
859 putchar('\n');
860}
861
862
863/*
e00b005a 864 * 'usage()' - Show program usage.
865 */
866
867void
868usage(const char *option) /* I - Option string or NULL */
869{
870 if (option)
871 fprintf(stderr, "ipptest: Unknown option \"%s\"!\n", option);
872
873 fputs("Usage: ipptest [options] URL testfile [ ... testfileN ]\n", stderr);
874 fputs("Options:\n", stderr);
875 fputs("\n", stderr);
876 fputs("-v Show all attributes in response, even on success.\n", stderr);
877
878 exit(1);
879}
880
881
882/*
bd7854cb 883 * End of "$Id: ipptest.c 5090 2006-02-08 17:08:01Z mike $".
ef416fc2 884 */