home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / brik.zoo / brik.1 next >
Internet Message Format  |  1989-07-22  |  52KB

  1. From ra!tut!draken!kth!mcvax!uunet!allbery Sat Jul 22 13:42:48 EET DST 1989
  2. Article 203 of comp.sources.misc:
  3. Path: chyde!ra!tut!draken!kth!mcvax!uunet!allbery
  4. >From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5. Newsgroups: comp.sources.misc
  6. Subject: v07i094: brik: a general-purpose CRC-32 program (part 01/03)
  7. Message-ID: <61157@uunet.UU.NET>
  8. Date: 22 Jul 89 01:03:03 GMT
  9. Sender: allbery@uunet.UU.NET
  10. Reply-To: dhesi@bsu-cs.bsu.edu (Rahul Dhesi)
  11. Lines: 1500
  12. Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  13.  
  14. Posting-number: Volume 7, Issue 94
  15. Submitted-by: dhesi@bsu-cs.bsu.edu (Rahul Dhesi)
  16. Archive-name: brik2/part01
  17.  
  18. Brik 2.0 is a general-purpose program that calculates both text and
  19. binary cyclic redundancy codes (CRCs).  Text-mode CRCs calculated by
  20. brik are portable across systems for files that are in the usual text
  21. format on each system.  Binary-mode CRCs are portable for files that
  22. are moved from system to system without any change.  Brik can also be
  23. used to verify and update a Checksum header of this type:
  24.  
  25. Checksum: 2656043176 (verify with "brik -cv")
  26.  
  27. Brik 2.0 is believed to compile and run under MS-DOS (Turbo C 2.0, MASM
  28. or TASM assemblers);  System V Release 2;  4.3BSD;  and VAX/VMS.
  29. Assembly code for the 8086 processor is included with makes the program
  30. quite fast under MS-DOS.
  31.  
  32. There are three shar archives.  Extract each separately.
  33.  
  34. #! /bin/sh
  35. # This is a shell archive, meaning:
  36. # 1. Remove everything above the #! /bin/sh line.
  37. # 2. Save the resulting text in a file.
  38. # 3. Execute the file with /bin/sh (not csh) to create:
  39. #    brik.c
  40. #    turboc.c
  41. #    brik.h
  42. # This archive created: Mon Jul 17 01:23:02 1989
  43. export PATH; PATH=/bin:/usr/bin:$PATH
  44. echo shar: "extracting 'brik.c'" '(29846 characters)'
  45. if test -f 'brik.c'
  46. then
  47.     echo shar: "will not over-write existing file 'brik.c'"
  48. else
  49. sed 's/^X//' << \SHAR_EOF > 'brik.c'
  50. X/* ::[[ @(#) brik.c 1.55 89/07/12 03:31:06 ]]:: */
  51. X#ifndef LINT
  52. X static char sccsid[]="::[[ @(#) brik.c 1.55 89/07/12 03:31:06 ]]::";
  53. X#endif
  54. X
  55. X#define DATESTAMP "1989/07/11"
  56. X#define VERSION   "2.0"
  57. X
  58. X/*
  59. X(c) Copyright 1989 Rahul Dhesi, All rights reserved.  Permission is
  60. Xgranted to use, copy, and distribute this file under the terms of the
  61. XGNU General Public License version 1.0.
  62. X*/
  63. X
  64. X/*
  65. XChecksum: 2990338384      (check or update this with "brik")
  66. X*/
  67. X
  68. Xstatic char copyright[] =
  69. X"\
  70. XCopyright 1989 Rahul Dhesi, All rights reserved.  Use and distribution is\n\
  71. Xpermitted under the terms of the GNU General Public License version 1.0.\n\
  72. X";
  73. X
  74. X/*
  75. XThe following code assumes the ASCII character set and 8-bit bytes.
  76. X*/
  77. X
  78. X#ifndef OK_STDIO
  79. X# include <stdio.h>
  80. X# define OK_STDIO
  81. X#endif
  82. X
  83. X#include "brik.h"          /* configuration options */
  84. X#include "assert.h"
  85. X
  86. Xtypedef unsigned long tcrc; /* type of crc value -- same as in addbfcrc.c */
  87. X
  88. X#ifdef GENTAB
  89. Xvoid mkcrctab PARMS ((void));
  90. X#endif /* GENTAB */
  91. X
  92. X#ifdef STDINCLUDE
  93. X# include <stdlib.h>
  94. X# include <string.h>
  95. X#else
  96. X FILE *fopen PARMS ((char *filename, char *mode));
  97. X char *nextfile PARMS ((int, char *, int));
  98. X char *strcat PARMS ((char *, char *));
  99. X char *strchr PARMS ((char *, char));
  100. X char *strcpy PARMS ((char *, char *));
  101. X char *strncat PARMS ((char *, char *, int));
  102. X int strcmp PARMS ((char *, char *));
  103. X int strlen PARMS ((char *));
  104. X void exit PARMS ((int status));
  105. X#endif /* STDINCLUDE */
  106. X
  107. X/* twilight zone functions -- may or may not be standard */
  108. Xint main PARMS ((int, char **));
  109. Xint getopt PARMS ((int, char **, char *));
  110. X
  111. X/* our own functions */
  112. XFILE *efopen PARMS ((char *filename, char *mode, int errlevel));
  113. Xchar suffix PARMS ((void));
  114. Xchar *nextfile PARMS ((int, char *, int));
  115. Xvoid dofname PARMS ((char *));
  116. Xvoid dofptr PARMS ((FILE *, char *));
  117. Xint lowerit PARMS ((int));
  118. Xvoid printhdr PARMS ((void));
  119. Xvoid readnames PARMS ((FILE *));
  120. Xvoid updatefile PARMS ((FILE *, long, tcrc, char *));
  121. Xint whole_check PARMS ((FILE *, char *));
  122. Xtcrc findcrc PARMS ((FILE *, char *, int *));
  123. Xtcrc xatol PARMS ((char *));
  124. Xvoid addbfcrc PARMS ((char *, int));
  125. Xvoid brktst PARMS ((void));
  126. Xvoid hdrcrc PARMS ((FILE *, char *));
  127. Xvoid longhelp PARMS ((void));
  128. Xvoid shorthelp PARMS ((void));
  129. Xvoid showerr PARMS ((char *, int));
  130. X
  131. X/* the following constants can be changed if you know what you are doing */
  132. X#define ERRLIMIT  127      /* exit(n) returns n not exceeding this */
  133. X#define LINESIZE  8192     /* handle lines of up to this length */
  134. X#define ERRBUFSIZ 1024     /* buffer size for perror() message */
  135. X#define BACKSIZE  1024     /* how much to seek back looking for header */
  136. X#define BINTABSIZ 256      /* size of binary char test table */
  137. X#ifdef CTRLZ_CHECK
  138. X# define Z_THRESHOLD 10    /* see how CTRLZ_CHECK is used later */
  139. X#endif /* CTRLZ_CHECK */
  140. X
  141. X/* the following constants should not be changed */
  142. X#define MYNL      10       /* newline for CRC calculation */
  143. X#define PATTERN   "Checksum:"    /* look for this header */
  144. X#define CHARSINCRC 10      /* characters in CRC */
  145. X#define CMTCH     '#'      /* begins comment in CRC list */
  146. X
  147. X/* error levels */
  148. X#define LVL_WARN  0
  149. X#define LVL_ERR   1
  150. X#define LVL_FATAL 2
  151. X
  152. X#ifdef  USEINDEX
  153. X# define strchr   index
  154. X#endif  /* USEINDEX */
  155. X
  156. X#ifdef NOTRAIL_B              /* avoid trailing "b" in mode string */
  157. X# define BRIK_RD  "r"
  158. X# define BRIK_RW  "r+"
  159. X# define BRIK_RDB "r"
  160. X#else
  161. X# define BRIK_RD  "r"
  162. X# define BRIK_RW  "r+"
  163. X# define BRIK_RDB "rb"
  164. X#endif   /* NOTRAIL_B */
  165. X
  166. X#define  whitespace(x)     (strchr(" \t\n",(x)) != NULL)
  167. X/* format strings for printing CRCs and filenames etc. */
  168. Xstatic char ok[] =      "ok ";
  169. Xstatic char bad[] =     "BAD";
  170. Xstatic char blank[] =   "   ";
  171. Xstatic char fmtstr[] = "%10lu%c %s %s\n";
  172. Xstatic char hdrfmt[] = "Checksum: %10lu  %s\n";
  173. X
  174. Xstatic char version[] = VERSION;
  175. Xchar bintab[BINTABSIZ];    /* binary char test table */
  176. Xint patlen;                /* length of PATTERN */
  177. Xint errcount = 0;          /* count of errors */
  178. Xint gen1 = 0;              /* generate CRCs for all files */
  179. Xint gen2 = 0;              /* generate CRCs for files with headers */
  180. Xint silent = 0;            /* be silent, just set error status */
  181. Xint quiet = 0;             /* talks less, but not completely silent */
  182. Xint verbose = 0;           /* be verbose, print message for good files too */
  183. Xint updfile = 0;           /* update file by inserting CRC */
  184. Xint check1 = 0;            /* whether to check header crcs */
  185. Xint check2 = 0;            /* whether to check whole file crcs */
  186. Xint fromfile = 0;          /* read filenames from a file */
  187. Xint binary = 0;            /* manipulate binary file */
  188. Xint trailing = 0;          /* include trailing empty lines */
  189. Xint prthdr = 0;            /* print Checksum: XXXXXXXXXX header */
  190. Xint autocheck = 0;         /* brik must decide if text or binary */
  191. Xint is_stdin = 0;          /* current file is stdin */
  192. Xint doubtful = 0;          /* text but doubtful */
  193. X
  194. X#ifdef DEBUG
  195. Xint debugging = 0;
  196. X#endif
  197. X
  198. X/* opens file, prints error message if can't open */
  199. XFILE *efopen (fname, mode, level)
  200. Xchar *fname;               /* filename to open */
  201. Xchar *mode;                /* mode, e.g. "r" or "r+" */
  202. Xint level;                 /* error level */
  203. X{
  204. X   FILE *fptr;
  205. X   fptr = fopen (fname, mode);
  206. X   if (fptr == NULL)
  207. X      showerr (fname, level);
  208. X   return (fptr);
  209. X}
  210. X
  211. X/* LOWERIT is a function or macro that returns lowercase of a character */
  212. X#ifndef LOWERIT
  213. X# ifdef AVOID_MACROS
  214. X#  define LOWERIT    lowerit
  215. X# else
  216. X#  define LOWERIT(c)        ((c)>='A' && (c)<='Z' ? ('a'-'A')+(c) : (c))
  217. X# endif
  218. X#endif
  219. X
  220. X/* Function needed by SEEKFIX code even if a macro is available */
  221. Xint lowerit (c) int c;  /* returns lowercase of an ASCII character */
  222. X{
  223. X  if (c >= 'A' && c <= 'Z') return (('a'-'A') + c);
  224. X  else return (c);
  225. X}
  226. X
  227. X/* STRNICMP is a case-insensitive strncmp */
  228. X#ifndef STRNICMP
  229. Xint STRNICMP (s1, s2, n)
  230. Xregister char *s1, *s2;
  231. Xint n;
  232. X{
  233. X   assert (n >= 0);
  234. X   assert (LOWERIT('X') == 'x');
  235. X   assert (LOWERIT('*') == '*');
  236. X
  237. X   for ( ; LOWERIT(*s1) == LOWERIT(*s2);  s1++, s2++) {
  238. X      if (--n == 0 || *s1 == '\0')
  239. X         return(0);
  240. X   }
  241. X   return(LOWERIT(*s1) - LOWERIT(*s2));
  242. X}
  243. X#endif /* STRNICMP */
  244. X
  245. X#ifdef AVOID_MACROS
  246. X# define BRINCMP     STRNICMP
  247. X#else
  248. X# define BRINCMP(s1,s2,n) (LOWERIT(*(s1))!=LOWERIT(*(s2))||STRNICMP(s1,s2,n))
  249. X#endif
  250. X
  251. X
  252. X#define xdigit(x)    ((x) >= '0' && (x) <= '9')
  253. X
  254. X/*
  255. Xxatol is given a string that (supposedly) begins with a string
  256. Xof digits.  It returns a corresponding positive numeric value.
  257. X*/
  258. Xtcrc xatol (str)
  259. Xchar *str;
  260. X{
  261. X   tcrc retval;
  262. X   retval = 0L;
  263. X   while (xdigit(*str)) {
  264. X      retval = retval * 10L + (*str-'0');
  265. X      str++;
  266. X   }
  267. X   return (retval);
  268. X}
  269. X
  270. Xmain (argc, argv)
  271. Xint argc;
  272. Xchar **argv;
  273. X{
  274. X   int i;
  275. X   int c;                        /* next option letter */
  276. X   int count = 0;                /* count of required options seen */
  277. X   char *infname;                /* name of file to read filenames from */
  278. X   FILE *infptr;                 /* open file ptr for infname */
  279. X
  280. X   extern int optind;            /* from getopt: next arg to process */
  281. X   extern int opterr;            /* used by getopt */
  282. X
  283. X   opterr = 1;                   /* so getopt will print err msg */
  284. X   argv[0] = "brik";             /* for getopt to use */
  285. X
  286. X   patlen = strlen (PATTERN);
  287. X
  288. X#ifdef DEBUG
  289. X   while ((c = getopt (argc, argv, "cCgGasqvWHfbThd")) != EOF)
  290. X#else
  291. X   while ((c = getopt (argc, argv, "cCgGasqvWHfbTh")) != EOF)
  292. X#endif
  293. X   {
  294. X      switch (c) {
  295. X         case 'a':   autocheck++; binary = 0; trailing = 0; break;
  296. X         case 'c':   check1++; count++; break;
  297. X         case 'C':   check2++; count++; break;
  298. X         case 'g':   gen1++; count++; break;
  299. X         case 'G':   gen2++; count++; break;
  300. X         case 's':   silent++; verbose = 0; break;
  301. X         case 'q':   quiet++; verbose = 0; break;
  302. X         case 'v':   verbose++; silent = 0; break;
  303. X         case 'W':   updfile++; break;
  304. X         case 'f':   fromfile++; break;
  305. X         case 'b':   binary++; autocheck = 0; trailing = 0; break;
  306. X         case 'T':   trailing++; binary = 0; autocheck = 0; break;
  307. X         case 'H':   prthdr++; break;
  308. X#ifdef DEBUG
  309. X         case 'd':   debugging++; break;
  310. X#endif
  311. X         case 'h':   longhelp();
  312. X         case '?':   shorthelp();
  313. X      }
  314. X   }
  315. X
  316. X   if (count != 1)
  317. X      shorthelp();
  318. X
  319. X   if (binary && (check1 || gen1)) {
  320. X      fprintf (stderr, "brik: fatal: Can't read or update CRC header in binary mode\n");
  321. X      exit (1);
  322. X   }
  323. X
  324. X   if ((updfile || prthdr) && !gen1) {
  325. X      fprintf (stderr, "brik: fatal: Use of -W and -H requires -g\n");
  326. X      exit (1);
  327. X   }
  328. X
  329. X#if 0
  330. X   if (gen1 || gen2 && !updfile)
  331. X      silent = 0;
  332. X#endif
  333. X
  334. X   if (gen1)
  335. X      autocheck = 0;
  336. X
  337. X#ifdef GENTAB
  338. X   /* generate CRC table */
  339. X   mkcrctab();
  340. X#endif /* GENTAB */
  341. X
  342. X   /* initialize binary char test table */
  343. X   for (i = 0;  i < BINTABSIZ;  i++) {
  344. X      if ( (i < 7) || (i > 13 && i < 26) || (i > 126)) /*ASCII binary chars*/
  345. X         bintab[i] = 1;
  346. X      else
  347. X         bintab[i] = 0;
  348. X   }
  349. X
  350. X   i = optind;
  351. X
  352. X   if (fromfile) {                  /* read filenames from file */
  353. X      if (i >= argc) {              /* need filenames after -f */
  354. X         fprintf (stderr, "brik: fatal: Filename(s) needed after -f\n");
  355. X         exit (1);
  356. X      }
  357. X      for (; i < argc;  i++) {
  358. X         infname = argv[i];
  359. X         if (strcmp(infname, "-") == 0) { /* "-" means stdin */
  360. X            readnames (stdin);
  361. X         } else {
  362. X#ifdef WILDCARD
  363. X            extern char *nextfile();
  364. X            nextfile (0, infname, 0);     /* initialize fileset 0 */
  365. X            while ((infname = nextfile(1, (char *) NULL, 0)) != NULL) {
  366. X               infptr = efopen (infname, BRIK_RD, LVL_ERR);
  367. X               readnames (infptr);
  368. X               fclose (infptr);
  369. X            }
  370. X#else
  371. X            infptr = efopen (infname, BRIK_RD, LVL_ERR);
  372. X            readnames (infptr);
  373. X            fclose (infptr);
  374. X#endif /* WILDCARD */
  375. X         }
  376. X      }
  377. X   } else {                         /* read filenames from command line */
  378. X      if (i >= argc) {
  379. X#ifndef BIN_STDIN_OK
  380. X         if (binary && !check2) {
  381. X            fprintf (stderr, "brik: fatal: Can't handle stdin in binary mode\n");
  382. X            exit (1);
  383. X         }
  384. X#endif
  385. X         is_stdin = 1;
  386. X         dofptr (stdin, "stdin");      /* if no files, read stdin */
  387. X      } else {
  388. X         for (;  i < argc;  i ++) {
  389. X#ifdef WILDCARD
  390. X            extern char *nextfile();
  391. X            char *one_name;               /* a matching filename */
  392. X            nextfile (0, argv[i], 0);     /* initialize fileset 0 */
  393. X            while ((one_name = nextfile(1, (char *) NULL, 0)) != NULL)
  394. X               dofname (one_name);
  395. X#else
  396. X            dofname (argv[i]);
  397. X#endif /* WILDCARD */
  398. X         }
  399. X      }
  400. X   }
  401. Xerrexit:
  402. X   if (errcount > ERRLIMIT)
  403. X      errcount = ERRLIMIT;       /* don't overflow status code */
  404. X   exit (errcount);
  405. X   return (errcount);            /* to keep turbo c and lint happy */
  406. X}
  407. X
  408. X/*
  409. X**   Reads names from supplied file pointer and handles them.  Just
  410. X**   returns if supplied NULL file pointer.  Will also expand wildcards
  411. X**   in names read from this file.
  412. X*/
  413. Xvoid readnames (infptr)
  414. XFILE *infptr;
  415. X{
  416. X   char buf[LINESIZE];
  417. X   if (infptr == NULL)
  418. X      return;
  419. X   while (fgets (buf, LINESIZE, infptr) != NULL) {
  420. X#ifdef WILDCARD
  421. X      char *fname;                  /* matching filename */
  422. X      extern char *nextfile();
  423. X#endif /* WILDCARD */
  424. X      buf[strlen(buf)-1] = '\0'; /* zap trailing newline */
  425. X#ifdef WILDCARD
  426. X      nextfile (0, buf, 1);     /* initialize fileset 1 */
  427. X      while ((fname = nextfile(1, (char *) NULL, 1)) != NULL) {
  428. X         dofname (fname);
  429. X      }
  430. X#else
  431. X      dofname (buf);
  432. X#endif /* WILDCARD */
  433. X   }
  434. X}
  435. X
  436. X/* do one filename */
  437. Xvoid dofname (this_arg)
  438. Xchar *this_arg;
  439. X{
  440. X   FILE *this_file;
  441. X   char *mode;                         /* "r", "rb", "rw", etc. for fopen */
  442. X#ifdef BRKTST
  443. X   extern void brktst();
  444. X   brktst();
  445. X#endif
  446. X
  447. X   if (autocheck)
  448. X      binary = 0;             /* always begin by assuming text */
  449. X
  450. X   if (strcmp(this_arg,"-") == 0) {
  451. X#ifndef BIN_STDIN_OK
  452. X      if (binary && !check2) {
  453. X         fprintf (stderr, "brik: fatal: Can't handle stdin in binary mode\n");
  454. X         exit (1);
  455. X      }
  456. X#endif
  457. X
  458. X      is_stdin = 1;
  459. X      this_file = stdin;
  460. X      this_arg = "stdin";
  461. X   } else {
  462. X      if (updfile) {
  463. X         assert (!binary);
  464. X         this_file = efopen (this_arg, BRIK_RW, LVL_ERR);
  465. X      } else {
  466. X         if (binary && !check2) /* check2 reads filenames, not data */
  467. X            mode = BRIK_RDB;
  468. X         else
  469. X            mode = BRIK_RD;
  470. X         this_file = efopen (this_arg, mode, LVL_ERR);
  471. X      }
  472. X   }
  473. X   if (this_file == NULL)
  474. X      errcount++;
  475. X   else {
  476. X#ifdef NOCASE
  477. X      char *p;
  478. X      for (p = this_arg;  *p != '\0';  p++)
  479. X         *p = LOWERIT(*p);
  480. X#endif
  481. X      dofptr (this_file, this_arg);
  482. X      if (this_file != NULL)
  483. X         fclose (this_file);
  484. X   }
  485. X}
  486. X
  487. X/* returns appropriate suffix character for CRC, based on global flags */
  488. Xchar suffix()
  489. X{
  490. X   return (doubtful ? '*' : (binary ? 'b' : (trailing ? 'T' : ' ')));
  491. X}
  492. X
  493. X
  494. X/*
  495. X**   Do one file pointer.  Decides if CRC header will be read or written,
  496. X**   or whether just the whole file will be read.
  497. X*/
  498. Xvoid dofptr (fptr, fname)
  499. XFILE *fptr;
  500. Xchar *fname;
  501. X{
  502. X   int retval;                      /* return value from findcrc */
  503. X   if (check2)
  504. X      whole_check (fptr, fname);    /* do whole file check from list */
  505. X   else if (gen1 || check1)         /* header-based CRC check or update */
  506. X      hdrcrc (fptr, fname);
  507. X   else {                           /* whole-file CRC calculation */
  508. X      extern tcrc crccode;
  509. X      assert (gen2);
  510. X      printhdr();
  511. X      (void) findcrc (fptr, fname, &retval);
  512. X      if (!silent) {
  513. X         if (!binary && retval == 1)
  514. X            doubtful = 1;                 /* tell suffix() it's '*' */
  515. X         printf (fmtstr, crccode, suffix(), blank, fname);
  516. X      }
  517. X   }
  518. X   is_stdin = 0;                    /* set, but not reset, by our caller */
  519. X   doubtful = 0;                    /* sphagetti code, need to fix later */
  520. X}
  521. X
  522. X/* Does whole file check from a list of files and CRCs */
  523. Xwhole_check (fptr, listname)
  524. XFILE *fptr;                   /* open file ptr of CRC list file */
  525. Xchar *listname;               /* name of CRC list file */
  526. X{
  527. X   tcrc fcrc;        /* recorded crc */
  528. X   char *fname;               /* name of file whose CRC being checked */
  529. X   char buf [LINESIZE];       /* line buffer */
  530. X   char *p;                   /* temp ptr */
  531. X   FILE *orgfile;             /* file pointer for original file to check */
  532. X   int lino = 0;              /* line no. in list file for error msg */
  533. X   char *mode;                /* mode string for fopen */
  534. X
  535. X   while (fgets (buf, LINESIZE, fptr) != NULL) {
  536. X      lino++;
  537. X      p = buf;
  538. X      if (*p == CMTCH)              /* skip comment lines */
  539. X         continue;
  540. X      while (*p != '\0' && whitespace(*p))      /* skip whitespace */
  541. X         p++;
  542. X      if (*p == '\0')
  543. X         continue;                              /* skip empty lines */
  544. X      if (!xdigit(*p))
  545. X         goto badline;
  546. X      fcrc = xatol (p); /* recorded CRC */
  547. X
  548. X      while (xdigit(*p))
  549. X         p++;                                   /* skip past numeric chars */
  550. X
  551. X      doubtful = binary = trailing = 0;
  552. X      if (*p == 'b')                            /* 'b' means binary */
  553. X         binary = 1;
  554. X
  555. X      if (*p == 'T')                            /* 'T' means trailing mode */
  556. X         trailing = 1;
  557. X
  558. X      if (*p == '*')
  559. X         doubtful = 1;                          /* text but doubtful */
  560. X
  561. X      while (*p != '\0' && !whitespace(*p)) /* to whitespace */
  562. X         p++;
  563. X      while (whitespace(*p))   /* skip whitespace */
  564. X         p++;
  565. X
  566. X      if (*p == '\n' || *p == '\0') {     /* if at end of line */
  567. X         goto badline;
  568. X      }
  569. X      fname = p;
  570. X      while (*p != '\0' && !whitespace(*p))  /* skip to whitespace */
  571. X         p++;
  572. X      *p = '\0';                    /* null-terminate filename */
  573. X
  574. X      if (binary)
  575. X         mode = BRIK_RDB;
  576. X      else
  577. X         mode = BRIK_RD;
  578. X
  579. X      orgfile = efopen (fname, mode, LVL_ERR);
  580. X      if (orgfile == NULL) {
  581. X         errcount++;
  582. X      } else {
  583. X         int retval;
  584. X         tcrc foundcrc;
  585. X         assert (!(binary && trailing));
  586. X         foundcrc = findcrc (orgfile, fname, &retval);
  587. X         if (foundcrc == fcrc) {
  588. X            if (verbose)
  589. X               printf (fmtstr, foundcrc, suffix(), ok, fname);
  590. X         } else {
  591. X            if (!silent)
  592. X               printf (fmtstr, foundcrc, suffix(), bad, fname);
  593. X            errcount ++;
  594. X         }
  595. X         if (orgfile != NULL)
  596. X            fclose (orgfile);
  597. X      }
  598. X   }
  599. X   return;
  600. Xbadline:
  601. X   fprintf (stderr,
  602. X      "brik: error: Abandoning %s due to badly formatted line %d\n",
  603. X      listname, lino);
  604. X   return;
  605. X}
  606. X
  607. X
  608. X/*
  609. XInitializing the CRC to all one bits avoids failure of detection
  610. Xshould entire data stream get cyclically bit-shifted by one position.
  611. XThe calculation of the probability of this happening is left as
  612. Xan exercise for the reader.
  613. X*/
  614. X#define INITCRC   0xFFFFFFFFL;
  615. X
  616. X/*
  617. X**   hdrcrc processes one file given an open file pointer
  618. X**   and the filename.  The filename is used for messages etc.
  619. X**   It does all manipulation of header-related CRCs, i.e.,
  620. X**   checking generating header CRC.  It deals only with text files.
  621. X*/
  622. Xvoid hdrcrc (fptr, fname)
  623. XFILE *fptr;
  624. Xchar *fname;
  625. X{
  626. X   char buf[LINESIZE];
  627. X   int lino = 0;
  628. X   char *ptr;
  629. X   tcrc fcrc;   /* crc recorded in file */
  630. X   extern tcrc crccode;
  631. X   int retval;                      /* return value from findcrc */
  632. X   long hdrpos;                     /* where we found crc header in file */
  633. X
  634. X   crccode = INITCRC;
  635. X
  636. X   assert (!binary);
  637. X
  638. X#ifndef NIXSEEK
  639. X   hdrpos = ftell (fptr);
  640. X#endif
  641. X   while (fgets (buf, LINESIZE, fptr) != NULL) {
  642. X#ifdef BRKTST
  643. X      extern void brktst();
  644. X      brktst();
  645. X#endif
  646. X      lino++;
  647. X      if (BRINCMP (buf, PATTERN, patlen) == 0) {      /* found header */
  648. X#ifdef NIXSEEK
  649. X         hdrpos = ftell (fptr);        /* seek posn of line with header */
  650. X#endif
  651. X         ptr = buf + patlen;           /* point to beyond header */
  652. X         while (*ptr != '\0' && whitespace(*ptr))
  653. X            ptr++;                     /* skip white space */
  654. X         fcrc = xatol (ptr);           /* get stored crc */
  655. X         while (xdigit(*ptr))
  656. X            ptr++;                     /* skip past digits */
  657. X         if (check1) {
  658. X            if (*ptr == 'T')           /* if 'T' suffix then */
  659. X               trailing = 1;          /* ..include trailing empty lines */
  660. X            else
  661. X               trailing = 0;
  662. X         }
  663. X
  664. X         /* find CRC for rest of file */
  665. X         (void) findcrc (fptr, fname, &retval);
  666. X
  667. X         if (gen1) {                   /* generating CRC */
  668. X            if (updfile) {             /* if updating file posn */
  669. X               updatefile (fptr, hdrpos, crccode, fname); /* then do it */
  670. X               if (prthdr && !silent)  /* printing header */
  671. X                  printf (hdrfmt, crccode, fname);
  672. X            } else {
  673. X               if (prthdr && !silent)  /* printing header */
  674. X                  printf (hdrfmt, crccode, fname);
  675. X               else if (!silent)
  676. X                  printf (fmtstr, crccode, suffix(), blank, fname);
  677. X            }
  678. X         } else {                      /* checking CRC */
  679. X            if (fcrc == crccode) {
  680. X               if (verbose)
  681. X                  printf (fmtstr, crccode, suffix(), ok, fname);
  682. X            } else {
  683. X               if (!silent)
  684. X                  printf (fmtstr, crccode, suffix(), bad, fname);
  685. X               errcount ++;
  686. X            }
  687. X         }
  688. X         return;
  689. X      } /* end if (BRINCMP (...) ) */
  690. X#ifndef NIXSEEK
  691. X      hdrpos = ftell (fptr);
  692. X#endif
  693. X   } /* end of while (fgets(...)) */
  694. X
  695. X   /* reach here if header not found -- this is an error */
  696. X   if (!silent)
  697. X      printf ("%10s      %s\n", "????", fname);
  698. X   errcount++;
  699. X   return;
  700. X}
  701. X
  702. X/* update file with CRC -- must be seekable */
  703. Xvoid updatefile (fptr, hdrpos, crccode, fname)
  704. XFILE *fptr;
  705. Xlong hdrpos;
  706. Xtcrc crccode;
  707. Xchar *fname;
  708. X{
  709. X   char buf[LINESIZE];
  710. X   int buflen;             /* will hold count of chars in buf */
  711. X   int chars_to_print;     /* chars needed to fill in CRC */
  712. X
  713. X   /*
  714. X   1 for blank, CHARSINCRC for actual CRC, and possibly
  715. X   1 more for 'T' suffix if including trailing empty lines too
  716. X   */
  717. X   chars_to_print = 1 + CHARSINCRC + (trailing ? 1 : 0);
  718. X
  719. X#ifndef NIXSEEK
  720. X   /* hdrpos is already seek position of header */
  721. X   if (fseek (fptr, hdrpos, 0) != 0) { /* seek back */
  722. X      fprintf(stderr,
  723. X         "brik: error: No CRC written, seek failed on %s\n",fname);
  724. X      return;
  725. X   }
  726. X
  727. XSEEKFIX
  728. X
  729. X   fgets (buf, LINESIZE, fptr);
  730. X   if (BRINCMP (buf, PATTERN, patlen) == 0)
  731. X      goto foundit;
  732. X   fprintf(stderr,
  733. X      "brik: error: No CRC written, header lost in %s\n",fname);
  734. X   return;
  735. X#else
  736. X   /* Following code does fseeks in a non-ANSI-conformant way */
  737. X   /* hdrpos is seek position *after* header was read.  Need to get back */
  738. X   if (hdrpos >= BACKSIZE)
  739. X      hdrpos -= BACKSIZE;
  740. X   else
  741. X      hdrpos = 0L;
  742. X   if (fseek (fptr, hdrpos, 0) != 0) {       /* seek back first */
  743. X      fprintf(stderr,"brik: error: No CRC written, seek failed on %s\n",fname);
  744. X      return;
  745. X   }
  746. X   /* now seek forward until we see CRC header again */
  747. X   hdrpos = ftell (fptr);
  748. X   while (fgets (buf, LINESIZE, fptr) != NULL) {
  749. X      if (BRINCMP (buf, PATTERN, patlen) == 0)
  750. X         goto foundit;
  751. X      hdrpos = ftell (fptr);
  752. X   }
  753. X   fprintf(stderr,"brik: error: No CRC written, header lost in %s\n",fname);
  754. X   return;
  755. X#endif /* NIXSEEK */
  756. X
  757. Xfoundit:    /* hdrpos points to line with header */
  758. X   if (fseek (fptr, hdrpos, 0) != 0) { /* seek failed */
  759. X      fprintf(stderr,"brik: error: No CRC written, seek failed on %s\n",fname);
  760. X      return;
  761. X   }
  762. XSEEKFIX
  763. X   /* we are seeked back to the line with the CRC header */
  764. X
  765. X#ifdef CHECKSEEK  /* triple-check seeks */
  766. X   {
  767. X      char tmpbf1[LINESIZE];
  768. X      char tmpbf2[LINESIZE];
  769. X      fseek (fptr, hdrpos, 0);
  770. X      assert (ftell (fptr) == hdrpos);
  771. XSEEKFIX
  772. X      fgets (tmpbf1, LINESIZE, fptr);
  773. X      fseek (fptr, 0L, 0); fseek (fptr, 0L, 2);    /* exercise seeks */
  774. X      fseek (fptr, hdrpos, 0);
  775. X      assert (ftell (fptr) == hdrpos);
  776. XSEEKFIX
  777. X      fgets (tmpbf2, LINESIZE, fptr);
  778. X      if (strcmp(tmpbf1,tmpbf2) != 0 || BRINCMP(tmpbf1,PATTERN,patlen) != 0) {
  779. X         fprintf (stderr,
  780. X            "brik: error: Bad seek on %s, abandoning this file\n", fname);
  781. X         return;
  782. X      }
  783. X      fseek (fptr, hdrpos, 0);
  784. XSEEKFIX
  785. X   }
  786. X#endif /* CHECKSEEK */
  787. X
  788. X#ifdef DEBUG
  789. X   if (debugging) {  /* zap newline, print buffer, restore newline */
  790. X      int nlpos; char savech;
  791. X      nlpos = strlen(buf) - 1;  savech = buf[nlpos];  buf[nlpos] = '\0';
  792. X      fprintf (stderr, "read header  [%s]\n", buf);
  793. X      buf[nlpos] = savech;
  794. X   }
  795. X#endif
  796. X
  797. X   buflen = strlen (buf);
  798. X#ifdef DEBUG
  799. X   if (debugging)  /* need chars_to_print plus one trailing space or newline */
  800. X      fprintf(stderr,"need %d chars, have %d\n",chars_to_print+1,buflen-patlen);
  801. X#endif
  802. X   if (buflen - patlen > chars_to_print) {      /* if enough space */
  803. X      char sprbuf[1+CHARSINCRC+1+1+6];  /* blank+CRC+suffix+null+fudge */
  804. X      char *ptr;
  805. X      int i;
  806. X      ptr = &buf[patlen];                 /* point to beyond header */
  807. X      sprintf (sprbuf, " %10lu%c", crccode, 'T');
  808. X      for (i = 0;  i < chars_to_print;  i++) /* trailing 'T' possibly ignored */
  809. X         ptr[i] = sprbuf[i];
  810. X      if (ptr[i] != '\n')
  811. X         ptr[i] = ' ';           /* terminate with newline or blank */
  812. X      fseek (fptr, 0L, 1);       /* after read, must seek before write */
  813. X      if (fwrite (buf, 1, buflen, fptr) != buflen) {
  814. X         fprintf(stderr,
  815. X            "brik: error: Write failed while writing CRC to %s\n",fname);
  816. X      } else if (verbose)
  817. X         printf (fmtstr, crccode, suffix(), blank, fname);
  818. X         /* printf ("%10lu      %s\n", crccode, fname); */
  819. X#ifdef DEBUG
  820. X      buf[strlen(buf)-1] = '\0'; /* zap trailing newline */
  821. X      if (debugging)
  822. X         fprintf (stderr, "wrote header [%s]\n", buf);
  823. X#endif
  824. X   } else {
  825. X      fprintf(stderr,"brik: error: Not enough space for CRC in %s\n",fname);
  826. X      return;
  827. X   }
  828. X}
  829. X
  830. Xvoid longhelp()
  831. X{
  832. Xprintf ("%s\n", copyright);
  833. X
  834. Xprintf (
  835. X"Usage:  brik -cCgGsqvWHfbT [ file ] ...  (must have one of -cCgG) \n\n");
  836. X
  837. Xprintf ("Brik %s (%s) generates and verifies CRC-32 checksums.  It can\n",
  838. X      version, DATESTAMP);
  839. X
  840. Xprintf ("\
  841. Xalso read or update a \"Checksum: xxxxxxxxxx\" header at the beginning\n\
  842. Xof a line in which xxxxxxxxxx represents the CRC of all lines in the file\n\
  843. X*after* this header.  A filename of \"-\" (or none) means standard input.\n\n\
  844. X");
  845. X
  846. Xprintf ("\
  847. X   -g     look for Checksum: header, generate CRC for rest of file\n\
  848. X   -c     get CRC from header, verify CRC of rest of file\n\
  849. X   -G     generate CRC for entire file (add -b for binary files)\n\
  850. X   -C     verify all file CRCs from output of -G (-f is not needed)\n\
  851. X   -b     use binary mode -- read file byte by byte, not line by line\n\
  852. X   -a     automatically decide whether each file is text or binary\n\
  853. X");
  854. X
  855. X#ifdef WILDCARD
  856. Xprintf ("   -f     read filenames (wildcards ok) from specified files\n");
  857. X#else
  858. Xprintf ("   -f     read filenames from specified files\n");
  859. X#endif
  860. X
  861. Xprintf ("\
  862. X   -v     be verbose, report all results (else only errors are reported)\n\
  863. X   -s     be silent, say nothing, just return status code\n\
  864. X   -q     be quiet, don't print header for -G\n\
  865. X   -W     after generating CRC with -g, write it to original header\n\
  866. X   -H     after generating CRC with -g, print header to stdout\n\
  867. X   -T     include trailing empty lines, normally ignored (text mode only)\n\
  868. X");
  869. Xexit (0);
  870. X}
  871. X
  872. X/*
  873. X**   Generates CRC of an open file, from current file position to end
  874. X**   Except in -T mode, will ignore all trailing empty lines in text
  875. X**   files.  Algorithm for this is:
  876. X**      1.   After each nonempty line, save crccode so far.
  877. X**      2.   At end of file, if last line was empty, use saved crccode rather
  878. X**           than current one.
  879. X**   In whole-file mode, if was text mode but binary file, and if auto
  880. X**   check is on, will re-open file in binary mode and do it again
  881. X**   (except if stdin was being read)
  882. X**   Returns 1 in retval if it detected that a text file contained binary
  883. X*    characters.
  884. X*/
  885. X
  886. Xtcrc findcrc (fptr, fname, retval)
  887. XFILE *fptr;
  888. Xchar *fname;
  889. Xint *retval;
  890. X{
  891. X   int count;
  892. X   char buf[LINESIZE];
  893. X   extern tcrc crccode;
  894. X   int warned = 0;
  895. X   tcrc savedcrc; /* save crccode for trailing empty lines */
  896. X   int buflen;
  897. X   *retval = 0;         /* will become 1 later if needed */
  898. X
  899. Xagain:      /* restart here if retrying in binary mode */
  900. X
  901. X   savedcrc = crccode = INITCRC;
  902. X
  903. X   if (binary) {                                   /* binary */
  904. X      while ((count = fread (buf, 1, LINESIZE, fptr)) > 0) {
  905. X#ifdef BRKTST
  906. X         extern void brktst(); brktst();
  907. X#endif
  908. X         addbfcrc (buf, count);
  909. X      }
  910. X   } else {                                           /* text */
  911. X#ifdef CTRLZ_CHECK
  912. X      int lines = 0;                /* will count lines */
  913. X#endif /* CTRLZ_CHECK */
  914. X      buflen = 1;                   /* assume empty lines so far */
  915. X      while (fgets (buf, LINESIZE, fptr) != NULL) {
  916. X         register char *p;
  917. X         char *limit;
  918. X#ifdef BRKTST
  919. X         extern void brktst(); brktst();
  920. X#endif
  921. X
  922. X#ifdef CTRLZ_CHECK
  923. X         lines++;    /* count lines */
  924. X#endif /* CTRLZ_CHECK */
  925. X
  926. X         buflen = strlen (buf);
  927. X         limit = buf + buflen;
  928. X         for (p = buf;  p != limit;  p++) {
  929. X            if (!warned && BINCHAR(*p)) {
  930. X               *retval = 1;
  931. X               if (autocheck && !is_stdin)/* restart, now known to be binary */
  932. X                  goto restart;
  933. X               else {               /* don't restart, just warn */
  934. X                  warned = 1;
  935. X               }
  936. X            }
  937. X            if (*p == '\n')
  938. X               *p = MYNL;
  939. X         }
  940. X         addbfcrc (buf, buflen);
  941. X         if (buflen != 1)
  942. X            savedcrc = crccode;
  943. X      }
  944. X#ifdef CTRLZ_CHECK
  945. X      if (gen2) {
  946. X         int z_bin_check PARMS ((FILE *fptr, char *fname));
  947. X         if (!warned && lines < Z_THRESHOLD && z_bin_check (fptr, fname)) {
  948. X            *retval = 1;
  949. X            if (autocheck && !is_stdin)
  950. X               goto restart;
  951. X         }
  952. X      }
  953. X#endif
  954. X      if (!trailing && buflen == 1)
  955. X         crccode = savedcrc;
  956. X   }
  957. X   if (ferror (fptr))
  958. X      fprintf (stderr, "brik: warning: error occurred while reading %s\n", fname);
  959. X   return (crccode);
  960. X
  961. X/*
  962. Xreach here if we were trying to get a text crc but the file was binary, we
  963. Xare in autocheck mode, and we are not reading stdin.  Now we re-initialize
  964. Xvariables, reopen the file in binary mode, and begin again.
  965. X*/
  966. Xrestart:
  967. X   binary = 1;
  968. X   fclose (fptr);  fptr = efopen (fname, BRIK_RDB, LVL_ERR);
  969. X   if (fptr == NULL) {
  970. X      errcount++;
  971. X      return (crccode);
  972. X   } else
  973. X      goto again;
  974. X}
  975. X
  976. Xvoid printhdr ()
  977. X{
  978. X   static int firsttime = 1;
  979. X   if (firsttime && !quiet && !silent) {
  980. X      printf ("%c Whole file CRCs generated by Brik v%s.  Use \"brik -C\" to verify them.\n\n",
  981. X         CMTCH, version);
  982. X        printf ("%c CRC-32        filename\n", CMTCH);
  983. X        printf ("%c ------        --------\n\n", CMTCH);
  984. X      firsttime = 0;
  985. X   }
  986. X}
  987. X
  988. X/*
  989. X**   Prints error message via perror().  The message is printed in the
  990. X**   format "brik: %s: %s" where the first %s is the level text ("warning",
  991. X**   "error", or "fatal") and the second %s is the string supplied by
  992. X**   perror().
  993. X**
  994. X*/
  995. X
  996. Xvoid showerr (errmsg, level)
  997. Xchar *errmsg;
  998. Xint level;
  999. X{
  1000. X#define ERRSTRMAX  40         /* don't copy more than this many chars */
  1001. X   static char leveltext[][7] =   {"warning", "error", "fatal"};
  1002. X   char errbuf[ERRBUFSIZ];       /* buffer for error message */
  1003. X   strcpy (errbuf, "brik: ");
  1004. X   assert (level >= LVL_WARN && level <= LVL_FATAL);
  1005. X   strncat (errbuf, leveltext[level], ERRSTRMAX);
  1006. X   strcat (errbuf, ": ");
  1007. X   strncat (errbuf, errmsg, ERRSTRMAX);
  1008. X   perror (errbuf);
  1009. X}
  1010. X
  1011. Xvoid shorthelp()
  1012. X{
  1013. X   fprintf (stderr, "%s\n\n%s", "Usage to get help:  brik -h", copyright);
  1014. X   exit (1);
  1015. X}
  1016. SHAR_EOF
  1017. fi
  1018. echo shar: "extracting 'turboc.c'" '(9089 characters)'
  1019. if test -f 'turboc.c'
  1020. then
  1021.     echo shar: "will not over-write existing file 'turboc.c'"
  1022. else
  1023. sed 's/^X//' << \SHAR_EOF > 'turboc.c'
  1024. X/* nextfile.c */
  1025. X/* ::[[ @(#) turboc.c 1.7 89/07/12 03:18:30 ]]:: */
  1026. X#ifndef LINT
  1027. Xstatic char sccsid[]="::[[ @(#) turboc.c 1.7 89/07/12 03:18:30 ]]::";
  1028. X#endif
  1029. X
  1030. X/*
  1031. XThis file is used only for MS-DOS.  It is used with Turbo C 1.0.  It also
  1032. Xapparently works with Microsoft C 5.1 (see makefile.msc).
  1033. X*/
  1034. X
  1035. X/*
  1036. XChecksum:   60385500      (check or update this with "brik")
  1037. X*/
  1038. X
  1039. X/*
  1040. Xnextfile() is a general wildcard expansion function that may be used
  1041. Xwith other programs.  Usage instructions are below.  It does not
  1042. Xsimply expand wildcards in an entire argument list.  Instead, it is
  1043. Xcalled in a loop as described below, and returns one matching
  1044. Xfilename each time it is called.
  1045. X
  1046. XThese functions are for the SMALL MEMORY MODEL ONLY.
  1047. X*/
  1048. X
  1049. X#include "assert.h"
  1050. X#include "brik.h"
  1051. X
  1052. X#define  FMAX  2        /* Number of different filename patterns */
  1053. X#define  PATHSIZE 200   /* Size of MS-DOS pathname */
  1054. X#define  NULL  0
  1055. X
  1056. X#ifdef ANSIPROTO
  1057. Xchar *strtcpy (char *, char *);
  1058. Xint strlen (char *);
  1059. Xchar *strcpy (char *, char *);
  1060. X#endif
  1061. X
  1062. X
  1063. X/* Structure definitions for MS-DOS software interrupt intdos() */
  1064. X
  1065. Xstruct WORD_REGISTERS {
  1066. X   unsigned int ax, bx, cx, dx, si, di, carry, flags;
  1067. X};
  1068. X
  1069. X/* byte registers */
  1070. X
  1071. Xstruct BYTE_REGISTERS {
  1072. X   unsigned char al, ah, bl, bh, cl, ch, dl, dh;
  1073. X};
  1074. X
  1075. Xunion REGS {
  1076. X   struct WORD_REGISTERS x;
  1077. X   struct BYTE_REGISTERS h;
  1078. X};
  1079. X
  1080. Xint intdos (union REGS *, union REGS *);
  1081. X
  1082. X/*
  1083. Xformat of disk transfer address after MS-DOS calls FindFirst and
  1084. XFindNext
  1085. X*/
  1086. Xstruct dta_t {
  1087. X   char junk[22];
  1088. X   int time;
  1089. X   int date;
  1090. X   long size;
  1091. X   char fname[13];
  1092. X   char just_in_case[4];   /* in case MS-DOS writes too much */
  1093. X};
  1094. X
  1095. Xvoid setdta (struct dta_t *);
  1096. Xvoid fcbpath (struct dta_t *, char *, char *);
  1097. X
  1098. X/*******************/
  1099. X/*
  1100. Xnextfile() returns the name of the next source file matching a filespec.
  1101. X
  1102. XINPUT
  1103. X   what: A flag specifying what to do.  If "what" is 0, nextfile()
  1104. X      initializes itself.  If "what" is 1, nextfile() returns the next
  1105. X      matching filename.
  1106. X   filespec:  The filespec, usually containing wildcard characters, that
  1107. X      specifies which files are needed.  If "what" is 0, filespec must be
  1108. X      the filespec for which matching filenames are needed.  If "what" is 1,
  1109. X      nextfile() does not use "filespec" and "filespec" should be NULL to
  1110. X      avoid an assertion error during debugging.
  1111. X   fileset:  nextfile() can keep track of more than one set of filespecs.
  1112. X      The fileset specifies which filespec is being matched and therefore
  1113. X      which set of files is being considered.  "fileset" can be in the
  1114. X      range 0:FMAX.  Initialization of one fileset does not affect the
  1115. X      other filesets.
  1116. X
  1117. XOUTPUT
  1118. X   IF what == 0 THEN
  1119. X      return value is NULL
  1120. X   ELSE IF what == 1 THEN
  1121. X      IF a matching filename is found THEN
  1122. X         return value is pointer to matching filename including supplied path
  1123. X      ELSE
  1124. X         IF at least one file matched previously but no more match THEN
  1125. X            return value is NULL
  1126. X         ELSE IF supplied filespec never matched any filename THEN
  1127. X            IF this is the first call with what == 1 THEN
  1128. X               return value is pointer to original filespec
  1129. X            ELSE
  1130. X               return value is NULL
  1131. X            END IF
  1132. X         END IF
  1133. X      END IF
  1134. X   END IF
  1135. X
  1136. XNOTE
  1137. X
  1138. X   Initialization done when "what"=0 is not dependent on the correctness
  1139. X   of the supplied filespec but simply initializes internal variables
  1140. X   and makes a local copy of the supplied filespec.  If the supplied
  1141. X   filespec was illegal, the only effect is that the first time that
  1142. X   nextfile() is called with "what"=1, it will return the original
  1143. X   filespec instead of a matching filename.  That the filespec was
  1144. X   illegal will become obvious when the caller attempts to open the
  1145. X   returned filename for input/output and the open attempt fails.
  1146. X
  1147. XUSAGE HINTS
  1148. X
  1149. Xnextfile() can be used in the following manner:
  1150. X
  1151. X      char *filespec;                  -- will point to filespec
  1152. X      char *this_file;                 -- will point to matching filename
  1153. X      filespec = parse_command_line(); -- may contain wildcards
  1154. X      FILE *stream;
  1155. X
  1156. X      nextfile (0, filespec, 0);          -- initialize fileset 0
  1157. X      while ((this_file = nextfile(1, (char *) NULL, 0)) != NULL) {
  1158. X         stream = fopen (this_file, "whatever");
  1159. X         if (stream == NULL)
  1160. X            printf ("could not open %s\n", this_file);
  1161. X         else
  1162. X            perform_operations (stream);
  1163. X      }
  1164. X*/
  1165. X
  1166. Xchar *nextfile (what, filespec, fileset)
  1167. Xint what;                        /* whether to initialize or match      */
  1168. Xregister char *filespec;         /* filespec to match if initializing   */
  1169. Xregister int fileset;            /* which set of files                  */
  1170. X{
  1171. X   static struct dta_t new_dta [FMAX+1];     /* our own private dta        */
  1172. X   static int first_time [FMAX+1];
  1173. X   static char pathholder [FMAX+1][PATHSIZE]; /* holds a pathname to return */
  1174. X   static char saved_fspec [FMAX+1][PATHSIZE];/* our own copy of filespec   */
  1175. X   union REGS regs;
  1176. X
  1177. X   assert(fileset >= 0 && fileset <= FMAX);
  1178. X   if (what == 0) {
  1179. X      assert(filespec != NULL);
  1180. X      strcpy (saved_fspec[fileset], filespec);  /* save the filespec */
  1181. X      first_time[fileset] = 1;
  1182. X      return ((char *) NULL);
  1183. X   }
  1184. X
  1185. X   setdta (&new_dta[fileset]);   /* set new dta -- our very own */
  1186. X   assert(what == 1);
  1187. X   assert(filespec == NULL);
  1188. X   assert(first_time[fileset] == 0 || first_time[fileset] == 1);
  1189. X
  1190. X   if (first_time[fileset]) {             /* first time -- initialize etc. */
  1191. X      /* find first matching file */
  1192. X      regs.h.ah = 0x4e;                   /* FindFirst MS-DOS call    */
  1193. X      regs.x.dx = (unsigned int) saved_fspec[fileset]; /* filespec to match */
  1194. X      regs.x.cx = 0;                      /* search attributes       */
  1195. X      intdos (®s, ®s);
  1196. X   } else {
  1197. X      /* find next matching file */
  1198. X      regs.h.ah = 0x4f;                   /* FindNext MS-DOS call     */
  1199. X      intdos (®s, ®s);
  1200. X   }
  1201. X
  1202. X   if (regs.x.carry != 0) {            /* if error status                  */
  1203. X      if (first_time[fileset]) {       /*   if file never matched then     */
  1204. X         first_time[fileset] = 0;
  1205. X         return (saved_fspec[fileset]);/*      return original filespec    */
  1206. X      } else {                         /*   else                           */
  1207. X         first_time[fileset] = 0;      /*                                  */
  1208. X         return ((char *) NULL);         /*      return (NULL) for no more   */
  1209. X      }
  1210. X   } else {                                        /* a file matched */
  1211. X      first_time[fileset] = 0;
  1212. X      /* add path info  */
  1213. X      fcbpath (&new_dta[fileset], saved_fspec[fileset], pathholder[fileset]);
  1214. X      return (pathholder[fileset]);                /* matching path  */
  1215. X   }
  1216. X} /* nextfile */
  1217. X
  1218. X/*******************/
  1219. X/* This function sets the dta to a new dta */
  1220. Xvoid setdta (dta)
  1221. Xstruct dta_t *dta;
  1222. X{
  1223. X   union REGS regs;
  1224. X   regs.h.ah = 0x1a;                /* SetDTA Call       */
  1225. X   regs.x.dx = (unsigned int) dta;  /* new DTA address   */
  1226. X   intdos (®s, ®s);
  1227. X}
  1228. X
  1229. X/*******************/
  1230. X/*
  1231. Xfcbpath() accepts a pointer to the Disk Transfer Area, a character
  1232. Xpointer to a pathname that may contain wildcards, and a character
  1233. Xpointer to a buffer.  It copies into the buffer the path prefix from
  1234. Xthe pathname and the filename prefix from the DTA so that it forms a
  1235. Xcomplete path.
  1236. X*/
  1237. X
  1238. Xvoid fcbpath (dta, old_path, new_path)
  1239. Xstruct dta_t *dta;
  1240. Xchar *old_path;
  1241. Xregister char *new_path;
  1242. X{
  1243. X   register int i;
  1244. X   int length, start_pos;
  1245. X
  1246. X   strcpy(new_path, old_path);               /* copy the whole thing first */
  1247. X   length = strlen(new_path);
  1248. X   i = length - 1;                           /* i points to end of path */
  1249. X   while (i >= 0 && new_path[i] != '/' && new_path[i] != '\\' && new_path[i] != ':')
  1250. X      i--;
  1251. X   /* either we found a "/", "\", or ":", or we reached the beginning of
  1252. X      the name.  In any case, i points to the last character of the
  1253. X      path part. */
  1254. X   start_pos = i + 1;
  1255. X   for (i = 0; i < 13; i++)
  1256. X      new_path[start_pos+i] = dta->fname[i];
  1257. X   new_path[start_pos+13] = '\0';
  1258. X}
  1259. X/* -- END OF nextfile() and related functions -- */
  1260. X
  1261. Xextern unsigned _stklen = 30000;
  1262. X
  1263. X#include <conio.h>
  1264. Xvoid brktst() { kbhit(); }      /* test for user interrupt */
  1265. X
  1266. X#ifdef CTRLZ_CHECK
  1267. X# define CTRLZ_BUFSIZ   1024
  1268. X# include <io.h>
  1269. X# include <fcntl.h>
  1270. X
  1271. X/*
  1272. Xz_bin_check is called to see if the specified file is a
  1273. Xbinary file.  If so, it will return nonzero.  To avoid an early control Z
  1274. Xfalsely indicating EOF, z_bin_check changes the mode of the file
  1275. Xto binary.
  1276. X*/
  1277. Xint z_bin_check (fptr, fname)
  1278. XFILE *fptr;
  1279. Xchar *fname;
  1280. X{
  1281. X   char *p;
  1282. X   char *limit;
  1283. X   char buf[CTRLZ_BUFSIZ];
  1284. X   int count;
  1285. X
  1286. X   setmode (fileno(fptr), O_BINARY);   /* set stream to binary mode */
  1287. X   fseek (fptr, 0L, SEEK_SET);         /* rewind */
  1288. X
  1289. X   while ((count = fread (buf, 1, CTRLZ_BUFSIZ, fptr)) > 0) {
  1290. X      limit = buf + count;
  1291. X      for (p = buf;  p != limit;  p++) {
  1292. X      extern char bintab[];      /* needed for BINCHAR */
  1293. X         if (BINCHAR(*p))
  1294. X            return (1);          /* indicate binary file */
  1295. X      }
  1296. X   }
  1297. X   return (0);
  1298. X}
  1299. X#endif /* CTRLZ_CHECK */
  1300. SHAR_EOF
  1301. fi
  1302. echo shar: "extracting 'brik.h'" '(8828 characters)'
  1303. if test -f 'brik.h'
  1304. then
  1305.     echo shar: "will not over-write existing file 'brik.h'"
  1306. else
  1307. sed 's/^X//' << \SHAR_EOF > 'brik.h'
  1308. X/* ::[[ @(#) brik.h 1.31 89/07/12 03:18:00 ]]:: */
  1309. X
  1310. X/*
  1311. XChecksum: 3082630653      (check or update this with "brik")
  1312. X*/
  1313. X
  1314. X/*
  1315. XThe contents of this file are hereby released to the public domain.
  1316. X
  1317. X                                   -- Rahul Dhesi 1989/03/10
  1318. X*/
  1319. X
  1320. X/*
  1321. XBrik assumes eight-bit bytes and the ASCII character set.  There may also
  1322. Xbe some implicit assumptions that the parity bit in characters in text
  1323. Xfiles is always zero.
  1324. X
  1325. XOptions for compiling brik.c on various systems.
  1326. X
  1327. XGENTAB      If this symbol is defined, brik will generate a CRC table at
  1328. X            runtime rather than using one statically stored in the
  1329. X            executable code.  This will make brik start up a tad slower
  1330. X            but will make the code smaller, since the CRC table takes
  1331. X            up about 256 * sizeof(unsigned long) bytes.  The code is
  1332. X            smaller only if your C compiler correctly handles
  1333. X            uninitialized static data by allocating space for it only
  1334. X            at runtime.  Not all compilers are this smart.  If yours
  1335. X            isn't, definining GENTAB can actually increase the size
  1336. X            of your code.
  1337. XNOTRAIL_B   Define this if a trailing "b" is not permitted in the fopen
  1338. X            mode string to open files in binary mode.  To the best of
  1339. X            my knowledge, only Ultrix objects to a trailing "b".
  1340. XBIN_STDIN_OK  If stdin can be a binary file, this should be defined so
  1341. X            that brik will allow binary CRCs to be calculated for stdin.
  1342. X            If it is not defined, brik will give an error message if a
  1343. X            binary CRC calculation is attempted on stdin.  Should be
  1344. X            defined for **IX and similar environments.
  1345. XWILDCARD    Define this if wildcards are to be expanded by this program.
  1346. X            If WILDCARD is defined, then a function nextfile() must also
  1347. X            be available that conforms to the specifications in turboc.c.
  1348. XUSEINDEX    Define this symbol to make brik use index() instead of strchr().
  1349. X            Probably needed only 4.2BSD and earlier.
  1350. XBRKTST      If defined, brik will explicitly test for user interrupts in
  1351. X            all long loops, so that the program can easily be interrupted
  1352. X            on microcomputers that don't accept user interrupts
  1353. X            asynchronously.  If BRKTST is defined, brik will call the
  1354. X            function brktst() periodically.  This function should check
  1355. X            for a user interrupt and abort the program if it has occurred.
  1356. XNIXSEEK     If seeks are UNIX-like, i.e., seeks are possible at any byte
  1357. X            offset even in text files, then NIXSEEK may be defined to make
  1358. X            the -gW option perform faster.  If NIXSEEK is not defined, all
  1359. X            seeks will be to line boundaries using an offset already
  1360. X            obtained from ftell().  Even on non-UNIX-like systems, it *may*
  1361. X            be possible to define NIXSEEK, since when brik seeks to an
  1362. X            arbitrary byte boundary, it always immediately reads
  1363. X            sequentially forward to a line boundary.  Seeks are needed only
  1364. X            for the -gW option, which causes brik to seek back to where
  1365. X            it found the Checksum: header so it can update the stored CRC.
  1366. XCHECKSEEK   If seeks are flaky it may help to define CHECKSEEK.  In this
  1367. X            case brik will seek, read a line, seek again, read the line
  1368. X            again, compare the two, and proceed only if both reads gave the
  1369. X            checksum header it was looking for, thus confirming that the
  1370. X            seeks are working right.  This is a very conservative strategy
  1371. X            to minimize the risk of corrupting a file by overwriting it at
  1372. X            the wrong place due to a faulty seek.
  1373. XBUG1,       If ftell() just after fgets() does not return the correct seek
  1374. XBUG2        offset of the next line, one of these two symbols can be defined
  1375. X            (but not both).  Each adds different bug fix code and one of them
  1376. X            may work for you.
  1377. XANSIPROTO   If defined, ANSI-style function prototypes will be used.
  1378. XSTDINCLUDE  If defined, ANSI-standard include files will be included.
  1379. X            If not defined, many standard functions will be declared
  1380. X            explicitly.
  1381. XNDEBUG      If this symbol is defined, assert() macros throughout the
  1382. X            brik code will get nulled out, making the executable code
  1383. X            slightly smaller.
  1384. XDEBUG       If this symbol is defined, an undocumented -d switch will
  1385. X            be accepted that will cause information about Checksum:
  1386. X            header reads and writes to be printed.
  1387. XEXITBUG     Define this symbol if the exit() function has a bug causing
  1388. X            anomalous results if the exit code is not exactly 1.
  1389. XAVOID_MACROS  Brik uses macros for speed in case-insensitive string
  1390. X            comparisons.  If you get "macro too long" or "expression too
  1391. X            complex" or similar compilation errors, you can define the
  1392. X            symbol AVOID_MACROS.  This will cause slower but more compact
  1393. X            code to be used that does not use long macros, possibly
  1394. X            allowing compilation.
  1395. XLOWERIT     If a fast macro or function call is available that will accept
  1396. X            a single parameter of type "int" and return its lowercase
  1397. X            value, the symbol LOWERIT may be defined to invoke it.  This
  1398. X            macro or function must accept any int value, whether or not
  1399. X            it represents an uppercase character.  Since LOWERIT is
  1400. X            never called with side-effects, it can safely be a macro.
  1401. X            If any include file is needed, include it here.  For example,
  1402. X            if a tolower() macro or function is available that requires
  1403. X            <ctype.h> to be included, use "#include <ctype.h>" followed
  1404. X            by "#define LOWERIT tolower" somewhere in brik.h.
  1405. XSTRNICMP    If a case-insensitive implementation of strncmp is available,
  1406. X            define STRNICMP to be equivalent to it.  If STRNICMP is not
  1407. X            defined, brik uses its own case-insensitive string comparison
  1408. X            function.  STRNICMP must accept the same arguments as strncmp.
  1409. XBINCHAR     Brik uses a table look-up to test if a character is binary, to
  1410. X            warn the user if a text mode CRC is being used on a binary file.
  1411. X            The user may optionally define his own BINCHAR(c) macro, which
  1412. X            must return nonzero if c should be considered a binary character.
  1413. XNOCASE      This symbol should be defined if the filesystem is case-
  1414. X            insensitive.  It will cause all filenames printed to be in
  1415. X            lowercase.  This will help make a list of files generated by
  1416. X            the -G option to be more easily usable on systems with case-
  1417. X            sensitive filesystems, as most file transfer mechanisms (e.g.
  1418. X            zmodem, kermit, zoo archives) will be compatible with this.
  1419. XCTRLZ_CHECK If this symbol is defined, special-case code is compiled in
  1420. X            that will more reliably detect when a file is binary, even
  1421. X            if control Z occurs early in a file causing the C runtime
  1422. X            library to falsely assume end-of-file.
  1423. X
  1424. X                                     -- Rahul Dhesi
  1425. X                                        1989/07/07
  1426. X                                        UUCP:      iuvax!bsu-cs!dhesi
  1427. X                                        Internet:  dhesi@bsu-cs.bsu.edu
  1428. X*/
  1429. X
  1430. X#ifdef TURBOC
  1431. X# define GENTAB
  1432. X# define WILDCARD
  1433. X# define ANSIPROTO
  1434. X# define STDINCLUDE
  1435. X# define BRKTST
  1436. X# define NOCASE
  1437. X# define STRNICMP    strnicmp
  1438. X# include <ctype.h>
  1439. X# define LOWERIT tolower
  1440. X# define CTRLZ_CHECK
  1441. X#endif /* TURBOC */
  1442. X
  1443. X/* Microsoft C 5.1 -- use supplied "makefile.msc" makefile -- not tested */
  1444. X#ifdef MSC51
  1445. X# define WILDCARD
  1446. X# define ANSIPROTO
  1447. X# define BRKTST
  1448. X/* # define BUG1 or BUG2 if necessary -- not tested */
  1449. X# define NOCASE
  1450. X# define STRNICMP    strnicmp
  1451. X  int strnicmp (char *, char *, unsigned);
  1452. X# include <ctype.h>
  1453. X# define LOWERIT tolower
  1454. X#endif /* MSC51 */
  1455. X
  1456. X#ifdef SYS_V
  1457. X# define NIXSEEK
  1458. X# define BIN_STDIN_OK
  1459. X#endif /* SYS_V */
  1460. X
  1461. X#ifdef BSD
  1462. X# define NIXSEEK
  1463. X# define USEINDEX
  1464. X# define BIN_STDIN_OK
  1465. X#endif /* BSD */
  1466. X
  1467. X#ifdef VMS
  1468. X# define WILDCARD
  1469. X# define CHECKSEEK
  1470. X# define BUG2
  1471. X# define EXITBUG
  1472. X# define NOCASE
  1473. X#endif /* VMS */
  1474. X
  1475. X#ifdef BUG1
  1476. X# define SEEKFIX  \
  1477. X fgetc(fptr);while(lowerit(fgetc(fptr))!='c')fseek(fptr,-2L,1);fseek(fptr,-1L,1);
  1478. X#endif
  1479. X
  1480. X#ifdef BUG2
  1481. X# define SEEKFIX  \
  1482. X   fseek(fptr,-2L,1);while(fgetc(fptr)!='\n');
  1483. X#endif
  1484. X
  1485. X#ifndef BUG1
  1486. X# ifndef BUG2
  1487. X#  define SEEKFIX
  1488. X# endif
  1489. X#endif
  1490. X
  1491. X/* another thing to try */
  1492. X/* fseek(fptr,-2L,1);while(lowerit(fgetc(fptr))!='C');fseek(fptr,-1L,1); */
  1493. X
  1494. X#ifdef EXITBUG
  1495. X# define exit bugexit
  1496. X#endif
  1497. X
  1498. X#ifndef PARMS
  1499. X# ifdef ANSIPROTO
  1500. X#  define   PARMS(x)    x
  1501. X# else
  1502. X#  define   PARMS(x)    ()
  1503. X# endif
  1504. X#endif
  1505. X
  1506. X/* macro for testing if chars within range -- table look-up */
  1507. X#ifndef BINCHAR
  1508. X# define BINCHAR(c)      bintab[(c) & 0xff]
  1509. X#endif /* BINCHAR */
  1510. SHAR_EOF
  1511. fi
  1512. exit 0
  1513. #    End of shell archive
  1514.  
  1515.  
  1516.