home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 163_01 / baseio1.c < prev    next >
Text File  |  1988-01-31  |  16KB  |  551 lines

  1. /*
  2. ** include baseio1.c -- base I/O routines part 1
  3. **
  4. ** simulate UNIX I/O interfaces
  5. **
  6. ** assumes that "errno.h" is included
  7. ** assumes that "sgtty.h" is included
  8. ** assumes that "doscall.h" is included
  9. ** assumes that "doscall.c" is included
  10. ** assumes that "heap.c" is included
  11. ** assumes that NUMFILES is defined
  12. */
  13.  
  14.  
  15. /*
  16. ** file descriptor (handle) array
  17. */
  18.  
  19. static int             /* would char *_filedes[] if array of * supported */
  20.   _filedes[NUMFILES];
  21.  
  22.  
  23. /*
  24. ** keyboard buffer
  25. */
  26.  
  27. static char
  28.   kbdbuf[255];
  29.  
  30.  
  31. /*
  32. ** base I/O initialization
  33. */
  34.  
  35. static _baseinit() {
  36.   int i;
  37.   i = 0;
  38.   while(i < NUMFILES) {
  39.     _filedes[i] = 0; /* clear pointer to DOS FCB in file descriptor array */
  40.     ++i;
  41.     }
  42.   kbdbuf[0]=kbdbuf[1]=0;
  43.   errno = 0;
  44.   }
  45.  
  46.  
  47. /*
  48. ** base I/O clean-up
  49. */
  50.  
  51. static _baseclnup() {
  52.   int i;
  53.   char *fcb;
  54.   i = 0;
  55.   while(i < NUMFILES) {
  56.     fcb = _filedes[i]; /* get address of DOS FCB */
  57.     if(*fcb != 0) _close(i); /* if file is open, close it */
  58.     ++i;
  59.     }
  60.   }
  61.  
  62.  
  63. /*
  64. ** open a file
  65. */
  66.  
  67. _open(name, mode) char *name; int mode; {
  68.  
  69.   /*
  70.   ** name -- path name
  71.   ** mode -- 0 - read, 1 - write, 2 - read/write
  72.   ** returns file descriptor
  73.   ** note:  always positions file to offset zero
  74.   */
  75.  
  76.   int filedes, mask;
  77.   char *fcb;
  78.   if((mode < 0) | (mode > 2)) {
  79.     errno = EINVAL;   /* invalid argument */
  80.     return -1;
  81.     }
  82.   filedes = _getfcb(name);     /* allocate & initialize DOS FCB */
  83.   if(filedes < 0) {
  84.     errno = EMFILE;   /* too many open files */
  85.     return -1;
  86.     }
  87.   fcb = _filedes[filedes];     /* get address of DOS FCB */
  88.   fcb[FCB_MODE] = mode;        /* save read/write mode */
  89.   if(mode==0)      mask=2;     /* read */
  90.   else if(mode==1) mask=1;     /* write */
  91.   else             mask=3;     /* read/write */
  92.   if((mask&fcb[FCB_FLAG])!=mask) { /* if wrong device type */
  93.     _freefcb(filedes); /* free the FCB we won't be using */
  94.     errno = ENODEV;
  95.     return -1;
  96.     }
  97.   if((fcb[FCB_FLAG]&255)==255) { /* if disk file */
  98.     if(_dosfcall(F_OPEN, fcb) == 0) { /* DOS open */
  99.       fcb[FCB_LRECL] = 1;        /* set "record length" to 1 */
  100.       fcb[FCB_LRECL+1] = 0;
  101.       fcb[FCB_FLGS] = 128 + 64 + 16;
  102.       fcb[FCB_FLGS+1] = 0;
  103.       return filedes;
  104.       }
  105.     else {
  106.       _freefcb(filedes); /* free the FCB we won't be using */
  107.       errno = ENOENT;   /* no such file */
  108.       return -1;
  109.       }
  110.     }
  111.   else {                       /* not a disk file */
  112.     if(fcb[FCB_FLAG] & 192) { /* if keyboard or screen */
  113.       fcb[FCB_FLGS] = 128 + 64 + 16 + 8;
  114.       fcb[FCB_FLGS+1] = 0;
  115.       }
  116.     else if(fcb[FCB_FLAG] & 32) { /* if printer */
  117.       fcb[FCB_FLGS] = 16;
  118.       fcb[FCB_FLGS+1] = 0;
  119.       }
  120.     else if(fcb[FCB_FLAG] & 16) { /* if async */
  121.       fcb[FCB_FLGS] = 128 + 64 + 32;
  122.       fcb[FCB_FLGS+1] = 0;
  123.       }
  124.     return filedes;
  125.     }
  126.   }
  127.  
  128.  
  129. /*
  130. ** create and open a file (or reopen if existing)
  131. */
  132.  
  133. _creat(name, mode) char *name; int mode; {
  134.  
  135.   /*
  136.   ** name -- path name
  137.   ** mode -- file attributes -- 0 - normal, 2 - system, 4 hidden
  138.   ** returns file descriptor
  139.   ** note:  always positions file to offset zero
  140.   ** note:  file is always opened for write
  141.   */
  142.  
  143.   int filedes;
  144.   char *fcb;
  145.   if((mode < 0) | (mode > 2)) {
  146.     errno = EINVAL;   /* invalid argument */
  147.     return -1;
  148.     }
  149.   filedes = _getfcb(name);     /* allocate & initialize DOS FCB */
  150.   if(filedes < 0) {
  151.     errno = EMFILE;   /* too many open files */
  152.     return -1;
  153.     }
  154.   fcb = _filedes[filedes];     /* get address of DOS FCB */
  155.   if((fcb[FCB_FLAG]&255)!=255) { /* if not a disk file */
  156.     _freefcb(filedes); /* free the FCB we won't be using */
  157.     return _open(name, 1);     /* use normal open for write */
  158.     }
  159.   fcb[FCB_ATTR] = mode;        /* set file attributes */
  160.   if(_dosfcall(F_CREATE, fcb) == 0) {       /* DOS create & open */
  161.     fcb[FCB_LRECL] = 1;        /* set "record length" to 1 */
  162.     fcb[FCB_LRECL+1] = 0;
  163.     fcb[FCB_FLGS] = 128 + 64 + 16;
  164.     fcb[FCB_FLGS+1] = 0;
  165.     fcb[FCB_MODE] = 1;         /* write only */
  166.     return filedes;
  167.     }
  168.   else {
  169.     _freefcb(filedes); /* free the FCB we won't be using */
  170.     errno = ENOSPC;   /* no space in disk directory */
  171.     return -1;
  172.     }
  173.   }
  174.  
  175.  
  176. /*
  177. ** close a file
  178. */
  179.  
  180. _close(filedes) int filedes; {
  181.   char *fcb;
  182.   int *ibuf;
  183.   if((filedes >= NUMFILES) | (filedes < 0)) {
  184.     errno = EINVAL;   /* invalid argument */
  185.     return -1;
  186.     }
  187.   fcb = _filedes[filedes];     /* get address of DOS FCB */
  188.   if(fcb[FCB_FLAG] == 0) {
  189.     errno = EBADF;    /* bad file number -- file not open */
  190.     return -1;
  191.     }
  192.   if((fcb[FCB_FLAG]&255) == 255) { /* if file is standard disk file */
  193.     /* if file is DOS format output (only) file, add the ctl-Z (end-of-file) */
  194.     if((fcb[FCB_FLGS]&16) && (fcb[FCB_MODE]&1)) {
  195.       _seek(filedes, 0, 5); /* find end of file */
  196.       _write(filedes, "\32", 1); /* add ctl-Z */
  197.       _iflush(fcb); /* if there is an intermediate buf, flush (ignore errors) */
  198.       ibuf = &fcb[FCB_IBUF];
  199.       if(*ibuf) free(*ibuf); /* free intermediate buffer (if any) */
  200.       }
  201.     if(_dosfcall(F_CLOSE, fcb) == 0) { /* DOS close */
  202.       _freefcb(filedes); /* free the DOS FCB */
  203.       return 0;
  204.       }
  205.     else {
  206.       errno = ENXIO; /* wrong disk may be mounted */
  207.       return -1;
  208.       }
  209.     }
  210.   else {
  211.     if(fcb[FCB_FLAG] & 32) { /* if printer */
  212.       _prnout('\f');
  213.       }
  214.     _freefcb(filedes); /* free the DOS FCB */
  215.     return 0;
  216.     }
  217.   }
  218.  
  219.  
  220. /*
  221. ** read from a file
  222. */
  223.  
  224. _read(filedes, buffer, nbytes) int filedes, nbytes; char *buffer; {
  225.   char *fcb, ch, mode, *source, *dest;
  226.   int rcode, rbytes, count;
  227.   if((filedes >= NUMFILES) | (filedes < 0)) {
  228.     errno = EINVAL;   /* invalid argument */
  229.     return -1;
  230.     }
  231.   if(nbytes <= 0) {
  232.     errno = EINVAL;   /* invalid argument */
  233.     return -1;
  234.     }
  235.   fcb = _filedes[filedes];     /* get address of DOS FCB */
  236.   if(fcb[FCB_FLAG] == 0) {
  237.     errno = EBADF;    /* bad file number -- file not open */
  238.     return -1;
  239.     }
  240.   if(fcb[FCB_MODE] & 128) {  /* if end-of-file exists */
  241.     return 0;        /* report end-of-file */
  242.     }
  243.   if((fcb[FCB_FLAG]&255) == 255) { /* if file is standard disk file */
  244.     if(fcb[FCB_MODE] & 1) {    /* if not read-mode file */
  245.       errno = EBADF;  /* bad file number -- file not read-mode */
  246.       return -1;
  247.       }
  248.     _dosfcall(F_SETDTA, buffer);    /* set disk transfer area */
  249.     rcode = _dosfxcall(F_READ, fcb, nbytes, &rbytes); /* read the file */
  250.     if(rcode==2) {
  251.       errno = EFAULT; /* bad address range (segment wrap) */
  252.       return -1;
  253.       }
  254.     if((rcode==1) | (rcode==3)) {       /* if end-of-file */
  255.       fcb[FCB_MODE] |= 128;    /* remember end-of-file for next call */
  256.       }
  257.     if(fcb[FCB_FLGS] & 16) { /* if CR-LF conversion */
  258.       source = buffer;
  259.       dest = buffer;
  260.       count = rbytes;
  261.       rbytes = 0;
  262.       mode = fcb[FCB_MODE];
  263.       while(count--) {
  264.         if(*source == '\32') { /* check for ctl-Z (EOF) */
  265.           fcb[FCB_MODE] |= 128; /* set EOF flag */
  266.           break;
  267.           }
  268.         else if(*source == '\r') { /* check for CR */
  269.           if(mode & 32) { /* if prior char was LF */
  270.             mode &= ~32; /* ignore the CR */
  271.             }
  272.           else { /* prior char was not LF */
  273.             *dest++ = '\n'; /* convert CR to LF */
  274.             ++rbytes;
  275.             mode |= 64; /* ignore possible following LF */
  276.             }
  277.           }
  278.         else if(*source == '\n') { /* check for LF */
  279.           if(mode & 64) { /* if prior char was CR */
  280.             mode &= ~64; /* ignore the LF */
  281.             }
  282.           else { /* prior char was not CR */
  283.             *dest++ = '\n'; /* "convert" LF to LF */
  284.             ++rbytes;
  285.             mode |= 32; /* ignore possible following CR */
  286.             }
  287.           }
  288.         else{ /* none of the above */
  289.           *dest++ = *source; /* copy the character */
  290.           ++rbytes;
  291.           mode &= ~(64 + 32); /* turn off CR and LF flags */
  292.           }
  293.         ++source; /* next source char */
  294.         } /* end of loop */
  295.       fcb[FCB_MODE] = mode; /* save CR & LF flags */
  296.       }
  297.     return rbytes;
  298.     }
  299.   else {
  300.     if(fcb[FCB_FLAG] & 128) { /* if keyboard */
  301.       dest = buffer;
  302.       rbytes = 0;
  303.       if(fcb[FCB_FLGS] & 34) { /* if raw or half-baked */
  304.         while(rbytes < nbytes) {
  305.           ch = _kbdinc(fcb); /* read a character */
  306.           if(fcb[FCB_FLGS] & 4) { /* if fold upper to lower case */
  307.             if((ch >= 'A') & (ch <= 'Z')) ch -= ('A' - 'a');
  308.             }
  309.           if(ch=='\r') {
  310.             if(fcb[FCB_FLGS] & 16) _scrnout('\n');
  311.             ch = '\n';
  312.             }
  313.           *dest++ = ch;
  314.           ++rbytes;
  315.           if(ch=='\n') break;
  316.           }
  317.         }
  318.       else { /* read keyboard a line at a time */
  319.         if(kbdbuf[0]==kbdbuf[1]) { /* if buffer is empty, fill it */
  320.           kbdbuf[0] = 255; /* size of buffer */
  321.           _dosfcall(F_BUFKBD, kbdbuf); /* read a line from kbd */
  322.           kbdbuf[0] = 0; /* number of characters read from buffer */
  323.           kbdbuf[2+(kbdbuf[1]&255)] = '\n'; /* replace CR with LF */
  324.           kbdbuf[1] += 1; /* make character count include LF */
  325.           if(fcb[FCB_FLGS] & 16) _scrnout('\n');
  326.           }
  327.         while(rbytes < nbytes) { /* read characters from buffer until enough */
  328.           ++rbytes;
  329.           if((*dest++ = kbdbuf[2+(kbdbuf[0]++&255)])=='\n') break;
  330.           if(kbdbuf[0]==kbdbuf[1]) break;
  331.           }
  332.         }
  333.       /* check for ctl-Z (EOF) */
  334.       source = buffer;
  335.       count = rbytes;
  336.       rbytes = 0;
  337.       while(count--) {
  338.         if(*source++ == '\32') { /* if ctl-Z found */
  339.           fcb[FCB_MODE] |= 128; /* set EOF flag */
  340.           break;
  341.           }
  342.         ++rbytes;
  343.         }
  344.       }
  345.     else if(fcb[FCB_FLAG] & 16) { /* if async */
  346.       ; /* read characters from the async port */
  347.       }
  348.     if(fcb[FCB_FLGS] & 4) { /* if UPPER -> lower conversion */
  349.       source = buffer;
  350.       count = rbytes;
  351.       while(count--) {
  352.         if((*source >= 'A') & (*source <= 'Z')) {
  353.           *source += ('a' - 'A');
  354.           }
  355.         ++source;
  356.         }
  357.       }
  358.     return rbytes;
  359.     }
  360.   }
  361.  
  362.  
  363. /*
  364. ** read a character from the keyboard
  365. **
  366. ** reads with/without CTRL-BREAK check
  367. ** and with/without echo
  368. */
  369.  
  370. static char
  371.   AL2;
  372. static _kbdinc(fcb) char fcb[]; {
  373.   char ch;
  374.   if(fcb[FCB_FLGS] & 32) { /* if raw mode */
  375.     if(fcb[FCB_FLGS] & 8) { /* if echo */
  376. #asm
  377.        MOV AH,6        ; direct console I/O
  378.        MOV DL,0FFH     ; we are doing input
  379.        INT 021H        ; call DOS
  380.        JZ $-2          ; loop until character received
  381.        MOV QAL2,AL     ; put the character where we can find it
  382. #endasm
  383.       ch = AL2;
  384.       }
  385.     else { /* no echo */
  386.       ch = _dosfcall(F_DIRNOE, 0);  /* direct read with no echo */
  387.       }
  388.     }
  389.   else {       /* half-baked mode */
  390.     if(fcb[FCB_FLGS] & 8) { /* if echo */
  391.       ch = _dosfcall(F_KBDECH, 0);  /* read with echo */
  392.       }
  393.     else { /* no echo */
  394.       ch = _dosfcall(F_KBDNOE, 0);  /* read with no echo */
  395.       }
  396.     }
  397.   return ch;
  398.   }
  399.  
  400.  
  401. /*
  402. ** write to a file
  403. */
  404.  
  405. _write(filedes, buffer, nbytes) int filedes, nbytes; char *buffer; {
  406.   char *fcb, ch, *source;
  407.   int rcode, rbytes, *ibuf, *iptr, *icnt, count;
  408.   if((filedes >= NUMFILES) | (filedes < 0)) {
  409.     errno = EINVAL;   /* invalid argument */
  410.     return -1;
  411.     }
  412.   if(nbytes < 0) { /* zero causes extension/truncation at current position */
  413.     errno = EINVAL;   /* invalid argument */
  414.     return -1;
  415.     }
  416.   fcb = _filedes[filedes];     /* get address of DOS FCB */
  417.   if(fcb[FCB_FLAG] == 0) {
  418.     errno = EBADF;    /* bad file number -- file not open */
  419.     return -1;
  420.     }
  421.   if((fcb[FCB_FLAG]&255) == 255) { /* if file is standard disk file */
  422.     if((fcb[FCB_MODE]&3)==0) {    /* if not write-mode file */
  423.       errno = EBADF;  /* bad file number -- file not write-mode */
  424.       return -1;
  425.       }
  426.     if(fcb[FCB_FLGS] & 16) { /* if CR-LF translation */
  427.       ibuf = &fcb[FCB_IBUF];   /* poor man's cast */
  428.       iptr = &fcb[FCB_IPTR];
  429.       icnt = &fcb[FCB_ICNT];
  430.       if(!*ibuf) { /* if intermediate buffer is not present */
  431.         if(!(*ibuf = *iptr = malloc(_BUFSIZE))) errno = 0;
  432.         *icnt = _BUFSIZE;
  433.         }
  434.       count = nbytes;
  435.       source = buffer;
  436.       rcode = 0;
  437.       while((count--) && !rcode) { /* process buffer into intermediate */
  438.         if(*source == '\n') { /* if char is LF (NL) */
  439.           rcode = _iwrite(fcb, '\r'); /* write a CR */
  440.           if(!rcode) rcode = _iwrite(fcb, '\n'); /* write a LF */
  441.           }
  442.         else { /* char is not LF */
  443.           rcode = _iwrite(fcb, *source); /* copy to intermediate */
  444.           }
  445.         ++source;
  446.         }
  447.       }
  448.     else { /* no CR-LF translation */
  449.       _dosfcall(F_SETDTA, buffer);    /* set disk transfer area */
  450.       rcode = _dosfxcall(F_WRITE, fcb, nbytes, &rbytes); /* write the file */
  451.       }
  452.     if(rcode==1) {
  453.       errno = ENOSPC; /* no room on diskette */
  454.       return -1;
  455.       }
  456.     if(rcode==2) {
  457.       errno = EFAULT; /* bad address range (segment wrap) */
  458.       return -1;
  459.       }
  460.     }
  461.   else {
  462.     rbytes = 0;
  463.     if(fcb[FCB_FLAG] & 64) { /* if screen */
  464.       while(rbytes<nbytes) {
  465.         ch = *buffer++;
  466.         if((ch=='\n') && (fcb[FCB_FLGS]&16)) _scrnout('\r');
  467.         _scrnout(ch);
  468.         ++rbytes;
  469.         }
  470.       }
  471.     else if(fcb[FCB_FLAG] & 32) { /* if printer */
  472.       while(rbytes<nbytes) {
  473.         ch = *buffer++;
  474.         if((ch=='\n') && (fcb[FCB_FLGS]&16)) _prnout('\r');
  475.         _prnout(ch);
  476.         ++rbytes;
  477.         }
  478.       }
  479.     else if(fcb[FCB_FLAG] & 16) { /* if async */
  480.       ; /* output line to the async port */
  481.       }
  482.     }
  483.   return nbytes;
  484.   }
  485.  
  486.  
  487. /*
  488. ** write a character to the intermediate buffer
  489. */
  490.  
  491. static _iwrite(fcb, ch) char *fcb, ch; {
  492.   int *ibuf, *iptr, *icnt, rcode, dummy;
  493.   ibuf = &fcb[FCB_IBUF];   /* poor man's cast */
  494.   iptr = &fcb[FCB_IPTR];
  495.   icnt = &fcb[FCB_ICNT];
  496.   if(*ibuf) { /* if intermediate buffer is present */
  497.     *(*iptr)++ = ch; /* store the character there */
  498.     if(--(*icnt)) { /* if buffer is full */
  499.       return _iflush(fcb); /* write the buffer */
  500.       }
  501.     else { /* the buffer still has space */
  502.       return 0;
  503.       }
  504.     }
  505.   else { /* no intermediate buffer */
  506.     _dosfcall(F_SETDTA, &ch); /* buffer = source char */
  507.     return _dosfxcall(F_WRITE, fcb, 1, &dummy); /* write one char at a time */
  508.     }
  509.   }
  510.  
  511.  
  512. /*
  513. ** flush the intermediate buffer
  514. */
  515.  
  516. static _iflush(fcb) char *fcb {
  517. int *ibuf, *iptr, *icnt, rcode, dummy;
  518.   ibuf = &fcb[FCB_IBUF];   /* poor man's cast */
  519.   iptr = &fcb[FCB_IPTR];
  520.   icnt = &fcb[FCB_ICNT];
  521.   if(*ibuf) { /* if intermediate buffer is present */
  522.     _dosfcall(F_SETDTA, *ibuf); /* buffer = intermediate bufer */
  523.     if(*iptr != *ibuf) /* CON can't handle zero length */
  524.       rcode = _dosfxcall(F_WRITE, fcb, (*iptr-*ibuf), &dummy);
  525.     *iptr = *ibuf; /* reset next char pointer */
  526.     *icnt = _BUFSIZE; /* reset # of chars remaining */
  527.     return rcode;
  528.     }
  529.   else {
  530.     return 0;
  531.     }
  532.   }
  533.  
  534.  
  535. /*
  536. * write a character to the screen
  537. */
  538.  
  539. static _scrnout(ch) char ch; {
  540.   _dosfcall(F_DSPOUT, ch);
  541.   }
  542.  
  543. /*
  544. * write a character to the pointer
  545. */
  546.  
  547. static _prnout(ch) char ch; {
  548.   _dosfcall(F_PRNOUT, ch);
  549.   }
  550.  
  551.