home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 3 Comm / 03-Comm.zip / CKPM5X_S.ZIP / CKUMYR.C < prev    next >
C/C++ Source or Header  |  1990-02-26  |  8KB  |  204 lines

  1. /* myread.c by Kristoffer Eriksson, ske@pkmab.se, 21 Feb 1990. */
  2.  
  3. #ifdef MYREAD
  4. /* Private buffer for myread() and it's companions. Not for use by anything
  5.  * else. ttflui() is allowed to reset them to initial values. ttchk() is
  6.  * allowed to read my_count.
  7.  *
  8.  * my_item is an index into mybuf[]. Increment it *before* reading mybuf[].
  9.  *
  10.  * A global parity mask variable could be useful too. We could use it to
  11.  * let myread() strip the parity on it's own, in stead of stripping sign
  12.  * bits as it does now.
  13.  */
  14.  
  15. static CHAR mybuf[256];            /* Buffer, including push back */
  16. static int my_count = 0;        /* Number of chars still in mybuf */
  17. static int my_item = -1;        /* Last index read from mybuf[] */
  18.  
  19.  
  20. /* myread() -- Efficient read of one character from communications line.
  21.  *
  22.  * Uses a private buffer to minimize the number of expensive read() system
  23.  * calls. Essentially performs the equivalent of read() of 1 character, which
  24.  * is then returned. By reading all available input from the system buffers
  25.  * to the private buffer in one chunk, and then working from this buffer, the
  26.  * number of system calls is reduced in any case where more than one character
  27.  * arrives during the processing of the previous chunk, for instance high
  28.  * baud rates or network type connections where input arrives in packets.
  29.  * If the time needed for a read() system call approaches the time for more
  30.  * than one character to arrive, then this mechanism automatically compensates
  31.  * for that by performing bigger read()s less frequently. If the system load
  32.  * is high, the same mechanism compensates for that too.
  33.  *
  34.  * myread() is a macro that returns the next character from the buffer. If the
  35.  * buffer is empty, mygetbuf() is called. See mygetbuf() for possible error
  36.  * returns.
  37.  *
  38.  * This should be efficient enough for any one-character-at-a-time loops.
  39.  * For even better efficiency you might use memcpy()/bcopy() or such between
  40.  * buffers (since they are often better optimized for copying), but it may not
  41.  * be worth it if you have to take an extra pass over the buffer to strip
  42.  * parity and check for CTRL-C anyway.
  43.  *
  44.  * Note that if you have been using myread() from another program module, you
  45.  * may have some trouble accessing this macro version and the private variables
  46.  * it uses. In that case, just add a function in this module, that invokes the
  47.  * macro.
  48.  */
  49. #define myread()  (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
  50.  
  51.  
  52. /* mygetbuf() -- Fill buffer for myread() and return first character.
  53.  *
  54.  * This function is what myread() uses when it can't get the next character
  55.  * directly from it's buffer. Firstly, it calls a system dependant myfillbuf()
  56.  * to read at least one new character into the buffer, and then it returns
  57.  * the first character just as myread() would have done. This function also
  58.  * is responsible for all error conditions that myread() can indicate.
  59.  *
  60.  * Returns: When OK => a positive character.
  61.  *        When EOF or error => -2.
  62.  *
  63.  * Older myread()s additionally returned -1 to indicate that there was nothing
  64.  * to read, upon which the caller would call myread() again until it got
  65.  * something. The new myread()/mygetbuf() always gets something. Any program
  66.  * that actually depends on the old behaviour will break.
  67.  *
  68.  * Also sets errno to 9999 on EOF for compatibility with the old myread().
  69.  * When ckucon is cleaned up to not depend on that, just remove this action
  70.  * from mygetbuf().
  71.  *
  72.  * You could have mygetbuf() return different codes for EOF and other errors,
  73.  * but kermit has currently no use for that. Most programs would just finish
  74.  * up in both cases anyway.
  75.  *
  76.  * The debug() call maybe should be removed for optimum performance.
  77.  */
  78. mygetbuf() {
  79.     my_count = myfillbuf();
  80.     debug(F101, "myfillbuf read", "", my_count);
  81.     if (my_count <= 0) {
  82.         if (my_count == 0)
  83.             errno = 9999;
  84.         return -2;
  85.     }
  86.     --my_count;
  87.     return(255 & (int)mybuf[my_item = 0]);
  88. }
  89.  
  90.  
  91. /* Specification: Push back up to one character onto myread()'s queue.
  92.  *
  93.  * This implementation: Push back characters into mybuf. At least one character
  94.  * must have been read through myread() before myunrd() may be used. After
  95.  * EOF or read error, again, myunrd() can not be used. Sometimes more than
  96.  * one character can be pushed back, but only one character is guaranteed.
  97.  * Since a previous myread() must have read it's character out of mybuf[],
  98.  * that guarantees that there is space for at least one character. If push
  99.  * back was really needed after EOF, a small addition could provide that.
  100.  *
  101.  * myunrd() is currently not called from anywhere inside kermit...
  102.  */
  103. myunrd(ch) CHAR ch; {
  104.     if (my_item >= 0) {
  105.         mybuf[my_item--] = ch;
  106.         ++my_count;
  107.     }
  108. }
  109.  
  110. /* myfillbuf(): System dependant read() into mybuf[], as many chars as possible.
  111.  *
  112.  * Returns: OK => number of characters read, always more than zero.
  113.  *          EOF => 0
  114.  *          Error => -1.
  115.  *
  116.  * If there is input available in the system's buffers, all of it should be
  117.  * read inte mybuf[] and the function return immediately. If no input is
  118.  * available, it should wait for a character to arrive, and return with that
  119.  * one in mybuf[] as soon as possible. It may wait somewhat past the first
  120.  * character, but be aware that any such delay lengthens the packet turnaround
  121.  * time during kermit file transfers. Should never return with zero characters
  122.  * unless EOF or irrecoverable read error.
  123.  *
  124.  * Correct functioning depends on the correct tty parameters being used.
  125.  * Better control of current parameters is required than may have been the
  126.  * case in kermit releases. For instance, O_NDELAY (or equivalent) can no
  127.  * longer be sometimes off and sometimes on like it used to, unless a special
  128.  * myfillbuf() is written to handle that. Otherwise the ordinary myfillbuf()s
  129.  * may think they have come to EOF.
  130.  *
  131.  * If your system has a facility to direclty perform the functioning of
  132.  * myfillbuf(), then use it. If the system can tell you have many characters
  133.  * are available in it's buffers, then read that amount (but not less than 1).
  134.  * If the system can return a special indication when you try to read without
  135.  * anything to read, while allowing you to read all there is when there is
  136.  * something, you may loop until there is something to read, but probably that
  137.  * is not good for the system load.
  138.  */
  139.  
  140. #ifdef UXIII
  141.     /* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
  142.      * and CLOCAL set any way you like. This way, read() will do exactly
  143.      * what is required by myfillbuf(): If there is data in the buffers
  144.      * of the O.S., all available data is read into mybuf, up to the size
  145.      * of mybuf. If there is none, the first character to arrive is
  146.      * awaited and returned.
  147.      */
  148. myfillbuf() {
  149.     return read(ttyfd, mybuf, sizeof(mybuf));
  150. }
  151.  
  152. #else /* UXIII */
  153.  
  154.  
  155. #ifdef aegis
  156.     /* This is quoted from the old myread(). The semantics seem to be
  157.      * alright, but maybe errno would not need to be set even when
  158.      * there is no error? I don't know aegis.
  159.      */
  160. myfillbuf() {
  161.     int count;
  162.  
  163.     count = ios_$get((short)ttyfd, ios_$cond_opt, mybuf, 256L, st);
  164.     errno = EIO;
  165.     if (st.all == ios_$get_conditional_failed) /* get at least one */
  166.         inbufc = ios_$get((short)ttyfd, 0, mybuf, 1L, st);
  167.     if (st.all == ios_$end_of_file)
  168.         return(0);
  169.     else if (st.all != status_$ok) {
  170.         errno = EIO;
  171.         return(-1);
  172.     }
  173.     return(count);
  174. }
  175. #else /* aegis */
  176.  
  177.  
  178. #ifdef FIONREAD
  179.     /* This is for systems with FIONREAD. FIONREAD returns the number
  180.      * of characters available for reading. If none are available, wait
  181.      * until something arrives, otherwise return all there is.
  182.      */
  183. myfillbuf() {
  184.     long avail;
  185.  
  186.     if (ioctl(ttyfd, FIONREAD, &avail) < 0  ||  avail == 0)
  187.         avail = 1;
  188.     return read(ttyfd, mybuf, avail);
  189. }
  190.  
  191. #else /* FIONREAD */
  192. /* Add other systems here, between #ifdef and #else, e.g. NETCON. */
  193.  
  194.     /* When there is no other possibility, read 1 character at a time. */
  195. myfillbuf() {
  196.     return read(ttyfd, mybuf, 1);
  197. }
  198.  
  199. #endif /* !FIONREAD */
  200. #endif /* !aegis */
  201. #endif /* !UXIII */
  202.  
  203. #endif /* MYREAD */
  204.