home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / LiterateA.C < prev    next >
C/C++ Source or Header  |  1998-09-17  |  12KB  |  480 lines

  1. // $Id: LiterateA.C,v 1.29 1998/09/17 13:09:23 zeller Exp $
  2. // Agent interface on a callback basis
  3.  
  4. // Copyright (C) 1995-1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char LiterateAgent_rcsid[] = 
  30.     "$Id: LiterateA.C,v 1.29 1998/09/17 13:09:23 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. #include "config.h"
  37. #include <iostream.h>
  38. #include <sys/types.h>
  39. #include <unistd.h>
  40. #include <errno.h>
  41. #include <stdio.h>        // On Linux, includes _G_config.h
  42. #include <ctype.h>
  43.  
  44. #if HAVE_FCNTL_H
  45. #include <fcntl.h>
  46. #endif
  47.  
  48. #if HAVE_FCNTL && !HAVE_FCNTL_DECL && !defined(fcntl)
  49. extern "C" int fcntl(int fd, int command, ...);
  50. #endif
  51.  
  52. #include "bool.h"
  53. #include "LiterateA.h"
  54. #include "SignalB.h"
  55. #include "ChunkQueue.h"
  56.  
  57. #include <limits.h>
  58.  
  59. #ifndef ARG_MAX
  60. #define ARG_MAX 4096
  61. #endif
  62.  
  63.  
  64. DEFINE_TYPE_INFO_1(LiterateAgent, AsyncAgent)
  65.  
  66. // ---------------------------------------------------------------------------
  67. // TTY blocking
  68. // ---------------------------------------------------------------------------
  69.  
  70. // This package reads data in non-blocking mode, reading only data
  71. // that is currently present.  Unfortunately, this is not a good idea
  72. // for ttys, since if the process is run in the background, it will
  73. // set non-blocking mode for its controlling tty.  Since this mode
  74. // change affects all processes reading from this tty, they will
  75. // detect an EOF on input and (most likely) exit.
  76.  
  77. // Consequently, we provide a special flag, BLOCK_TTY_INPUT.  If
  78. // BLOCK_TTY_INPUT is TRUE, we use blocking mode for TTYs and read
  79. // only one line at a time.  This works fine unless the process
  80. // runs in raw or cbreak mode.  If BLOCK_TTY_INPUT is FALSE, we
  81. // have no special treatment for TTYs.
  82.  
  83. // Determine an appropriate default setting
  84. bool LiterateAgent::default_block_tty_input()
  85. {
  86. #if defined(BLOCK_TTY_INPUT)
  87.     return BLOCK_TTY_INPUT;
  88.  
  89. #elif defined(linux)
  90.     // All Linux variants want BLOCK_TTY_INPUT to be unset:
  91.  
  92.     // * Andi <ak@muc.de> states that Linux with GNU libc 5.3.12 wants
  93.     //   BLOCK_TTY_INPUT to be unset.
  94.     // * Ronald Wahl <rwahl@gmx.net>, Phil Romig <romig@bierstadt.unl.edu> 
  95.     //   and Michael Marxmeier <mike@msede.com> report the same for GNU 
  96.     //   libc 5.4.33.
  97.     // * Terence Spielman <terence@globeset.com> says that Linux
  98.     //   with GNU libc 5.4.35 also doesn't want BLOCK_TTY_INPUT.  
  99.     // * Anders Wegge Jakobsen <wegge@wegge.dk> reports the same for
  100.     //   GNU libc 5.4.38.
  101.     // * Ray Dassen <jdassen@wi.LeidenUniv.nl> reports that Linux with
  102.     //   GNU libc 6 (that is, glibc 2.x or later) wants BLOCK_TTY_INPUT
  103.     //   to be unset.
  104.  
  105.     // There are no reports for earlier Linux variants, so let's keep
  106.     // it this way.
  107.     return false;
  108.  
  109. #else  // !LINUX && !BLOCK_TTY_INPUT
  110.     // For all other systems, the default is BLOCK_TTY_INPUT set.  (I
  111.     // don't know whether this is the `best' setting, but I have no
  112.     // reason to change a default that has been around successfully
  113.     // for so long...)
  114.  
  115.     return true;
  116. #endif // !LINUX && !BLOCK_TTY_INPUT
  117. }
  118.  
  119.  
  120. // ---------------------------------------------------------------------------
  121. // I/O functions
  122. // ---------------------------------------------------------------------------
  123.  
  124. // Input data handling
  125. int LiterateAgent::readInput(char*& data)
  126. {
  127.     data = "";
  128.     if (inputfp() == 0 || !activeIO)
  129.     return -1;
  130.  
  131.     return _readInput(data);
  132. }
  133.  
  134. // Error data handling
  135. int LiterateAgent::readError(char*& data)
  136. {
  137.     data = "";
  138.     if (errorfp() == 0 || !activeIO)
  139.     return -1;
  140.  
  141.     return _readError(data);
  142. }
  143.  
  144. // Write a whole string
  145. int LiterateAgent::write(const char *data, int length)
  146. {
  147.     if (outputfp() == 0 || !activeIO)
  148.     return -1;
  149.  
  150.     int failures = 0;
  151.  
  152.     while (length > 0)
  153.     {
  154.     errno = 0;
  155.     int nitems = ::write(fileno(outputfp()), data, length);
  156.  
  157.     if (nitems <= 0)
  158.     {
  159.         if (false
  160. #ifdef EAGAIN
  161.         || errno == EAGAIN 
  162. #endif
  163. #ifdef EWOULDBLOCK
  164.         || errno == EWOULDBLOCK
  165. #endif
  166. #ifdef EINTR
  167.         || errno == EINTR
  168. #endif
  169.         )
  170.         {
  171.         continue;    // Try again, possibly blocking
  172.         }
  173.  
  174.         if (nitems == 0 && ++failures <= 3)
  175.         {
  176.         ostrstream os;
  177.         os << "write failed (attempt #" 
  178.            << failures << ", still trying)";
  179.         string s(os);
  180.         raiseIOMsg(s);
  181.         sleep(1);
  182.         continue;
  183.         }
  184.         else
  185.         {
  186.         raiseIOMsg("write failed");
  187.         return -1;
  188.         }
  189.     }
  190.  
  191.     assert(nitems > 0);
  192.     dispatch(Output, (char *)data, nitems);
  193.  
  194.     length -= nitems;
  195.     data += nitems;
  196.     }
  197.  
  198.     if (failures)
  199.     raiseMsg("write ok");
  200.  
  201.     return 0;
  202. }
  203.  
  204. // Flush output buffers
  205. int LiterateAgent::flush()
  206. {
  207.     // Not needed, since we use immediate write()
  208.     return 0;
  209. }
  210.  
  211.  
  212. // Read from fp without delay
  213. int LiterateAgent::_readNonBlocking(char *buffer, int nelems, FILE *fp)
  214. {
  215.     // Avoid being stopped when file is non-blocking
  216.     SignalBlocker sb;
  217.  
  218. #if HAVE_FCNTL && defined(O_NONBLOCK)
  219.     // Make file non-blocking
  220.     int flags = fcntl(fileno(fp), F_GETFL, 0);
  221.     if (flags == -1)
  222.     _raiseIOWarning("cannot get file descriptor status flags");
  223.     if (fcntl(fileno(fp), F_SETFL, flags | O_NONBLOCK) == -1)
  224.     _raiseIOWarning("cannot set file to non-blocking mode");
  225. #endif
  226.  
  227.     // Read stuff
  228.     int nitems = fread(buffer, sizeof(char), nelems, fp);
  229.  
  230.     if (nitems <= 0)
  231.     {
  232.     if (false
  233. #ifdef EAGAIN
  234.     || errno == EAGAIN
  235. #endif
  236. #ifdef EWOULDBLOCK
  237.     || errno == EWOULDBLOCK
  238. #endif
  239.     )
  240.     {
  241.         // Resource temporarily unavailable: an operation that
  242.         // would block was attempted on an object that has
  243.         // non-blocking mode selected.  Trying the same operation
  244.         // again will block until some external condition makes it
  245.         // possible to read, write, or connect (whatever the
  246.         // operation).  So, just try again next time.
  247.         nitems = 0;
  248.  
  249.         // Linux libc 5.4.39 and later treats EAGAIN and
  250.         // EWOULDBLOCK as EOF condition.  This is a bad idea.
  251.         clearerr(fp);
  252.     }
  253.     }
  254.  
  255.  
  256. #if HAVE_FCNTL && defined(F_SETFL)
  257.     // Reset file state
  258.     if (fcntl(fileno(fp), F_SETFL, flags) == -1)
  259.     _raiseIOWarning("cannot restore file mode");
  260. #endif
  261.  
  262.     return nitems;
  263. }
  264.  
  265.  
  266. // Read from fp
  267. int LiterateAgent::_read(char*& data, FILE *fp)
  268. {
  269.     static ChunkQueue queue(ARG_MAX);
  270.  
  271.     queue.discard();
  272.     char buffer[ARG_MAX + 1];
  273.     
  274.     if (blocking_tty(fp))
  275.     {
  276.     // Non-blocking ttys are nasty, so we read only the 
  277.     // single line available here and now.
  278.     char *s = fgets(buffer, ARG_MAX, fp);
  279.  
  280.     if (s != 0)
  281.         queue.append(buffer, strlen(buffer));
  282.     else if (false
  283. #ifdef EAGAIN
  284.          || errno == EAGAIN
  285. #endif
  286. #ifdef EINTR
  287.          || errno == EINTR
  288. #endif
  289. #ifdef EWOULDBLOCK
  290.          || errno == EWOULDBLOCK
  291. #endif
  292.         )
  293.     {
  294.         // Linux libc 5.4.39 and later treats EAGAIN and
  295.         // EWOULDBLOCK as EOF condition.  This is a bad idea.
  296.         clearerr(fp);
  297.     }
  298.     }
  299.     else
  300.     {
  301.     // Otherwise, read and accumulate whatever's there - up to
  302.     // ARG_MAX characters
  303.     int length = -1;
  304.     while (queue.length() < ARG_MAX
  305.            && (length = _readNonBlocking(buffer, ARG_MAX, fp)) > 0)
  306.         queue.append(buffer, length);
  307.  
  308.     if (length < 0)
  309.         raiseIOMsg("read from agent failed");
  310.     }
  311.  
  312.     data = queue.data();
  313.     return queue.length();
  314. }
  315.  
  316. int LiterateAgent::_readInput(char*& data)
  317. {
  318.     return _read(data, inputfp());
  319. }
  320.  
  321. int LiterateAgent::_readError(char*& data)
  322. {
  323.     return _read(data, errorfp());
  324. }
  325.  
  326.  
  327.  
  328. // ---------------------------------------------------------------------------
  329. // Dispatchers
  330. // ---------------------------------------------------------------------------
  331.  
  332. // dispatch data to <type> handler 
  333. void LiterateAgent::dispatch(int type, char *data, int length)
  334. {
  335.     char c = data[length];
  336.     if (c != '\0')
  337.     data[length] = '\0';
  338.  
  339.     DataLength dl(data, length);
  340.  
  341.     // call global handlers
  342.     callHandlers(type, &dl);
  343.  
  344.     if (c != '\0')
  345.     data[length] = c;
  346. }
  347.     
  348.  
  349. // ---------------------------------------------------------------------------
  350. // Handlers
  351. // ---------------------------------------------------------------------------
  352.  
  353. // Data handlers
  354.  
  355. void LiterateAgent::outputReady(AsyncAgent *c)
  356. {
  357.     ptr_cast(LiterateAgent, c)->callHandlers(Ready);
  358. }
  359.  
  360. void LiterateAgent::inputReady(AsyncAgent *c)
  361. {
  362.     char data[ARG_MAX];
  363.     char *datap = data;
  364.     LiterateAgent *lc = ptr_cast(LiterateAgent, c);
  365.     if (lc != 0)
  366.     {
  367.     int length = lc->readInput(datap);
  368.     if (length > 0)
  369.         lc->dispatch(Input, datap, length);
  370.     else if (length == 0 && lc->inputfp() != 0 && feof(lc->inputfp()))
  371.         lc->inputEOF();
  372.     }
  373. }
  374.  
  375. void LiterateAgent::errorReady(AsyncAgent *c)
  376. {
  377.     char data[ARG_MAX];
  378.     char *datap = data;
  379.     LiterateAgent *lc = ptr_cast(LiterateAgent, c);
  380.     if (lc != 0)
  381.     {
  382.     int length = lc->readError(datap);
  383.     if (length > 0)
  384.         lc->dispatch(Error, datap, length);
  385.     else if (length == 0 && lc->errorfp() != 0 && feof(lc->errorfp()))
  386.         lc->errorEOF();
  387.     }
  388. }
  389.  
  390. // Input Data is available: read all and call Input handlers of current job
  391. void LiterateAgent::readAndDispatchInput(bool expectEOF)
  392. {
  393.     char *data;
  394.  
  395.     int length = readInput(data);
  396.     if (length > 0)
  397.     {
  398.     dispatch(Input, data, length);
  399.     }
  400.     else if (length == 0 && inputfp() != 0 && feof(inputfp()))
  401.     {
  402.     if (expectEOF)
  403.         clearerr(inputfp());
  404.     else
  405.         inputEOF();
  406.     }
  407. }
  408.  
  409. // Error Data is available: read all and call Error handlers of current job
  410. void LiterateAgent::readAndDispatchError(bool expectEOF)
  411. {
  412.     char *data;
  413.  
  414.     int length = readError(data);
  415.     if (length > 0)
  416.     {
  417.     dispatch(Error, data, length);
  418.     }
  419.     else if (length == 0 && errorfp() != 0 && feof(errorfp()))
  420.     {
  421.     if (expectEOF)
  422.         clearerr(errorfp());
  423.     else
  424.         errorEOF();
  425.     }
  426. }
  427.  
  428.  
  429. // (Re)set I/O handlers
  430. void LiterateAgent::handlerChange()
  431. {
  432.     if (activeIO)
  433.     _activateIO();
  434. }
  435.  
  436. // Activate Handlers
  437. void LiterateAgent::_activateIO()
  438. {
  439.     // We do select this event only if a handler is present
  440.     // Otherwise, outputReady() may be called all the time
  441.     setHandler(OutputReady, hasHandler(Ready) ? outputReady : 0);
  442.     setHandler(InputReady,  inputReady);
  443.     setHandler(ErrorReady,  errorReady);
  444. }
  445.  
  446. // Deactivate Handlers
  447. void LiterateAgent::_deactivateIO()
  448. {
  449.     setHandler(OutputReady, 0);
  450.     setHandler(InputReady,  0);
  451.     setHandler(ErrorReady,  0);
  452. }
  453.  
  454.  
  455. // Starter
  456. void LiterateAgent::start()
  457. {
  458.     AsyncAgent::start();
  459.     
  460.     // Dispatch input data that may already be there  (if there is some)
  461.     if (inputfp() != 0 && !blocking_tty(inputfp()))
  462.     readAndDispatchInput(true);
  463.  
  464.     if (errorfp() != 0 && !blocking_tty(errorfp()))
  465.     readAndDispatchError(true);
  466. }
  467.  
  468. // Terminator
  469. void LiterateAgent::abort()
  470. {
  471.     // Dispatch remaining input data (if there is some remaining)
  472.     activateIO();
  473.     readAndDispatchInput(true);
  474.     readAndDispatchError(true);
  475.  
  476.     // Clean up now
  477.     deactivateIO();
  478.     AsyncAgent::abort();
  479. }
  480.