home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-A.06 / NETKIT-A / NetKit-A-0.06 / ytalk-3.0.1 / fd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-27  |  5.9 KB  |  286 lines

  1. /* fd.c */
  2.  
  3. /*               NOTICE
  4.  *
  5.  * Copyright (c) 1990,1992,1993 Britt Yenne.  All rights reserved.
  6.  * 
  7.  * This software is provided AS-IS.  The author gives no warranty,
  8.  * real or assumed, and takes no responsibility whatsoever for any 
  9.  * use or misuse of this software, or any damage created by its use
  10.  * or misuse.
  11.  * 
  12.  * This software may be freely copied and distributed provided that
  13.  * no part of this NOTICE is deleted or edited in any manner.
  14.  * 
  15.  */
  16.  
  17. /* Mail comments or questions to ytalk@austin.eds.com */
  18.  
  19. #include "header.h"
  20. #include "menu.h"
  21. #include <sys/time.h>
  22. #include <signal.h>
  23. #ifdef _AIX
  24. # include <sys/select.h>
  25. #endif
  26.  
  27. static fd_set fdset;        /* descriptors to select on */
  28. static fd_set fdtmp;        /* descriptors to select on (input_loop) */
  29. static fd_set sel;        /* currently readable descriptors */
  30. static int high_fd = 0;        /* highest fd so far */
  31. int input_flag = 0;        /* flag: waiting for user input */
  32. int user_winch = 0;        /* flag: user window/status changed */
  33.  
  34. struct fd_func {
  35.     void (*func)();            /* user function */
  36. };
  37. static struct fd_func tag[MAX_FILES];    /* one function per file descriptor */
  38.  
  39. /* Initialize fdset data.
  40.  */
  41. void
  42. init_fd()
  43. {
  44.     FD_ZERO(&fdset);
  45. }
  46.  
  47. /* Add a file descriptor to the current checklist.  The supplied
  48.  * function will be called whenever the file descriptor has input
  49.  * waiting.
  50.  */
  51. void
  52. add_fd(fd, user_func)
  53.   int fd;
  54.   void (*user_func)();
  55. {
  56.     if(fd < 0 || fd >= MAX_FILES)
  57.     {
  58.     show_error("add_fd: descriptor out of range");
  59.     return;
  60.     }
  61.     FD_SET(fd, &fdset);
  62.     tag[fd].func = user_func;
  63.     if(fd >= high_fd)
  64.     high_fd = fd + 1;
  65. }
  66.  
  67. /* Remove a file descriptor from the checklist.
  68.  */
  69. void
  70. remove_fd(fd)
  71.   int fd;
  72. {
  73.     if(fd < 0 || fd >= MAX_FILES)
  74.     {
  75.     show_error("remove_fd: descriptor out of range");
  76.     return;
  77.     }
  78.     FD_CLR(fd, &fdset);
  79.     FD_CLR(fd, &fdtmp);
  80.     FD_CLR(fd, &sel);
  81. }
  82.  
  83. /* Read an entire length of data.
  84.  * Returns 0 on success, -1 on error.
  85.  */
  86. int
  87. full_read(fd, buf, len)
  88.   int fd;
  89.   register char *buf;
  90.   register int len;
  91. {
  92.     register int rc;
  93.  
  94.     while(len > 0)
  95.     {
  96.     if((rc = read(fd, buf, len)) <= 0)
  97.         return -1;
  98.     buf += rc;
  99.     len -= rc;
  100.     }
  101.     return 0;
  102. }
  103.  
  104. /* -- MAIN LOOPS -- */
  105.  
  106. static ylong lastping, curtime;
  107.  
  108. void
  109. main_loop()
  110. {
  111.     register int fd, rc;
  112.     struct timeval tv;
  113. #ifndef Y_USE_SIGHOLD
  114.     int mask, old_mask;
  115. #endif
  116.  
  117.     /* Some signals need to be blocked while doing internal
  118.      * processing, else some craziness might occur.
  119.      */
  120.  
  121. #ifndef Y_USE_SIGHOLD
  122.  
  123.     mask = 0;
  124.  
  125. # ifdef SIGWINCH
  126.     mask |= sigmask(SIGWINCH);
  127. # endif
  128.  
  129. #endif
  130.  
  131. #if defined(SIGCHLD)
  132.     signal(SIGCHLD, SIG_IGN);
  133. #elif defined(SIGCLD)
  134.     signal(SIGCLD, SIG_IGN);
  135. #endif
  136.  
  137.     /* For housecleaning to occur every CLEAN_INTERVAL seconds, we make
  138.      * our own little timer system.  SIGALRM is nice; in fact it's so
  139.      * useful that we'll be using it in other parts of YTalk.  Since
  140.      * we therefore can't use it here, we affect the timer manually.
  141.      */
  142.  
  143.     house_clean();
  144.     curtime = lastping = (ylong)time(NULL);
  145.     for(;;)
  146.     {
  147.     /* check if we're done */
  148.  
  149.     if(connect_list == NULL
  150.     && wait_list == NULL
  151.     && menu_ptr == NULL
  152.     && running_process == 0)
  153.         bail(0);
  154.  
  155.     /* select */
  156.  
  157.     sel = fdset;
  158.     if(curtime > lastping + CLEAN_INTERVAL)
  159.         tv.tv_sec = 0;
  160.     else
  161.         tv.tv_sec = (lastping + CLEAN_INTERVAL) - curtime;
  162.     tv.tv_usec = 0;
  163.     if((rc = select(high_fd, &sel, 0, 0, &tv)) < 0)
  164.         if(errno != EINTR)
  165.         show_error("main_loop: select failed");
  166.  
  167.     /* block signals while doing internal processing */
  168.  
  169. #ifdef Y_USE_SIGHOLD
  170. # ifdef SIGWINCH
  171.     sighold(SIGWINCH);
  172. # endif
  173. #else
  174.     old_mask = sigblock(mask);
  175. #endif
  176.  
  177.     /* process file descriptors with input waiting */
  178.  
  179.     if(rc > 0)
  180.         for(fd = 0; fd < high_fd; fd++)
  181.         if(FD_ISSET(fd, &sel))
  182.         {
  183.             errno = 0;
  184.             tag[fd].func(fd);
  185.             if(--rc <= 0)
  186.             break;
  187.         }
  188.  
  189.     /* check timer */
  190.  
  191.     curtime = (ylong)time(NULL);
  192.     if(curtime - lastping >= CLEAN_INTERVAL)
  193.     {
  194.         house_clean();
  195.         lastping = (ylong)time(NULL);
  196.     }
  197.  
  198.     /* re-allow signals */
  199.  
  200. #ifdef Y_USE_SIGHOLD
  201. # ifdef SIGWINCH
  202.     sigrelse(SIGWINCH);
  203. # endif
  204. #else
  205.     sigsetmask(old_mask);
  206. #endif
  207.     if(user_winch)
  208.     {
  209.         /* This is a cute hack that updates a user menu
  210.          * dynamically as information changes.  So I had
  211.          * some free time.  there.
  212.          */
  213.         user_winch = 0;
  214.         update_user_menu();
  215.     }
  216.     }
  217. }
  218.  
  219. /* Input loop.  This loop keeps everything except user input going until
  220.  * input is received from <me>.  This is necessary for answering pressing
  221.  * questions without needing to add a getch_term() function to the terminal
  222.  * definition library.  Hack?  maybe.  Fun, tho.
  223.  */
  224. void
  225. input_loop()
  226. {
  227.     register int fd, rc;
  228.     struct timeval tv;
  229.     static int left_loop;
  230.  
  231.     left_loop = 0;
  232.     fdtmp = fdset;
  233.     while(io_len <= 0)
  234.     {
  235.     /* select */
  236.  
  237.     sel = fdtmp;
  238.     if(curtime > lastping + CLEAN_INTERVAL)
  239.         tv.tv_sec = 0;
  240.     else
  241.         tv.tv_sec = (lastping + CLEAN_INTERVAL) - curtime;
  242.     tv.tv_usec = 0;
  243.     if((rc = select(high_fd, &sel, 0, 0, &tv)) < 0)
  244.         if(errno != EINTR)
  245.         show_error("input_loop: select failed");
  246.  
  247.     /* process file descriptors with input waiting */
  248.  
  249.     if(rc > 0)
  250.         for(fd = 0; fd < high_fd; fd++)
  251.         if(FD_ISSET(fd, &sel))
  252.         {
  253.             /* Here the hack begins.  Any function that takes user
  254.              * input should clear "input_flag" and return.  This
  255.              * tells us to ignore this function for now.  Any
  256.              * function which receives input from <me> should leave
  257.              * my input in io_ptr/io_len.
  258.              */
  259.             errno = 0;
  260.             input_flag = 1;
  261.             tag[fd].func(fd);
  262.             if(left_loop) /* recursive input_loop()s.  argh! */
  263.             return;   /* let my parent function re-call me */
  264.             if(input_flag == 0)
  265.             {
  266.             /* don't check this descriptor anymore */
  267.             FD_CLR(fd, &fdtmp);
  268.             }
  269.             if(--rc <= 0)
  270.             break;
  271.         }
  272.  
  273.     /* check timer */
  274.  
  275.     curtime = (ylong)time(NULL);
  276.     if(curtime - lastping >= CLEAN_INTERVAL)
  277.     {
  278.         input_flag = 1;
  279.         house_clean();
  280.         lastping = (ylong)time(NULL);
  281.     }
  282.     }
  283.     input_flag = 0;
  284.     left_loop = 1;
  285. }
  286.