home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2 / Openstep-4.2-Intel-User.iso / NextLibrary / PrivateFrameworks / Uucp.framework / Versions / A / Resources / contrib / uurate.c < prev    next >
C/C++ Source or Header  |  1995-05-26  |  63KB  |  1,855 lines

  1. /*
  2.  * @(#)uurate.c 1.2 - Thu Sep  3 18:32:46 1992
  3.  *
  4.  * This program digests log and stats files in the "Taylor" format
  5.  * and outputs various statistical data to standard out.
  6.  *
  7.  * Author:
  8.  *      Bob Denny (denny@alisa.com)
  9.  *      Fri Feb  7 13:38:36 1992
  10.  *
  11.  * Original author:
  12.  *      Mark Pizzolato   mark@infopiz.UUCP
  13.  *
  14.  * Edits:
  15.  *      Bob Denny - Fri Feb  7 15:04:54 1992
  16.  *      Heavy rework for Taylor UUCP. This was the (very old) uurate from
  17.  *      DECUS UUCP, which had a single logfile for activity and stats.
  18.  *      Personally, I would have done things differently, with tables
  19.  *      and case statements, but in the interest of time, I preserved
  20.  *      Mark Pizzolato's techniques and style.
  21.  *
  22.  *      Bob Denny - Sun Aug 30 14:18:50 1992
  23.  *      Changes to report format suggested by Francois Pinard and others.
  24.  *      Add summary report, format from uutraf.pl (perl script), again
  25.  *      thanks to Francois. Integrate and checkout with 1.03 of Taylor UUCP.
  26.  *
  27.  *      Stephan Niemz <stephan@sunlab.ka.sub.org> - Fri Apr 9 1993
  28.  *      - Print totals in summary report,
  29.  *      - show all commands in execution report,
  30.  *      - count incoming calls correctly,
  31.  *      - suppress empty tables,
  32.  *      - don't divide by zero in efficiency report,
  33.  *      - limit the efficiency to 100% (could be more with the i-protocol),
  34.  *      - suppress some zeros to improve readability,
  35.  *      - check for failure of calloc,
  36.  *      - -h option changed to -s for consistency with all other uucp commands
  37.  *        (but -h was left in for comptibility).
  38.  *
  39.  *      Scott Boyd <scott@futures.com> - Thu Aug 26 13:21:34 PDT 1993
  40.  *      - Changed hosts linked-list insertion routine so that hosts
  41.  *        are always listed in alphabetical order on reports.
  42.  *
  43.  *      Klaus Dahlenburg <kdburg@incoahe.hanse.de> - Fri Jun 18 1993 (1.2.2)
  44.  *      - redesigned the printed layout (sticked to those 80 column tubes).
  45.  *      - 'Retry time not ...' and ' ERROR: All matching ports ...' will now be
  46.  *        counted as calls and will raise the failed-call counter.
  47.  *      - times now shown as hh:mm:ss; the fields may hold up to 999 hrs  
  48.  *        (a month equals 744 hrs at max). Printing will be as follows:
  49.  *
  50.  *         hrs > 0  hh:mm:ss
  51.  *         min > 0     mm:ss
  52.  *         sec > 0        ss
  53.  *         leading zeroes are suppressed.
  54.  *
  55.  *      - the bytes xfered will be given in thousands only (we're counting 
  56.  *        so 1K is 1000 bytes!). Sums up to 9,999,999.9 thousand can be shown.
  57.  *      - dropped the fractions of a byte in columns: bytes/second (avg cps).
  58.  *      - File statistic changed to display in/out in one row instead of 2
  59.  *        separate reports.
  60.  *      - eliminated the goto in command report and tightened the code; also
  61.  *        the 'goto usage' has been replaced by a call to void usage() with no
  62.  *        return (exit 1).
  63.  *      - a totaling is done for all reports now; the total values are held 
  64.  *        within the structure; after finishing read there will be an alloc
  65.  *        for a site named 'Total' so that the totals line will be printed
  66.  *        more or less automatically.
  67.  *      - option -t implemented: that is every possible report will be given.
  68.  *      - the start and end date/time of the input files are printed; can be
  69.  *        dropped by the -q option at run time.
  70.  *      - it is now possible to use Log/Stats files from V2_LOGGING configs.
  71.  *        They must however not be mixed together (with each other).
  72.  *      - the Log/Stats files are taken from config which is passed via
  73.  *        Makefile at compile time. Variable to set is: newconfigdir. If the
  74.  *        default config can't be read the default values are used
  75.  *        (the config is optional!).
  76.  *        Note: keyword/filename must be on the same line (no continuation).
  77.  *      - -I option implemented to run with a different config file. In case
  78.  *        the file can't be opened the run is aborted!
  79.  *      - -q option implemented to run without environment report (default is
  80.  *        FALSE: print the report).
  81.  *      - -p option added to print protocol statistics: one for the packets
  82.  *        and one for the errors encountered
  83.  *      - reapplied patch by Scott Boyd <scott@futures.com> that I did not
  84.  *        get knowledge of
  85.  */
  86. /* $Log: uurate.c,v $
  87.  * Revision 1.15  1994/04/07  21:47:11  kdburg
  88.  * printed 'no data avail' while there was data; layout chnaged
  89.  * (cosmetic only)
  90.  *
  91.  * Revision 1.14  1994/04/07  21:16:32  kdburg
  92.  * the layout of the protocol-used line within the LOGFILE changed
  93.  * from 1.04 to 1.05; both formats may be used together; output
  94.  * changed for packet report (columns adjusted)
  95.  *
  96.  * Revision 1.13  1994/04/04  10:04:35  kdburg
  97.  * cosmetic change to the packet-report (separator lines)
  98.  *
  99.  * Revision 1.12  1994/03/30  19:52:04  kdburg
  100.  * incorporated patch by Scott Boyd which was missing from this version
  101.  * of uurate.c. Left the comment in cronological order.
  102.  *
  103.  * Revision 1.11  1994/03/28  18:53:22  kdburg
  104.  * config not checked properly for 'logfile/statsfile' overwrites, bail-out
  105.  * possible; wrong file name written to log for statsfile when found
  106.  *
  107.  * Revision 1.10  1993/09/28  16:46:51  kdburg
  108.  * transmission failures denoted by: failed after ... in stats file
  109.  * have not been counted at all.
  110.  *
  111.  * Revision 1.9  1993/08/17  23:38:36  kdburg
  112.  * sometimes a line(site) was missing from the protocol stats due
  113.  * to a missing +; added option -d and -v reassing option -h to print
  114.  * the help; a zero was returned instead of a null-pointer by
  115.  * prot_sum
  116.  *
  117.  * Revision 1.8  1993/07/03  06:58:55  kdburg
  118.  * empty input not handled properly; assigned some buffer to input; msg
  119.  * not displayed when no protocol data was available
  120.  *
  121.  * Revision 1.7  1993/06/27  10:31:53  kdburg
  122.  * rindex was replaced by strchr must be strrchr
  123.  *
  124.  * Revision 1.6  1993/06/26  06:59:18  kdburg
  125.  * switch hdr_done not reset at beginning of protocol report
  126.  *
  127.  * Revision 1.5  1993/06/25  22:22:30  kdburg
  128.  * changed rindex to strchr; if there is no NEWCONFIG defined take
  129.  * appropriate action
  130.  *
  131.  * Revision 1.4  1993/06/25  20:04:07  kdburg
  132.  * added comment about -p option; inserted proto for rindex
  133.  *
  134.  * Revision 1.3  1993/06/25  19:31:14  kdburg
  135.  * major rework done; added protocol reports (normal/errors)
  136.  *
  137.  * Revision 1.2  1993/06/21  19:53:54  kdburg
  138.  * init
  139.  * */
  140.  
  141. char version[] = "@(#) Taylor UUCP Log File Summary Filter, Version 1.2.2";
  142. static char rcsid[] = "$Id: uurate.c,v 1.15 1994/04/07 21:47:11 kdburg Rel $";
  143. #include <ctype.h>            /* Character Classification      */
  144. #include <math.h>
  145. #include "uucp.h"
  146. /* uucp.h includes string.h or strings.h, no include here. */
  147.  
  148. #if HAVE_SYS_PARAM_H
  149. #include <sys/param.h>
  150. #endif
  151.  
  152. #define _DEBUG_ 0
  153.  
  154. /*
  155.  * Direction of Calling and Data Transmission
  156.  */
  157.  
  158. #define IN      0            /* Inbound            */
  159. #define OUT     1            /* Outbound            */
  160.  
  161. /*
  162.  *  define some limits
  163.  */
  164. #define MAXCOLS    8        /* report has this # of columns incl. 'name' */
  165. #define MAXREP     6        /* number of reports available */
  166. #define MAXFNAME  64        /* max input file name length incl. path*/
  167. #define MAXDNAME   8        /* max display (Hostname) name length  */
  168.  
  169. /*
  170.  * Data structures used to collect information
  171.  */
  172. struct File_Stats
  173.     {
  174.     int files;                      /* Files Transferred      */
  175.     unsigned long bytes;      /* Data Size Transferred*/
  176.     double time;                /* Transmission Time      */
  177.     };
  178.  
  179. struct Phone_Call
  180.     {
  181.     int calls;                           /* Call Count            */
  182.     int succs;                           /* Successful calls     */
  183.     double connect_time;           /* Connect Time Spent      */
  184.     struct File_Stats flow[2];       /* Rcvd & Sent Data      */
  185.     };
  186.  
  187. struct Execution_Command
  188.     {
  189.     struct Execution_Command *next;
  190.     char Commandname[64];
  191.     int count;
  192.     };
  193.  
  194. struct Protocol_Summary
  195.     {
  196.     struct Protocol_Summary *next;
  197.     char type[3];
  198.     long int  pr_cnt;
  199.     long int  pr_psent;
  200.     long int  pr_present;
  201.     long int  pr_preceived;
  202.     long int  pr_eheader;
  203.     long int  pr_echksum;
  204.     long int  pr_eorder;
  205.     long int  pr_ereject;
  206.     long int  pr_pwinmin;
  207.     long int  pr_pwinmax;
  208.     long int  pr_psizemin;
  209.     long int  pr_psizemax;
  210.     };
  211.  
  212. struct Host_entry
  213.     {
  214.     struct Host_entry *next;
  215.     char Hostname[32];
  216.     struct Execution_Command *cmds;      /* Local Activities */
  217.     struct Phone_Call call[2];            /* In & Out Activities */
  218.     struct Protocol_Summary *proto;
  219.     };
  220.  
  221.   struct Host_entry *hosts = NULL;
  222.   struct Host_entry *tot = NULL;
  223.   struct Host_entry *cur = NULL;
  224.   struct Execution_Command *cmd, *t_cmds = NULL;
  225.   struct Protocol_Summary *prot, *t_prot, *s_prot, *ss_prot = NULL;
  226. /*
  227.  * Stuff for getopt()
  228.  */
  229.  
  230. extern int optind;                /* GETOPT : Option Index */
  231. extern char *optarg;            /* GETOPT : Option Value */
  232. #if ! HAVE_STDLIB_H
  233.    extern pointer *calloc();
  234. #endif  /* HAVE_STDLIB_H */
  235. /*
  236.  * Default files to read. Taken from Taylor compile-time configuration.
  237.  * def_logs must look like an argvec, hence the dummy argv[0].
  238.  * Maybe later modified by scanning the config
  239.  */
  240.  
  241. static char *def_logs[3] = { NULL, NULL, NULL};
  242. char *I_conf = NULL;            /* points to config lib given by -I option */
  243. char *D_conf = NULL;            /* points to config lib from makefile */
  244. char *Tlog = NULL;              /* points to Log-file */
  245. char *Tstat = NULL;             /* points to Stats-file */
  246. char Pgm_name[64];              /* our pgm-name */
  247. char logline[BUFSIZ+1];         /* input area */
  248. char noConf[] = "- not defined -";
  249. char buff[16*BUFSIZ];
  250. char sbuff[2*BUFSIZ];
  251.  
  252. /*
  253.  * Boolean switches for various decisions
  254.  */
  255.  
  256.   int p_done = FALSE;           /* TRUE: start date/time of file printed */
  257.   int hdr_done = FALSE;         /* TRUE: report header printed */
  258.   int show_files = FALSE;       /* TRUE: -f option given */
  259.   int show_calls = FALSE;       /* TRUE: -c option given */
  260.   int show_commands = FALSE;    /* TRUE: -x option given */
  261.   int show_efficiency = FALSE;  /* TRUE: -e option given */
  262.   int show_all = FALSE;         /* TRUE: -t option given */
  263.   int show_proto = FALSE;       /* TRUE: -p option given */
  264.   int use_stdin = FALSE;        /* TRUE: -i option given */
  265.   int be_quiet = FALSE;         /* TRUE: -q option given */
  266.   int have_files[2];            /* TRUE: [IN] or [OUT] files found */
  267.   int have_calls = FALSE;       /* TRUE: in/out calls found */
  268.   int have_commands = FALSE;    /* TRUE: found uuxqt records */
  269.   int have_proto = FALSE;       /* TRUE: protocol data found */
  270.   int no_records = TRUE;        /* FALSE: got one record from file */
  271.  
  272. /*
  273.  * protos
  274.  */
  275.  
  276. static pointer *getmem(unsigned n);
  277. static void inc_cmd(struct Execution_Command **, char *name);
  278. static void fmtime(double sec, char *buf);
  279. static void fmbytes(unsigned long n, char *buf);
  280. static void usage();
  281. static int  chk_config(char *conf, int n, int type);
  282. static void hdrprt(char c, int bot);
  283. struct Protocol_Summary *prot_sum(struct Protocol_Summary **, char *, int);
  284.  
  285. /*
  286.  * BEGIN EXECUTION
  287.  */
  288.  
  289. int main(argc, argv)
  290.          int argc;
  291.          char *argv[];
  292. {
  293.   FILE *Log = NULL;
  294.   int c; 
  295.   char *p, *s, *stt, *flq = NULL;
  296.   char Hostname[MAXHOSTNAMELEN]; /* def taken from <sys/param.h> */
  297.   char Filename[15];             /* filename to be printed */
  298.   char in_date[14];              /* holds the date info of record read*/
  299.   char in_time[14];              /* holds the time info of record read */
  300.   char dt_info[31];  /* holds the date info from the last record read */
  301.   char *logmsg;
  302.   int sent, called = IN;
  303.   int report = 0;            /* if <= 0 give msg that no report was avail. */
  304.   int junk;
  305.  
  306.   /* --------------------------------------------------------------------
  307.    *           P r o l o g
  308.    * --------------------------------------------------------------------
  309.    */
  310.  
  311.    Hostname[0] = '\0';
  312.    have_files[IN]= have_files[OUT]= FALSE;
  313.    setvbuf(stdout,sbuff,_IOFBF,sizeof(sbuff));
  314.  
  315.   /*
  316.    * get how we've been called isolate the name from the path
  317.    */
  318.  
  319.    if ((stt = strrchr(argv[0],'/')) != NULL)
  320.       strcpy(Pgm_name,++stt);
  321.    else
  322.       strcpy(Pgm_name,argv[0]);
  323.    def_logs[0] = Pgm_name;
  324.    
  325.   /*
  326.    * I wish the compiler had the #error directive!
  327.    */
  328.  
  329. #if !HAVE_TAYLOR_LOGGING && !HAVE_V2_LOGGING
  330.   fprintf(stderr,"\a%s: (E) %s\n",Pgm_name,"Your config of Taylor UUCP is not yet supported.");
  331.   fprintf(stderr,"%s: (E) %s\n",Pgm_name,"Current support is for V2 or TAYLOR logging only.");
  332.   puts("   Run aborted due to errors\n")
  333.   exit(1);
  334. #endif
  335.  
  336.   /*
  337.    *  get some mem to store the default config name (def's are in
  338.    *  policy.h )
  339.    */
  340.  
  341.   if (sizeof(NEWCONFIGLIB) > 1)       /* defined at compile time */
  342.   {
  343.      D_conf = (char *)getmem((sizeof(NEWCONFIGLIB) + sizeof("/config")));
  344.      strcpy(D_conf,NEWCONFIGLIB);       /* passed by makefile */
  345.      strcat(D_conf,"/config");
  346.   }
  347.   Tlog   = (char *)getmem(sizeof(LOGFILE));
  348.   Tstat  = (char *)getmem(sizeof(STATFILE));
  349.   Tlog   = LOGFILE;
  350.   Tstat  = STATFILE;
  351.   
  352.   /*
  353.    * Process the command line arguments
  354.    */
  355.  
  356.   while((c = getopt(argc, argv, "I:s:cfdexaitphv")) != EOF)
  357.   {
  358.     switch(c)
  359.     {
  360.          case 'h':
  361.                   (void) usage();
  362.          case 's':
  363.                   strcpy(Hostname, optarg);
  364.                     break;
  365.          case 'c':
  366.                   show_calls = TRUE;
  367.                   ++report;
  368.                   break;
  369.          case 'd':
  370.                   printf("%s: (I) config-file default: %s\n",Pgm_name,D_conf);
  371.                   exit (0);
  372.                   break;
  373.          case 'f':
  374.                   show_files = TRUE;
  375.                   ++report;
  376.                   break;
  377.          case 'x':
  378.                   show_commands = TRUE;
  379.                   ++report;
  380.                   break;
  381.          case 'e':
  382.                   show_efficiency = TRUE;
  383.                   ++report;
  384.                   break;
  385.          case 'a':
  386.                   show_calls = show_files = show_commands = show_efficiency = TRUE;
  387.                   report = 4;
  388.                   break;
  389.          case 'i':
  390.                   use_stdin = TRUE;
  391.                   break;
  392.          case 't':
  393.                   show_all = TRUE;
  394.                   report = MAXREP;
  395.                   break;
  396.          case 'p':
  397.                   show_proto = TRUE;
  398.                   ++report;
  399.                   break;
  400.          case 'I':
  401.                   I_conf = (char *)getmem(sizeof(optarg));
  402.                   I_conf = optarg;
  403.                   break;
  404.                   case 'q':
  405.                   be_quiet = TRUE;
  406.                   break;
  407.          case 'v':
  408.                   printf("%s\n",rcsid);
  409.                   exit (0);
  410.          default :
  411.                   (void) usage();
  412.      }
  413.   }
  414.   if (report == 0)           /* no options given */
  415.      ++report;               /* at least summary can be printed */
  416.   if (! be_quiet)
  417.      hdrprt('i',0);         /* print header for environment info */
  418.  
  419.   /*
  420.    * Adjust argv and argc to account for the args processed above.
  421.    */
  422.  
  423.   argc -= (optind - 1);
  424.   argv += (optind - 1);
  425.  
  426.   /*
  427.    * If further args present, Assume rest are logfiles for us to process
  428.    * which should be given in pairs (log plus stat) otherwise the results may
  429.    * not come out as expected! If no further args are present take input from 
  430.    * Log and Stat files provided in the compilation environment of Taylor UUCP. 
  431.    * If -i was given, Log already points to stdin and no file args are accepted.
  432.    */
  433.  
  434.    if (use_stdin)           /* If -i, read from stdin */
  435.    {
  436.       if (argc != 1)            /* No file arguments allowed */
  437.       {
  438.          fprintf(stderr,"\a%s: (E) %s\n",Pgm_name,
  439.                          "it's not posssible to give file args with '-i'");
  440.          (void) usage();
  441.       }
  442.       else
  443.       {
  444.          argc = 2;
  445.          Log = stdin;
  446.          if (! be_quiet)
  447.             puts("   Input from stdin; no other files will be used\n");
  448.       }
  449.    }
  450.    else
  451.    {
  452.       if (argc != 1)                    /* file arguments are present */
  453.       {
  454.          if (! be_quiet)
  455.             puts("   No defaults used; will use passed file arguments\n");
  456.       }
  457.       else                            /* Read from current logs */
  458.       {
  459.          def_logs[1] = Tlog;      /* prime the */
  460.          def_logs[2] = Tstat;     /*   file names */   
  461.          if (! be_quiet)
  462.             printf("   Config for this run: ");
  463.  
  464.          if (I_conf != NULL)
  465.          {
  466.             junk = 0;
  467.             if (! be_quiet)
  468.                 printf("%s\n",I_conf);
  469.             if (0 != (chk_config(I_conf,be_quiet,junk)))
  470.                return (8);
  471.          }
  472.          else
  473.          {
  474.            if (D_conf != NULL)
  475.            {
  476.               junk = 1;             /* indicate default (compiled) config */
  477.               if (! be_quiet)
  478.                  printf("%s\n",D_conf);
  479.               chk_config(D_conf,be_quiet,junk);
  480.            }
  481.            else
  482.               if (! be_quiet)
  483.                  printf("%s\n",noConf);
  484.          }
  485.          def_logs[1] = Tlog;      /* final setting of */
  486.          def_logs[2] = Tstat;     /*   file names */   
  487.          argv = def_logs;            /* Bash argvec to log/stat files */
  488.          argc = sizeof(def_logs) / sizeof(def_logs[0]);
  489.        }
  490.    }
  491.  
  492.   /* --------------------------------------------------------------------
  493.    *                 MAIN LOGFILE PROCESSING LOOP
  494.    * --------------------------------------------------------------------
  495.    */
  496.  
  497.   if (!use_stdin)
  498.   {
  499.      if (argc < 3 && ! be_quiet)
  500.      {
  501.         puts("   (W) there is only one input file!");
  502.         puts("   (W) some reports may not be printed");
  503.      }
  504.      if (! be_quiet)
  505.         hdrprt('d',0);      /* give subheaderline  */
  506.   }
  507.  
  508.   while (argc > 1)
  509.   {
  510.     if (!use_stdin && (Log = fopen(argv[1], "r")) == NULL)
  511.     {
  512.        perror(argv[1]);
  513.        exit (8);
  514.     }
  515.     setvbuf(Log,buff,_IOFBF,sizeof(buff));
  516.     if ((flq = strrchr(argv[1], '/')) == NULL)
  517.        strncpy(Filename,argv[1],sizeof(Filename)-1);
  518.     else
  519.        strncpy(Filename,++flq,sizeof(Filename)-1);
  520.        
  521.     strcpy(in_date,"   n/a");
  522.     strcpy(in_time,"   n/a");
  523.     p_done = FALSE;             /* no info printed yet */
  524.     no_records = TRUE;          /* not read any record yet */
  525.  
  526.     /*
  527.      * Read each line of the logfile and collect information
  528.      */
  529.  
  530.     while (fgets(logline, sizeof(logline), Log))
  531.     {
  532.         /*
  533.          * The host name of the other end of the connection is
  534.          * always the second field of the log line, whether we
  535.          * are reading a Log file or a Stats file. Set 'p' to
  536.          * point to the second field, null-terminated. Skip
  537.          * the line if something is funny. V2 and Taylor ar identical
  538.          * up to this part. Put out the start/end date of the files read;
  539.          */
  540.  
  541.       if (NULL == (p = strchr(logline, ' ')))
  542.          continue;
  543.       no_records = FALSE;          /* got one (usable) record at least */
  544.       ++p;
  545.  
  546.       if (NULL != (stt = strchr(p, '(')))
  547.       {
  548.          if (! p_done && ! use_stdin && ! be_quiet)
  549.          {  
  550.  
  551. #if HAVE_TAYLOR_LOGGING
  552.          sscanf(++stt,"%s%*c%[^.]",in_date,in_time);
  553. #endif /* HAVE_TAYLOR_LOGGING */
  554.  
  555. #if HAVE_V2_LOGGING
  556.          sscanf(++stt,"%[^-]%*c%[1234567890:]",in_date,in_time);
  557. #endif /* HAVE_V2_LOGGING */
  558.  
  559.             printf("   %-14s %10s %8s",Filename, in_date, in_time);
  560.             strcpy(in_date,"   n/a");         /* reset to default */
  561.             strcpy(in_time,"   n/a");
  562.             p_done = TRUE;
  563.          }
  564.          else
  565.          {
  566.             if (! use_stdin && ! be_quiet)  /* save for last time stamp prt. */
  567.                strncpy(dt_info,++stt,sizeof(dt_info)-1);
  568.          }
  569.       }
  570.  
  571.       if (NULL != (s = strchr(p, ' ')))
  572.          *s = '\0';
  573.       for (s = p; *s; ++s)
  574.           if (isupper(*s))
  575.              *s = tolower(*s);
  576.  
  577.         /*
  578.          * Skip this line if we got -s <host> and
  579.          * this line does not contain that host name.
  580.          * Don't skip the `incoming call' line with the system name `-'.
  581.          */
  582.  
  583.       if (Hostname[0] != '\0')
  584.          if ( (p[0] != '-' || p[1] != '\0') && 0 != strcmp(p, Hostname) )
  585.             continue;
  586.  
  587.         /*
  588.          * We are within a call block now. If this line is a file
  589.          * transfer record, determine the direction. If not then
  590.          * skip the line if it is not interesting.
  591.          */
  592.       
  593.       if ((s = strchr(++s, ')')) == NULL)
  594.          continue;
  595.  
  596. #if ! HAVE_TAYLOR_LOGGING
  597. #if HAVE_V2_LOGGING
  598.       if ((strncmp(s,") (",3)) ==  0)      /* are we in stats file ?) */
  599.          if ((s = strchr(++s, ')')) == NULL)
  600.             continue;                     /* yes but strange layout */
  601. #endif /* HAVE_V2_LOGGING */
  602. #endif /* ! HAVE_TAYLOR_LOGGING  */ 
  603.  
  604.        logmsg = s + 2;            /* Message is 2 characters after ')' */
  605.        if ((0 != strncmp(logmsg, "Call complete", 13)) &&
  606.           (0 != strncmp(logmsg, "Calling system", 14)) &&
  607.           (0 != strncmp(logmsg, "Incoming call", 13)) &&
  608.           (0 != strncmp(logmsg, "Handshake successful", 20)) &&
  609.           (0 != strncmp(logmsg, "Retry time not", 14)) &&
  610.           (0 != strncmp(logmsg, "ERROR: All matching ports", 25)) &&
  611.           (0 != strncmp(logmsg, "Executing", 9)) &&
  612.           (0 != strncmp(logmsg, "Protocol ", 9)) &&
  613.           (0 != strncmp(logmsg, "sent ", 5)) &&
  614.           (0 != strncmp(logmsg, "received ", 9)) &&
  615.           (0 != strncmp(logmsg, "failed after ", 13)) &&
  616.           (0 != strncmp(logmsg, "Errors: ", 8)))
  617.           continue;
  618.  
  619.         /*
  620.          * Find the Host_entry for this host, or create a new
  621.          * one and link it on to the list.
  622.          */
  623.  
  624.        if ((cur == NULL) || (0 != strcmp(p, cur->Hostname)))
  625.        {
  626.           struct Host_entry *e, *last;
  627.  
  628.           for (e= cur= hosts; cur != NULL ; e= cur, cur= cur->next)
  629.               if (0 == strcmp(cur->Hostname, p))
  630.                  break;
  631.               if (cur == NULL)
  632.               {
  633.                  cur= (struct Host_entry *)getmem(sizeof(*hosts));
  634.                  strcpy(cur->Hostname, p);
  635.                  if (hosts == NULL)
  636.                     e= hosts= cur;
  637.          else {
  638.                     e = hosts;
  639.                     last = NULL;
  640.                     while (e != NULL) {
  641.                           if (strcmp(e->Hostname, cur->Hostname) <= 0) {
  642.                              if (e->next == NULL) {
  643.                                 e->next = cur;
  644.                                 break;
  645.                              }
  646.                              last = e;
  647.                              e = e->next;
  648.                           }
  649.                           else {
  650.                              cur->next = e;
  651.                              if (last == NULL)
  652.                                 hosts = cur;
  653.                              else
  654.                                 last->next = cur;
  655.                              break;
  656.                           }
  657.                      }   /*  while (e != NULL) */ 
  658.                  }    /*  hosts == NULL  */ 
  659.               }   /* cur == NULL */
  660.        }
  661.  
  662.         /*
  663.          * OK, if this is a uuxqt record, find the Execution_Command
  664.          * structure for the command being executed, or create a new
  665.          * one. Then count an execution of this command.
  666.          * (Log file only)
  667.          */
  668.  
  669.         if (0 == strncmp(logmsg, "Executing", 9))
  670.         {
  671.             if (NULL == (p = strchr(logmsg, '(')))
  672.                continue;
  673.             if ((s = strpbrk(++p, " )")) == NULL)
  674.                continue;
  675.             *s = '\0';
  676.             inc_cmd(&cur->cmds, p);
  677.             inc_cmd(&t_cmds, p);
  678.             have_commands = TRUE;
  679.             continue;
  680.         }
  681.  
  682.         /*
  683.          * Count start of outgoing call.
  684.          */
  685.  
  686.         if ((0 == strncmp(logmsg, "Calling system", 14)) ||
  687.             (0 == strncmp(logmsg, "Retry time not", 14)) ||
  688.             (0 == strncmp(logmsg, "ERROR: All matching ports", 25)))
  689.         {
  690.            called = OUT;
  691.            cur->call[OUT].calls++;
  692.            have_calls = TRUE;
  693.            s_prot = NULL;              /* destroy pointer to protocol */
  694.            continue;
  695.         }
  696.  
  697.         /*
  698.          * Count start of incoming call.
  699.          */
  700.  
  701.         if (0 == strncmp(logmsg, "Incoming call", 13))
  702.         {
  703.            called = IN;
  704.            s_prot = NULL;              /* destroy pointer to protocol */
  705.            continue;
  706.         }
  707.  
  708.         /*
  709.          * On an incoming call, get system name from the second line.
  710.          * Get protocol type and size/window too
  711.          */
  712.  
  713.         if (0 == strncmp(logmsg, "Handshake successful", 20))
  714.         {
  715.            if ( called==IN )
  716.               cur->call[IN].calls++;
  717.            have_calls = TRUE;
  718.            s_prot = NULL;              /* destroy pointer to protocol */
  719.            if (NULL == (p = strchr(logmsg, '(')))
  720.               continue;
  721.            if (0 == strncmp(p, "(protocol ", 10))
  722.            {
  723.               if (NULL == (p = strchr(p, '\'')))
  724.                  continue;
  725.               ss_prot = prot_sum(&cur->proto, ++p, 1);
  726.               s_prot  = prot_sum(&t_prot, p, 1);
  727.               continue;
  728.            }
  729.         }
  730.  
  731.         /*
  732.          * check protocol type and get stats
  733.          *
  734.          */
  735.  
  736.         if (0 == strncmp(logmsg, "Protocol ", 9))
  737.         {
  738.            s_prot = NULL;              /* destroy pointer to protocol */
  739.            if (NULL == (p = strchr(logmsg, '\'')))
  740.               continue;
  741.            ss_prot = prot_sum(&cur->proto, ++p, 2);
  742.            s_prot = prot_sum(&t_prot, p, 2);
  743.            continue;
  744.         }
  745.  
  746.         /*
  747.          * check protocol errors. Unfortunately the line does not contain
  748.          * the used protocol, so if any previous line did contain that
  749.          * information and we did process that line we will save the pointer
  750.          * to that particular segment into s_prot. If this pointer is not set
  751.          * the error info is lost for we don't know where to store.
  752.          *
  753.          */
  754.  
  755.         if ((0 == strncmp(logmsg, "Errors: header", 14)) && s_prot != NULL)
  756.         {
  757.           int i1,i2,i3,i4 = 0;
  758.           sscanf(logmsg,"%*s %*s %d%*c%*s %d%*c%*s %d%*c%*s %*s%*c %d",&i1,&i2,&i3,&i4);
  759.           ss_prot->pr_eheader += i1;
  760.           ss_prot->pr_echksum += i2;
  761.           ss_prot->pr_eorder += i3;
  762.           ss_prot->pr_ereject += i4;
  763.           s_prot->pr_eheader += i1;
  764.           s_prot->pr_echksum += i2;
  765.           s_prot->pr_eorder += i3;
  766.           s_prot->pr_ereject += i4;
  767.           s_prot = NULL;
  768.           continue;
  769.         }
  770.  
  771.         /*
  772.          * Handle end of call. Pick up the connect time.
  773.          * position is on the closing paren of date/time info
  774.          * i.e: ) text....  
  775.          */
  776.  
  777.         if (0 == strncmp(logmsg, "Call complete", 13))
  778.         {
  779.            cur->call[called].succs++;
  780.            s_prot = NULL;              /* destroy pointer to protocol */
  781.            if (NULL == (s = strchr(logmsg, '(')))
  782.               continue;
  783.            cur->call[called].connect_time += atof(s+1);
  784.            continue;
  785.         }
  786.  
  787.         /*
  788.          * We are definitely in a Stats file now.
  789.          * If we reached here, this must have been a file transfer
  790.          * record. Count it in the field corresponding to the
  791.          * direction of the transfer. Count bytes transferred and
  792.          * the time to transfer as well.
  793.          * Position within the record is at the word 'received' or 'sent'
  794.          * depending on the direction.
  795.          */
  796.  
  797.         sent = IN;              /* give it an initial value */
  798.         if (0 == strncmp(logmsg, "failed after ",13))
  799.            logmsg += 13;        /* the transmission failed for any reason */
  800.                                 /* so advance pointer */
  801.         if (0 == strncmp(logmsg, "sent", 4)) 
  802.            sent = OUT;
  803.         else if (0 == strncmp(logmsg, "received", 8))
  804.                 sent = IN;
  805.         have_files[sent] = TRUE;
  806.         cur->call[called].flow[sent].files++;
  807.         if (NULL == (s = strchr(logmsg, ' ')))       /* point past keyword */
  808.            continue;                                 /* nothing follows */
  809.                                    /* we should be at the bytes column now*/
  810. #if HAVE_TAYLOR_LOGGING
  811.         cur->call[called].flow[sent].bytes += atol(++s);
  812. #endif /* HAVE_TAYLOR_LOGGING */
  813. #if HAVE_V2_LOGGING
  814.         if (NULL == (s = strpbrk(s, "0123456789")))  /* point to # bytes */
  815.            continue;
  816.         cur->call[called].flow[sent].bytes += atol(s);
  817. #endif /* HAVE_V2_LOGGING */
  818.         if (NULL == (s = strchr(s, ' ')))          /* point past # of bytes */
  819.            continue;
  820.         if (NULL == (s = strpbrk(s, "0123456789"))) /* point to # of seconds */
  821.            continue;
  822.         cur->call[called].flow[sent].time += atof(s);
  823.  
  824.     }   /* end of while (fgets(logline...)) */
  825.  
  826.     if (stt != NULL && ! use_stdin && ! be_quiet && ! no_records)
  827.     {  
  828.  
  829. #if HAVE_TAYLOR_LOGGING
  830.          sscanf(dt_info,"%s%*c%[^.]",in_date,in_time);
  831. #endif /* HAVE_TAYLOR_LOGGING */
  832.  
  833. #if HAVE_V2_LOGGING
  834.          sscanf(dt_info,"%[^-]%*c%[1234567890:]",in_date,in_time);
  835. #endif /* HAVE_V2_LOGGING */
  836.  
  837.        printf("  %10s %8s\n",in_date, in_time);
  838.        p_done = FALSE;
  839.     }
  840.     if (Log != stdin)
  841.     {
  842.        if (0 != ferror(Log))
  843.        {
  844.           if (! be_quiet)
  845.              printf("   %-14s data is incomplete; read error"," ");
  846.           else
  847.             fprintf(stderr,"%s (W) data is incomplete; read error on %s\n",
  848.                                    Pgm_name,argv[1]);
  849.        }
  850.        else
  851.        {
  852.           if (! be_quiet && no_records)
  853.              printf("   %-14s %10s\n",Filename, " is empty ");
  854.        }         
  855.      }
  856.      fclose(Log);
  857.  
  858.     argc--;
  859.     argv++;
  860.   }  /* end of while (for (argv ....) */
  861.  
  862.   /*
  863.    *   do we have *any* data ?
  864.    */
  865.  
  866.   if (cur == NULL)
  867.   {
  868.      puts("\n(I) Sorry! No data is available for any requested report\n");
  869.      exit(0);
  870.   }
  871.  
  872.   /*
  873.    *   truncate hostname, alloc the structure holding the totals and
  874.    *   collect the totals data
  875.    */
  876.  
  877.   for (cur = hosts; cur != NULL;cur = cur->next)
  878.   {
  879.       cur->Hostname[MAXDNAME] = '\0';
  880.       if (cur->next == NULL)            /* last so will have to alloc totals */
  881.       {
  882.          cur->next = (struct Host_entry *)getmem(sizeof(*hosts));
  883.          strcpy(cur->next->Hostname,"Totals");
  884.          tot = cur->next;
  885.          for (cur = hosts; cur != NULL; cur = cur->next)
  886.          {
  887.            if (cur->next != NULL)        /* don't count totals to totals */
  888.            {
  889.               tot->call[IN].flow[IN].bytes += cur->call[IN].flow[IN].bytes;
  890.               tot->call[OUT].flow[IN].bytes += cur->call[OUT].flow[IN].bytes;
  891.               tot->call[IN].flow[OUT].bytes  += cur->call[IN].flow[OUT].bytes;
  892.               tot->call[OUT].flow[OUT].bytes += cur->call[OUT].flow[OUT].bytes;
  893.               tot->call[IN].flow[IN].time  += cur->call[IN].flow[IN].time;
  894.               tot->call[OUT].flow[IN].time += cur->call[OUT].flow[IN].time;
  895.               tot->call[IN].flow[OUT].time  += cur->call[IN].flow[OUT].time;
  896.               tot->call[OUT].flow[OUT].time += cur->call[OUT].flow[OUT].time;
  897.               tot->call[IN].flow[IN].files  += cur->call[IN].flow[IN].files;
  898.               tot->call[OUT].flow[IN].files += cur->call[OUT].flow[IN].files;
  899.               tot->call[IN].flow[OUT].files  += cur->call[IN].flow[OUT].files;
  900.               tot->call[OUT].flow[OUT].files += cur->call[OUT].flow[OUT].files;
  901.               tot->call[OUT].succs += cur->call[OUT].succs; 
  902.               tot->call[OUT].calls += cur->call[OUT].calls; 
  903.               tot->call[OUT].connect_time += cur->call[OUT].connect_time;
  904.               tot->call[IN].succs += cur->call[IN].succs; 
  905.               tot->call[IN].calls += cur->call[IN].calls; 
  906.               tot->call[IN].connect_time += cur->call[IN].connect_time;
  907.            }
  908.          }
  909.          break;                   /* totals is last in Host_Entry */
  910.      }
  911.   }
  912.  
  913.   /*
  914.    *                       ***********
  915.    *                       * REPORTS *
  916.    *                       ***********
  917.    */
  918.  
  919. #if _DEBUG_
  920.   putchar('\n');
  921. #endif
  922.  
  923.   /* ------------------------------------------------------------------
  924.    *
  925.    * Summary report only when no other report except option -t is given
  926.    *
  927.    * I know, this code could be tightened (rbd)...
  928.    * ------------------------------------------------------------------
  929.    */
  930.  
  931.   if (  !(show_calls || show_files ||
  932.           show_efficiency || show_commands || show_proto) || show_all)
  933.   {
  934.      if (have_calls || have_files[IN] || have_files[OUT])
  935.      {
  936.         char t1[32], t2[32], t3[32], t4[32], t5[32];
  937.         long ib, ob, b, rf, sf;
  938.         double it, ot, ir, or;
  939.  
  940.         hdr_done = FALSE;
  941.         for (cur = hosts; cur != NULL; cur = cur->next)
  942.         {
  943.            ib = (cur->call[IN].flow[IN].bytes +
  944.                 cur->call[OUT].flow[IN].bytes);
  945.            fmbytes(ib, t1);
  946.  
  947.            ob = (cur->call[IN].flow[OUT].bytes +
  948.                 cur->call[OUT].flow[OUT].bytes);
  949.            fmbytes(ob, t2);
  950.  
  951.                  /* Don't print null-lines. */
  952.            if (( b= ib+ob ) == 0 )
  953.               continue;
  954.                  /* Don't print the header twice. */
  955.              if (! hdr_done)
  956.              {
  957.                 hdrprt('s',0);            /* print the header line(s) */
  958.                 hdr_done = TRUE;
  959.              }
  960.  
  961.              fmbytes(b, t3);
  962.  
  963.              it = cur->call[IN].flow[IN].time +
  964.                   cur->call[OUT].flow[IN].time;
  965.              fmtime(it, t4);
  966.  
  967.              ot = cur->call[IN].flow[OUT].time +
  968.                   cur->call[OUT].flow[OUT].time;
  969.              fmtime(ot, t5);
  970.  
  971.              rf = cur->call[IN].flow[IN].files +
  972.                   cur->call[OUT].flow[IN].files;
  973.  
  974.              sf = cur->call[IN].flow[OUT].files +
  975.                   cur->call[OUT].flow[OUT].files;
  976.  
  977.              ir = (it == 0.0) ? 0.0 : (ib / it);
  978.              or = (ot == 0.0) ? 0.0 : (ob / ot);
  979.  
  980.              if (cur->next == NULL)            /* totals line reached ? */
  981.                 hdrprt('s',1);                 /* print the separator line */
  982.  
  983.              printf("%-8s %4d %4d %9s %9s %9s %9s %9s %5.0f %5.0f\n",
  984.                    cur->Hostname, rf, sf,
  985.                    t1, t2, t3, t4, t5,
  986.                    ir, or);
  987.         } 
  988.         if (! hdr_done)
  989.         {
  990.             puts("\n(I) No data found to print Compact summary report");
  991.         }
  992.      }
  993.      else
  994.      {
  995.         puts("\n(I) No data available for Compact summary report");
  996.         --report;
  997.      }
  998.   }
  999.  
  1000.   /* ------------------------------------------------------------------
  1001.    *                     Protocol statistics report
  1002.    * ------------------------------------------------------------------
  1003.    */
  1004.  
  1005.   if (show_proto || show_all)
  1006.   {
  1007.      if (have_proto)
  1008.      {
  1009.                         /* ---------------------  */
  1010.                         /* protocol packet report */
  1011.                         /* ---------------------  */
  1012.  
  1013.         char *type = NULL;
  1014.         hdr_done = FALSE;
  1015.         for (cur = hosts; cur != NULL; cur = cur->next)
  1016.         {
  1017.             type = cur->Hostname;
  1018.             if (cur->next == NULL)
  1019.             {
  1020.                if (hdr_done)
  1021.    puts("-------------------------------------------------------------------");
  1022.             cur->proto = t_prot;
  1023.             }
  1024.             for (prot = cur->proto; prot != NULL; prot = prot->next)
  1025.             {
  1026.                 if (! hdr_done)
  1027.                 {
  1028.                     hdrprt('p',0);            /* print the header line(s) */
  1029.                     hdr_done = TRUE;
  1030.                 }
  1031.                 printf("%-8s %3s  %4d %4d %5d %4d    %10d %7d %10d\n",
  1032.                                     type == NULL ? " ":cur->Hostname,
  1033.                                     prot->type,
  1034.                                     prot->pr_psizemin,
  1035.                                     prot->pr_psizemax,
  1036.                                     prot->pr_pwinmin,
  1037.                                     prot->pr_pwinmax,
  1038.                                     prot->pr_psent,
  1039.                                     prot->pr_present,
  1040.                                     prot->pr_preceived);
  1041.                 type = NULL;
  1042.              }
  1043.          }
  1044.          if (! hdr_done)
  1045.             puts("\n(I) No data found to print Protocol packet report");
  1046.  
  1047.                         /* --------------------- */
  1048.                         /* protocol error report */
  1049.                         /* --------------------- */
  1050.  
  1051.         type = NULL;
  1052.         hdr_done = FALSE;
  1053.         if (t_prot != NULL)
  1054.         {
  1055.            for (cur = hosts; cur != NULL; cur = cur->next)
  1056.            {
  1057.                type = cur->Hostname;
  1058.                if (cur->next == NULL)
  1059.                {
  1060.                   if (hdr_done)
  1061.         puts("--------------------------------------------------------------");
  1062.                cur->proto = t_prot;
  1063.                }
  1064.  
  1065.                for (prot = cur->proto; prot != NULL; prot = prot->next)
  1066.                {
  1067.                    if ((prot->pr_eheader + prot->pr_echksum +
  1068.                       prot->pr_eorder + prot->pr_ereject) != 0)
  1069.                    {
  1070.                       if (! hdr_done)
  1071.                       {
  1072.                          hdrprt('p',1);       /* print the header line(s) */
  1073.                          hdr_done = TRUE;
  1074.                       }
  1075.                       printf("%-8s %3s  %11d %11d  %11d %11d\n",
  1076.                                     type == NULL ? " ":cur->Hostname,
  1077.                                     prot->type,
  1078.                                     prot->pr_eheader,
  1079.                                     prot->pr_echksum,
  1080.                                     prot->pr_eorder,
  1081.                                     prot->pr_ereject);
  1082.                       type = NULL;
  1083.                    } 
  1084.                 }
  1085.             }
  1086.         }
  1087.         if (! hdr_done)
  1088.            puts("\n(I) No data found to print Protocol error report");
  1089.      }
  1090.      else
  1091.      {
  1092.         puts("\n(I) No data available for Protocol reports");
  1093.         --report;
  1094.      }
  1095.   }
  1096.  
  1097.   /* ------------------------------------------------------------------
  1098.    *                     Call statistics report
  1099.    * ------------------------------------------------------------------
  1100.    */
  1101.  
  1102.   if (show_calls || show_all)
  1103.   {
  1104.      if (have_calls)
  1105.      {
  1106.         char t1[32], t2[32];
  1107.  
  1108.         hdr_done = FALSE;
  1109.         for (cur = hosts; cur != NULL; cur = cur->next)
  1110.         {
  1111.             if (cur->next == NULL)
  1112.             {
  1113.                if (hdr_done)
  1114.                   hdrprt('c',1);                 /* print the separator line */
  1115.             }
  1116.             else
  1117.             {
  1118.                   /* Don't print null-lines on deatail lines */
  1119.                if ( cur->call[OUT].calls + cur->call[IN].calls == 0 )
  1120.                   continue;
  1121.  
  1122.                  /* Don't print the header twice. */
  1123.                if (! hdr_done)
  1124.                {
  1125.                    hdrprt('c',0);               /* print the header line(s) */
  1126.                    hdr_done = TRUE;
  1127.                }
  1128.             }
  1129.             if ( cur->call[OUT].calls > 0 || cur->next == NULL)
  1130.             {
  1131.                fmtime(cur->call[OUT].connect_time, t1);
  1132.                printf( "   %-8s %7d %7d %7d %9s",
  1133.                      cur->Hostname,
  1134.                      cur->call[OUT].succs,
  1135.                      cur->call[OUT].calls - cur->call[OUT].succs,
  1136.                      cur->call[OUT].calls,
  1137.                      t1 );
  1138.              }
  1139.              else
  1140.              {
  1141.                 printf( "   %-42s", cur->Hostname );
  1142.              }
  1143.              if ( cur->call[IN].calls > 0 || cur->next == NULL )
  1144.              {
  1145.                 fmtime(cur->call[IN].connect_time, t2);
  1146.                 printf( " %7d %7d %7d %9s",
  1147.                        cur->call[IN].succs,
  1148.                        cur->call[IN].calls - cur->call[IN].succs,
  1149.                        cur->call[IN].calls,
  1150.                        t2 );
  1151.               }
  1152.               putchar('\n');
  1153.         }
  1154.         if (! hdr_done)
  1155.         {
  1156.             puts("\n(I) No data found to print Call statistics report");
  1157.         }
  1158.      }
  1159.      else
  1160.      {
  1161.         puts("\n(I) No data available for Call statistics report");
  1162.         --report;
  1163.      }
  1164.   }
  1165.  
  1166.   /* ------------------------------------------------------------------
  1167.    *                    File statistics report
  1168.    * ------------------------------------------------------------------
  1169.    */
  1170.  
  1171.   if (show_files || show_all)
  1172.   {
  1173.      if (have_files[IN] || have_files[OUT])
  1174.      {
  1175.         char t1[32], t2[32];
  1176.         double rate = 0, time = 0;
  1177.         int b = 0; 
  1178.         int lineOut = 0;
  1179.  
  1180.         hdr_done = FALSE;
  1181.         for (cur = hosts; cur != NULL; cur = cur->next)
  1182.         {
  1183.             lineOut = 0;
  1184.             for (sent= IN; sent <= OUT; ++sent)
  1185.             {  
  1186.                 b    = cur->call[IN].flow[sent].bytes +
  1187.                        cur->call[OUT].flow[sent].bytes;
  1188.                 time = cur->call[IN].flow[sent].time +
  1189.                        cur->call[OUT].flow[sent].time;
  1190.  
  1191.                    /* Don't print null-lines on detail lines. */
  1192.                 if ( (b != 0 && time != 0.0) || cur->next == NULL)
  1193.                 {
  1194.                       /* Don't print the header twice. */
  1195.                    if (! hdr_done)
  1196.                    {
  1197.                       hdrprt('f',0);          /* print the header line(s) */
  1198.                       hdr_done = TRUE;
  1199.                    }
  1200.                    fmbytes(b, t1);
  1201.                    rate = (cur->call[IN].flow[sent].bytes +
  1202.                           cur->call[OUT].flow[sent].bytes) / time;
  1203.                    fmtime((cur->call[IN].flow[sent].time +
  1204.                           cur->call[OUT].flow[sent].time), t2);
  1205.  
  1206.                    if (lineOut == 0)         /* first half not printed yet ? */
  1207.                    {
  1208.                       if (cur->next == NULL)       /* totals line ? */
  1209.                          hdrprt('f',1);          /* print the separator line */
  1210.                       printf("   %-8s", cur->Hostname);
  1211.                       if (sent == OUT)     /* can't happen whith totals line */
  1212.                          printf("%34s", " ");
  1213.                     }
  1214.  
  1215.                     printf(" %5d %11s %9s %5.0f",
  1216.                           cur->call[IN].flow[sent].files +
  1217.                           cur->call[OUT].flow[sent].files,
  1218.                           t1, t2, rate);
  1219.                     lineOut = 1;
  1220.                  }
  1221.             }    /* end:  for (sent ... ) */  
  1222.             if (lineOut)
  1223.                 printf("\n");
  1224.         }    /* end:  for (cur= ... ) */
  1225.         if (! hdr_done)
  1226.         {
  1227.            puts("\n(I) No data found to print File statistics report");
  1228.         }
  1229.      }
  1230.      else
  1231.      {
  1232.         puts("\n(I) No data available for File statistics report");
  1233.         --report;
  1234.      }
  1235.   }
  1236.  
  1237.   /* ------------------------------------------------------------------
  1238.    *                       Efficiency report
  1239.    * ------------------------------------------------------------------
  1240.    */
  1241.  
  1242.   if (show_efficiency || show_all)
  1243.   {
  1244.      if (have_files[IN] || have_files[OUT])
  1245.      {
  1246.         char t1[32], t2[32], t3[32];
  1247.         double total, flow;
  1248.  
  1249.         hdr_done = FALSE;
  1250.         for (cur = hosts; cur != NULL; cur = cur->next)
  1251.         {
  1252.                  /* Don't print null-lines. */
  1253.             if ( 0 == cur->call[IN].flow[IN].files +
  1254.                       cur->call[IN].flow[OUT].files +
  1255.                       cur->call[OUT].flow[IN].files +
  1256.                       cur->call[OUT].flow[OUT].files ||
  1257.                  0.0 == (total= cur->call[IN].connect_time +
  1258.                         cur->call[OUT].connect_time))
  1259.             {
  1260.                continue;
  1261.             }
  1262.  
  1263.             if (! hdr_done)
  1264.             {
  1265.                hdrprt('e',0);                 /* print the header line(s) */
  1266.                hdr_done = TRUE;
  1267.             }
  1268.  
  1269.             flow = cur->call[IN].flow[IN].time + 
  1270.                    cur->call[IN].flow[OUT].time +
  1271.                    cur->call[OUT].flow[IN].time +
  1272.                    cur->call[OUT].flow[OUT].time;
  1273.              fmtime(total, t1);
  1274.              fmtime(flow, t2);
  1275.              fmtime(total-flow, t3);
  1276.  
  1277.             if (cur->next == NULL)
  1278.                hdrprt('e',1);                 /* print the separator line */
  1279.  
  1280.             printf("   %-8s %10s %10s %10s %7.2f\n",
  1281.                    cur->Hostname, t1, t2, t3,
  1282.             flow >= total ? 100.0: flow*100.0/total);
  1283.         }   /* end: for (cur= .. */
  1284.         if (! hdr_done)
  1285.         {
  1286.            puts("\n(I) No data found to print Efficiency report");
  1287.         }
  1288.      }
  1289.      else
  1290.      {
  1291.         puts("\n(I) No data available for Efficiency report");
  1292.         --report;
  1293.      }
  1294.   }
  1295.  
  1296.   /* ------------------------------------------------------------------
  1297.    *                   Command execution report
  1298.    * ------------------------------------------------------------------
  1299.    */
  1300.  
  1301.   if (show_commands || show_all)
  1302.   { 
  1303.      if (have_commands)
  1304.      {
  1305.         int ncmds, i, match;
  1306.  
  1307.         /* 
  1308.          *  layout the header line. The column's header is the command name
  1309.          */
  1310.  
  1311.         hdr_done = FALSE;
  1312.         for (ncmds= 0, cmd= t_cmds;
  1313.              cmd != NULL && ncmds <= MAXCOLS-1;
  1314.              ncmds++, cmd= cmd->next)
  1315.         {
  1316.             if (! hdr_done)
  1317.             {
  1318.                puts("\nCommand executions:");
  1319.                puts("-------------------");
  1320.                puts("   Name of ");
  1321.                fputs("   site    ", stdout);
  1322.                hdr_done = TRUE;
  1323.             }
  1324.             printf(" %7s", cmd->Commandname);
  1325.          }
  1326.          if (! hdr_done)
  1327.          {
  1328.             puts("\n(I) No data found to print Command execution report");
  1329.          }
  1330.          else
  1331.          {
  1332.            fputs("\n   --------", stdout);
  1333.            for (i= 0; i<ncmds; i++)
  1334.                fputs("  ------", stdout);
  1335.            putchar('\n');
  1336.  
  1337.         /* 
  1338.          *  print out the number of executions for each host/command
  1339.          */
  1340.  
  1341.            for (cur= hosts; cur != NULL; cur= cur->next)
  1342.            {
  1343.                if (cur->next == NULL)
  1344.                   break;
  1345.  
  1346.                  /* Don't print null-lines. */
  1347.  
  1348.               if (cur->cmds == NULL)
  1349.                  continue;
  1350.  
  1351.               printf("   %-8s", cur->Hostname);
  1352.               for (cmd= t_cmds; cmd != NULL; cmd= cmd->next)
  1353.               {
  1354.                   struct Execution_Command *ec;
  1355.                   match = FALSE;
  1356.                   for(ec= cur->cmds; ec != NULL; ec= ec->next)
  1357.                   {
  1358.                      if ( 0 == strcmp(cmd->Commandname, ec->Commandname) )
  1359.                      { 
  1360.                         printf(" %7d", ec->count);
  1361.                         match = TRUE;
  1362.                         break;
  1363.                      }
  1364.                    }
  1365.                    if (! match)
  1366.                       printf("%8s"," ");    /* blank out column */
  1367.                }
  1368.                putchar('\n');
  1369.             }
  1370.  
  1371.          /*
  1372.           *  print the totals line 
  1373.           */
  1374.  
  1375.             fputs("   --------", stdout);
  1376.             for (i= 0; i<ncmds; i++)
  1377.                 fputs("--------", stdout);
  1378.             printf("\n   %-8s", cur->Hostname);
  1379.             for (cmd= t_cmds; cmd != NULL; cmd= cmd->next)
  1380.             {
  1381.                 printf(" %7d", cmd->count);
  1382.             }
  1383.             putchar('\n');
  1384.         }
  1385.      }
  1386.      else
  1387.      {
  1388.         puts("\n(I) No data available for Command execution report");
  1389.         --report;
  1390.      }
  1391.   }
  1392.   if (report <= 0 )       /* any reports ? */
  1393.   {
  1394.      puts("\n(I) Sorry! No data is available for any requested report\n");
  1395.      exit(1);
  1396.   }
  1397.  
  1398.   puts("\n(I) End of reports\n");
  1399.   exit (0);
  1400. }  /* end of main */
  1401.  
  1402.   /* ------------------------------------------------------------------
  1403.    *                       * Functions *
  1404.    * ------------------------------------------------------------------
  1405.    */
  1406.  
  1407.   /* ------------------------------------------------------------------
  1408.    *                    display the help 
  1409.    * ------------------------------------------------------------------
  1410.    */
  1411.  
  1412. void usage()
  1413. {
  1414.   fprintf(stderr,"Usage uurate [-acdefhiptvx] [-s hostname] [-I config file] [logfile(s) ... logfile(s)]\n");
  1415.   fprintf(stderr,"where:\t-a\tPrint reports c,e,f,x\n");
  1416.   fprintf(stderr,"\t-c\tReport call statistics\n");
  1417.   fprintf(stderr,"\t-d\tPrint the name of the default config file\n");
  1418.   fprintf(stderr,"\t-e\tReport efficiency statistics\n");
  1419.   fprintf(stderr,"\t-f\tReport file transfer statistics\n");
  1420.   fprintf(stderr,"\t-h\tPrint this help\n");
  1421.   fprintf(stderr,"\t-i\tRead log info from standard input\n");
  1422.   fprintf(stderr,"\t-p\tReport protocol statistics\n");
  1423.   fprintf(stderr,"\t-t\tAll available reports plus compact summary report\n");
  1424.   fprintf(stderr,"\t-v\tPrint version number\n");
  1425.   fprintf(stderr,"\t-x\tReport command execution statistics\n");
  1426.   fprintf(stderr,"\t-s host\tReport activities involving HOST only\n");
  1427.   fprintf(stderr,"\t-I config Use config instead of standard config file\n");
  1428.   fprintf(stderr,"If no report options given, a compact summary report is printed.\n");
  1429.   fprintf(stderr,"log files should be given as pairs that is Log/Stats ... .\n");
  1430.   fprintf(stderr,"If neither -i nor logfiles given, those names found in config will be used\n");
  1431.  
  1432.   exit (1);
  1433. }
  1434.  
  1435.  /* ------------------------------------------------------------------
  1436.   *                    getmem - get some memory
  1437.   * ------------------------------------------------------------------
  1438.   */
  1439.  
  1440. static pointer *getmem(n)
  1441.                     unsigned n;
  1442. {
  1443.   pointer *p;
  1444.  
  1445.   if( NULL== (p= calloc(1, n)) )
  1446.     {
  1447.       fprintf(stderr,"\a%s (C) %s\n",Pgm_name, "out of memory\n");
  1448.       exit (8);
  1449.     }
  1450.   return p;
  1451. }
  1452.  
  1453.   /* ------------------------------------------------------------------
  1454.    *             inc_cmd - increment command count
  1455.    * ------------------------------------------------------------------
  1456.    */
  1457.  
  1458. static void inc_cmd(cmds, name)
  1459.                     struct Execution_Command **cmds;
  1460.                     char *name;
  1461. {
  1462.   int cnt = 0;
  1463.   struct Execution_Command *cmd, *ec;
  1464.  
  1465.   for (ec = cmd = *cmds; cmd != NULL; ec= cmd, cmd= cmd->next, cnt++)
  1466.       if ( (0 == strcmp(cmd->Commandname, name)) ||
  1467.            (0 == strcmp(cmd->Commandname, "Misc.")) )
  1468.          break;
  1469.   if (cmd == NULL)
  1470.   {
  1471.      cmd= (struct Execution_Command *)getmem(sizeof(*cmd));
  1472.      if (cnt <= MAXCOLS-1)   /* first col prints site name therefore < max-1 */
  1473.      {
  1474.         strcpy(cmd->Commandname, name);
  1475.         if (*cmds == NULL)
  1476.            ec = *cmds = cmd;
  1477.         else
  1478.            ec->next= cmd;
  1479.      }
  1480.      else
  1481.      {
  1482.         strcpy(ec->Commandname, "Misc.");  /* reached high-water-mark */
  1483.         cmd = ec;                          /* backtrack */
  1484.      }
  1485.   }
  1486.   cmd->count++;
  1487. }
  1488.  
  1489.  
  1490.   /* ------------------------------------------------------------------
  1491.    *             prot_sum - collect protocol data
  1492.    * ------------------------------------------------------------------
  1493.    */
  1494.  
  1495.    struct Protocol_Summary *
  1496.    prot_sum(proto, ptype, ind)
  1497.                     struct Protocol_Summary **proto;
  1498.                     char *ptype;
  1499.                     int ind;
  1500. {
  1501.   int cnt = 0;
  1502.   int i1, i2, i3 = 0;
  1503.   struct Protocol_Summary *cur, *first;
  1504.  
  1505.   for (first = cur = *proto; cur != NULL; first= cur, cur= cur->next, cnt++)
  1506.   {
  1507.       if ( (0 == strncmp(cur->type, ptype,strlen(cur->type))))
  1508.          break;
  1509.   }
  1510.   if (cur == NULL)
  1511.   {
  1512.      cur= (struct Protocol_Summary *)getmem(sizeof(*cur));
  1513.      sscanf(ptype,"%[^\' ]3",cur->type);
  1514.      if (*proto == NULL)
  1515.         first = *proto = cur;
  1516.      else
  1517.         first->next= cur;
  1518.   }
  1519.   if (NULL == (ptype = strchr(ptype, ' ')))
  1520.          return (NULL);
  1521.   cur->pr_cnt++;
  1522.   have_proto = TRUE;
  1523.   ++ptype;
  1524.   switch(ind)
  1525.   {
  1526.      case 1:              /* used protocol line */
  1527.   /*
  1528.    * uucp-1.04 format: .... packet size ssss window ww)
  1529.    * uucp-1.05 format: .... remote packet/window ssss/ww local ssss/ww)
  1530.    *           (the remote packet/window will be used!)
  1531.    */
  1532.  
  1533.           i1 = i2 = 0;    /* reset */
  1534.  
  1535.           if (NULL == (strchr(ptype, '/')))
  1536.              sscanf(ptype,"%*s %*s %d %*s %d",&i1,&i2);
  1537.           else
  1538.              sscanf(ptype,"%*s %*s %d/%d",&i1,&i2);
  1539.  
  1540.           if (i1 > cur->pr_psizemax)
  1541.              cur->pr_psizemax = i1;
  1542.           if (i1 < cur->pr_psizemin || cur->pr_psizemin == 0)
  1543.              cur->pr_psizemin = i1;
  1544.  
  1545.           if (i2 > cur->pr_pwinmax)
  1546.              cur->pr_pwinmax = i2;
  1547.           if (i2 < cur->pr_pwinmin || cur->pr_pwinmin == 0)
  1548.              cur->pr_pwinmin = i2;
  1549.           break;
  1550.      case 2:              /* protocol statistics line */
  1551.           i1 = i2 = i3 = 0;    /* reset */
  1552.           sscanf(ptype,"%*s %*s %d%*c %*s %d%*c %*s %d",&i1,&i2,&i3);
  1553.           cur->pr_psent += i1;
  1554.           cur->pr_present += i2;
  1555.           cur->pr_preceived += i3;
  1556.           break;
  1557.      default:
  1558.           break;
  1559.   }
  1560.   return (cur);
  1561. }
  1562.   /* ------------------------------------------------------------------
  1563.    *           fmtime() - Format time in hours & minutes & seconds;
  1564.    * ------------------------------------------------------------------
  1565.    */
  1566.  
  1567. static void fmtime(dsec, buf)
  1568.                   double dsec;
  1569.                   char *buf;
  1570. {
  1571.   long hrs, min, lsec;
  1572.  
  1573.   if( dsec <= 0 )
  1574.     {
  1575.       strcpy(buf, "0" );
  1576.       return;
  1577.     }
  1578.   lsec = fmod(dsec+0.5, 60L);        /* round to the next full second */
  1579.   hrs = dsec / 3600L;
  1580.   min = ((long)dsec / 60L) % 60L;
  1581.   if (hrs == 0)
  1582.      if (min == 0)
  1583.        sprintf(buf,"%6s%2ld"," ",lsec);
  1584.      else
  1585.        sprintf(buf,"%3s%2ld:%02ld"," ",min,lsec);
  1586.   else
  1587.     sprintf(buf,"%2ld:%02ld:%02ld",hrs,min,lsec);
  1588.  
  1589. }
  1590.  
  1591.   /* ------------------------------------------------------------------
  1592.    *                 fmbytes - Format size in bytes
  1593.    * ------------------------------------------------------------------
  1594.    */
  1595.  
  1596. static void fmbytes(n, buf)
  1597.                    unsigned long n;
  1598.                    char *buf;
  1599. {
  1600.   if ( n == 0 )
  1601.   {
  1602.      strcpy( buf, "0.0" );
  1603.      return;
  1604.   }
  1605.   sprintf(buf, "%.1f", (double)n / 1000.0);    /* Display in Kilobytes */
  1606. }
  1607.  
  1608.  
  1609.   /* ------------------------------------------------------------------
  1610.    *                 chk_config - Read the config file
  1611.    *    check on keywords: logfile and statfile. When found override
  1612.    *    the corresponding default
  1613.    * ------------------------------------------------------------------
  1614.    */
  1615.  
  1616. int chk_config(char *T_conf,int be_quiet, int type)
  1617. {
  1618.    FILE *Conf;
  1619.    char keywrd[9];
  1620.    char name[MAXPATHLEN+1];
  1621.    char *pos1, *pos2;
  1622.    int i = 0;
  1623.    int logf = FALSE;
  1624.    int statf = FALSE;
  1625.  
  1626.    if ((Conf = fopen(T_conf, "r")) == NULL)
  1627.    {
  1628.       if (! be_quiet)
  1629.       {
  1630.          puts("   Could not open config");
  1631.          if (type == 0)
  1632.          {
  1633.             puts("   The run will be aborted\n");
  1634.             return (8);
  1635.          }
  1636.       }
  1637.       else
  1638.       {
  1639.          fprintf(stderr,"%s (E) %s %s \n",Pgm_name,
  1640.                                      "could not open config:",
  1641.                                       T_conf);
  1642.          if (type != 0)
  1643.             fprintf(stderr,"%s (W) defaults used for all files\n",
  1644.                                                Pgm_name);
  1645.          else
  1646.          {
  1647.             fprintf(stderr,"%s (C) ended due to errors\n",
  1648.                                                Pgm_name);
  1649.             return (8);
  1650.          } 
  1651.       }
  1652.    }
  1653.    else
  1654.    {
  1655.       while (fgets(logline, sizeof(logline), Conf))
  1656.       {
  1657.         if (logline[0] == '#')
  1658.            continue;
  1659.         sscanf(logline,"%8s %s",keywrd,name);
  1660.         if (0 == strncmp(keywrd,"logfile",7))
  1661.         {
  1662.            pos1 = pos2 = name;
  1663.            for (i=0;(i<=MAXPATHLEN && *pos1 != '\0');pos1++,pos2++,i++)
  1664.            {
  1665.                if (*pos1 == '#')     /* name immed followed by comment */
  1666.                   break;
  1667.                if (*pos1 == '\\')    /* quoted comment (filename has #) */
  1668.                {
  1669.                   ++pos1;               /* skip escape char */
  1670.                   if (*pos1 != '#')     /* continuation ? */
  1671.                   {
  1672.                      puts("   Config error:");
  1673.                      puts("   Found filename continuation; bailing out\n");
  1674.                      exit (8);
  1675.                   }
  1676.                }
  1677.                *pos2 = *pos1;        /* move char */
  1678.            }
  1679.            *pos2 = '\0';             /* terminate string */
  1680.            Tlog   = (char *)getmem(strlen(name)+1);
  1681.            strcpy(Tlog,name);
  1682.            if (! be_quiet)
  1683.               printf("   logfile used:        %s\n",Tlog);
  1684.            logf = TRUE;
  1685.            if  (statf)                /* statsfile still to come ? */
  1686.                break;                 /* no finished */
  1687.            continue;
  1688.         }
  1689.  
  1690.         if (0 == strncmp(keywrd,"statfile",8))
  1691.         {
  1692.            pos1 = pos2 = name;
  1693.            for (i=0;(i<=MAXPATHLEN && *pos1 != '\0');pos1++,pos2++,i++)
  1694.            {
  1695.                if (*pos1 == '#')     /* name immed followed by comment */
  1696.                   break;
  1697.                if (*pos1 == '\\')    /* quoted comment (filename has #) */
  1698.                {
  1699.                   ++pos1;               /* skip escape char */
  1700.                   if (*pos1 != '#')     /* continuation ? */
  1701.                   {
  1702.                      puts("   Config error:");
  1703.                      puts("   Found filename continuation; bailing out\n");
  1704.                      exit (8);
  1705.                   }
  1706.                }
  1707.                *pos2 = *pos1;        /* move char */
  1708.            }
  1709.            *pos2 = '\0';             /* terminate string */
  1710.            Tstat   = (char *)getmem(strlen(name)+1);
  1711.            strcpy(Tstat,name);
  1712.            if (! be_quiet)
  1713.               printf("   statfile used:       %s\n",Tstat);
  1714.            statf = TRUE;
  1715.            if  (logf)                 /* logfile still to come ? */
  1716.                break;                 /* no finished */
  1717.            continue;
  1718.         }
  1719.       }
  1720.       fclose(Conf);
  1721.    }
  1722.  
  1723.    if (! be_quiet)
  1724.    {
  1725.       if (! logf)
  1726.          puts("   logfile used:        - default -");
  1727.       if (! statf)
  1728.          puts("   statfile used:       - default -");
  1729.    }
  1730.  
  1731. return 0;
  1732. }
  1733.  
  1734.  
  1735.   /* ------------------------------------------------------------------
  1736.    *   hdrprt - Print Header/Trailer lines (constant data)
  1737.    * ------------------------------------------------------------------
  1738.    */
  1739.  
  1740. static void hdrprt(char head, int bot)
  1741. {
  1742.   switch(head)
  1743.   {
  1744.      case('s'):                   /* standard summary report */
  1745.           if (bot == 0)
  1746.           {
  1747.              puts("\nCompact summary:");
  1748.              puts("----------------");
  1749.              puts("\
  1750. Name of  + Files + +------- Bytes/1000 --------+ +------ Time -----+ + Avg CPS +\n\
  1751. site       in  out   inbound  outbound     total   inbound  outbound    in   out\n\
  1752. -------- ---- ---- --------- --------- --------- --------- --------- ----- -----");
  1753.           }
  1754.           else
  1755.              puts("\
  1756. --------------------------------------------------------------------------------");
  1757.           break;
  1758.  
  1759.  
  1760.      case('f'):                   /* file statistic report */
  1761.           if (bot == 0)
  1762.           {
  1763.              puts("\nFile statistics:");
  1764.              puts("----------------");
  1765.              puts("   Name of  +----------- Inbound -----------+ +---------- Outbound -----------+");
  1766.             puts("   site     files  Bytes/1000  xfr time B/sec files  Bytes/1000  xfr time B/sec");
  1767.             puts("   -------- ----- ----------- --------- ----- ----- ----------- --------- -----");
  1768.           }
  1769.           else
  1770.             puts("\
  1771.    ----------------------------------------------------------------------------");
  1772.           break;
  1773.  
  1774.  
  1775.      case('c'):                   /* calls statistic report */
  1776.           if (bot == 0)
  1777.           {
  1778.              puts("\nCall statistics:");
  1779.              puts("----------------");
  1780.              puts("   Name of   +------- Outbound Calls -------+  +-------- Inbound Calls  ------+");
  1781.              puts("   site       succ.  failed   total      time   succ.  failed   total      time");
  1782.             puts("   --------  ------  ------  ------ ---------  ------  ------  ------ ---------");
  1783.           }
  1784.           else
  1785.             puts("\
  1786.    ----------------------------------------------------------------------------");
  1787.           break;
  1788.  
  1789.  
  1790.      case('e'):                   /* efficiency statistic report */
  1791.           if (bot == 0)
  1792.           {
  1793.              puts("\nEfficiency:");
  1794.              puts("-----------");
  1795.              puts("   Name of   +------ Times inbound/outbound -------+");
  1796.              puts("   site      connected   xfr time   overhead  eff. %");
  1797.              puts("   --------  ---------  ---------  ---------  ------");
  1798.           }
  1799.           else
  1800.             puts("   -------------------------------------------------");
  1801.           break;
  1802.  
  1803.      case('i'):                   /* Environment information */
  1804.           if (bot == 0)
  1805.           {
  1806.              puts("\nEnvironment Information:");
  1807.              puts("------------------------");
  1808.              printf("   Default config:      %s\n",D_conf == NULL ?
  1809.                                                    noConf:D_conf);
  1810.              printf("   Default logfile:     %s\n",Tlog);
  1811.              printf("   Default statfile:    %s\n\n",Tstat);
  1812.           }
  1813.           break;
  1814.  
  1815.      case('d'):                   /* Date/time coverage */
  1816.           if (bot == 0)
  1817.           {
  1818.              puts("\n   Date coverage of input files:");
  1819.              puts("   Name of        +----- Start -----+  +------ End ------+");
  1820.              puts("   file                 date     time        date     time");
  1821.              puts("   --------       ---------- --------  ---------- --------");
  1822.           }
  1823.           break;
  1824.  
  1825.      case('p'):                   /* Protocol stats */
  1826.           if (bot == 0)
  1827.           {
  1828.              puts("\nProtocol packet report:");
  1829.              puts("-----------------------");
  1830.              puts("          +------- protocol -----+   +--------- Packets ----------+");
  1831.              puts("Name of         packet     window ");
  1832.              puts("site      typ  min  max   min  max          sent  resent   received");
  1833.             puts("--------  --- ---- ----  ---- ----   ----------- ------- ----------");
  1834.           }
  1835.           else
  1836.           {
  1837.              puts("\nProtocol error report:");
  1838.              puts("----------------------");
  1839.              puts("Name of   +----------------- Error Types --------------------+");
  1840.              puts("site      typ      header    checksum        order  rem-reject");
  1841.              puts("--------  --- -----------  ----------  -----------  ----------");
  1842.           }
  1843.           break;
  1844.  
  1845.      default:
  1846.           if (bot == 0)
  1847.           {
  1848.              puts("\nNo header for this report defined:");
  1849.           }
  1850.           else
  1851.             puts("  ");
  1852.          break;
  1853.    }
  1854. }
  1855.