home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume11 / vitals < prev    next >
Text File  |  1987-09-20  |  14KB  |  480 lines

  1. Subject:  v11i066:  Word counts, checksums, etc.
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: Alan Silverstein <hpda!hpfcla!hpfcdt!ajs>
  7. Posting-number: Volume 11, Issue 66
  8. Archive-name: vitals
  9.  
  10. This program was developed by Hewlett-Packard and will be part of our
  11. HP-UX product offering.  We have found it useful.  It is most useful
  12. when most widely and commonly shared, so here it is.
  13.  
  14. We have not tested it except on HP-UX, which is mainly AT&T-compatible.
  15. However, it should be pretty portable.  Caveat emptor.  Oh, and the
  16. usual disclaimer that I'm not really an official HP spokesperson.
  17.  
  18. Alan Silverstein, Hewlett-Packard Systems Software Operation, Fort Collins,
  19. Colorado; {ihnp4 | hplabs}!hpfcla!ajs; 303-229-3053; (lat-long on request :-)
  20.  
  21.  
  22.  
  23. # This is a shell archive.  Remove anything before this line,
  24. # then unpack it by saving it in a file and typing "sh file".
  25. #
  26. # This archive contains:
  27. #    Makefile    vitals.1    vitals.c    
  28. #
  29. # Error checking via wc(1) will be performed.
  30.  
  31. echo x - Makefile
  32. cat >Makefile <<'@EOF'
  33. all:    vitals
  34. install:    all vitals.1
  35.     @echo install in appropriate directories.
  36. vitals:    vitals.c
  37.     $(CC) $(CFLAGS) -o vitals vitals.c
  38. @EOF
  39. echo Assuming Makefile is OK -- the moderator did not repack the kit...
  40. echo x - vitals.1
  41. cat >vitals.1 <<'@EOF'
  42. .\" $Header: vitals.1,v 1.1 87/08/10 12:07:47 $
  43. .TH VITALS 1 ""
  44. .ad b
  45. .SH NAME
  46. vitals \- crc, sum, line, word, and character counts
  47. .SH SYNOPSIS
  48. .B vitals
  49. [
  50. .B \-rslwcb
  51. ] [
  52. .I file ...
  53. ]
  54. .SH DESCRIPTION
  55. .I Vitals
  56. checks data integrity by
  57. computing vital statistics related to the data in the given
  58. file(s) or standard input (by default).
  59. The statistics include a four-digit hex CRC, a 16-bit byte sum (similar to
  60. .IR sum (1)
  61. without the block count)
  62. and line, word, and character counts (similar to
  63. .IR wc (1)).
  64. One line is printed for each input file or standard input, consisting of
  65. five statistics fields 
  66. followed by the file name, if known.
  67. If a file is specified as "\fB\-\fR", the program reads standard 
  68. input at that
  69. point and shows "\fB\-\fR" as the file name.
  70. .SS Options 
  71. .TP 15
  72. .B \-r
  73. Compute only the CRC:  a true 16-bit cyclic redundancy count
  74. that can
  75. detect, among other things, exchanged characters.
  76. .TP 
  77. .B \-s
  78. Compute only the byte sum:  the modulo-2\(**\(**16, unsigned, circular sum
  79. of all the bytes, each taken as an
  80. .B int
  81. (therefore normally in the range 0-255).
  82. .TP
  83. .B \-l
  84. Compute only the line count:  the number of newline characters in the input.
  85. .TP
  86. .B \-w
  87. Compute only the word count:  the number of 
  88. character sequences
  89. delimited by blanks, tabs, or newlines.
  90. As in
  91. .IR wc (1),
  92. non-printable characters are totally ignored when looking for words.
  93. .TP
  94. .B \-c
  95. Compute only the character count.
  96. .TP
  97. .B \-b
  98. Print only file basenames, not full path names.
  99. .PP
  100. These options can be used in any combination.
  101. The default is
  102. .BR \-rslwc ,
  103. that is, all but
  104. .BR \-b .
  105. .PP
  106. .I Vitals 
  107. is more efficient than separate commands tied together
  108. with a shell script because the input data is read only once.
  109. Unlike
  110. .IR wc (1),
  111. this program does not compute totals, since it is intended for fast data
  112. validation, not size counting.
  113. .SH DIAGNOSTICS
  114. If any file open or read fails, the program writes a message to standard
  115. error when the problem is encountered, and continues with the next file.
  116. It ultimately returns non-zero if any error occurs, else zero.
  117. .SH AUTHOR
  118. .I Vitals
  119. was developed by Hewlett-Packard.
  120. .SH "SEE ALSO"
  121. sum(1), wc(1).
  122. @EOF
  123. if test "`wc -lwc <vitals.1`" != '     80    375   2154'
  124. then
  125.     echo ERROR: wc results of vitals.1 are `wc -lwc <vitals.1` should be      80    375   2154
  126. fi
  127.  
  128. chmod 444 vitals.1
  129.  
  130. echo x - vitals.c
  131. cat >vitals.c <<'@EOF'
  132. static char *HPUX_ID = "@(#)27.1   85/02/04";
  133. /* HPUX_ID: @(#)vitals.c    27.1     85/02/04  */
  134. /*
  135.  * Compute vital statistics of data:  crc, sum, line, word, and character
  136.  * counts.  See the manual entry for details.
  137.  *
  138.  * Compile with -DTABLE to produce an alternate program, which prints a
  139.  * CRC table for use in this program.
  140.  *
  141.  * The CRC code was lifted from a USENET posting:
  142.  *
  143.  * hpfcla:net.sources / hcrvax!sft /  8:17 pm  Nov 15, 1984
  144.  *
  145.  * The following program is a command to calculate the CRC of files.
  146.  * It is useful for the same purposes as sum(1).  It calculates the
  147.  * true CRC16 (unlike CP/M utilities that say they calculate CRCs
  148.  * but really just hash).  Crc detects more errors than old sum(1);
  149.  * for example, it detects exchanges of characters.  It is also
  150.  * (now) in the public domain.
  151.  *
  152.  *  CRC16 polynomial: x**0 + x**2 + x**15 + x**16 (0xA001)
  153.  * (CCITT polynomial: x**0 + x**5 + x**12 + x**16 (0x8408))
  154.  * Initial condition: 0
  155.  *
  156.  * D. Hugh Redelmeier, 1983 April 15; latest change: 1984 April 2.
  157.  */
  158.  
  159.  
  160. #include <stdio.h>
  161.  
  162. char    *USAGE = "usage: %s [-rslwcb] [files...]\n";
  163.  
  164. #define    proc                /* null; easy to grep for procs */
  165. #define    chNull       ('\0')
  166. #define    chNewline  ('\n')
  167. #define    sbNull       ((char *) NULL)
  168. #define    fileNull   ((FILE *) NULL)
  169. #define    false       0
  170. #define    true       1
  171.  
  172. char    *myname;                /* how command invoked    */
  173. int    rflag = false;                /* -r (crc) option    */
  174. int    sflag = false;                /* -s (sum) option    */
  175. int    lflag = false;                /* -l (lines) option    */
  176. int    wflag = false;                /* -w (words) option    */
  177. int    cflag = false;                /* -c (chars) option    */
  178. int    bflag = false;                /* -b (basenames) opt    */
  179.  
  180. int    retval = 0;                /* return value         */
  181. char    *defaultargs[] = {"-", sbNull};        /* read stdin by default */
  182.  
  183. #define    PrintErr(part1,part2) \
  184.         fprintf (stderr, "%s: %s %s\n", myname, part1, part2);
  185.  
  186.  
  187. /************************************************************************
  188.  * M A I N
  189.  *
  190.  * Initialize, check arguments, open files, and call another routine to
  191.  * do each file.
  192.  */
  193.  
  194. proc main (argc, argv)
  195. register int    argc;
  196. register char    **argv;
  197. {
  198. extern     int    optind;            /* for getopt()  */
  199.      int    optchar;        /* from getopt() */
  200. register FILE    *filep;            /* file to read     */
  201.  
  202. #ifdef TABLE                    /* just print table */
  203.     PrintTable();
  204. #else
  205.  
  206. /*
  207.  * CHECK ARGUMENTS:
  208.  */
  209.  
  210.     myname = *argv;
  211.  
  212.     while ((optchar = getopt (argc, argv, "rslwcb")) != EOF)
  213.         switch (optchar)
  214.         {
  215.         case 'r':    rflag = true;    break;
  216.         case 's':    sflag = true;    break;
  217.         case 'l':    lflag = true;    break;
  218.         case 'w':    wflag = true;    break;
  219.         case 'c':    cflag = true;    break;
  220.         case 'b':    bflag = true;    break;
  221.         default:    fprintf (stderr, USAGE, myname); exit (1);
  222.         }
  223.  
  224.     if (! (rflag || sflag || lflag || wflag || cflag))
  225.         rflag = sflag = lflag = wflag = cflag = true;
  226.  
  227.     argc -= optind;
  228.     argv += optind;
  229.  
  230.     if (argc < 1)                /* use default arguments */
  231.         argv = defaultargs;
  232.  
  233. /*
  234.  * OPEN AND DO EACH INPUT FILE:
  235.  *
  236.  * Be careful to keep stdin open for filenames of "-".
  237.  * Argc is not altered; if < 1, it means no file args were given.
  238.  */
  239.  
  240.     for ( ; *argv != sbNull; argv++)        /* each argument */
  241.     {
  242.         if (strcmp (*argv, "-") == 0)        /* read stdin */
  243.         filep = stdin;
  244.  
  245.         else if ((filep = fopen (*argv, "r")) == fileNull)
  246.         {
  247.         PrintErr ("can't open", *argv);
  248.         retval = 1;
  249.         continue;
  250.         }
  251.  
  252.         DoFile (filep, (argc < 1), *argv);
  253.  
  254.         if (filep != stdin)            /* keep stdin open for reuse */
  255.         fclose (filep);
  256.     }
  257.     exit (retval);
  258.  
  259. #endif /* not TABLE */
  260.  
  261. } /* main */
  262.  
  263.  
  264. #ifdef TABLE
  265.  
  266. /************************************************************************
  267.  * P R I N T   T A B L E
  268.  *
  269.  * Print table needed for CRC computation, as a C array declaration.
  270.  * The output can then be included in this program.  It would be easy
  271.  * to just build the table in memory each time the program is run, but
  272.  * what the heck -- this way is a little more complicated, but already
  273.  * done, and shaves off a bit of startup time.
  274.  *
  275.  * Assumes unsigned and short are at least 16 bits.
  276.  */
  277.  
  278. proc PrintTable()
  279. {
  280. register unsigned index = 0;        /* place in table    */
  281. register unsigned entry;        /* table entry        */
  282. register int      count;        /* for changing entry    */
  283.  
  284.     printf ("unsigned short CRCtable [256] = {");
  285.  
  286.     while (true)
  287.     {
  288.         if ((index % 8) == 0)        /* time for new line */
  289.         putchar (chNewline);
  290.  
  291.         for (entry = index, count = 8; (count--) > 0; )
  292.         {
  293.         if (entry & 1)            /* low bit set */
  294.             entry = (entry >> 1) ^ 0xA001;
  295.         else
  296.             entry >>= 1;
  297.         }
  298.  
  299.         printf ("\t0x%4.4x", entry);
  300.  
  301.         if (++index == 256)
  302.         break;
  303.  
  304.         putchar (',');
  305.     }
  306.  
  307.     printf ("\n};\n");
  308.  
  309. } /* PrintTable */
  310.  
  311.  
  312. #else /* not TABLE */
  313.  
  314.  
  315. /************************************************************************
  316.  * CRC TABLE AND BYTE SUM STRUCTS
  317.  *
  318.  * CRCtable[], output from PrintTable(), is used for CRC calculation.
  319.  * Structures are used for circular mod-2**16 byte sums.  They assume
  320.  * that two shorts == one long!
  321.  */
  322.  
  323. unsigned short CRCtable [256] = {
  324.     0x0000,    0xc0c1,    0xc181,    0x0140,    0xc301,    0x03c0,    0x0280,    0xc241,
  325.     0xc601,    0x06c0,    0x0780,    0xc741,    0x0500,    0xc5c1,    0xc481,    0x0440,
  326.     0xcc01,    0x0cc0,    0x0d80,    0xcd41,    0x0f00,    0xcfc1,    0xce81,    0x0e40,
  327.     0x0a00,    0xcac1,    0xcb81,    0x0b40,    0xc901,    0x09c0,    0x0880,    0xc841,
  328.     0xd801,    0x18c0,    0x1980,    0xd941,    0x1b00,    0xdbc1,    0xda81,    0x1a40,
  329.     0x1e00,    0xdec1,    0xdf81,    0x1f40,    0xdd01,    0x1dc0,    0x1c80,    0xdc41,
  330.     0x1400,    0xd4c1,    0xd581,    0x1540,    0xd701,    0x17c0,    0x1680,    0xd641,
  331.     0xd201,    0x12c0,    0x1380,    0xd341,    0x1100,    0xd1c1,    0xd081,    0x1040,
  332.     0xf001,    0x30c0,    0x3180,    0xf141,    0x3300,    0xf3c1,    0xf281,    0x3240,
  333.     0x3600,    0xf6c1,    0xf781,    0x3740,    0xf501,    0x35c0,    0x3480,    0xf441,
  334.     0x3c00,    0xfcc1,    0xfd81,    0x3d40,    0xff01,    0x3fc0,    0x3e80,    0xfe41,
  335.     0xfa01,    0x3ac0,    0x3b80,    0xfb41,    0x3900,    0xf9c1,    0xf881,    0x3840,
  336.     0x2800,    0xe8c1,    0xe981,    0x2940,    0xeb01,    0x2bc0,    0x2a80,    0xea41,
  337.     0xee01,    0x2ec0,    0x2f80,    0xef41,    0x2d00,    0xedc1,    0xec81,    0x2c40,
  338.     0xe401,    0x24c0,    0x2580,    0xe541,    0x2700,    0xe7c1,    0xe681,    0x2640,
  339.     0x2200,    0xe2c1,    0xe381,    0x2340,    0xe101,    0x21c0,    0x2080,    0xe041,
  340.     0xa001,    0x60c0,    0x6180,    0xa141,    0x6300,    0xa3c1,    0xa281,    0x6240,
  341.     0x6600,    0xa6c1,    0xa781,    0x6740,    0xa501,    0x65c0,    0x6480,    0xa441,
  342.     0x6c00,    0xacc1,    0xad81,    0x6d40,    0xaf01,    0x6fc0,    0x6e80,    0xae41,
  343.     0xaa01,    0x6ac0,    0x6b80,    0xab41,    0x6900,    0xa9c1,    0xa881,    0x6840,
  344.     0x7800,    0xb8c1,    0xb981,    0x7940,    0xbb01,    0x7bc0,    0x7a80,    0xba41,
  345.     0xbe01,    0x7ec0,    0x7f80,    0xbf41,    0x7d00,    0xbdc1,    0xbc81,    0x7c40,
  346.     0xb401,    0x74c0,    0x7580,    0xb541,    0x7700,    0xb7c1,    0xb681,    0x7640,
  347.     0x7200,    0xb2c1,    0xb381,    0x7340,    0xb101,    0x71c0,    0x7080,    0xb041,
  348.     0x5000,    0x90c1,    0x9181,    0x5140,    0x9301,    0x53c0,    0x5280,    0x9241,
  349.     0x9601,    0x56c0,    0x5780,    0x9741,    0x5500,    0x95c1,    0x9481,    0x5440,
  350.     0x9c01,    0x5cc0,    0x5d80,    0x9d41,    0x5f00,    0x9fc1,    0x9e81,    0x5e40,
  351.     0x5a00,    0x9ac1,    0x9b81,    0x5b40,    0x9901,    0x59c0,    0x5880,    0x9841,
  352.     0x8801,    0x48c0,    0x4980,    0x8941,    0x4b00,    0x8bc1,    0x8a81,    0x4a40,
  353.     0x4e00,    0x8ec1,    0x8f81,    0x4f40,    0x8d01,    0x4dc0,    0x4c80,    0x8c41,
  354.     0x4400,    0x84c1,    0x8581,    0x4540,    0x8701,    0x47c0,    0x4680,    0x8641,
  355.     0x8201,    0x42c0,    0x4380,    0x8341,    0x4100,    0x81c1,    0x8081,    0x4040
  356. };
  357.  
  358. struct shorts {            /* as used, order is irrelevant */
  359.     unsigned short    high, low;
  360. };
  361.  
  362. typedef union {            /* to map one long to two shorts */
  363.     unsigned long    sum;
  364.     struct     shorts    shorts;
  365. } convert;
  366.  
  367.  
  368. /************************************************************************
  369.  * D O   F I L E
  370.  *
  371.  * Read one file, calculate values, and print an output line.
  372.  * Sets retval if necessary.  ch is int, not char, to be sure
  373.  * it can distinguish 0xff and EOF.  As a result, all normal
  374.  * values of ch should be positive, 0..255.
  375.  */
  376.  
  377. proc DoFile (filep, nullname, filename)
  378. register FILE    *filep;        /* file to read        */
  379.      int    nullname;    /* ignore filename? */
  380.      char    *filename;    /* name of filep    */
  381. {
  382. register int    ch;        /* current char    */
  383. register unsigned crc = 0;    /* crc sum    */
  384. register long    sum   = 0L;    /* byte sum    */
  385. register long    lines = 0L;    /* line count    */
  386. register long    words = 0L;    /* word count    */
  387. register long    chars = 0L;    /* char count    */
  388.  
  389.      convert conv;        /* for 16-sum    */
  390. register int notword = true;    /* not in word?    */
  391.  
  392. /*
  393.  * READ FILE AND COMPUTE SUMS:
  394.  *
  395.  * CRCtable[] values have 16 bits, so the masking is necessary before each
  396.  * repeated index into the array.  sum is allowed to increment to more than
  397.  * 16 bits; overflow is handled later.  Line and char counts are accumulated
  398.  * regardless whether they are needed; it's faster not to check.  Words are
  399.  * counted in the same strange way as wc(1), ignoring special chars.
  400.  */
  401.  
  402.     while ((ch = getc (filep)) != EOF)
  403.     {
  404.         if (rflag)
  405.         crc = (crc >> 8) ^ (CRCtable [(crc ^ ch) & 0xff]);
  406.  
  407.         if (sflag)
  408.         sum += ch;
  409.  
  410.         if (ch == chNewline)
  411.         lines++;
  412.  
  413.         chars++;
  414.  
  415.         if (wflag)
  416.         {
  417.         if ((' ' < ch) && (ch < '\177'))    /* word char */
  418.         {
  419.             if (notword)            /* start of word */
  420.             {
  421.             words++;
  422.             notword = false;
  423.             }
  424.         }
  425.         else if ((ch == ' ') || (ch == '\t') || (ch == chNewline))
  426.         {
  427.             notword = true;
  428.         }
  429.         }
  430.     } /* while */
  431.  
  432. /*
  433.  * REPORT ERROR OR PRINT TOTALS:
  434.  */
  435.  
  436.     if (ferror (filep))
  437.     {
  438.         PrintErr ("read failed from", nullname ? "stdin" : filename);
  439.         retval = 1;
  440.     }
  441.     else
  442.     {
  443.         conv.sum = sum;        /* for adding back overflow */
  444.  
  445.         if (rflag)    printf (" %4.4x", crc);
  446.         if (sflag)    printf (" %5u",   conv.shorts.high + conv.shorts.low);
  447.         if (lflag)    printf (" %6ld",  lines);
  448.         if (wflag)    printf (" %6ld",  words);
  449.         if (cflag)    printf (" %6ld",  chars);
  450.  
  451.         if (! nullname)        /* have name to print */
  452.         {
  453.         if (bflag)        /* basename only */
  454.         {
  455.             char *cp = filename;
  456.  
  457.             while (*cp != chNull)    /* till end of name */
  458.             if (*cp++ == '/')    /* directory level  */
  459.                 filename = cp;    /* set past '/'        */
  460.         }
  461.         printf (" %s", filename);
  462.         }
  463.         putchar (chNewline);
  464.  
  465.     } /* else */
  466.  
  467. } /* DoFile */
  468.  
  469. #endif /* not TABLE */
  470. @EOF
  471. if test "`wc -lwc <vitals.c`" != '    338   1577   9781'
  472. then
  473.     echo ERROR: wc results of vitals.c are `wc -lwc <vitals.c` should be     338   1577   9781
  474. fi
  475.  
  476. chmod 444 vitals.c
  477.  
  478. exit 0
  479.  
  480.