Adapt copyright for a new version
[ltp-debian.git] / lib / tst_res.c
blob719ccdf79546f48321fe052fd13a3840d5e954b2
1 /*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 * Copyring (c) 2009 Cyril Hrubis chrubis@suse.cz
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * Further, this software is distributed without any warranty that it is
14 * free of the rightful claim of any third person regarding infringement
15 * or the like. Any license provided herein, whether implied or
16 * otherwise, applies only to this software file. Patent licenses, if
17 * any, provided herein do not apply to combinations of this program with
18 * other software, or any other product whatsoever.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write the Free Software Foundation, Inc., 59
22 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
24 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
25 * Mountain View, CA 94043, or:
27 * http://www.sgi.com
29 * For further information regarding this notice, see:
31 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
35 /* $Id: tst_res.c,v 1.12 2009/08/28 11:05:36 vapier Exp $ */
37 /**********************************************************
39 * OS Testing - Silicon Graphics, Inc.
41 * FUNCTION NAME :
42 * tst_res() - Print result message (include file contents)
43 * tst_resm() - Print result message
44 * tst_brk() - Print result message (include file contents)
45 * and break remaining test cases
46 * tst_brkm() - Print result message and break remaining test
47 * cases
48 * tst_brkloop() - Print result message (include file contents)
49 * and break test cases remaining in current loop
50 * tst_brkloopm() - Print result message and break test case
51 * remaining in current loop
52 * tst_flush() - Print any messages pending because of
53 * CONDENSE mode, and flush output stream
54 * tst_exit() - Exit test with a meaningful exit value.
55 * tst_environ() - Keep results coming to original stdout
57 * FUNCTION TITLE : Standard automated test result reporting mechanism
59 * SYNOPSIS:
60 * #include "test.h"
62 * void tst_res(ttype, fname, tmesg [,arg]...)
63 * int ttype;
64 * char *fname;
65 * char *tmesg;
67 * void tst_resm(ttype, tmesg [,arg]...)
68 * int ttype;
69 * char *tmesg;
71 * void tst_brk(ttype, fname, cleanup, tmesg, [,argv]...)
72 * int ttype;
73 * char *fname;
74 * void (*cleanup)();
75 * char *tmesg;
77 * void tst_brkm(ttype, cleanup, tmesg [,arg]...)
78 * int ttype;
79 * void (*cleanup)();
80 * char *tmesg;
82 * void tst_brkloop(ttype, fname, cleanup, char *tmesg, [,argv]...)
83 * int ttype;
84 * char *fname;
85 * void (*cleanup)();
86 * char *tmesg;
88 * void tst_brkloopm(ttype, cleanup, tmesg [,arg]...)
89 * int ttype;
90 * void (*cleanup)();
91 * char *tmesg;
93 * void tst_flush()
95 * void tst_exit()
97 * int tst_environ()
99 * AUTHOR : Kent Rogers (from Dave Fenner's original)
101 * CO-PILOT : Rich Logan
103 * DATE STARTED : 05/01/90 (rewritten 1/96)
105 * MAJOR CLEANUPS BY : Cyril Hrubis
107 * DESCRIPTION
108 * See the man page(s).
110 *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
111 #include <errno.h>
112 #include <string.h>
113 #include <stdio.h>
114 #include <stdlib.h>
115 #include <stdarg.h>
116 #include <unistd.h>
117 #include "test.h"
118 #include "usctest.h"
120 #define VERBOSE 1 /* flag values for the T_mode variable */
121 #define CONDENSE 2
122 #define NOPASS 3
123 #define DISCARD 4
125 #define MAXMESG 80 /* max length of internal messages */
126 #define USERMESG 2048 /* max length of user message */
127 #define TRUE 1
128 #define FALSE 0
130 #undef tst_brk
131 #undef tst_brkm
134 * EXPAND_VAR_ARGS - Expand the variable portion (arg_fmt) of a result
135 * message into the specified string.
137 #define EXPAND_VAR_ARGS(arg_fmt, str) { \
138 va_list ap; /* varargs mechanism */ \
140 if (arg_fmt != NULL) { \
141 if ( Expand_varargs == TRUE ) { \
142 va_start(ap, arg_fmt); \
143 vsprintf(str, arg_fmt, ap); \
144 va_end(ap); \
145 } else { \
146 strcpy(str, arg_fmt); \
148 } else { \
149 str[0] = '\0'; \
154 * Define local function prototypes.
156 static void check_env(void);
157 static void tst_condense(int tnum, int ttype, char *tmesg);
158 static void tst_print(char *tcid, int tnum, int trange, int ttype, char *tmesg);
159 static void cat_file(char *filename);
163 * Define some static/global variables.
165 static FILE *T_out = NULL; /* tst_res() output file descriptor */
166 static char *File; /* file whose contents is part of result */
167 static int T_exitval = 0; /* exit value used by tst_exit() */
168 static int T_mode = VERBOSE; /* flag indicating print mode: VERBOSE, */
169 /* CONDENSE, NOPASS, DISCARD */
171 static int Expand_varargs = TRUE; /* if TRUE, expand varargs stuff */
172 static char Warn_mesg[MAXMESG]; /* holds warning messages */
175 * These are used for condensing output when NOT in verbose mode.
177 static int Buffered = FALSE; /* TRUE if condensed output is currently */
178 /* buffered (i.e. not yet printed) */
179 static char *Last_tcid; /* previous test case id */
180 static int Last_num; /* previous test case number */
181 static int Last_type; /* previous test result type */
182 static char *Last_mesg; /* previous test result message */
186 * These globals may be externed by the test.
188 int Tst_count = 0; /* current count of test cases executed; NOTE: */
189 /* Tst_count may be externed by other programs */
190 int Tst_lptotal = 0; /* tst_brkloop() external */
191 int Tst_lpstart = 0; /* tst_brkloop() external */
192 int Tst_range = 1; /* for specifying multiple results */
193 int Tst_nobuf = 1; /* this is a no-op; buffering is never done, but */
194 /* this will stay for compatibility reasons */
197 * These globals must be defined in the test.
199 extern char *TCID; /* Test case identifier from the test source */
200 extern int TST_TOTAL; /* Total number of test cases from the test */
201 /* source */
204 * This global is used by the temp. dir. maintenance functions,
205 * tst_tmpdir()/tst_rmdir(), tst_wildcard()/tst_tr_rmdir(). It is the
206 * name of the directory created (if any). It is defined here, so that
207 * it only has to be declared once and can then be referenced from more
208 * than one module. Also, since the temp. dir. maintenance functions
209 * rely on the tst_res.c package this seemed like a reasonable place.
211 char *TESTDIR = NULL;
213 struct pair {
214 const char *name;
215 int val;
217 #define PAIR(def) [def] = { .name = #def, .val = def, },
218 const char *pair_lookup(struct pair *pair, int pair_size, int idx)
220 if (idx < 0 || idx >= pair_size || pair[idx].name == NULL)
221 return "???";
222 return pair[idx].name;
224 #define pair_lookup(pair, idx) pair_lookup(pair, ARRAY_SIZE(pair), idx)
227 * strttype() - convert a type result to the human readable string
229 const char *strttype(int ttype)
231 struct pair ttype_pairs[] = {
232 PAIR(TPASS)
233 PAIR(TFAIL)
234 PAIR(TBROK)
235 PAIR(TRETR)
236 PAIR(TCONF)
237 PAIR(TWARN)
238 PAIR(TINFO)
240 return pair_lookup(ttype_pairs, TTYPE_RESULT(ttype));
244 * strerrnodef() - convert an errno value to its C define
246 static const char *strerrnodef(int err)
248 struct pair errno_pairs[] = {
249 PAIR(EPERM)
250 PAIR(ENOENT)
251 PAIR(ESRCH)
252 PAIR(EINTR)
253 PAIR(EIO)
254 PAIR(ENXIO)
255 PAIR(E2BIG)
256 PAIR(ENOEXEC)
257 PAIR(EBADF)
258 PAIR(ECHILD)
259 PAIR(EAGAIN)
260 PAIR(ENOMEM)
261 PAIR(EACCES)
262 PAIR(EFAULT)
263 PAIR(ENOTBLK)
264 PAIR(EBUSY)
265 PAIR(EEXIST)
266 PAIR(EXDEV)
267 PAIR(ENODEV)
268 PAIR(ENOTDIR)
269 PAIR(EISDIR)
270 PAIR(EINVAL)
271 PAIR(ENFILE)
272 PAIR(EMFILE)
273 PAIR(ENOTTY)
274 PAIR(ETXTBSY)
275 PAIR(EFBIG)
276 PAIR(ENOSPC)
277 PAIR(ESPIPE)
278 PAIR(EROFS)
279 PAIR(EMLINK)
280 PAIR(EPIPE)
281 PAIR(EDOM)
282 PAIR(ERANGE)
283 PAIR(ENAMETOOLONG)
285 return pair_lookup(errno_pairs, err);
289 * tst_res() - Main result reporting function. Handle test information
290 * appropriately depending on output display mode. Call
291 * tst_condense() or tst_print() to actually print results.
292 * All result functions (tst_resm(), tst_brk(), etc.)
293 * eventually get here to print the results.
295 void tst_res(int ttype, char *fname, char *arg_fmt, ...)
297 int i;
298 char tmesg[USERMESG];
299 int ttype_result = TTYPE_RESULT(ttype);
301 #if DEBUG
302 printf("IN tst_res; Tst_count = %d; Tst_range = %d\n",
303 Tst_count, Tst_range); fflush(stdout);
304 #endif
306 EXPAND_VAR_ARGS(arg_fmt, tmesg);
309 * Save the test result type by ORing ttype into the current exit
310 * value (used by tst_exit()).
312 T_exitval |= ttype_result;
315 * Unless T_out has already been set by tst_environ(), make tst_res()
316 * output go to standard output.
318 if (T_out == NULL)
319 T_out = stdout;
322 * Check TOUTPUT environment variable (if first time) and set T_mode
323 * flag.
325 check_env();
327 if (Tst_range <= 0) {
328 Tst_range = 1;
329 tst_print(TCID, 0, 1, TWARN,
330 "tst_res(): Tst_range must be positive");
333 if (fname != NULL && access(fname, F_OK) == 0)
334 File = fname;
337 * Set the test case number and print the results, depending on the
338 * display type.
340 if (ttype_result == TWARN || ttype_result == TINFO) {
341 if (Tst_range > 1)
342 tst_print(TCID, 0, 1, TWARN,
343 "tst_res(): Range not valid for TINFO or TWARN types");
344 tst_print(TCID, 0, 1, ttype, tmesg);
345 } else {
346 if (Tst_count < 0)
347 tst_print(TCID, 0, 1, TWARN,
348 "tst_res(): Tst_count < 0 is not valid");
351 * Process each display type.
353 switch (T_mode) {
354 case DISCARD: /* do not print any results */
355 break;
357 case NOPASS: /* passing result types are filtered by tst_print() */
358 case CONDENSE:
359 tst_condense(Tst_count + 1, ttype, tmesg);
360 break;
362 default: /* VERBOSE */
363 for (i = 1 ; i <= Tst_range ; i++)
364 tst_print(TCID, Tst_count + i, Tst_range, ttype, tmesg);
365 break;
368 Tst_count += Tst_range;
371 Tst_range = 1;
372 Expand_varargs = TRUE;
377 * tst_condense() - Handle test cases in CONDENSE or NOPASS mode (i.e.
378 * buffer the current result and print the last result
379 * if different than the current). If a file was
380 * specified, print the current result and do not
381 * buffer it.
383 static void tst_condense(int tnum, int ttype, char *tmesg)
385 char *file;
386 int ttype_result = TTYPE_RESULT(ttype);
388 #if DEBUG
389 printf("IN tst_condense: tcid = %s, tnum = %d, ttype = %d, tmesg = %s\n",
390 TCID, tnum, ttype, tmesg);
391 fflush(stdout);
392 #endif
395 * If this result is the same as the previous result, return.
397 if (Buffered == TRUE) {
398 if (strcmp(Last_tcid, TCID) == 0 && Last_type == ttype_result &&
399 strcmp(Last_mesg, tmesg) == 0 && File == NULL )
400 return;
403 * This result is different from the previous result. First,
404 * print the previous result.
406 file = File;
407 File = NULL;
408 tst_print(Last_tcid, Last_num, tnum - Last_num, Last_type,
409 Last_mesg);
410 free(Last_tcid);
411 free(Last_mesg);
412 File = file;
416 * If a file was specified, print the current result since we have no
417 * way of retaining the file contents for comparing with future
418 * results. Otherwise, buffer the current result info for next time.
420 if (File != NULL) {
421 tst_print(TCID, tnum, Tst_range, ttype, tmesg);
422 Buffered = FALSE;
423 } else {
424 Last_tcid = (char *)malloc(strlen(TCID) + 1);
425 strcpy(Last_tcid, TCID);
426 Last_num = tnum;
427 Last_type = ttype_result;
428 Last_mesg = (char *)malloc(strlen(tmesg) + 1);
429 strcpy(Last_mesg, tmesg);
430 Buffered = TRUE;
436 * tst_flush() - Print any messages pending because of CONDENSE mode,
437 * and flush T_out.
439 void tst_flush(void)
441 #if DEBUG
442 printf("IN tst_flush\n");
443 fflush(stdout);
444 #endif
447 * Print out last line if in CONDENSE or NOPASS mode.
449 if (Buffered == TRUE && (T_mode == CONDENSE || T_mode == NOPASS)) {
450 tst_print(Last_tcid, Last_num, Tst_count - Last_num + 1,
451 Last_type, Last_mesg);
452 Buffered = FALSE;
455 fflush(T_out);
460 * tst_print() - Actually print a line or range of lines to the output
461 * stream.
463 static void tst_print(char *tcid, int tnum, int trange, int ttype, char *tmesg)
465 const char *type;
466 int ttype_result = TTYPE_RESULT(ttype);
468 #if DEBUG
469 printf("IN tst_print: tnum = %d, trange = %d, ttype = %d, tmesg = %s\n",
470 tnum, trange, ttype, tmesg);
471 fflush(stdout);
472 #endif
475 * Save the test result type by ORing ttype into the current exit value
476 * (used by tst_exit()). This is already done in tst_res(), but is
477 * also done here to catch internal warnings. For internal warnings,
478 * tst_print() is called directly with a case of TWARN.
480 T_exitval |= ttype_result;
483 * If output mode is DISCARD, or if the output mode is NOPASS and this
484 * result is not one of FAIL, BROK, or WARN, just return. This check
485 * is necessary even though we check for DISCARD mode inside of
486 * tst_res(), since occasionally we get to this point without going
487 * through tst_res() (e.g. internal TWARN messages).
489 if (T_mode == DISCARD || (T_mode == NOPASS && ttype_result != TFAIL &&
490 ttype_result != TBROK && ttype_result != TWARN))
491 return;
494 * Build the result line and print it.
496 type = strttype(ttype);
497 if (T_mode == VERBOSE) {
498 fprintf(T_out, "%-8s %4d %s : %s", tcid, tnum, type, tmesg);
499 } else {
500 if (trange > 1)
501 fprintf(T_out, "%-8s %4d-%-4d %s : %s",
502 tcid, tnum, tnum + trange - 1, type, tmesg);
503 else
504 fprintf(T_out, "%-8s %4d %s : %s",
505 tcid, tnum, type, tmesg);
507 if (ttype & TERRNO) {
508 int err = errno; /* avoid unintended side effects */
509 fprintf(T_out, ": errno=%s(%i): %s", strerrnodef(err),
510 err, strerror(err));
512 if (ttype & TTERRNO)
513 fprintf(T_out, ": TEST_ERRNO=%s(%i): %s", strerrnodef(TEST_ERRNO),
514 (int)TEST_ERRNO, strerror(TEST_ERRNO));
515 fprintf(T_out, "\n");
518 * If tst_res() was called with a file, append file contents to the
519 * end of last printed result.
521 if (File != NULL)
522 cat_file(File);
524 File = NULL;
529 * check_env() - Check the value of the environment variable TOUTPUT and
530 * set the global variable T_mode. The TOUTPUT environment
531 * variable should be set to "VERBOSE", "CONDENSE",
532 * "NOPASS", or "DISCARD". If TOUTPUT does not exist or
533 * is not set to a valid value, the default is "VERBOSE".
535 static void check_env(void)
537 static int first_time = 1;
538 char *value;
540 #if DEBUG
541 printf("IN check_env\n");
542 fflush(stdout);
543 #endif
545 if (!first_time)
546 return;
548 first_time = 0;
550 /* TOUTPUT not defined, use default */
551 if ((value = getenv(TOUTPUT)) == NULL) {
552 T_mode = VERBOSE;
553 return;
556 if (strcmp(value, TOUT_CONDENSE_S) == 0) {
557 T_mode = CONDENSE;
558 return;
561 if (strcmp(value, TOUT_NOPASS_S) == 0) {
562 T_mode = NOPASS;
563 return;
566 if (strcmp(value, TOUT_DISCARD_S) == 0) {
567 T_mode = DISCARD;
568 return;
571 /* default */
572 T_mode = VERBOSE;
573 return;
578 * tst_exit() - Call exit() with the value T_exitval, set up by
579 * tst_res(). T_exitval has a bit set for most of the
580 * result types that were seen (including TPASS, TFAIL,
581 * TBROK, TWARN, TCONF). Also, print the last result (if
582 * necessary) before exiting.
584 void tst_exit(void)
586 #if DEBUG
587 printf("IN tst_exit\n"); fflush(stdout);
588 fflush(stdout);
589 #endif
592 * Call tst_flush() flush any ouput in the buffer or the last
593 * result not printed because of CONDENSE mode.
595 tst_flush();
598 * Mask out TRETR, TINFO, and TCONF results from the exit status.
600 exit(T_exitval & ~(TRETR | TINFO | TCONF));
605 * tst_environ() - Preserve the tst_res() output location, despite any
606 * changes to stdout.
608 int tst_environ(void)
610 if ((T_out = fdopen(dup(fileno(stdout)), "w")) == NULL)
611 return -1;
612 else
613 return 0;
618 * tst_brk() - Fail or break current test case, and break the remaining
619 * tests cases.
621 void tst_brk(int ttype, char *fname, void (*func)(void), char *arg_fmt, ...)
623 char tmesg[USERMESG];
624 int ttype_result = TTYPE_RESULT(ttype);
626 #if DEBUG
627 printf("IN tst_brk\n"); fflush(stdout);
628 fflush(stdout);
629 #endif
631 EXPAND_VAR_ARGS(arg_fmt, tmesg);
634 * Only FAIL, BROK, CONF, and RETR are supported by tst_brk().
636 if (ttype_result != TFAIL && ttype_result != TBROK &&
637 ttype_result != TCONF && ttype_result != TRETR) {
638 sprintf(Warn_mesg, "tst_brk(): Invalid Type: %d. Using TBROK",
639 ttype_result);
640 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
641 ttype = TBROK;
644 /* Print the first result, if necessary. */
645 if (Tst_count < TST_TOTAL)
646 tst_res(ttype, fname, "%s", tmesg);
648 /* Determine the number of results left to report. */
649 Tst_range = TST_TOTAL - Tst_count;
651 /* Print the rest of the results, if necessary. */
652 if (Tst_range > 0) {
653 if (ttype == TCONF) {
654 tst_res(ttype, NULL,
655 "Remaining cases not appropriate for configuration");
656 } else {
657 if ( ttype == TRETR )
658 tst_res(ttype, NULL, "Remaining cases retired");
659 else
660 tst_res(TBROK, NULL, "Remaining cases broken");
662 } else {
663 Tst_range = 1;
664 Expand_varargs = TRUE;
668 * If no cleanup function was specified, just return to the caller.
669 * Otherwise call the specified function. If specified function
670 * returns, call tst_exit().
672 if (func != NULL) {
673 (*func)();
674 tst_exit();
680 * tst_brkloop() - Fail or break current test case, and break the
681 * remaining test cases within test case loop.
683 void tst_brkloop(int ttype, char *fname, void (*func)(void), char *arg_fmt, ...)
685 char tmesg[USERMESG];
687 #if DEBUG
688 printf("IN tst_brkloop\n"); fflush(stdout);
689 fflush(stdout);
690 #endif
692 EXPAND_VAR_ARGS(arg_fmt, tmesg);
694 if (Tst_lpstart < 0 || Tst_lptotal < 0) {
695 tst_print(TCID, 0, 1, TWARN,
696 "tst_brkloop(): Tst_lpstart & Tst_lptotal must both be assigned non-negative values");
697 Expand_varargs = TRUE;
698 return;
702 * Only FAIL, BROK, CONF, and RETR are supported by tst_brkloop().
704 if (ttype != TFAIL && ttype != TBROK && ttype != TCONF &&
705 ttype != TRETR) {
706 sprintf(Warn_mesg,
707 "tst_brkloop(): Invalid Type: %d(%s). Using TBROK",
708 ttype, strttype(ttype));
709 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
710 ttype = TBROK;
713 /* Print the first result, if necessary. */
714 if (Tst_count < Tst_lpstart + Tst_lptotal)
715 tst_res(ttype, fname, "%s", tmesg);
717 /* Determine the number of results left to report. */
718 Tst_range = Tst_lptotal + Tst_lpstart - Tst_count;
720 /* Print the rest of the results, if necessary. */
721 if (Tst_range > 0) {
722 if (ttype == TCONF) {
723 tst_res(ttype, NULL,
724 "Remaining cases in loop not appropriate for configuration");
725 } else {
726 if (ttype == TRETR)
727 tst_res(ttype, NULL, "Remaining cases in loop retired");
728 else
729 tst_res(TBROK, NULL, "Remaining cases in loop broken");
731 } else {
732 Tst_range = 1;
733 Expand_varargs = TRUE;
736 /* If a cleanup function was specified, call it. */
737 if (func != NULL)
738 (*func)();
743 * tst_resm() - Interface to tst_res(), with no filename.
745 void tst_resm(int ttype, char *arg_fmt, ...)
747 char tmesg[USERMESG];
749 #if DEBUG
750 printf("IN tst_resm\n"); fflush(stdout);
751 fflush(stdout);
752 #endif
754 EXPAND_VAR_ARGS(arg_fmt, tmesg);
756 tst_res(ttype, NULL, "%s", tmesg);
761 * tst_brkm() - Interface to tst_brk(), with no filename.
763 void tst_brkm(int ttype, void (*func)(void), char *arg_fmt, ...)
765 char tmesg[USERMESG];
767 #if DEBUG
768 printf("IN tst_brkm\n"); fflush(stdout);
769 fflush(stdout);
770 #endif
772 EXPAND_VAR_ARGS(arg_fmt, tmesg);
774 tst_brk(ttype, NULL, func, "%s", tmesg);
779 * tst_brkloopm() - Interface to tst_brkloop(), with no filename.
781 void tst_brkloopm(int ttype, void (*func)(void), char *arg_fmt, ...)
783 char tmesg[USERMESG];
785 #if DEBUG
786 printf("IN tst_brkloopm\n");
787 fflush(stdout);
788 #endif
790 EXPAND_VAR_ARGS(arg_fmt, tmesg);
792 tst_brkloop(ttype, NULL, func, "%s", tmesg);
797 * tst_require_root() - Test for root permissions and abort if not.
799 void tst_require_root(void (*func)(void))
801 if (geteuid() != 0)
802 tst_brkm(TCONF, func, "Test needs to be run as root");
807 * cat_file() - Print the contents of a file to standard out.
809 static void cat_file(char *filename)
811 FILE *fp;
812 int b_read, b_written;
813 char buffer[BUFSIZ];
815 #if DEBUG
816 printf("IN cat_file\n"); fflush(stdout);
817 #endif
819 if ((fp = fopen(filename, "r")) == NULL) {
820 sprintf(Warn_mesg,
821 "tst_res(): fopen(%s, \"r\") failed; errno = %d: %s",
822 filename, errno, strerror(errno));
823 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
824 return;
827 errno = 0;
829 while ((b_read = fread(buffer, 1, BUFSIZ, fp)) != 0) {
830 if ((b_written = fwrite(buffer, 1, b_read, T_out)) != b_read) {
831 sprintf(Warn_mesg,
832 "tst_res(): While trying to cat \"%s\", fwrite() wrote only %d of %d bytes",
833 filename, b_written, b_read);
834 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
835 break;
839 if (!feof(fp)) {
840 sprintf(Warn_mesg,
841 "tst_res(): While trying to cat \"%s\", fread() failed, errno = %d: %s",
842 filename, errno, strerror(errno));
843 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
846 if (fclose(fp) != 0) {
847 sprintf(Warn_mesg,
848 "tst_res(): While trying to cat \"%s\", fclose() failed, errno = %d: %s",
849 filename, errno, strerror(errno));
850 tst_print(TCID, 0, 1, TWARN, Warn_mesg);
855 #ifdef UNIT_TEST
856 /****************************************************************************
857 * Unit test code: Takes input from stdin and can make the following
858 * calls: tst_res(), tst_resm(), tst_brk(), tst_brkm(),
859 * tst_flush_buf(), tst_exit().
860 ****************************************************************************/
861 int TST_TOTAL = 10;
862 char *TCID = "TESTTCID";
864 #define RES "tst_res.c UNIT TEST message; ttype = %d; contents of \"%s\":"
865 #define RESM "tst_res.c UNIT TEST message; ttype = %d"
867 int main(void)
869 int ttype;
870 int range;
871 char chr;
872 char fname[MAXMESG];
874 printf("UNIT TEST of tst_res.c. Options for ttype:\n\
875 -1 : call tst_exit()\n\
876 -2 : call tst_flush()\n\
877 -3 : call tst_brk()\n\
878 -4 : call tst_brkloop()\n\
879 -5 : call tst_res() with a range\n\
880 %2i : call tst_res(TPASS, ...)\n\
881 %2i : call tst_res(TFAIL, ...)\n\
882 %2i : call tst_res(TBROK, ...)\n\
883 %2i : call tst_res(TWARN, ...)\n\
884 %2i : call tst_res(TRETR, ...)\n\
885 %2i : call tst_res(TINFO, ...)\n\
886 %2i : call tst_res(TCONF, ...)\n\n",
887 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
889 while (1) {
890 printf("Enter ttype (-5,-4,-3,-2,-1,%i,%i,%i,%i,%i,%i,%i): ",
891 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
892 scanf("%d%c", &ttype, &chr);
894 switch (ttype) {
895 case -1:
896 tst_exit();
897 break;
899 case -2:
900 tst_flush();
901 break;
903 case -3:
904 printf("Enter the current type (%i=FAIL, %i=BROK, %i=RETR, %i=CONF): ",
905 TFAIL, TBROK, TRETR, TCONF);
906 scanf("%d%c", &ttype, &chr);
907 printf("Enter file name (<cr> for none): ");
908 gets(fname);
909 if (strcmp(fname, "") == 0)
910 tst_brkm(ttype, tst_exit, RESM, ttype);
911 else
912 tst_brk(ttype, fname, tst_exit, RES, ttype, fname);
913 break;
915 case -4:
916 printf("Enter the size of the loop: ");
917 scanf("%d%c", &range, &chr);
918 Tst_lpstart = Tst_count;
919 Tst_lptotal = range;
920 printf("Enter the current type (%i=FAIL, %i=BROK, %i=RETR, %i=CONF): ",
921 TFAIL, TBROK, TRETR, TCONF);
922 scanf("%d%c", &ttype, &chr);
923 printf("Enter file name (<cr> for none): ");
924 gets(fname);
926 if (strcmp(fname, "") == 0)
927 tst_brkloopm(ttype, NULL, RESM, ttype);
928 else
929 tst_brkloop(ttype, fname, NULL, RES, ttype, fname);
930 break;
932 case -5:
933 printf("Enter the size of the range: ");
934 scanf("%d%c", &Tst_range, &chr);
935 printf("Enter the current type (%i,%i,%i,%i,%i,%i,%i): ",
936 TPASS, TFAIL, TBROK, TWARN, TRETR, TINFO, TCONF);
937 scanf("%d%c", &ttype, &chr);
938 default:
939 printf("Enter file name (<cr> for none): ");
940 gets(fname);
942 if (strcmp(fname, "") == 0)
943 tst_resm(ttype, RESM, ttype);
944 else
945 tst_res(ttype, fname, RES, ttype, fname);
946 break;
952 #endif /* UNIT_TEST */