sum.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * sum [file1] [file2] [file3] ...
  3. * sum utility written for GNU - checksum and count blocks in a file
  4. * Copyright (C) 1986 Kayvan Aghaiepour
  5. *
  6. * This program is distributed in the hope that it will be useful,
  7. * but without any warranty. No author or distributor
  8. * accepts responsibility to anyone for the consequences of using it
  9. * or for whether it serves any particular purpose or works at all,
  10. * unless he says so in writing.
  11. *
  12. * Everyone is granted permission to copy, modify and redistribute
  13. * this program, but only under the conditions described in the
  14. * document "GNU Emacs copying permission notice". An exact copy
  15. * of the document is supposed to have been given to you along with
  16. * GNU Emacs so that you can know how you may redistribute it all.
  17. * It should be in a file named COPYING. Among other things, the
  18. * copyright notice and this notice must be preserved on all copies.
  19. *
  20. */
  21. #include <stdio.h>
  22. /* macro to right-rotate an integer variable */
  23. #define ROTATE(c) if ((c) & 01) (c) = ((c) >>1) + 0x8000; else (c) >>= 1;
  24. main (argc, argv)
  25. int argc;
  26. char **argv;
  27. {
  28. int error;
  29. error = 0;
  30. switch (argc)
  31. {
  32. case 1: /* no arguments */
  33. if (sumfile (NULL, 0) < 0)
  34. {
  35. error += 10;
  36. }
  37. break;
  38. case 2: /* one argument */
  39. if (sumfile (argv[1], 0) < 0)
  40. {
  41. error += 10;
  42. }
  43. break;
  44. default: /* more than one argument */
  45. for (argc--, argv++; argc > 0; argc--, argv++)
  46. {
  47. if (sumfile (argv[0], 1) < 0)
  48. {
  49. error += 10;
  50. }
  51. }
  52. }
  53. return (error);
  54. }
  55. /*
  56. * sumfile does the checksum itself. Returns negative if something goes
  57. * wrong. Else, it returns non-negative and prints the desired information.
  58. */
  59. sumfile (s, printname)
  60. char *s; /* filename of file to check */
  61. int printname; /* boolean. print file name or not? */
  62. {
  63. register FILE *readfile; /* the file */
  64. register unsigned checksum; /* the checksum mod 2^16. */
  65. register long bytenum; /* the number of bytes. */
  66. register int ch; /* The character to read */
  67. if (s == NULL)
  68. {
  69. readfile = stdin; /* no arguments, so read from stdin */
  70. }
  71. else if ((readfile = fopen (s, "r")) == NULL)
  72. {
  73. perror_with_name (s); /* File inaccessible for some reason */
  74. return (-1);
  75. }
  76. checksum = 0;
  77. bytenum = 0;
  78. while ((ch = getc (readfile)) != EOF)
  79. {
  80. bytenum++;
  81. ROTATE (checksum);
  82. checksum += ch;
  83. checksum &= 0xffff; /* keep it within bounds */
  84. }
  85. if (ferror (readfile))
  86. { /* something bad has happened */
  87. perror_with_name (s);
  88. return (-1);
  89. }
  90. printf ("%05u%6ld", checksum, (bytenum + BUFSIZ - 1) / BUFSIZ);
  91. if (printname)
  92. printf (" %s\n", s);
  93. else
  94. putchar ('\n');
  95. fclose (readfile);
  96. return (1);
  97. }
  98. perror_with_name (name)
  99. char *name;
  100. {
  101. extern int errno, sys_nerr;
  102. extern char *sys_errlist[];
  103. char *s;
  104. if (errno < sys_nerr)
  105. fprintf (stderr, "%s for %s\n", name);
  106. else
  107. fprintf (stderr, "(Unknown error) cannot open %s", name);
  108. }