home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume22 / average / part01 / average.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-13  |  5.1 KB  |  246 lines

  1. /*
  2.  * average -- produce a composite file from multiple, similar, files
  3.  *
  4.  *    This general-purpose program takes multiple files containing
  5.  *    text (which should be the same in all files) and numbers (which
  6.  *    may differ from file to file), and it outputs one file, with
  7.  *    the same text, and with each occurence of a number replaced
  8.  *    by its average over all of the input files.  There is an option
  9.  *    for outputting [min,average,max] tuples instead of a single number.
  10.  *
  11.  * HISTORY
  12.  *
  13.  *    1987/03/31    Liudvikas Bukys <bukys@cs.rochester.edu>
  14.  *
  15.  *        Version 1.0 created.
  16.  *
  17.  *        I needed it to compute some average runtimes from several
  18.  *        timing runs of some multiprocessor code.
  19.  *
  20.  *        There is no support for numbers with 'e', 'E', or '+' in
  21.  *        them.  Those characters would be parsed as text.
  22.  *
  23.  *        The whole file is sucked into memory.
  24.  */
  25.  
  26. #define USAGE "USAGE:  %s [-m] file1 [file2 ...]\n"
  27.  
  28. #include <stdio.h>
  29. #include <ctype.h>
  30.  
  31. extern char *malloc();
  32. extern char *strchr();    /* or try index() if you don't have strchr() */
  33.  
  34. #define MAX(a,b)    (((a)>(b))?(a):(b))
  35. #define MIN(a,b)    (((a)<(b))?(a):(b))
  36.  
  37. struct token
  38.     {
  39.     struct token *next;
  40.     char *buffer;
  41.     int precision;
  42.     double average, min, max;
  43.     int count;
  44.     } head = { 0, };
  45.  
  46. /*
  47.  * MAXTOKENLEN doesn't show through to the user, who doesn't care whether
  48.  * a bunch of text is parsed as a single 20000-byte token or a pile of
  49.  * 512-byte tokens.  The only thing it might affect would be if you had
  50.  * numbers with length > MAXTOKENLEN, but this code doesn't have any
  51.  * bignum support anyway.
  52.  */
  53. #define MAXTOKENLEN 512
  54.  
  55.  
  56. main(argc, argv)
  57. int argc;
  58. char **argv;
  59.     {
  60.     register int i;
  61.     register FILE *f;
  62.     register struct token *p;
  63.     int minmaxflag = 0;
  64.  
  65.     if (argc <= 1)
  66.         {
  67.         (void) fprintf(stderr, USAGE, argv[0]);
  68.         exit(1);
  69.         }
  70.  
  71.     /*
  72.      * Read in each of my input files and tokenize it.
  73.      */
  74.     for (i= 1; i < argc; i++)
  75.         if (argv[i][0] == '-')
  76.             if (argv[i][1] == 'm')
  77.                 minmaxflag = 1;
  78.             else
  79.                 {
  80.                 (void) fprintf(stderr, USAGE, argv[0]);
  81.                 exit(1);
  82.                 }
  83.         else if ((f= fopen(argv[i], "r")) != NULL)
  84.             {
  85.             for (p= &head;  !feof(f);  p= p->next)
  86.                 readword(p, f);
  87.             (void) fclose(f);
  88.             }
  89.         else
  90.             perror(argv[i]);
  91.  
  92.     /*
  93.      * Output the token list.
  94.      * Numbers retain the maximum precision of the input numbers.
  95.      */
  96.     for (p = head.next;  p;  p = p->next)
  97.         if (p->buffer)
  98.             (void) printf("%s", p->buffer);
  99.         else if (p->precision == 0)
  100.             if (p->min == p->max)
  101.                 (void) printf("%d", (int) p->min);
  102.             else if (minmaxflag)
  103.                 (void) printf("[%d %d %d]", (int) p->min, (int) p->average, (int) p->max);
  104.             else
  105.                 (void) printf("%d", (int) p->average);
  106.         else
  107.             if (p->min == p->max)
  108.                 (void) printf("%.*lf", p->precision-1, p->min);
  109.             else if (minmaxflag)
  110.                 (void) printf("[%.*lf %.*lf %.*lf]",
  111.                     p->precision-1, p->min,
  112.                     p->precision-1, p->average,
  113.                     p->precision-1, p->max);
  114.             else
  115.                 (void) printf("%.*lf", p->precision-1, p->average);
  116.  
  117.     exit (0);
  118.     }
  119.  
  120. /*
  121.  * Read one token -- either a number or a text string.
  122.  */
  123. readword(ptail, f)
  124. struct token *ptail;
  125. FILE *f;
  126.     {
  127.     register struct token *p;
  128.     register int c, hasdigit, wasseparator;
  129.     register unsigned len;
  130.     char tok[MAXTOKENLEN+1];
  131.  
  132.     /*
  133.      * get next token, or add a new one to the end of the list
  134.      */
  135.     if (p= ptail->next)
  136.         ;
  137.     else if (ptail->next = p = (struct token *) malloc(sizeof *p))
  138.         {
  139.         p->next = 0;
  140.         p->buffer = 0;
  141.         p->count = 0;
  142.         p->precision = 0;
  143.         }
  144.     else
  145.         {
  146.         (void) fprintf(stderr, "malloc failed\n");
  147.         exit(1);
  148.         }
  149.     
  150.     c = getc(f);
  151.     (void) ungetc(c, f);
  152.     if (strchr("0123456789.-", c))
  153.         {
  154.         /*
  155.          * possibly data -- defer judgement until after I see some
  156.          * digits (this might just be a string of '-', after all).
  157.          */
  158.         len = 0;
  159.         hasdigit = 0;
  160.         while (len < MAXTOKENLEN && ((c= getc(f)) != EOF))
  161.             if (strchr("0123456789.-", c))
  162.                 {
  163.                 tok[len++] = c;
  164.                 if (strchr("0123456789", c))
  165.                     hasdigit = 1;
  166.                 }
  167.             else
  168.                 {
  169.                 (void) ungetc(c, f);
  170.                 break;
  171.                 }
  172.         tok[len] = '\0';
  173.         if (hasdigit)
  174.             dodata(p, tok, len);
  175.         else
  176.             dotext(p, tok, len);
  177.         }
  178.     else
  179.         {
  180.         /*
  181.          * text
  182.          */
  183.         wasseparator = 0;
  184.         len = 0;
  185.         while (len < MAXTOKENLEN && ((c= getc(f)) != EOF))
  186.             if (wasseparator && strchr("0123456789.-", c))
  187.                 {
  188.                 (void) ungetc(c, f);
  189.                 break;
  190.                 }
  191.             else
  192.                 {
  193.                 tok[len++] = c;
  194.                 wasseparator = !isascii(c) || !isalnum(c);
  195.                 }
  196.         tok[len] = '\0';
  197.         dotext(p, tok, len);
  198.         }
  199.     }
  200.  
  201. /*
  202.  * Do number-specific processing -- compute min, max, average
  203.  */
  204. dodata(p, tok, len)
  205. struct token *p;
  206. char *tok;
  207. unsigned len;
  208.     {
  209.     char *dot;
  210.     double value;
  211.  
  212.     if (dot= strchr(tok, '.'))
  213.         p->precision = MAX(p->precision, (tok+len)-dot);
  214.  
  215.     value = 0.0;
  216.     (void) sscanf(tok, "%lf", &value);
  217.  
  218.     if (p->count++)
  219.         {
  220.         p->min = MIN(p->min, value);
  221.         p->max = MAX(p->max, value);
  222.         p->average = p->average*((p->count-1.0)/(p->count)) + value/p->count;
  223.         }
  224.     else
  225.         p->min = p->max = p->average = value;
  226.     }
  227.  
  228. /*
  229.  * Do text-specific processing -- save the text permanently (but only the first time!)
  230.  */
  231. dotext(p, tok, len)
  232. struct token *p;
  233. char *tok;
  234. unsigned len;
  235.     {
  236.     if (p->buffer)
  237.         ; /* remember the old string only */
  238.     else if (p->buffer= malloc(len+1))
  239.         bcopy(tok, p->buffer, len+1);
  240.     else
  241.         {
  242.         (void) fprintf(stderr, "malloc failed\n");
  243.         exit(1);
  244.         }
  245.     }
  246.