home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 15 / BBS in a box XV-2.iso / Files II / Prog / M / MacPerl 4.13 source.sit / Perl Source ƒ / MacPerl / MPConsole.cp < prev    next >
Encoding:
Text File  |  1994-05-04  |  9.4 KB  |  456 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Standalone Perl
  3. File        :    MPConsole.cp    -    Console interface for GUSI
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: MPConsole.cp,v $
  8. Revision 1.2  1994/05/04  02:49:57  neeri
  9. Safer Interrupts.
  10.  
  11. Revision 1.1  1994/02/27  23:04:58  neeri
  12. Initial revision
  13.  
  14. Revision 0.2  1993/08/30  00:00:00  neeri
  15. ShowWindow -> DoShowWindow
  16.  
  17. Revision 0.1  1993/08/14  00:00:00  neeri
  18. Remember rectangles    
  19.  
  20. *********************************************************************/
  21.  
  22. #include "GUSI_P.h"
  23.  
  24. #include <Resources.h>
  25. #include <Windows.h>
  26. #include <Errors.h>
  27. #include <Folders.h>
  28. #include <PLStringFuncs.h>
  29. #include <SysEqu.h>
  30. #include <OSEvents.h>
  31.  
  32. #include <ioctl.h>
  33. #include <sys/types.h>
  34. #include <Signal.h>
  35.  
  36. extern "C" {
  37. #include "MPConsole.h"
  38.  
  39. #include "MPGlobals.h"
  40. #include "MPAppleEvents.h"
  41. #include "MPWindow.h"
  42. #include "MPFile.h"
  43. #include "MPMain.h"
  44. }
  45.  
  46. #define AF_CONSOLE 17
  47.  
  48. class MPConsoleSocket;                             // That's what this file's all about
  49.  
  50. class MPConsoleSocket : public Socket    {        
  51.     friend class MPConsoleSocketDomain;    
  52.     friend void CloseConsole(Ptr cookie);
  53.     friend void HarvestConsole(DPtr doc, MPConsoleSocket * sock);
  54.     friend int GUSIConsoleSpin(spin_msg msg, long arg);
  55.     
  56.                     MPConsoleSocket(DPtr window);
  57.                     
  58.     virtual         ~MPConsoleSocket();
  59.     
  60.     DPtr                    window;
  61.     Handle                input;
  62.     Boolean                nonblocking;
  63.     Boolean                eof;
  64. public:
  65.     virtual int    read(void * buffer, int buflen);
  66.     virtual int write(void * buffer, int buflen);
  67.     virtual int    fcntl(unsigned int cmd, int arg);
  68.     virtual void pre_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
  69.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  70.     virtual void post_select(Boolean wantRead, Boolean wantWrite, Boolean wantExcept);
  71.     virtual int    ioctl(unsigned int request, void *argp);
  72.     virtual int    isatty();
  73. };    
  74.  
  75. class MPConsoleSocketDomain : public DeviceSocketDomain {
  76.     MPConsoleSocket *    first;
  77. public:
  78.     MPConsoleSocketDomain()    :    DeviceSocketDomain(AF_CONSOLE)    {    }
  79.     
  80.     virtual     Socket * open(const char * filename, int oflag);
  81. };
  82.  
  83. MPConsoleSocketDomain    MPConsoleSockets;
  84.  
  85. #pragma segment MPConsole
  86.  
  87. /************************ MPConsoleSocket members ************************/
  88.  
  89. void HarvestConsole(DPtr doc, MPConsoleSocket * sock)
  90. {                
  91.     HLock((*doc->theText)->hText);
  92.     
  93.     char * chr = *(*doc->theText)->hText + (*doc->theText)->teLength;
  94.     char * end = *(*doc->theText)->hText + doc->u.cons.fence;
  95.  
  96.     if (gGotEof == doc) {
  97.         PtrAndHand(end, sock->input, chr - end);
  98.         
  99.         doc->u.cons.fence = (*doc->theText)->teLength;
  100.         sock->eof            = true;
  101.     } else 
  102.         while (chr-- > end)
  103.             if (*chr == '\n') {
  104.                 PtrAndHand(end, sock->input, ++chr - end);
  105.                 doc->u.cons.fence = chr - *(*doc->theText)->hText;
  106.                 
  107.                 break;
  108.             }
  109.     
  110.     HUnlock((*doc->theText)->hText);
  111. }
  112.  
  113. MPConsoleSocket::MPConsoleSocket(DPtr window)
  114.     : window(window)
  115. {
  116.     nonblocking                    =    false;
  117.     eof                            =    false;
  118.     input                            =    NewHandle(0);
  119.     window->u.cons.cookie    =    Ptr(this);
  120. }
  121.  
  122. void CloseConsole(Ptr cookie)
  123. {
  124.     if (cookie)
  125.         ((MPConsoleSocket *) cookie)->window = nil;
  126. }
  127.  
  128. MPConsoleSocket::~MPConsoleSocket()
  129. {
  130.     DisposeHandle(input);
  131.     
  132.     if (window)
  133.         window->u.cons.cookie    = nil;
  134. }
  135.  
  136. int MPConsoleSocket::fcntl(unsigned int cmd, int arg)
  137. {
  138.     switch (cmd)    {
  139.     case F_GETFL:
  140.         if (nonblocking)
  141.             return FNDELAY;
  142.         else
  143.             return 0;
  144.     case F_SETFL:
  145.         if (arg & FNDELAY)
  146.             nonblocking = true;
  147.         else
  148.             nonblocking = false;
  149.             
  150.         return 0;
  151.     default:
  152.         return GUSI_error(EOPNOTSUPP);
  153.     }
  154. }
  155.  
  156. int MPConsoleSocket::ioctl(unsigned int request, void *argp)
  157. {
  158.     switch (request)    {
  159.     case FIONBIO:
  160.         nonblocking    =    (Boolean) *(long *) argp;
  161.         
  162.         return 0;
  163.     case FIONREAD:
  164.         *(unsigned long *) argp    = GetHandleSize(input);
  165.         
  166.         return 0;
  167.     case FIOINTERACTIVE:
  168.         return 0;
  169.     case WIOSELECT:
  170.         if (window)
  171.             SelectWindow(window->theWindow);
  172.             
  173.         return 0;
  174.     default:
  175.         return GUSI_error(EOPNOTSUPP);
  176.     }
  177. }
  178.  
  179. int MPConsoleSocket::read(void * buffer, int buflen)
  180. {
  181.     int    avail;
  182.     
  183.     avail = int(GetHandleSize(input));
  184.     
  185.     if (!avail)    {
  186.         if (eof) {
  187.             eof = false;
  188.             
  189.             return 0;
  190.         }
  191.         if (!window)
  192.             return 0;
  193.         else if (nonblocking)
  194.             return GUSI_error(EWOULDBLOCK);
  195.         else {
  196.             if (!((WindowPeek) window->theWindow)->visible)
  197.                 DoShowWindow(window->theWindow);
  198.             if (!((WindowPeek) window->theWindow)->hilited)
  199.                 SelectWindow(window->theWindow);
  200.                 
  201.             window->u.cons.selected = true;
  202.             ShowWindowStatus();
  203.             
  204.             SPIN(!(avail = int(GetHandleSize(input))) && !eof && window, SP_STREAM_READ, 0);
  205.     
  206.             if (!avail && eof)
  207.                 eof = false;
  208.                 
  209.             window->u.cons.selected = false;
  210.             ShowWindowStatus();
  211.         }
  212.     }
  213.         
  214.     buflen = min(avail, buflen);
  215.     
  216.     HLock(input);
  217.     memcpy(buffer, *input, buflen);
  218.     if (avail -= buflen)
  219.         memcpy(*input, *input+buflen, avail);
  220.     HUnlock(input);
  221.     SetHandleSize(input, avail);
  222.     
  223.     return buflen;
  224. }
  225.  
  226. int MPConsoleSocket::write(void * buffer, int buflen)
  227. {
  228.     short    oldStart;
  229.     short    oldEnd;
  230.     int    len = buflen;
  231.     
  232.     if (!window)
  233.         return GUSI_error(ESHUTDOWN);
  234.  
  235.     HarvestConsole(window, this);
  236.     
  237.     if (len > window->u.cons.memory) {
  238.         buffer = (void *) (Ptr(buffer) + len - window->u.cons.memory);
  239.         len = window->u.cons.memory;
  240.     }
  241.     
  242.     (*window->theText)->teLength += buflen;
  243.     EnforceMemory(window, window->theText);
  244.     (*window->theText)->teLength -= buflen;
  245.     
  246.     oldStart    =    (*window->theText)->selStart;
  247.     oldEnd    =    (*window->theText)->selEnd;
  248.     
  249.     if (oldStart >= window->u.cons.fence)
  250.         oldStart += buflen;
  251.     if (oldEnd >= window->u.cons.fence)
  252.         oldEnd += buflen;
  253.         
  254.     TESetSelect(window->u.cons.fence, window->u.cons.fence, window->theText);
  255.     TEInsert(buffer, buflen, window->theText);
  256.  
  257.     if (!((WindowPeek) window->theWindow)->visible) {
  258.         HideControl(window->vScrollBar);
  259.         HideControl(window->hScrollBar);
  260.         
  261.         DoShowWindow(window->theWindow);
  262.     }
  263.  
  264.     ShowSelect(window);
  265.     DrawPageExtras(window);
  266.     
  267.     TESetSelect(oldStart, oldEnd, window->theText);
  268.  
  269.     if (window->u.cons.fence < 32767)
  270.         window->u.cons.fence += buflen;
  271.     
  272.     return buflen;
  273. }
  274.  
  275. static Boolean StatusNeedsUpdate = false;
  276.  
  277. void MPConsoleSocket::pre_select(Boolean canRead, Boolean, Boolean)
  278. {
  279.     if (canRead && window) {
  280.         StatusNeedsUpdate = window->u.cons.selected = true;
  281.         
  282.         if (!((WindowPeek) window->theWindow)->visible)
  283.             DoShowWindow(window->theWindow);
  284.     }
  285. }
  286.  
  287. void MPConsoleSocket::post_select(Boolean canRead, Boolean, Boolean)
  288. {
  289.     if (canRead && window)
  290.         StatusNeedsUpdate = window->u.cons.selected = false;
  291. }
  292.  
  293. int MPConsoleSocket::select(Boolean * canRead, Boolean * canWrite, Boolean * exception)
  294. {
  295.     int        goodies     =     0;
  296.  
  297.     if (StatusNeedsUpdate) {
  298.         ShowWindowStatus();
  299.         
  300.         StatusNeedsUpdate = false;
  301.     }
  302.         
  303.     if (canRead)
  304.         if (*canRead = (GetHandleSize(input) > 0 || eof))
  305.             ++goodies;
  306.     
  307.     if (canWrite) {
  308.         *canWrite = true;
  309.         ++goodies;
  310.     }
  311.     
  312.     if (exception)
  313.         *exception = false;
  314.     
  315.     return goodies;
  316. }
  317.  
  318. int MPConsoleSocket::isatty()
  319. {
  320.     return 1;
  321. }
  322.  
  323. /********************* MPConsoleSocketDomain member **********************/
  324.  
  325. #pragma force_active on
  326.  
  327. static Boolean spinInstalled = false;
  328.  
  329. Socket * MPConsoleSocketDomain::open(const char * filename, int flags)
  330. {
  331.     DPtr                doc;
  332.     Socket *            sock = nil;
  333.     char                 title[256];
  334.     Boolean            nudoc = false;
  335.     
  336.     strncpy(title, filename, 7);
  337.     title[7] = 0;
  338.     
  339.     if (equalstring(title, (char *) "stdin", false, true)) {
  340.         flags = O_RDONLY;
  341.         
  342.         if (filename[5])
  343.             return (Socket *) TryNextDevice;
  344.         else
  345.             filename += 5;
  346.     } else if (equalstring(title, (char *) "stdout", false, true)) {
  347.         flags = O_WRONLY;
  348.         
  349.         if (filename[6])
  350.             return (Socket *) TryNextDevice;
  351.         else
  352.             filename += 6;
  353.     } else if (equalstring(title, (char *) "console", false, true)) {
  354.         switch (filename[7]) {
  355.         case ':':
  356.             ++filename;
  357.         case 0:
  358.             filename += 7;
  359.             break;
  360.         default:
  361.             return (Socket *) TryNextDevice;
  362.         }
  363.     } else
  364.         return (Socket *) TryNextDevice;
  365.  
  366.     if (*filename) {
  367.         for (doc = gConsoleList; doc; doc = doc->u.cons.next)
  368.             if (doc->kind == kConsoleWindow) {
  369.                 getwtitle(doc->theWindow, title);
  370.                 
  371.                 if (equalstring(title, (char *) filename, false, true)) {
  372.                     if (doc->u.cons.cookie)
  373.                         sock = (Socket *) doc->u.cons.cookie;
  374.  
  375.                     goto found;
  376.                 }
  377.             }
  378.             
  379.         nudoc    = true;                
  380.         doc    = NewDocument(false, kConsoleWindow);
  381.         
  382.         setwtitle(doc->theWindow, (char *) filename);
  383.         
  384.         RestoreConsole(doc);
  385.     } else {
  386.         for (doc = gConsoleList; doc; doc = doc->u.cons.next)
  387.             if (doc->kind == kWorksheetWindow) {
  388.                 if (doc->u.cons.cookie)
  389.                     sock = (Socket *) doc->u.cons.cookie;
  390.  
  391.                 goto found;
  392.             }
  393.             
  394.         nudoc    = true;                
  395.         doc = NewDocument(false, kWorksheetWindow);
  396.         
  397.         SetWTitle(doc->theWindow, StringPtr(CurApName));
  398.  
  399.         RestoreConsole(doc);
  400.     }
  401.  
  402. found:    
  403.     if (!sock) {
  404.         errno = 0;
  405.         sock     = new MPConsoleSocket(doc);
  406.         
  407.         if (sock && errno) {
  408.             if (nudoc)
  409.                 CloseMyWindow(doc->theWindow);
  410.  
  411.             delete sock;
  412.             
  413.             return nil;
  414.         }
  415.  
  416.         if (!spinInstalled) {
  417.             GUSISetSpin(GUSIConsoleSpin);
  418.             
  419.             spinInstalled = true;
  420.         }
  421.     } else
  422.         ((MPConsoleSocket *)sock)->eof = false;
  423.  
  424.     if (!(flags & 1))
  425.         doc->u.cons.fence = (*doc->theText)->teLength;
  426.     else if (nudoc)
  427.         doc->u.cons.fence = 32767;
  428.  
  429.     return sock;
  430. }
  431.  
  432. /********************* A kinder, gentler, spin **********************/
  433.  
  434. int GUSIConsoleSpin(spin_msg spin, long)
  435. {
  436.     if (!gInBackground && GUSIInterrupt() && gRunningPerl) {
  437.         FlushEvents(-1, 0);
  438.  
  439.         if (spin == SP_AUTO_SPIN)
  440.             raise(SIGINT);
  441.         else
  442.             return -1;
  443.     }
  444.         
  445.     MainEvent(spin != SP_SELECT && spin != SP_STREAM_READ);
  446.     
  447.     for (DPtr doc = gConsoleList; doc; doc = doc->u.cons.next)
  448.         if (doc->dirty) {
  449.             if (doc->u.cons.cookie) 
  450.                 HarvestConsole(doc, (MPConsoleSocket *) doc->u.cons.cookie);
  451.             doc->dirty = false;
  452.         }
  453.     
  454.     return 0;
  455. }
  456.