home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 126_01 / raniolib.c < prev    next >
Text File  |  1985-03-10  |  9KB  |  285 lines

  1. /*********************************************************************\
  2. ** .---------------------------------------------------------------. **
  3. ** |                                                               | **
  4. ** |                                                               | **
  5. ** |         Copyright (c) 1981, 1982, 1983 by Eric Martz.         | **
  6. ** |                                                               | **
  7. ** |                                                               | **
  8. ** |       Permission is hereby granted to use this source         | **
  9. ** |       code only for non-profit purposes. Publication of       | **
  10. ** |       all or any part of this source code, as well as         | **
  11. ** |       use for business purposes is forbidden without          | **
  12. ** |       written permission of the author and copyright          | **
  13. ** |       holder:                                                 | **
  14. ** |                                                               | **
  15. ** |                          Eric Martz                           | **
  16. ** |                         POWER  TOOLS                          | **
  17. ** |                    48 Hunter's Hill Circle                    | **
  18. ** |                      Amherst MA 01002 USA                     | **
  19. ** |                                                               | **
  20. ** |                                                               | **
  21. ** `---------------------------------------------------------------' **
  22. \*********************************************************************/
  23.  
  24. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ 
  25.  
  26. /*
  27. #define DEBUG 1
  28. */
  29.  
  30. #include <bdscio.h>
  31. #include "bdscio+.h"
  32. #define BUF 512
  33.  
  34. /*    RANDOM I/O LIBRARY
  35.  
  36.         ranfget(buf,fp,offset,bytecnt)
  37.         ranfput(
  38.         ranrec(buf, rw, fp, record)
  39.         seekend(fp,offset)
  40. */
  41. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ 
  42. /*
  43. These functions must be used in conjunction with fio1.h, fio2.h, fio3.h,
  44. and the renamed BDS library functions described therein.
  45. See also a-open.c, getc.c, putc.c, rawgetc.c supplied on this disk.
  46. */
  47. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ 
  48. ranfget(buf,fp,offset,bytecnt)
  49.  
  50. /* THIS FUNCTION READS FROM THE FILE SPECIFIED BY fp A STRING
  51. BEGINNING AT A RANDOM POSITION IN A FILE. THE OFFSET WHERE
  52. READING BEGINS IS INDICATED BY offset, A POINTER TO A STRUCTURE
  53. WHICH CONTAINS AN UNSIGNED seccnt AND AN INT charcnt (SEE
  54. bdscio+.h). IF bytecnt IS 0, ranfget() STOPS AT THE NEXT NEWLINE
  55. IN THE FILE, WHICH IS NOT PUT INTO BUF. IF bytecnt IS A POSITIVE
  56. INTEGER, ranfget() READS THE SPECIFIED NUMBER OF
  57. BYTES, */
  58.  
  59. /* ASSUMES INPUT FILE IS OPEN */
  60.  
  61.     char *buf;
  62.     FILE *fp;
  63.     struct foffset *offset;
  64.     int bytecnt;
  65.     {
  66.     int check, i;
  67.     seek(fp->_fd,offset->record,0);
  68.     check = read(fp->_fd,fp->_buff,NSECTS);
  69.     if (check == ERROR) {
  70.         printf("DISK READ ERROR (ranfget)\n");
  71.         exit(0);
  72.     }
  73.     fp->_nextp = fp->_buff + offset->byte;
  74.     fp->_nleft = (check * SECSIZ) - offset->byte;
  75.     if (!bytecnt) {
  76.         check = fnnlgetl(buf,fp,BUF);
  77.         if (!check) goto bad;
  78.     }
  79.     else {
  80.         for (i=0; i<=bytecnt-1; i++) {
  81.             check = rawgetc(fp);
  82.  
  83. /* rawgetc() IS EQUIVALENT TO BDSC getc() WHICH PASSES ALL
  84. CHARACTERS THROUGH. I HAVE MODIFIED getc() TO RETURN EOF (-1) WHEN IT GETS
  85. A ^Z (CPMEOF), IN ACCORD WITH STANDARD K&R C. */
  86.  
  87.             if (check EQ EOF) {
  88. bad:
  89.                 fprintf(STDERR,
  90.                     "ATTEMPT TO READ PAST EOF (ranfget)\n");
  91.                 exit(0);
  92.             }
  93.             buf[i] = check;
  94.         }
  95.         /* NO NULL APPENDED TO buf HERE ON ASSUMPTION CALLING PROGRAM
  96.         DOES NOT REQUIRE A NULL TERMINATED STRING */
  97.     }
  98.     return(0);
  99. }
  100. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ 
  101. ranfput(buf, fp, offset, bytecount)
  102.  
  103. /* PUTS bytecount BYTES (OR THE NULL-TERMINATED STRING IN buf IF
  104. bytecount IS 0; NULL IS NOT WRITTEN INTO FILE) INTO FILE
  105. BEGINNING AT THE RANDOM RECORD/BYTE SPECIFIED BY offset.
  106.  
  107. ASSUMES FILE IS OPEN, AND WILL BE CLOSED BY THE CALLING PROGRAM
  108. AFTER ranfput RETURNS.
  109. */
  110.     char *buf;
  111.     FILE *fp;
  112.     struct foffset *offset;
  113.     int bytecount;
  114.     {
  115.     char recbuf[129];
  116.     int i, recpos, atrec;
  117.  
  118. #ifdef DEBUG
  119. printf("RANFPUT bytes %d:\n",bytecount);
  120. for (i=0;i<=bytecount-1;i++)dispchar(buf[i]);
  121. printf("\n");
  122. #endif
  123.  
  124.     atrec = offset->record;
  125.     ranrec(recbuf,'r',fp,atrec); /* read current record */
  126.  
  127. #ifdef DEBUG
  128. printf("OLD RECORD FROM FILE:\n",bytecount);
  129. for (i=0;i<RECSIZ;i++)dispchar(recbuf[i]);
  130. printf("\n");
  131. #endif
  132.  
  133.     recpos = offset->byte;
  134.     if (bytecount) {
  135.         for (i=0; i<bytecount; i++, recpos++) {
  136.             if (recpos EQ 128) { /* this byte is first in next record */
  137.                 ranrec(recbuf,'w',fp,atrec);
  138.                 ranrec(recbuf,'r',fp,++atrec);
  139.                 recpos = 0;
  140.             }
  141.             recbuf[recpos] = buf[i];
  142.         }
  143.     }
  144.  
  145.  
  146.     else {
  147.         i = 0;
  148.         while (buf[i]) {
  149.             if (recpos EQ 128) { /* this byte is first in next record */
  150.                 ranrec(recbuf,'w',fp,atrec);
  151.                 ranrec(recbuf,'r',fp,++atrec);
  152.                 recpos = 0;
  153.             }
  154.             recbuf[recpos] = buf[i++];
  155.             recpos++;
  156.         }
  157.     }
  158.     ranrec(recbuf,'w',fp,atrec); /* flush final record */
  159. }
  160. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ 
  161. ranrec(buf, rw, fp, record)
  162.  
  163. /* READS OR WRITES A RANDOMLY POSITIONED RECORD (128 BYTES
  164. REGARDLESS OF DISK FORMAT) USING CP/M 2.2 BDOS CALLS.
  165.  
  166. rw MUST BE 'r' OR 'w'; NO ERROR CHECKING IS DONE. FILE MUST BE
  167. OPEN BEFORE CALL AND MUST BE CLOSED AFTER ranrec WRITE CALLS.
  168. */
  169.     char *buf, rw;
  170.     FILE *fp;
  171.     int record;
  172.     {
  173.     int *pi, c;
  174.     char *pfcb; /* POINTER TO CP/M FILE CONTROL BLOCK */
  175.  
  176.     /* SET RANDOM RECORD NUMBER IN FCB */
  177.     pfcb = fcbaddr(fp->_fd);
  178.     pi = 33 + pfcb;
  179.     *pi = record;
  180.  
  181.     /* SET SO-CALLED DMA ADDRESS */
  182.     /* n.b.: if this is done before the above call to fcbaddr the
  183.     function fails -- ?? */
  184.     bdos(26,buf);
  185.  
  186.     if (rw EQ 'r') bdos(33,pfcb); /* READ */
  187.     else bdos(34,pfcb);            /* OR WRITE */
  188.  
  189.     putchar('\0'); /* required to fix a bug in CP/M! */
  190.     
  191.     bdos(26,0x80); /* RESTORE SO-CALLED DMA ADDRESS TO ITS USUAL
  192.                 VALUE*/
  193. }
  194. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ 
  195. seekend(fp,offset)
  196.  
  197. /* THE FILE MUST HAVE BEEN OPENED FOR APPEND (fopen(filename,
  198. "a")) PRIOR TO CALLING seekend(). seekend() POSITIONS THE
  199. POINTERS IN THE FILE BUFFER _buf SO THAT THE NEXT CHARACTER
  200. WRITTEN WILL BE APPENDED TO EXISTING CONTENTS OF THE FILE, I.E.
  201. WILL OVERWRITE THE PREVIOUS ^Z.
  202.  
  203. IN SOME APPLICATIONS, IT IS LATER DESIRED TO READ THE SAME STRING
  204. RANDOMLY FROM THE FILE, SO THE OFFSET IS NEEDED. FOR THIS
  205. PURPOSE, seekend() PROVIDES IN offset (SEE bdscio+.h) THE NEEDED
  206. INFORMATION. ranfget() CAN LATER BE CALLED WITH THIS offset. */
  207.  
  208.  
  209.     FILE *fp;
  210.     struct foffset *offset;
  211.     {
  212.     char *fcb, *fcbaddr(), bdos();
  213.     int i, c, getc(), *pi;
  214.     fcb = fcbaddr(fp->_fd); /* GET POINTER TO FILE CONTROL BLOCK */
  215.  
  216. #ifdef DEBUG
  217. showfcb(fcb);
  218. #endif
  219.  
  220.     bdos(35,fcb); /* INSTALL RECORD COUNT IN FILE CONTROL BLOCK */
  221.  
  222. #ifdef DEBUG
  223. showfcb(fcb);
  224. #endif
  225.  
  226.     if (*(fcb+35) == 1) {
  227.         printf("RECORD COUNT IS 65536;\n");
  228.         printf("TOO LARGE FOR SEEKEND DURING OPEN FOR APPEND\n");
  229.         exit(0);
  230.     }
  231.  
  232.     /* GET COUNT OF FILLED SECTORS WRITTEN = TOTAL SECTORS - 1 */
  233.     pi = fcb+33;
  234.     offset->record = (*pi)-1;
  235.  
  236.     /* SEEK TO BEGINNING OF LAST SECTOR */
  237.     seek(fp->_fd,offset->record,0);
  238.  
  239.     /* GET COUNT OF CHARACTERS IN LAST SECTOR BY LOOKING FOR CTRL-Z */
  240.     fp->_nleft = 0; /* forces reading of new sector with getc() */
  241.     for (i=1; i <= (SECSIZ) && ((c=getc(fp)) != EOF); i++);
  242.  
  243.     /* IN MY LIBRARY, getc() HAS BEEN MODIFIED TO RETURN EOF WHEN A CPMEOF
  244.     (^Z) IS READ, SO AS TO BE CONSISTENT WITH K&R C */
  245.  
  246.     if (c == EOF) {
  247.         ungetc(CPMEOF,fp); /* NOT c ! ALSO, SINCE THIS ASSIGNS CPMEOF
  248.                         TO *_nextp, GETC MUST INCREMENT _nextp
  249.                         EVEN ON EOF! */
  250.         i -= 1;
  251.     }
  252.     offset->byte = i;
  253.  
  254.     /* ABOVE CALL TO getc() READS ONLY ONE SECTOR AND SETS *_nleft=128--;
  255.     SINCE A BUFFER FOR WRITING ALWAYS HAS 1024 AVAILABLE (AND THIS IS
  256.     ASSUMED BY fflush()) WE NEXT CORRECT NLEFT TO INDICATE TRUE ROOM
  257.     REMAINING IN THE BUFFER */
  258.     fp->_nleft += (NSECTS - 1) * SECSIZ;
  259.  
  260.     /* SEEK AGAIN SO THAT THE NEXT WRITE (BY THE PROGRAM WHICH CALLED
  261.     seekend() WILL REWRITE THE PRESENT LAST SECTOR */
  262.     seek(fp->_fd,offset->record,0);
  263.  
  264. #ifdef DEBUG
  265. printf("fp=%u, offset=%u, record=%u, byte=%d\n",
  266. fp, offset, offset->record, offset->byte);
  267. #endif
  268. }
  269. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ 
  270. /* END OF RANDOM I/O LIBRARY */
  271. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ 
  272. checkbig(m,s)
  273. /* ROUTINE TO WRITE TO STDERR STRINGS TOO BIG FOR fprintf() */
  274.     char *m, *s;
  275.     {
  276.     /* m IS FOR A MESSAGE */
  277.     while (*m) putc(*m++,STDERR);
  278.     if (*s) {
  279.         putc('<',STDERR);
  280.         while (*s) putc(*s++,STDERR);
  281.         if (*(s-1) NE NEWLINE)
  282.             fputs(">\n",STDERR);
  283.     }
  284. }
  285.  ABOV