home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Moscow ML 1.42 / ANSIshellƒ / os_mac.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-26  |  77.1 KB  |  2,758 lines  |  [TEXT/R*ch]

  1. /* os_mac.c
  2.  * 12Sep92  e  adapted from the file of the same name in the Gambit Project
  3.  * Macintosh specific stuff (for THINK C 7 or CodeWarrior 4 compiler).
  4.  * portions Copyright © 1992-1994 Marc Feeley and Douglas H. Currie, Jr.
  5.  */
  6.  
  7. #ifdef THINK_C
  8. #include <MacHeaders>
  9. #else
  10. #ifdef __MWERKS__
  11. #else
  12. "Unknown compiler!"
  13. #endif
  14. #endif
  15.  
  16. #include "os_mac.h"
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #include <errno.h>
  21. #include <signal.h>
  22. #ifdef THINK_C
  23. #include <ansi_e.h>
  24. #else
  25. Boolean XlateRETURN = 0;
  26. #endif
  27.  
  28. /*---------------------------------------------------------------------------*/
  29.  
  30. #include <Files.h>
  31. #include <Gestalt.h>
  32. #include <AppleEvents.h>
  33. #include <AERegistry.h>
  34.  
  35. static void init_ae();
  36.  
  37. #if ( CREATOR == 'Moml' )
  38. char *image_name = 0; // May97 e
  39. FSSpec appFSS;
  40. #endif
  41. static Boolean been_there_done_that = false;
  42. char      gReceivedAE = 0;
  43. Boolean   gMadeAppFSS = false;
  44. Boolean        gDoQuit = false;
  45. Boolean        gHasAppleEvents = false;
  46. Boolean        gPrintPage = false;
  47. Boolean        gHasStdFile = false;
  48. Boolean   gCursRgnOK = false;
  49. Boolean   gInBackground = false;
  50. Boolean   gLowMemory = false;
  51. Boolean   gSpareBool;
  52.  
  53. // Boolean     gHasWNE = true;
  54. // Boolean     gHasHWPriv = true;
  55.  
  56. static Handle rainy_day_fund;
  57. #define kRamReserve 65536
  58. #define kRamSlop    16384
  59.  
  60. Ptr empty_buffer;
  61.  
  62. #include "os_mac_eventchk.h"
  63. long next_eventchk_ticks;
  64.  
  65. /*---------------------------------------------------------------------------*/
  66.  
  67. TextStyle prefStylNormal =
  68. { monaco, 0, 0, FontSize, { 65536, 65536, 65536 } /* RGBColor Black */ };
  69. TextStyle prefStylHilite =
  70. { monaco, 0, 0, FontSize, { 65536, 65536, 65536 } /* RGBColor Black */ };
  71.  
  72. short prefTabs = dfltTabs;
  73. short prefWrap = dfltWrap;
  74. short prefAutoInd = dfltAutoInd;
  75.  
  76. short current_menus;
  77.  
  78. MenuHandle menus[7];
  79.  
  80. Cursor watch_cursor;
  81. Cursor gc_cursor;
  82. Cursor ibeam_cursor;
  83. Cursor *current_cursor;
  84.  
  85. unsigned char *find_string, *replace_string;
  86.  
  87. Boolean find_ci   = FALSE;
  88. Boolean find_wrap = FALSE;
  89.  
  90. static Boolean smKeyBdP;
  91. static Boolean showPosnP;
  92.  
  93. short interaction_id = 0;
  94. short interrupted = 0;
  95.  
  96. static struct {
  97.   WindowPtr wptr;
  98.   ControlHandle vscroll;
  99.   ControlHandle hscroll;
  100.   TeHANDLE hTE;
  101.   short bold_input;
  102.   short height;
  103.   short dirty;
  104.   short out_len;
  105.   long pos, len;
  106.   char *buf;
  107.   Handle out_buf;
  108.   long needs_inval_ticks;
  109.   char  in_use;
  110.   char  is_file; // 0: console, 1: new,  2: fss good
  111.   FSSpec fss;
  112. } wind_table[MAX_NB_WINDOWS];
  113.  
  114. #define WINDOW_OWNS_FILE_P( id, fss ) \
  115.  (wind_table[id].in_use != 0 && \
  116.   wind_table[id].is_file == 2 && \
  117.   wind_table[id].fss.vRefNum == fss->vRefNum && \
  118.   wind_table[id].fss.parID == fss->parID && \
  119.   (compare_p_to_p( wind_table[id].fss.name, fss->name ) == 0))
  120.  
  121. RgnHandle gCursorRgn;
  122.  
  123. long gWaitTicksBG = 20; /* in ticks, should be 6..60 */
  124. long gWaitTicksFG =  1; /* in ticks, should be 1..15 */
  125.  
  126. /* */
  127.  
  128. static void setup_cursors()
  129. { CursHandle hCurs;
  130.   hCurs = GetCursor(watchCursor);
  131.   watch_cursor = **hCurs;
  132.   /* 28Jan93  e
  133.   hCurs = GetCursor(gc_cursorID);
  134.   gc_cursor = **hCurs;
  135.   */
  136.   hCurs = GetCursor(iBeamCursor);
  137.   ibeam_cursor = **hCurs;
  138.  
  139.   current_cursor = &watch_cursor;
  140. }
  141.  
  142. static void ParamText1( Str255 text )
  143. {
  144.     ParamText( text, "\p", "\p", "\p" );
  145. }
  146.  
  147. /* *** preferences saved to disk *** */
  148.  
  149. static OSErr findPrefFolder( short *foundVRefNum, long *foundDirID )
  150. {    
  151.   *foundVRefNum = 0;
  152.   *foundDirID = 0;
  153.   /* MacTraps2 has FindFolder() glue */
  154.   return FindFolder( kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  155.                        foundVRefNum, foundDirID );
  156. }
  157.  
  158. struct prefs
  159. { short version;
  160.   short tabs;
  161.   short wrap;
  162.   Boolean find_ci;
  163.   Boolean find_wrap;
  164.   Boolean spare0;        /* smKeyBdP in Gambit */
  165.   Boolean showPosnP;
  166.   short spare2;
  167.   short spare3;
  168.   short autoInd;
  169.   TextStyle stylNormal;
  170.   TextStyle stylHilite;
  171.   unsigned char fontnmNormal[64];
  172.   unsigned char fontnmHilite[64];
  173. };
  174.  
  175. void savePrefs( ConstStr255Param fn )
  176. {
  177.     short rRef;
  178.       OSErr err;
  179.     struct prefs **hRes;
  180.     struct prefs  *pRes;
  181.     short foundVRefNum;
  182.     long  foundDirID;
  183.     Str255 fontnmNormal, fontnmHilite;
  184.     
  185.     err = findPrefFolder( &foundVRefNum, &foundDirID );
  186.     if( err != noErr ) return;
  187.     
  188.     if( ( rRef = HOpenResFile( foundVRefNum, foundDirID, fn, fsRdWrPerm ) ) < 0)
  189.     {    HCreateResFile( foundVRefNum, foundDirID, fn );
  190.         { HFileInfo pb;
  191.           pb.ioCompletion = (void *)0;
  192.           pb.ioNamePtr = (StringPtr )fn;
  193.           pb.ioVRefNum = foundVRefNum;
  194.           pb.ioFDirIndex = 0;
  195.           pb.ioDirID = foundDirID;
  196.           err = PBHGetFInfoSync( (HParmBlkPtr )&pb );
  197.           pb.ioCompletion = (void *)0;
  198.           pb.ioNamePtr = (StringPtr )fn;
  199.           pb.ioVRefNum = foundVRefNum;
  200.           pb.ioFDirIndex = 0;
  201.           pb.ioDirID = foundDirID;
  202.           pb.ioFlFndrInfo.fdCreator = CREATOR;
  203.           pb.ioFlFndrInfo.fdType    = 'gamP';
  204.           if( err == noErr )
  205.             PBHSetFInfoSync( (HParmBlkPtr )&pb );
  206.         }
  207.         rRef = HOpenResFile( foundVRefNum, foundDirID, fn, fsRdWrPerm );
  208.     }
  209.     if( rRef < 0 )
  210.         return;
  211.     hRes = (struct prefs **)GetResource('ePrf', 357);
  212.     if(    hRes == 0 || rRef != HomeResFile( (Handle )hRes ) )
  213.     {    hRes = (struct prefs **)NewHandle( sizeof( struct prefs ) );
  214.         if( hRes == 0 )
  215.         {    CloseResFile( rRef );
  216.             return;
  217.         }
  218.         AddResource( (Handle )hRes, (ResType )'ePrf', 357, (ConstStr255Param)"\p" );
  219.         if( LMGetResErr() != noErr )
  220.         {    DisposeHandle( (Handle )hRes );
  221.             CloseResFile( rRef );
  222.             return;
  223.         }
  224.     }
  225.     pRes = *hRes;
  226.     (*pRes).version    = 1;
  227.     (*pRes).tabs       = prefTabs;
  228.     (*pRes).wrap       = prefWrap;
  229.     (*pRes).find_ci    = find_ci;
  230.     (*pRes).find_wrap  = find_wrap;
  231.     (*pRes).spare0     = 0;
  232.     (*pRes).showPosnP  = showPosnP;
  233.     (*pRes).spare2     = 0;
  234.     (*pRes).spare3     = 0;
  235.     (*pRes).autoInd    = prefAutoInd;
  236.     (*pRes).stylNormal = prefStylNormal;
  237.     (*pRes).stylHilite = prefStylHilite;
  238.     GetFontName( prefStylNormal.tsFont, fontnmNormal );
  239.     if( fontnmNormal[0] > 63 ) fontnmNormal[0] = 63;
  240.     p_to_p( fontnmNormal, (**hRes).fontnmNormal );
  241.     GetFontName( prefStylHilite.tsFont, fontnmHilite );
  242.     if( fontnmHilite[0] > 63 ) fontnmHilite[0] = 63;
  243.     p_to_p( fontnmHilite, (**hRes).fontnmHilite );
  244.     
  245.     ChangedResource( (Handle )hRes );
  246.     CloseResFile( rRef );
  247. }
  248.  
  249. static void readPrefs( ConstStr255Param fn )
  250. {
  251.     short rRef;
  252.       OSErr err;
  253.     struct prefs **hRes;
  254.     struct prefs  *pRes;
  255.     short foundVRefNum;
  256.     long  foundDirID;
  257.  
  258.     err = findPrefFolder( &foundVRefNum, &foundDirID );
  259.     if( err != noErr ) return;
  260.     
  261.     rRef = HOpenResFile( foundVRefNum, foundDirID, fn, fsRdWrPerm );
  262.     /* don't test rRef here since resource may come from elsewhere, e.g., from appl. */
  263.     hRes = (struct prefs **)GetResource('ePrf', 357);
  264.     if(    hRes != 0 )
  265.     {    pRes = *hRes;
  266.         if( (*pRes).version == 1 )
  267.         {    prefTabs   = (*pRes).tabs;
  268.             prefWrap   = (*pRes).wrap;
  269.             find_ci    = (*pRes).find_ci;
  270.             find_wrap  = (*pRes).find_wrap;
  271.             prefAutoInd = (*pRes).autoInd;
  272.             showPosnP  = (*pRes).showPosnP;
  273.             prefStylNormal = (*pRes).stylNormal;
  274.             prefStylHilite = (*pRes).stylHilite;
  275.             GetFNum( (**hRes).fontnmNormal, &prefStylNormal.tsFont );
  276.             if( prefStylNormal.tsFont < 0 ) prefStylNormal.tsFont = 0;
  277.             GetFNum( (**hRes).fontnmHilite, &prefStylHilite.tsFont );
  278.             if( prefStylHilite.tsFont < 0 ) prefStylHilite.tsFont = 0;
  279.         }
  280.     }
  281.     if( rRef >= 0 ) CloseResFile( rRef );
  282. }
  283.  
  284. /* *** */
  285.  
  286. #define fustItem 3
  287. static short itemtowindid[MAX_NB_WINDOWS];
  288. static short windidtodigit[MAX_NB_WINDOWS];
  289. static short qWindItems = 0;
  290.  
  291. #if GENERATINGPOWERPC
  292. #pragma options align=mac68k
  293. #endif
  294.  
  295. typedef struct { short nbmenus6, right, dummy; struct { MenuHandle mh; short left; } menu[100]; } menu_list;
  296.  
  297. #if GENERATINGPOWERPC
  298. #pragma options align=reset
  299. #endif
  300.  
  301. static short cmd_key_exists( char c )
  302. {
  303.   menu_list **ml = (menu_list **)LMGetMenuList();
  304.   short n = (*ml)->nbmenus6/6;
  305.   short i, j, m, cmd;
  306.   for (i=0; i<n; i++)
  307.   { MenuHandle mh = (*ml)->menu[i].mh;
  308.     m = CountMItems( mh );
  309.     for (j=1; j <= m; j++)
  310.     {
  311.       GetItemCmd( mh, j, &cmd );
  312.       if (cmd == c) return 1;
  313.     }
  314.   }
  315.   return 0;
  316. }
  317.  
  318. static void addWindMenuItem( short id )
  319. {    short d, i, j;
  320.     Str255 title, key = "\p / ";
  321.     WindowPtr wind = wind_table[id].wptr;
  322.     if (qWindItems >= MAX_NB_WINDOWS) return;
  323.     for (d=1; d<10; d++) if (!cmd_key_exists('0'+d)) break;
  324.     if (d < 10) key[3] = '0'+d; else key[2] = ' ';
  325.     windidtodigit[id] = d;
  326.     for (i=0; i < qWindItems; i++)
  327.       if (windidtodigit[itemtowindid[i]] > d) break;
  328.     for (j=qWindItems; j > i; j--) // was: qWindItems-1 -- 1997Jul26 e
  329.       itemtowindid[j] = itemtowindid[j-1];
  330.     itemtowindid[i] = id;
  331.     GetWTitle( wind, title );
  332.     InsertMenuItem( menus[windowsM], key, i+fustItem-1 );
  333.     SetMenuItemText( menus[windowsM], i+fustItem, title );
  334.     qWindItems++;
  335. }
  336.  
  337. static void delWindMenuItem( short id )
  338. {    register short i;
  339.     for(i = 0; i < qWindItems; i++)
  340.     {    if( id == itemtowindid[i] )
  341.         {    DeleteMenuItem( menus[windowsM], i+fustItem );
  342.             for( i++; i < qWindItems; i++ )
  343.                 itemtowindid[i-1] = itemtowindid[i];
  344.             qWindItems--;
  345.             break;
  346.         }
  347.     }
  348. }
  349.  
  350. static void eSmudgeWindow( register short w )
  351. {    register short i;
  352.     if( ! wind_table[w].dirty )
  353.     {    wind_table[w].dirty = 1;
  354.         for( i = 0; i < qWindItems; i++ )
  355.         {    if( w == itemtowindid[i] )
  356.             {    SetItemMark( menus[windowsM], i+fustItem, '◊');
  357.                 break;
  358.             }
  359.         }
  360.     }
  361. }
  362.  
  363. static void eUnSmudgeWindow( register short w, TeHANDLE hTE )
  364. {    register short i;
  365.     (**hTE).dirty = 0;
  366.     if( wind_table[w].dirty )
  367.     {    wind_table[w].dirty = 0;
  368.         for( i = 0; i < qWindItems; i++ )
  369.         {    if( w == itemtowindid[i] )
  370.             {    SetItemMark( menus[windowsM], i+fustItem, 0);
  371.                 break;
  372.             }
  373.         }
  374.     }
  375. }
  376.  
  377. static void eMaybeSmudgeWindow( short w, TeHANDLE hTE )
  378. {
  379.     if( (**hTE).dirty )
  380.         eSmudgeWindow( w );
  381.     else
  382.         eUnSmudgeWindow( w, hTE );    /* for Undo */
  383. }
  384.  
  385. void select_and_show( WindowPtr wptr )
  386. {
  387.   SelectWindow( wptr );
  388.   ShowWindow( wptr );
  389. }
  390.  
  391. /* ************* */
  392.  
  393. static void wind_begin(void)
  394. { short i;
  395.   long result;
  396.   for (i=0; i<MAX_NB_WINDOWS; i++) wind_table[i].in_use = 0;
  397.   InitGraf( &qd.thePort );
  398.   InitFonts();
  399.   FlushEvents( everyEvent, 0 );
  400.   InitWindows();
  401.   InitMenus();
  402.   TEInit();
  403.   eTeInit();
  404.   InitDialogs( 0L );
  405.   InitCursor();
  406.  
  407.   prefStylHilite.tsFace = bold+condense;
  408.  
  409.   menus[appleM] = GetMenu( appleID );
  410.   AppendResMenu( menus[appleM], 'DRVR' );
  411.   menus[fileM]    = GetMenu( fileID );
  412.   menus[editM]    = GetMenu( editID );
  413.   menus[findM]    = GetMenu( findID );
  414.   menus[commandM] = GetMenu( commandID );
  415.   menus[windowsM] = GetMenu( windowsID );
  416.  
  417.   ClearMenuBar();
  418.   for ( (i=appleM); (i<=windowsM); i++ ) InsertMenu(menus[i], 0);
  419.   DrawMenuBar();
  420.   current_menus = 0;
  421.  
  422.   setup_cursors();
  423.  
  424.   find_string =    (unsigned char *)NewPtr( 256 );
  425.   replace_string = (unsigned char *)NewPtr( 256 );
  426.   if( find_string == NULL || replace_string == NULL )
  427.   {    SysBeep(10);
  428.       os_quit();
  429.   }
  430.   find_string[0] = '\0';
  431.   replace_string[0] = '\0';
  432.  
  433.   gCursorRgn = NewRgn();
  434.   SetRectRgn(gCursorRgn, -32768, -32768, 32766, 32766);
  435.   
  436.   empty_buffer = NewPtr( 4 );
  437.   *empty_buffer = 0;
  438.  
  439.   // gHasWNE = TrapExists(_WaitNextEvent);
  440.   // gHasHWPriv = TrapExists(_HWPriv);
  441.   
  442.   gHasStdFile = (Gestalt(gestaltStandardFileAttr, &result) ? false
  443.                   : (result & (1 << gestaltStandardFile58)) != 0);
  444.  
  445.   readPrefs( PREFS_FILENAME );
  446.  
  447.   XlateRETURN = XlateRETURNp;
  448.  
  449.   init_ae();
  450. }
  451.  
  452. static void wind_close( short id )
  453. { TeHANDLE hTE = wind_table[id].hTE;
  454.   if (id == interaction_id)
  455.   { HideWindow( wind_table[id].wptr );
  456.     eTeSetSelect( hTE, 0, eTeTextLength( hTE ));
  457.     eTeDelete( hTE );
  458.   }
  459.   else if (wind_table[id].in_use)
  460.   { wind_table[id].in_use = 0;
  461.     HideWindow( wind_table[id].wptr );
  462.     eTeDispose( hTE );
  463.     delWindMenuItem( id );
  464.     DisposeControl( wind_table[id].vscroll );
  465.     DisposeControl( wind_table[id].hscroll );
  466.     DisposeWindow( wind_table[id].wptr );
  467.     if (wind_table[id].buf != NULL)
  468.     { DisposePtr( wind_table[id].buf ); wind_table[id].buf = NULL; }
  469.     if( wind_table[id].out_buf != NULL )
  470.     { DisposeHandle( wind_table[id].out_buf ); wind_table[id].out_buf = NULL; }
  471.   }
  472. }
  473.  
  474. static void wind_end(void)
  475. { short id;
  476.   for (id=MAX_NB_WINDOWS-1; id>=0; id--) wind_close( id );
  477.   eTePutScrap();
  478. }
  479.  
  480. static pascal click_scroll();
  481.  
  482. static short wind_open( unsigned char *wname, short visible, short goaway, short bold_input )
  483. { Rect viewRect, vScrollRect, bounds;
  484.   short width = 80 /*(screenBits.bounds.right-SBarWidth-2*Border-11)/FontW*/;
  485.   short height;
  486.   short id;
  487.  
  488.   for (id=0; id<MAX_NB_WINDOWS; id++) if (!wind_table[id].in_use) break;
  489.   if (id == MAX_NB_WINDOWS) return -1;
  490.  
  491.   height = (qd.screenBits.bounds.bottom-Border-48-SBarWidth)/FontH - id;
  492.  
  493.   bounds.left   = 3 + id*5;
  494.   bounds.right  = bounds.left + width*FontW + SBarWidth + Border;
  495.   bounds.top    = 41 + id*(FontH+3);
  496.   bounds.bottom = bounds.top + height*FontH + SBarWidth + Border;
  497.  
  498.   wind_table[id].wptr = (WindowPtr )
  499.     NewWindow( NULL, &bounds, wname, visible, documentProc, (WindowPtr)-1L, goaway, 0L );
  500.   if (wind_table[id].wptr == NULL) return -1;
  501.  
  502.   SetPort( wind_table[id].wptr );
  503.   TextFont( prefStylNormal.tsFont );
  504.   TextSize( prefStylNormal.tsSize );
  505.  
  506.   vScrollRect = (*wind_table[id].wptr).portRect;
  507.   vScrollRect.left = vScrollRect.right-SBarWidth;
  508.   vScrollRect.right += 1;
  509.   vScrollRect.bottom -= SBarWidth-1;
  510.   vScrollRect.top -= 1;
  511.  
  512.   wind_table[id].vscroll =
  513.     NewControl( wind_table[id].wptr, &vScrollRect, "\p", 1, 0, 0, 0,
  514.                 scrollBarProc, 0L);
  515.  
  516.   if (wind_table[id].vscroll != NULL)
  517.   { static FontInfo fInfo;
  518.  
  519.     vScrollRect = (*wind_table[id].wptr).portRect;
  520.     vScrollRect.top = vScrollRect.bottom-SBarWidth;
  521.     vScrollRect.bottom += 1;
  522.     vScrollRect.left += (vScrollRect.right-vScrollRect.left)>>1;
  523.     vScrollRect.right -= SBarWidth-1;
  524.     wind_table[id].hscroll =
  525.       NewControl( wind_table[id].wptr, &vScrollRect, "\p", 1, 0, 0, 0,
  526.                 scrollBarProc, 0L);
  527.     if (wind_table[id].hscroll != NULL)
  528.     {
  529.  
  530.       viewRect = (*wind_table[id].wptr).portRect;
  531.       viewRect.top    += Border;
  532.       viewRect.left   += Border;
  533.       viewRect.bottom -= SBarWidth;
  534.       viewRect.right  -= SBarWidth;
  535.  
  536.       wind_table[id].hTE = eTeNew( wind_table[id].wptr, viewRect, prefTabs, prefWrap,
  537.                                       prefAutoInd, wind_table[id].hscroll, wind_table[id].vscroll );
  538.  
  539.       if (wind_table[id].hTE != NULL)
  540.       {
  541.         eTeSetStyles( wind_table[id].hTE, &prefStylNormal, &prefStylHilite );
  542.         wind_table[id].height     = height;
  543.         wind_table[id].bold_input = bold_input;
  544.         wind_table[id].dirty      = 0;
  545.         wind_table[id].pos        = 0;
  546.         wind_table[id].len        = 0;
  547.         wind_table[id].buf        = NULL;
  548.         wind_table[id].out_buf    = NULL;
  549.         wind_table[id].out_len    = 0;
  550.         wind_table[id].is_file    = 0;
  551.         wind_table[id].fss.name[0]= 0;
  552.         wind_table[id].in_use     = 1;
  553.         addWindMenuItem( id );
  554.         return id;
  555.       }
  556.       DisposeControl( wind_table[id].hscroll );
  557.     }
  558.     DisposeControl( wind_table[id].vscroll );
  559.   }
  560.   DisposeWindow( wind_table[id].wptr );
  561.   return -1;
  562. }
  563.  
  564. static short discard_changes( short id )
  565. { Str255 title;
  566.   GetWTitle( wind_table[id].wptr, title );
  567.   ParamText( "\pDiscard changes to \"", title, "\p\"?", "\p" );
  568.   SysBeep( 10 );
  569.   switch (CautionAlert( ok_cancel_alertID, 0L ))
  570.   { case 3: return 1;
  571.     default: return 0;
  572.   }
  573. }
  574.  
  575. static short mem_full = 0;
  576. static short supress_mem_full_dialog = 0;
  577.  
  578. static pascal long mem_full_err( long size )
  579. {
  580.   #pragma unused (size)
  581.   if (mem_full)
  582.   { SetGrowZone( NULL );
  583.       ParamText1( "\pOut of memory.  The application will exit." );
  584.     SysBeep( 10 );
  585.     StopAlert( ok_alertID, 0L );
  586.     ExitToShell();
  587.   }
  588.   mem_full = 1;
  589.   if ( ! supress_mem_full_dialog )
  590.   { ParamText1( "\pOut of memory." );
  591.     SysBeep( 10 );
  592.     StopAlert( ok_alertID, 0L );
  593.   }
  594.   return 0;
  595. }
  596.  
  597. static void already_open_err( Str255 name )
  598. { ParamText( "\p\"", name, "\p\"", "\pis already open.  Close it first." );
  599.   SysBeep( 10 );
  600.   StopAlert( ok_alertID, 0L );
  601. }
  602.  
  603. static void path_too_long_err( Str255 name )
  604. { ParamText( "\pPath to file \"", name, "\p\" is too long.", "\p" );
  605.   SysBeep( 10 );
  606.   StopAlert( ok_alertID, 0L );
  607. }
  608.  
  609. static void wind_err(void)
  610. { ParamText1( "\pCan't open window" );
  611.   SysBeep( 10 );
  612.   StopAlert( ok_alertID, 0L );
  613. }
  614.  
  615. void io_err( short io )
  616. { unsigned char errnostr[16];
  617.   switch (io)
  618.   { case wrPermErr    : ParamText1( "\pCan't write file!" ); break;
  619.     case dupFNErr     : ParamText1( "\pDuplicate file name!" ); break;
  620.     case fBsyErr      : ParamText1( "\pFile is busy!" ); break;
  621.     case vLckdErr     : ParamText1( "\pVolume is locked!" ); break;
  622.     case fLckdErr     : ParamText1( "\pFile is locked!" ); break;
  623.     case fnfErr       : ParamText1( "\pFile not found!" ); break;
  624.     case bdNamErr     : ParamText1( "\pBad filename!" ); break;
  625.     case ioErr        : ParamText1( "\pIO transfer error!" ); break;
  626.     case dskFulErr    : ParamText1( "\pDisk full!" ); break;
  627.     case dirFulErr    : ParamText1( "\pDirectory full!" ); break;
  628.     case mFulErr      : ParamText1( "\pFile is too large for memory!" ); break;
  629.                         
  630.     case -4101          : ParamText1( "\pNo printer selected. Use the Chooser." ); break;
  631.     default           : NumToString( io, errnostr );
  632.                         ParamText( "\pIO Error! Mac error number: ", errnostr, "\p", "\p" );
  633.                         break;
  634.   }
  635.   SysBeep( 10 );
  636.   StopAlert( ok_alertID, 0L );
  637. }
  638.  
  639. static void te_limit_err(void)
  640. { ParamText1( "\pFile unopened due to size limit on buffer (32000 lines)." );
  641.   SysBeep( 10 );
  642.   StopAlert( ok_alertID, 0L );
  643. }
  644.  
  645. static short check_TEWrite( char *ptr, long len, eTeHandle hTE, short bold )
  646. {    eTeWrite( hTE, ptr, len, bold );
  647.     if (mem_full) { mem_full = 0; return 1; }
  648.     return 0;
  649. }
  650.  
  651. short check_TEInsert( char *ptr, long len, eTeHandle hTE, short bold )
  652. {    eTeInsert( hTE, ptr, len, bold );
  653.     if (mem_full) { mem_full = 0; return 1; }
  654.     return 0;
  655. }
  656.  
  657. static short check_TECut( eTeHandle hTE )
  658. { eTeCut( hTE );
  659.   if (mem_full) { mem_full = 0; return 1; }
  660.   return 0;
  661. }
  662.  
  663. static short check_TECopy( eTeHandle hTE )
  664. { eTeCopy( hTE );
  665.   if (mem_full) { mem_full = 0; return 1; }
  666.   return 0;
  667. }
  668.  
  669. static short check_TEPaste( eTeHandle hTE, short bold )
  670. {     eTePaste( hTE, bold );
  671.     if (mem_full) { mem_full = 0; return 1; }
  672.     return 0;
  673. }
  674.  
  675. static short check_TEKey( char c, eTeHandle hTE, short bold, EventRecord *event )
  676. {    eTeKey( hTE, c, (event->message & keyCodeMask) >> 8, event->modifiers, bold );
  677.     if (mem_full) { mem_full = 0; return 1; }
  678.     return 0;
  679. }
  680.  
  681. short getfullpath( 
  682.     short vRefNum,
  683.     long dirID,
  684.     Str255 fName,
  685.     char *Path,
  686.     short MaxLength,
  687.     short warn )
  688. {
  689.   char *p, *q;
  690.   long len;
  691.   CInfoPBRec block;
  692.   Str255 directoryName;
  693.  
  694.   p = &Path[MaxLength];
  695.   *--p = '\0';
  696.  
  697.   len = (unsigned char)fName[0];
  698.   p -= len;
  699.   if (p < Path) goto too_long;
  700.   BlockMove( &fName[1], p, len );
  701.  
  702.   block.dirInfo.ioNamePtr = directoryName;
  703.   block.dirInfo.ioDrParID = dirID;
  704.  
  705.   do
  706.   { block.dirInfo.ioVRefNum = vRefNum;
  707.     block.dirInfo.ioFDirIndex = -1;
  708.     block.dirInfo.ioDrDirID = block.dirInfo.ioDrParID;
  709.  
  710.     if (PBGetCatInfoSync( &block ) != noErr) return 0;
  711.     *--p = ':';
  712.     len = (unsigned char)directoryName[0];
  713.     p -= len;
  714.     if (p < Path) goto too_long;
  715.     BlockMove( &directoryName[1], p, len );
  716.   } while ( block.dirInfo.ioDrDirID != fsRtDirID );
  717.  
  718.   q = Path;
  719.   while (*p != '\0') *q++ = *p++;
  720.   *q = '\0';
  721.  
  722.   return (short )( q - Path );
  723.  
  724.   too_long:
  725.   if (warn) path_too_long_err( fName );
  726.   return 0;
  727. }
  728.  
  729. Point SFGwhere = { 90, 82 };
  730. Point SFPwhere = { 106, 104 };
  731.  
  732. short get_file(
  733.     FSSpec *fss,
  734.     short nbtypes,
  735.     SFTypeList ftypes
  736.    )
  737. {
  738.   StandardFileReply reply;
  739.  
  740.   eTePutScrap();
  741.   if (nbtypes == 0) nbtypes = -1;
  742.   if(gHasStdFile)
  743.   {
  744.     StandardGetFile( 0L, nbtypes, ftypes, &reply );
  745.     *fss = reply.sfFile;
  746.   }
  747.   else
  748.   {
  749.     SFReply reply2;
  750.     long procID;
  751.     SFGetFile( SFGwhere, "\p", 0L, nbtypes, ftypes, 0L, &reply2 );
  752.     if( (reply.sfGood = reply2.good) != 0 )
  753.     {
  754.       GetWDInfo( reply2.vRefNum, &fss->vRefNum, &fss->parID, &procID );
  755.       p_to_p( reply2.fName, fss->name );
  756.     }
  757.   }
  758.   eTeGetScrap();
  759.   return reply.sfGood;
  760. }
  761.  
  762. short put_file(
  763.     FSSpec *fss,
  764.     Str255 prompt,
  765.     Str255 deflt
  766.    )
  767. {
  768.   StandardFileReply reply;
  769.  
  770.   eTePutScrap();
  771.   if(gHasStdFile)
  772.   {
  773.     StandardPutFile( prompt, deflt, &reply );
  774.     *fss = reply.sfFile;
  775.   }
  776.   else
  777.   {
  778.     SFReply reply2;
  779.     long procID;
  780.     SFPutFile( SFPwhere, prompt, deflt, 0L, &reply2 );
  781.     if( (reply.sfGood = reply2.good) != 0 )
  782.     {
  783.       GetWDInfo( reply2.vRefNum, &fss->vRefNum, &fss->parID, &procID );
  784.       p_to_p( reply2.fName, fss->name );
  785.     }
  786.   }
  787.   eTeGetScrap();
  788.   return reply.sfGood;
  789. }
  790.  
  791. static short wptr_to_id( WindowPtr w )
  792. { short id;
  793.   for (id=0; id<MAX_NB_WINDOWS; id++)
  794.     if ((wind_table[id].in_use) && (wind_table[id].wptr == (WindowPtr )w)) return id;
  795.   return -1;
  796. }
  797.  
  798. static void setup_view( short id )
  799. { WindowPtr w = wind_table[id].wptr;
  800.   TeHANDLE hTE = wind_table[id].hTE;
  801.   Rect view = w->portRect;
  802.   view.top    += Border;
  803.   view.left   += Border;
  804.   view.bottom -= SBarWidth;
  805.   view.right  -= SBarWidth;
  806.   eTeNewView( hTE, &view );
  807. }
  808.  
  809. static void really_inval_msgrect( short w )
  810. { GrafPtr port = wind_table[w].wptr;
  811.   Rect r = port->portRect;
  812.   r.right -= (( r.right - r.left ) >> 1 ) + SBarWidth + 1;
  813.   r.top = r.bottom - SBarWidth + 1;
  814.   SetPort( port );
  815.   InvalRect( &r );
  816. }
  817. static void inval_msgrect( short w )
  818. { if ( showPosnP ) wind_table[w].needs_inval_ticks = TickCount();
  819. }
  820.  
  821. #if LiveScrollP
  822. // live scrolling -- 960716 e
  823. static ControlActionUPP vSBarThumbActionProcUPP;
  824. static ControlActionUPP hSBarThumbActionProcUPP;
  825. static ControlHandle globalScroller;
  826. static Rect globalScrollCtlRect;
  827. static eTeHandle globalScrollhTE;
  828. static short globalScrollCntlCode;
  829. static short globalScrollMin;
  830. static short globalScrollMax;
  831. static short globalScrollSize;
  832. static void vSBarThumbActionProc( void )
  833. {
  834.   EventRecord event;
  835.   short cntlVal;
  836.   OSEventAvail(0L, &event); // a NULL event with the global mouse location
  837.   if(    event.where.h > globalScrollCtlRect.left
  838.       && event.where.h < globalScrollCtlRect.right
  839.       // && event.where.v > globalScrollCtlRect.top - 24
  840.       // && event.where.v < globalScrollCtlRect.bottom + 24
  841.     )
  842.   { // in the scrollbar...
  843.     cntlVal = ((event.where.v - globalScrollCtlRect.top) * globalScrollSize)
  844.                 / (globalScrollCtlRect.bottom - globalScrollCtlRect.top);
  845.     if( cntlVal < globalScrollMin ) cntlVal = globalScrollMin;
  846.     if( cntlVal > globalScrollMax ) cntlVal = globalScrollMax;
  847.     if( cntlVal != globalScrollCntlCode )
  848.     {
  849.       SetPort( (**globalScrollhTE).macPort );
  850.       ClipRect( &(**globalScrollhTE).macPort->portRect );
  851.       SetControlValue( globalScroller, cntlVal );
  852.       eTeScroll( globalScrollhTE, 0, cntlVal - globalScrollCntlCode, TRUE );
  853.       globalScrollCntlCode = cntlVal;
  854.       // leave the window clipped to exclude the scrollbar
  855.       //  so TrackControl's drawing is obscured
  856.     }
  857.   }
  858. }
  859. static void hSBarThumbActionProc( void )
  860. {
  861.   EventRecord event;
  862.   short cntlVal;
  863.   OSEventAvail(0L, &event); // a NULL event with the global mouse location
  864.   if(    event.where.v > globalScrollCtlRect.top
  865.       && event.where.v < globalScrollCtlRect.bottom
  866.       // && event.where.h > globalScrollCtlRect.left - 24
  867.       // && event.where.h < globalScrollCtlRect.right + 24
  868.     )
  869.   { // in the scrollbar...
  870.     cntlVal = ((event.where.h - globalScrollCtlRect.left) * globalScrollSize)
  871.                 / (globalScrollCtlRect.right - globalScrollCtlRect.left);
  872.     if( cntlVal < globalScrollMin ) cntlVal = globalScrollMin;
  873.     if( cntlVal > globalScrollMax ) cntlVal = globalScrollMax;
  874.     if( cntlVal != globalScrollCntlCode )
  875.     {
  876.       SetPort( (**globalScrollhTE).macPort );
  877.       ClipRect( &(**globalScrollhTE).macPort->portRect );
  878.       SetControlValue( globalScroller, cntlVal );
  879.       eTeScroll( globalScrollhTE, cntlVal - globalScrollCntlCode, 0, TRUE );
  880.       globalScrollCntlCode = cntlVal;
  881.       // leave the window clipped to exclude the scrollbar
  882.       //  so TrackControl's drawing is obscured
  883.     }
  884.   }
  885. }
  886. static ControlActionUPP init_live_scroll( eTeHandle hTE, ControlHandle theControl )
  887. {
  888.   globalScrollhTE = hTE;
  889.   globalScroller = theControl;
  890.   globalScrollCntlCode = GetControlValue( theControl );
  891.   globalScrollCtlRect = (**theControl).contrlRect;
  892.   LocalToGlobal( (Point *)&(globalScrollCtlRect.top) );      /* topLeft  */
  893.   LocalToGlobal( (Point *)&(globalScrollCtlRect.bottom) );   /* botRight */
  894.   globalScrollMin = GetControlMinimum( theControl );
  895.   globalScrollMax = GetControlMaximum( theControl );
  896.   globalScrollSize = globalScrollMax - globalScrollMin + 1;
  897.   if( (**theControl).contrlRect.left < (**theControl).contrlRect.top ) 
  898.   { // horizontal
  899.     globalScrollCtlRect.left += 24; // arrows
  900.     globalScrollCtlRect.right -= 24;
  901.     globalScrollCtlRect.top -= 2; // mouse slop
  902.     globalScrollCtlRect.bottom += 2;
  903.     if( hSBarThumbActionProcUPP == NULL )
  904.       // no!: hSBarThumbActionProcUPP = NewControlActionProc(hSBarThumbActionProc);
  905.       hSBarThumbActionProcUPP = 
  906.        (ControlActionUPP) NewRoutineDescriptor((ProcPtr)(hSBarThumbActionProc),
  907.                                    kPascalStackBased, GetCurrentArchitecture());
  908.     return hSBarThumbActionProcUPP;
  909.   }
  910.   else
  911.   { // vertical
  912.     globalScrollCtlRect.top += 24; // arrows
  913.     globalScrollCtlRect.bottom -= 24;
  914.     globalScrollCtlRect.left -= 2; // mouse slop
  915.     globalScrollCtlRect.right += 2;
  916.     if( vSBarThumbActionProcUPP == NULL )
  917.       // no!: vSBarThumbActionProcUPP = NewControlActionProc(vSBarThumbActionProc);
  918.       vSBarThumbActionProcUPP = 
  919.        (ControlActionUPP) NewRoutineDescriptor((ProcPtr)(vSBarThumbActionProc),
  920.                                    kPascalStackBased, GetCurrentArchitecture());
  921.     return vSBarThumbActionProcUPP;
  922.   }
  923. }
  924. #endif // LiveScrollP
  925.  
  926. static void content( short id, EventRecord *event )
  927. { WindowPtr w = wind_table[id].wptr;
  928.   eTeHandle hTE = wind_table[id].hTE;
  929.   short cntlCode;
  930.   ControlHandle theControl;
  931.   ChPos oldCaret;
  932.  
  933.   SetPort( w );
  934.   ClipRect( &w->portRect );
  935.   GlobalToLocal( &event->where );
  936.   if ((cntlCode = FindControl( event->where, w, &theControl )) == 0 )
  937.   { if (PtInRect( event->where, &(**hTE).viewRect ))
  938.     { oldCaret = (**hTE).caretChPos;
  939.       eTeClick( hTE, event->where, event->modifiers, event->when );
  940.       if ( *(long *)&oldCaret != *(long *)&(**hTE).caretChPos ) inval_msgrect( id );
  941.     }
  942.   }
  943.   else if (cntlCode == kControlIndicatorPart) // inThumb
  944.   {
  945. #if LiveScrollP
  946.     TrackControl( theControl, event->where, init_live_scroll( hTE, theControl ) );
  947.     SetControlValue( theControl, globalScrollCntlCode );
  948. #else
  949.     cntlCode = GetControlValue( theControl );
  950.     TrackControl( theControl, event->where, 0L );
  951.     if ( ( cntlCode = GetControlValue( theControl ) - cntlCode ) != 0 )
  952.         if( (**theControl).contrlRect.left < (**theControl).contrlRect.top )
  953.             eTeScroll( hTE, cntlCode, 0, TRUE );
  954.         else
  955.             eTeScroll( hTE, 0, cntlCode, TRUE );
  956. #endif
  957.   }
  958.   else
  959.     TrackControl( theControl, event->where, (void *)-1L );
  960. }
  961.  
  962. static void update_window( short w )
  963. { GrafPtr port = wind_table[w].wptr;
  964.   Rect r = port->portRect;
  965.   Str255 tStr;
  966.   eTeHandle hTE;
  967.   r.right -= (( r.right - r.left ) >> 1 ) + SBarWidth + 1;
  968.   r.top = r.bottom - SBarWidth;
  969.   SetPort( port );
  970.   ClipRect( &port->portRect );
  971.   BeginUpdate( port );
  972.   EraseRect( &port->portRect );
  973.   DrawControls( port );
  974.   DrawGrowIcon( port );
  975.   EraseRect( &r );
  976.   MoveTo( r.left, r.top );
  977.   LineTo( r.right, r.top );
  978. #ifdef USE_eTe_debug
  979.   NumToString( eTeTextLength( wind_table[w].hTE ), tStr);
  980.   MoveTo( r.left + 4, r.bottom - 4 );
  981.   ClipRect( &r );
  982.   DrawString( (ConstStr255Param )tStr );
  983. #else
  984.   if ( showPosnP )
  985.   { hTE = wind_table[w].hTE;
  986.     MoveTo( r.left + 4, r.bottom - 4 );
  987.     ClipRect( &r );
  988.     NumToString( (long )(**hTE).caretChPos.v+1, tStr);
  989.     DrawString( (ConstStr255Param )tStr );
  990.     DrawString( "\p:" );
  991.     NumToString( (long )(**hTE).caretChPos.h, tStr);
  992.     DrawString( (ConstStr255Param )tStr );
  993.   }
  994. #endif
  995.   eTeUpdate( wind_table[w].hTE );
  996.   EndUpdate( port );
  997. }
  998.  
  999. static void grow_window( short id, Point p )
  1000. { WindowPtr w = wind_table[id].wptr;
  1001.   long result;
  1002.   Rect r;
  1003.   
  1004.   SetPort( w );
  1005.  
  1006.   /* 16Sep92  e  increase min size for H scroll bar
  1007.   SetRect(&r, 80, 80, screenBits.bounds.right, screenBits.bounds.bottom); */
  1008.   /* 13Oct92  e  per: bernard@sigi.cs.colorado.edu
  1009.   SetRect(&r, 150, 80, screenBits.bounds.right, screenBits.bounds.bottom); */
  1010.   r = (**GetGrayRgn()).rgnBBox;
  1011.   r.top = 80;
  1012.   r.left = 150;
  1013.   /*  13Oct92  e  */
  1014.   result = GrowWindow( w, p, &r );
  1015.   if (result == 0) return;
  1016.   SizeWindow( w, LoWord(result), HiWord(result), 1);
  1017.  
  1018.   InvalRect(&w->portRect);
  1019.   setup_view( id );
  1020.   HideControl( wind_table[id].vscroll );
  1021.   MoveControl( wind_table[id].vscroll, w->portRect.right - SBarWidth, w->portRect.top-1);
  1022.   SizeControl( wind_table[id].vscroll, SBarWidth+1, w->portRect.bottom - w->portRect.top-(SBarWidth-2));
  1023.   HideControl( wind_table[id].hscroll );
  1024.   MoveControl( wind_table[id].hscroll,
  1025.                   w->portRect.right-((w->portRect.right-w->portRect.left)>>1),
  1026.                   w->portRect.bottom - SBarWidth);
  1027.   SizeControl( wind_table[id].hscroll,
  1028.                   ((w->portRect.right-w->portRect.left)>>1)-(SBarWidth-1),
  1029.                   SBarWidth+1);
  1030.   ShowControl( wind_table[id].hscroll );
  1031.   ValidRect(&(*wind_table[id].hscroll)->contrlRect );
  1032.   ShowControl( wind_table[id].vscroll );
  1033.   ValidRect(&(*wind_table[id].vscroll)->contrlRect );
  1034.   update_window( id );
  1035.   /* dunno (sometimes appropriate, sometimes not)... eTeShowCaret( wind_table[id].hTE ); */
  1036. }
  1037.  
  1038. static void put_input( short id, char *ptr, long len, short cr, short flush, short freshline )
  1039. { if (wind_table[id].in_use)
  1040.   { long len1;
  1041.     register long len2 = (wind_table[id].len - wind_table[id].pos);
  1042.     register char *buf, *p1, *p2;
  1043.     if ((len2 < 0) || flush) len2 = 0;
  1044.     len1 = ((cr)?1:0) + len2 + (long)len;
  1045.     buf = NewPtr( len1 );
  1046.     if (buf == NULL) { SysBeep(10); return; }
  1047.     p1 = buf;
  1048.     p2 = wind_table[id].buf + wind_table[id].pos;
  1049.     while (len2 > 0) { *p1++ = *p2++; len2--; }
  1050.     p2 = ptr;
  1051.     while (len > 0) { *p1++ = *p2++; len--; }
  1052.     if (cr) *p1++ = '\r';
  1053.     if (wind_table[id].buf != NULL) DisposePtr( wind_table[id].buf );
  1054.     wind_table[id].buf = buf;
  1055.     wind_table[id].pos = 0;
  1056.     wind_table[id].len = len1;
  1057.     if (freshline)
  1058.     { eTeHandle hTE = wind_table[id].hTE;
  1059.       if ( (**hTE).caretChPos.h > 0 )
  1060.         check_TEInsert( "\r", 1L, hTE, 0 );
  1061.       (**hTE).writeChPos = (**hTE).caretChPos;
  1062.       eTeShowCaret( hTE );
  1063.     }
  1064.   }
  1065. }
  1066.  
  1067. void put_input_str (char *text)
  1068. {
  1069.   check_TEInsert( text, strlen(text), wind_table[interaction_id].hTE, 1 );
  1070.   put_input( interaction_id, text, strlen (text), 1, 0, 1 );
  1071. }
  1072.  
  1073. static void handle_interrupt()
  1074. { interrupted = 1;
  1075. }
  1076.  
  1077. static short open_file( short id, short for_output, short txt, short *io )
  1078. { short refnum;
  1079.   short file_existed = 1;
  1080.   OSErr err;
  1081.   
  1082.   if (for_output)
  1083.   {
  1084.     err = FSpCreate( &wind_table[id].fss, CREATOR, txt ? 'TEXT' : 'DATA', smSystemScript );
  1085.     file_existed = (err == dupFNErr);
  1086.     if ((err != noErr) && !file_existed)
  1087.     { *io = err;  return -1; }
  1088.   }
  1089.   err = FSpOpenDF( &wind_table[id].fss, for_output ? fsRdWrPerm : fsRdPerm, &refnum );
  1090.   if (err != noErr)
  1091.   { *io = err;
  1092.     if (for_output && !file_existed)
  1093.       FSpDelete( &wind_table[id].fss );
  1094.     return -1;
  1095.   }
  1096.   *io = for_output ? SetEOF( refnum, 0L ) : noErr;
  1097.   return refnum;
  1098. }
  1099.  
  1100. static short close_file( short refnum, short *io )
  1101. { *io = FSClose( refnum );
  1102.   return (*io != noErr);
  1103. }
  1104.  
  1105. static short read_file( short id, long line, long chr, long sesz )
  1106. { TeHANDLE hTE = wind_table[id].hTE;
  1107.   short refnum;
  1108.   short io, io2;
  1109.   long pos = 0;
  1110.   short beep = 0;
  1111.   long size, count;
  1112.   ChPos chPos;
  1113.   Handle hData;
  1114.   
  1115.   if ( line > 32768 )
  1116.   { te_limit_err();
  1117.     return 0;
  1118.   }
  1119.   chPos.v = (line==0) ? 0 : line-1;
  1120.   chPos.h = (line==0) ? 0 : chr;
  1121.  
  1122.   SelectWindow( wind_table[id].wptr );
  1123.  
  1124.   if (wind_table[id].dirty)
  1125.     if (!discard_changes( id )) return 0;
  1126.  
  1127.   refnum = open_file( id, 0, 1, &io );
  1128.   if (refnum == -1)
  1129.   { io_err( io );
  1130.     return 0;
  1131.   }
  1132.  
  1133.   // eTeSetTextPtr( hTE, empty_buffer, 1L ); why!? 22Jul96 e
  1134.   io = GetEOF(refnum, &size);
  1135.   if( io == noErr )    {
  1136.     if( (hData = NewHandle( size + 1 )) != 0 )
  1137.     {    HLock( hData );
  1138.         count = size;
  1139.         io = FSRead( refnum, &count, *hData );
  1140.         HUnlock( hData );
  1141.         if( ( io != noErr ) || ( count != size ) )
  1142.         {    DisposeHandle( hData );
  1143.             if ( io == noErr ) io = ioErr;
  1144.             /* io_err( io ); will happen */
  1145.             /* added these next lines 7Jul92  e */
  1146.             mem_full = 0;
  1147.               // eTeSetTextPtr( hTE, empty_buffer, 1L ); why!? 22Jul96 e
  1148.         }
  1149.         else
  1150.         {    ((char *)*hData)[size] = '\0';
  1151.             io = eTeSetTextHandleDetabify( hTE, hData, prefTabs );
  1152.             if ( io == noErr )
  1153.             {   count = eTeChPosToOffset( hTE, chPos );
  1154.                 eTeSetSelect( hTE, count, count + sesz );
  1155.                 eTeShowCaret( hTE );
  1156.             }
  1157.             else
  1158.             {    DisposeHandle( hData );
  1159.                 /* io_err( io ); will happen */
  1160.                 /* added these next lines 7Jul92  e */
  1161.                 mem_full = 0;
  1162.                   eTeSetTextPtr( hTE, empty_buffer, 1L ); // ok
  1163.             }
  1164.           }
  1165.       }
  1166.       else
  1167.       { mem_full = 0; io = mFulErr; }
  1168.   }
  1169.  
  1170.   if (close_file( refnum, &io2 ) || ((io != eofErr) && (io != noErr)))
  1171.   { if ((io != eofErr) && (io != noErr)) io_err( io ); else io_err( io2 );
  1172.       // eSmudgeWindow( id ); why!? 22Jul96 e
  1173.       return 0;
  1174.   }
  1175.   /*  why!? 22Jul96 e
  1176.   if (io != noErr)
  1177.       eSmudgeWindow( id );
  1178.   else */
  1179.       eUnSmudgeWindow( id, hTE );
  1180.   return (io == noErr);
  1181. }
  1182.  
  1183. static void write_file( short id )
  1184. { TeHANDLE hTE = wind_table[id].hTE;
  1185.   short refnum;
  1186.   short io, io2;
  1187.   long count;
  1188.  
  1189.   refnum = open_file( id, 1, 1, &io );
  1190.   if (refnum == -1)
  1191.   { io_err( io );
  1192.     return;
  1193.   }
  1194.  
  1195.   count = eTeTextLength( hTE );
  1196.   io = FSWrite( refnum, &count, *((**hTE).hText) );
  1197.   
  1198.   /* FlushVol added 19Apr93  e  */
  1199.   if ( io == noErr )
  1200.   { io = GetVRefNum( refnum, &io2 );
  1201.       if ( io == noErr )
  1202.         io = FlushVol( 0L, io2 );
  1203.   }
  1204.   
  1205.   if (close_file( refnum, &io2 ) || (io != noErr))
  1206.   { if (io != noErr) io_err( io ); else io_err( io2 );
  1207.     return;
  1208.   }
  1209.   
  1210.   FlushVol( 0L, wind_table[id].fss.vRefNum );
  1211.  
  1212.   eUnSmudgeWindow( id, hTE );
  1213. }
  1214.  
  1215. short edit( FSSpec *fss, long line, long chr, long size )
  1216. { short id;
  1217.   Str255 pname;
  1218.   int len = getfullpath( fss->vRefNum, fss->parID, fss->name, (char *)&pname[1], 254, 1 );
  1219.   pname[0] = len;
  1220.   
  1221.   if (len != 0)
  1222.   { for (id=0; id<MAX_NB_WINDOWS; id++)
  1223.       if WINDOW_OWNS_FILE_P( id, fss )
  1224.         break;
  1225.   }
  1226.   else
  1227.     id = MAX_NB_WINDOWS;
  1228.  
  1229.   if (id == MAX_NB_WINDOWS) id = wind_open( pname, FALSE, TRUE, FALSE );
  1230.   if (id < 0)
  1231.     wind_err();
  1232.   else
  1233.   { wind_table[id].fss = *fss;
  1234.     wind_table[id].is_file = 2;
  1235.     supress_mem_full_dialog = 1;
  1236.     if ( read_file( id, line, chr, size ) || wind_table[id].dirty )
  1237.         select_and_show( wind_table[id].wptr );
  1238.     else
  1239.     {
  1240.         wind_close( id );
  1241.         id = -1;
  1242.     }
  1243.     supress_mem_full_dialog = 0;
  1244.   }
  1245.   return id;
  1246. }
  1247.  
  1248. void save_as( short id, FSSpec *fss )
  1249. { short i;
  1250.   Str255 ppath;
  1251.   int len = getfullpath( fss->vRefNum, fss->parID, fss->name, (char *)&ppath[1], 254, 1 );
  1252.   ppath[0] = len;
  1253.  
  1254.   for (i=0; i<MAX_NB_WINDOWS; i++)
  1255.     if WINDOW_OWNS_FILE_P( i, fss )
  1256.     { already_open_err( ppath );
  1257.       return;
  1258.     }
  1259.   wind_table[id].fss = *fss;
  1260.   if (wind_table[id].is_file != 0)
  1261.   { // don't make console into a file
  1262.     wind_table[id].is_file = 2;
  1263.     SetWTitle( wind_table[id].wptr, ppath );
  1264.   }
  1265.   if ( id != interaction_id )
  1266.   { delWindMenuItem( id );
  1267.     addWindMenuItem( id );
  1268.   }
  1269.   write_file( id );
  1270. }
  1271.  
  1272. static void wind_quit(void)
  1273. { short id;
  1274.   for (id=MAX_NB_WINDOWS-1; id>=0; id--)
  1275.   { if (wind_table[id].in_use && wind_table[id].is_file && wind_table[id].dirty)
  1276.     { if (!discard_changes( id )) gDoQuit = 0;
  1277.       else wind_close( id );
  1278.     }
  1279.   }
  1280.   eTePutScrap();
  1281. }
  1282.  
  1283. static void handle_close( short id )
  1284. { if (wind_table[id].is_file)
  1285.   { if ((wind_table[id].dirty) && (!discard_changes( id ))) return;
  1286.     wind_close( id );
  1287.   }
  1288. }
  1289.  
  1290. static char upcase( char c )
  1291. { if( c >= 'a' &&  c <= 'z' ) return c - 0x20;
  1292.   else return c;
  1293. }
  1294.  
  1295. Boolean find_next( short id )
  1296. { TeHANDLE hTE = wind_table[id].hTE;
  1297.   char *txt = *((**hTE).hText);
  1298.   long pos = eTeChPosToOffset( hTE, (**hTE).selActive ? (**hTE).selEnd : (**hTE).caretChPos );
  1299.   register char *start = txt + pos - 1;
  1300.   register short len = (unsigned char)find_string[0];
  1301.   register char *end = txt + eTeTextLength( hTE ) - len;
  1302.   register short i;
  1303.   Boolean again = TRUE;
  1304.   Str255 ci_string;
  1305.   if ( len == 0 ) goto not_found;
  1306.   if( find_ci )
  1307.   { for (i=len; i>0; i--)
  1308.       ci_string[i] = upcase( find_string[i] );
  1309.     /* ci_string[0] = len; -- not used */
  1310.   }
  1311.   find_begin:
  1312.   while (start < end)
  1313.   { if( find_ci )
  1314.     { for (i=len; i>0; i--)
  1315.         if( upcase( start[i] ) != (char )ci_string[i] ) goto next_pos;
  1316.     }
  1317.     else
  1318.     { for (i=len; i>0; i--)
  1319.         if (start[i] != (char )find_string[i]) goto next_pos;
  1320.     }
  1321.     eTeSetSelect( hTE, (long)(start-txt+1), (long)(start-txt+1+len) );
  1322.     return 1;
  1323.     next_pos:
  1324.     start++;
  1325.   }
  1326.   if( find_wrap && again ) 
  1327.   { start = txt;
  1328.     end = start + pos - len;
  1329.     again = FALSE;
  1330.     goto find_begin;
  1331.   }
  1332. not_found:
  1333.   SysBeep(10);
  1334.   return 0;
  1335. }
  1336.  
  1337. void replace_next( short id )
  1338. { TeHANDLE hTE = wind_table[id].hTE;
  1339.   if ( ! (**hTE).selActive )
  1340.     SysBeep(10);
  1341.   else
  1342.   { long len = (unsigned char)replace_string[0];
  1343.     check_TEInsert( ((char *)replace_string)+1, len, hTE, wind_table[id].bold_input );
  1344.     find_next( id );
  1345.     eTeShowCaret( hTE );
  1346.   }
  1347. }
  1348.  
  1349. void replace_all( short id )
  1350. { TeHANDLE hTE = wind_table[id].hTE;
  1351.   long len = (unsigned char)replace_string[0];
  1352.   
  1353.   if ( (**hTE).selActive )
  1354.   { long pos = eTeChPosToOffset( hTE, (**hTE).selStart );
  1355.     eTeSetSelect( hTE, pos, pos );
  1356.   }
  1357.   while ( find_next( id ) )
  1358.     check_TEInsert( ((char *)replace_string)+1, len, hTE, wind_table[id].bold_input );
  1359.   eTeShowCaret( hTE );
  1360. }
  1361.  
  1362. static void find_dialog( short id )
  1363. { DialogPtr dp;
  1364.   short i, s;
  1365.   Handle h;
  1366.   Rect r;
  1367.   eTePutScrap();
  1368.   ParamText( "\pFind:", "\pReplace with:", "\p", "\p" );
  1369.   dp = GetNewDialog( find_dlogID, 0L, (WindowPtr)-1L );
  1370.   if (dp == NULL) return;
  1371.   GetDialogItem( dp, 3, &i, &h, &r );
  1372.   SetDialogItemText( h, find_string );
  1373.   GetDialogItem( dp, 5, &i, &h, &r );
  1374.   SetDialogItemText( h, replace_string );
  1375.   GetDialogItem( dp, 7, &i, &h, &r);
  1376.   SetControlValue( (ControlHandle )h, find_wrap );
  1377.   GetDialogItem( dp, 8, &i, &h, &r);
  1378.   SetControlValue( (ControlHandle )h, find_ci );
  1379.   SelectDialogItemText( dp, 3, 0, find_string[0] );
  1380.   SetCursor( &qd.arrow );
  1381.   do
  1382.   { ModalDialog( 0L, &s );
  1383.     switch( s )
  1384.     { case 1:
  1385.         GetDialogItem( dp, 3, &i, &h, &r );
  1386.         GetDialogItemText( h, find_string );
  1387.         GetDialogItem( dp, 5, &i, &h, &r );
  1388.         GetDialogItemText( h, replace_string );
  1389.         GetDialogItem( dp, 7, &i, &h, &r);
  1390.         find_wrap = GetControlValue( (ControlHandle )h );
  1391.         GetDialogItem( dp, 8, &i, &h, &r);
  1392.         find_ci   = GetControlValue( (ControlHandle )h );
  1393.         break;
  1394.       case 7:
  1395.       case 8:
  1396.         GetDialogItem( dp, s, &i, &h, &r );
  1397.         SetControlValue( (ControlHandle )h, GetControlValue( (ControlHandle )h ) ^ 1 );
  1398.         break;
  1399.     }
  1400.   } while( s != 1 && s != 2 );
  1401.   CloseDialog( dp );
  1402.   if( s == 1 ) find_next( id );
  1403.   eTeGetScrap();
  1404. }
  1405.  
  1406. static void handle_pgsetup( short id )
  1407.   TeHANDLE hTE = wind_table[id].hTE;
  1408.   SetCursor(&qd.arrow);
  1409.   PageSetupDialog( hTE );
  1410. }
  1411.  
  1412. static void handle_print( short id )
  1413.   OSErr err;
  1414.   TeHANDLE hTE = wind_table[id].hTE;
  1415.   
  1416.   SetCursor(&qd.arrow);
  1417.   err = noErr;
  1418.   if ( ! (**hTE).hPrint )
  1419.     err = PageSetupDialog( hTE );
  1420.   if( ! err )
  1421.   {    err = eTePrint( hTE, true, true, wind_table[id].fss.name );
  1422.     eTePrint( nil, false, false, nil );
  1423.   }
  1424.   if( err && err != userCanceledErr && err != iPrAbort ) io_err( err );
  1425. }
  1426.  
  1427. static short handle_menu( long result, short id )
  1428. { short theItem, theMenu, m, w;
  1429.   MenuHandle mh;
  1430.   Str255 name;
  1431.  
  1432.   theItem = LoWord( result );
  1433.   theMenu = HiWord( result );
  1434.   if (theMenu == 0) return 1;
  1435.   mh = GetMenuHandle( theMenu );
  1436.   for (m=appleM; m<=windowsM; m++) if (menus[m] == mh) break;
  1437.   switch (m)
  1438.   { case appleM:
  1439.       if (theItem == 1)
  1440.       { eDoDialog(0);    /* about */
  1441.       }
  1442.       else if (theItem == 2)
  1443.         ;
  1444.       else
  1445.       { GetMenuItemText( menus[appleM], theItem, name );
  1446.         OpenDeskAcc( name );
  1447.       }
  1448.       break;
  1449.     case fileM: 
  1450.       switch (theItem)
  1451.       { case newCommand:
  1452.         { short w = wind_open( "\pUntitled", TRUE, TRUE, FALSE );
  1453.           if (w < 0)
  1454.             wind_err();
  1455.           else
  1456.             wind_table[w].is_file = 1;
  1457.           break;
  1458.         }
  1459.         case openCommand:
  1460.         { short i;
  1461.           for (i=0; i<MAX_NB_WINDOWS; i++) if (!wind_table[i].in_use) break;
  1462.           if (i == MAX_NB_WINDOWS)
  1463.             wind_err();
  1464.           else
  1465.           { FSSpec fss;
  1466.             SFTypeList tl;
  1467.               tl[0] = 'TEXT';
  1468.             if (get_file( &fss, 1, tl ))
  1469.               edit( &fss, 0L, 0L, 0L );
  1470.           }
  1471.           break;
  1472.         }
  1473.         case closeCommand:
  1474.           if (id >= 0)
  1475.             handle_close( id );
  1476.           break;
  1477.         case saveCommand:
  1478.           if (id >= 0)
  1479.             if (wind_table[id].is_file == 2 )
  1480.             { write_file( id );
  1481.               break;
  1482.             }
  1483.         case saveasCommand:
  1484.           if (id >= 0)
  1485.           { FSSpec fss;
  1486.             if (put_file( &fss, "\pSave as:", wind_table[id].fss.name ))
  1487.               save_as( id, &fss );
  1488.           }
  1489.           break;
  1490.         case revertCommand:
  1491.           if (id >= 0)
  1492.             read_file( id, 0L, 0L, 0L );
  1493.           break;
  1494.         case pgsetupCommand:
  1495.           if (id >= 0)
  1496.             handle_pgsetup( id );
  1497.           break;
  1498.         case printCommand:
  1499.           if (id >= 0)
  1500.             handle_print( id );
  1501.           break;
  1502.         case quitCommand:
  1503.           gDoQuit = 1;
  1504.           wind_quit();
  1505.           if (gDoQuit) os_quit();
  1506.           break;
  1507.       }
  1508.       break;
  1509.     case editM: 
  1510.       if (id < 0)
  1511.         SystemEdit(theItem-1);
  1512.       else
  1513.       { TeHANDLE hTE = wind_table[id].hTE;
  1514.         switch (theItem)
  1515.         { case undoCommand:
  1516.             eTeUndo( hTE );
  1517.             eMaybeSmudgeWindow( id, hTE );
  1518.             break;
  1519.           case cutCommand:
  1520.             check_TECut( hTE );
  1521.             eMaybeSmudgeWindow( id, hTE );
  1522.             break;
  1523.           case copyCommand:
  1524.             check_TECopy( hTE );
  1525.             break;
  1526.           case pasteCommand:
  1527.             check_TEPaste( hTE, wind_table[id].bold_input );
  1528.             eMaybeSmudgeWindow( id, hTE );
  1529.             break;
  1530.           case clearCommand:
  1531.             eTeDelete( hTE );
  1532.             eMaybeSmudgeWindow( id, hTE );
  1533.             break;
  1534.           case selAllCommand:
  1535.             eTeSetSelect( hTE, 0, eTeTextLength( hTE ));
  1536.             break;
  1537.           case stylesCommand:
  1538.             eStyleDlg( hTE );
  1539.               break;
  1540.           case showPosnCommand:
  1541.               showPosnP ^= 1;
  1542.             CheckItem( menus[editM], showPosnCommand, showPosnP );
  1543.             for (w=0; w<MAX_NB_WINDOWS; w++)
  1544.                 if (wind_table[w].in_use) really_inval_msgrect( w );
  1545.               break;
  1546.           default: ;
  1547.         }
  1548.         eTeShowCaret( hTE );
  1549.       }
  1550.       break;
  1551.     case findM:
  1552.       if (id >= 0)
  1553.       { TeHANDLE hTE = wind_table[id].hTE;
  1554.         switch (theItem)
  1555.         { case findCommand:
  1556.             find_dialog( id );
  1557.             break;
  1558.           case againCommand:
  1559.             find_next( id );
  1560.             break;
  1561.           case replaceCommand:
  1562.             replace_next( id );
  1563.             eMaybeSmudgeWindow( id, hTE );
  1564.             break;
  1565.           case fEnterCommand:
  1566.           { long sel_sta, sel_end, sel_len = 0;
  1567.             if( (**hTE).selActive ) {
  1568.               sel_sta = eTeChPosToOffset( hTE, (**hTE).selStart );
  1569.               sel_end = eTeChPosToOffset( hTE, (**hTE).selEnd );
  1570.               sel_len = sel_end - sel_sta;
  1571.             }
  1572.             if (sel_len > 0)
  1573.             { if( sel_len > 255 ) sel_len = 255;
  1574.               buf_to_p( (unsigned short)sel_len, *((**hTE).hText) + sel_sta, find_string );
  1575.             }
  1576.             else
  1577.               SysBeep( 1 );
  1578.             break;
  1579.           }
  1580.           case replaceAllCommand:
  1581.             replace_all( id );
  1582.             eMaybeSmudgeWindow( id, hTE );
  1583.             break;
  1584.  
  1585. #if ( CREATOR == 'Moml' )
  1586.  
  1587.           case findErrorCommand:        /* thanks: 26Aug93 PSC */
  1588.           { long sel_sta, sel_end, sel_len = 0;
  1589.             if( (**hTE).selActive ) {
  1590.               sel_sta = eTeChPosToOffset( hTE, (**hTE).selStart );
  1591.               sel_end = eTeChPosToOffset( hTE, (**hTE).selEnd );
  1592.               sel_len = sel_end - sel_sta;
  1593.               sel_len = sel_len > 255 ? 255 : sel_len;
  1594.             }
  1595.             if (sel_len > 0)
  1596.             { extern void find_error(char *);
  1597.               char selection[256];
  1598.               strncpy( selection, (char *)*((**hTE).hText) + sel_sta, sel_len );
  1599.               selection[sel_len] = 0;
  1600.               find_error(selection);
  1601.             }
  1602.             else
  1603.               SysBeep( 1 );
  1604.             break;
  1605.           }
  1606. #endif
  1607.  
  1608.         }
  1609.         eTeShowCaret( hTE );
  1610.       }
  1611.       break;
  1612.     case commandM: 
  1613.       switch (theItem)
  1614.       { case interruptCommand:
  1615.           HiliteMenu(0);
  1616.           handle_interrupt();
  1617.           return 0;
  1618.         default:
  1619.           eDoCommand(theItem);
  1620.           break;
  1621.       }
  1622.       break;
  1623.     case windowsM:
  1624.       switch(theItem)
  1625.       { case 1:
  1626.           select_and_show( wind_table[interaction_id].wptr );
  1627.           break;
  1628.         case 2: /* blank line */
  1629.           break;
  1630.         default:
  1631.           theItem -= fustItem;
  1632.           if(theItem < qWindItems)
  1633.             SelectWindow( wind_table[itemtowindid[theItem]].wptr );
  1634.           break;
  1635.       }
  1636.       break;
  1637.    }
  1638.   HiliteMenu(0);
  1639.   return 1;
  1640. }
  1641.  
  1642. static short do_tasks()
  1643. { short w;
  1644.   register short i;
  1645.   short men;
  1646.   EventRecord event;
  1647.   Rect r;
  1648.   RgnHandle rgn;
  1649.   long ticks = LMGetTicks();
  1650.  
  1651.   for (i=0; i<MAX_NB_WINDOWS; i++)
  1652.     if (wind_table[i].in_use)
  1653.     { if (wind_table[i].out_len > 0)
  1654.       { HLock( wind_table[i].out_buf );
  1655.         check_TEWrite( *wind_table[i].out_buf, (long)wind_table[i].out_len, wind_table[i].hTE, 0 );
  1656.         HUnlock( wind_table[i].out_buf );
  1657.         wind_table[i].out_len = 0;
  1658.       }
  1659.       /* display caret position */
  1660.       if ( wind_table[i].needs_inval_ticks != 0
  1661.            && ( wind_table[i].needs_inval_ticks + 15 ) < ticks )
  1662.       { really_inval_msgrect( i );
  1663.         wind_table[i].needs_inval_ticks = 0;
  1664.       }
  1665.     }
  1666.   w = wptr_to_id( FrontWindow() );
  1667.   if ( (!gInBackground) && (w >= 0) )
  1668.   { Cursor *curs;
  1669.     OSEventAvail(0L, &event); /* This returns a NULL event with the global mouse location */
  1670.     if( gCursRgnOK && PtInRgn( event.where, gCursorRgn ) )
  1671.     { /* punt... SetCursor( current_cursor ); */
  1672.     }
  1673.     else
  1674.     { SetPort( (GrafPtr)wind_table[w].wptr );
  1675.       r = (**wind_table[w].hTE).viewRect;
  1676.       LocalToGlobal((Point *)&(r.top));      /* topLeft  */
  1677.       LocalToGlobal((Point *)&(r.bottom));   /* botRight */
  1678.       if (PtInRect( event.where, &r ))
  1679.       { curs = &ibeam_cursor;
  1680.         RectRgn(gCursorRgn, &r);
  1681.       }
  1682.       else
  1683.       { curs = &qd.arrow;
  1684.         SetRectRgn(gCursorRgn, -32768, -32768, 32766, 32766);
  1685.         rgn = NewRgn();
  1686.         RectRgn(rgn, &r);
  1687.         DiffRgn(gCursorRgn, rgn, gCursorRgn);
  1688.         DisposeRgn(rgn);
  1689.       }
  1690.       if (!gCursRgnOK || current_cursor != curs)
  1691.       { current_cursor = curs;
  1692.         SetCursor( current_cursor );
  1693.       }
  1694.       gCursRgnOK = true;
  1695.     }
  1696.     eTeIdle( wind_table[w].hTE );
  1697.     men = (wind_table[w].is_file == 2 ) ? 1 : 0;
  1698.   }
  1699.   else
  1700.   { SetRectRgn(gCursorRgn, -32768, -32768, 32766, 32766);
  1701.     gCursRgnOK = false;
  1702.     SetCursor(&qd.arrow);
  1703.     men = 2;
  1704.   }
  1705.   
  1706.   // 21Jul96 -- rainy day fund
  1707.   if ( rainy_day_fund == NULL )
  1708.   { rainy_day_fund = NewHandle(0);
  1709.     EmptyHandle( rainy_day_fund );
  1710.   }
  1711.   if ( gLowMemory )
  1712.   { supress_mem_full_dialog = 1;
  1713.     ReallocateHandle ( rainy_day_fund, kRamReserve + kRamSlop );
  1714.     if ( *rainy_day_fund != NULL )
  1715.     { SetHandleSize( rainy_day_fund, kRamReserve );
  1716.       HPurge( rainy_day_fund );
  1717.       gLowMemory = false;
  1718.     }
  1719.     else
  1720.     { men = 3;
  1721.       mem_full = 0;
  1722.     }
  1723.     supress_mem_full_dialog = 0;
  1724.   }
  1725.   else if ( *rainy_day_fund == NULL )
  1726.   { supress_mem_full_dialog = 1;
  1727.     ReallocateHandle( rainy_day_fund, kRamReserve );
  1728.     if ( *rainy_day_fund != NULL ) HPurge( rainy_day_fund );
  1729.     else
  1730.     { ParamText1( "\p We're getting low on memory; closing some windows may help." );
  1731.       SysBeep( 10 );
  1732.       CautionAlert( ok_alertID, 0L );
  1733.       gLowMemory = true;
  1734.       men = 3;
  1735.       mem_full = 0;
  1736.     }
  1737.     supress_mem_full_dialog = 0;
  1738.   }
  1739.   else ;
  1740.  
  1741.   if ( (!gInBackground) && (men != current_menus) )
  1742.   { current_menus = men;
  1743.     switch (men)
  1744.     { case 0:
  1745.       case 1:
  1746.         EnableItem( menus[fileM], newCommand );
  1747.         EnableItem( menus[fileM], openCommand );
  1748.         EnableItem( menus[fileM], saveCommand );
  1749.         EnableItem( menus[fileM], saveasCommand );
  1750.         if (men == 0)
  1751.           DisableItem( menus[fileM], revertCommand );
  1752.         else
  1753.           EnableItem( menus[fileM], revertCommand );
  1754.         EnableItem( menus[fileM], pgsetupCommand );
  1755.         EnableItem( menus[fileM], printCommand );
  1756.         EnableItem( menus[editM], selAllCommand );
  1757.         EnableItem( menus[editM], stylesCommand );
  1758.         EnableItem( menus[editM], showPosnCommand );
  1759.         EnableItem( menus[findM], 0 );
  1760.         break;
  1761.       case 2:
  1762.         EnableItem( menus[fileM], newCommand );
  1763.         EnableItem( menus[fileM], openCommand );
  1764.         DisableItem( menus[fileM], saveCommand );
  1765.         DisableItem( menus[fileM], saveasCommand );
  1766.         DisableItem( menus[fileM], revertCommand );
  1767.         DisableItem( menus[fileM], pgsetupCommand );
  1768.         DisableItem( menus[fileM], printCommand );
  1769.         DisableItem( menus[editM], selAllCommand );
  1770.         DisableItem( menus[editM], stylesCommand );
  1771.         DisableItem( menus[editM], showPosnCommand );
  1772.         DisableItem( menus[findM], 0 );
  1773.         break;
  1774.       case 3:
  1775.         DisableItem( menus[fileM], newCommand );
  1776.         DisableItem( menus[fileM], openCommand );
  1777.         EnableItem( menus[fileM], saveCommand );
  1778.         EnableItem( menus[fileM], saveasCommand );
  1779.         DisableItem( menus[fileM], revertCommand );
  1780.         DisableItem( menus[fileM], pgsetupCommand );
  1781.         DisableItem( menus[fileM], printCommand );
  1782.         DisableItem( menus[editM], selAllCommand );
  1783.         DisableItem( menus[editM], stylesCommand );
  1784.         DisableItem( menus[editM], showPosnCommand );
  1785.         DisableItem( menus[findM], 0 );
  1786.         break;
  1787.     }
  1788.     DrawMenuBar();
  1789.   }
  1790.  
  1791.   if ( (!gInBackground) && (w>=0) )
  1792.   { register EvQElPtr q = (EvQElPtr )LMGetEventQueue();
  1793.     for (q = (EvQElPtr)((QHdrPtr )q)->qHead; q != NULL; q = (EvQElPtr)q->qLink)
  1794.       if ((q->evtQWhat == keyDown) && ((char)q->evtQMessage == '.') &&
  1795.           (q->evtQModifiers & cmdKey))
  1796.       { while (GetNextEvent(keyDownMask+keyUpMask+autoKeyMask,&event) &&
  1797.                !((event.what == keyDown) && ((event.message & charCodeMask) == '.') &&
  1798.                  ((event.modifiers & cmdKey) != 0) )) ;
  1799.         handle_interrupt();
  1800.         return 0;
  1801.       }
  1802.   }
  1803.   return 1;
  1804. }
  1805.  
  1806. /* from MacDTS */
  1807. #define kDITop                    0x0050        /* kTopLeft - for positioning the Disk */
  1808. #define kDILeft                    0x0070        /*   Initialization dialogs. */
  1809.  
  1810. void handle_activate( WindowPtr wptr, Boolean activep )
  1811. { GrafPtr port;
  1812.   Rect r;
  1813.   short w = wptr_to_id( wptr );
  1814.   if( w >= 0 )
  1815.   { port = wind_table[w].wptr;
  1816.     r = port->portRect;
  1817.     r.left = r.right - (SBarWidth+1);
  1818.     SetPort( port );
  1819.     InvalRect( &r );
  1820.     r = port->portRect;
  1821.     r.top = r.bottom - (SBarWidth+1);
  1822.     InvalRect( &r );
  1823.     if ( activep )
  1824.     { eTeActivate( wind_table[w].hTE );
  1825.       ShowControl( wind_table[w].vscroll );
  1826.       ShowControl( wind_table[w].hscroll );
  1827.     }
  1828.     else
  1829.     { eTeDeactivate( wind_table[w].hTE );
  1830.       HideControl( wind_table[w].vscroll );
  1831.       HideControl( wind_table[w].hscroll );
  1832.     }
  1833.   }
  1834. }
  1835.  
  1836. static short handle_event( EventRecord *event )
  1837. { short w;
  1838.   WindowPtr event_window;
  1839.  
  1840. #if (CREATOR == 'Caml') || (CREATOR == 'Moml')
  1841. extern int DoGraphEvent(EventRecord *event, WindowPtr window);
  1842. #endif
  1843.  
  1844.   if (IsDialogEvent( event ))
  1845.   { DialogPtr dp;
  1846.     short item;
  1847.     DialogSelect( event, &dp, &item );
  1848.     return 1;
  1849.   }
  1850.   
  1851.   event_window = FrontWindow();
  1852.   
  1853. #if (CREATOR == 'Caml') || (CREATOR == 'Moml')
  1854.   if ( DoGraphEvent( event, event_window ) ) return 1;
  1855. #endif
  1856.  
  1857.   w = wptr_to_id( event_window );
  1858.   { switch (event->what)
  1859.     { case mouseDown:
  1860.         gCursRgnOK = false;
  1861.         switch (FindWindow(event->where,&event_window))
  1862.         { case inDesk: 
  1863.             SysBeep( 10 );
  1864.             break;
  1865.           case inGoAway:
  1866.             if ((w = wptr_to_id( event_window )) >= 0)
  1867.               if (TrackGoAway(event_window,event->where)) handle_close( w );
  1868.             break;
  1869.           case inMenuBar:
  1870.           { TeHANDLE hTE = NULL;
  1871.             if( w >= 0) hTE = wind_table[w].hTE;
  1872.             eTeEditMenuUpdate( hTE, menus[editM] );
  1873.             return handle_menu( MenuSelect(event->where), w );
  1874.           }
  1875.           case inSysWindow:
  1876.             SystemClick(event,event_window);
  1877.             break;
  1878.           case inDrag:
  1879.             if ((w = wptr_to_id( event_window )) >= 0)
  1880.               DragWindow(event_window,event->where,&qd.screenBits.bounds);
  1881.             break;
  1882.           case inGrow:
  1883.             if ((w = wptr_to_id( event_window )) >= 0)
  1884.               grow_window( w, event->where );
  1885.             break;
  1886.           case inContent:
  1887.             if (event_window != FrontWindow())
  1888.               SelectWindow(event_window);
  1889.             else 
  1890.               if ((w = wptr_to_id( event_window )) >= 0)
  1891.                 content( w, event );
  1892.             break;
  1893.           default: ;
  1894.         }
  1895.         gLastMouseDown = *event;
  1896.         break;
  1897.       case mouseUp:
  1898.         gLastMouseUp = *event;
  1899.         break;
  1900.       case keyDown:
  1901.       case autoKey:
  1902.         { unsigned char c = event->message & charCodeMask;
  1903.           TeHANDLE hTE = (w>=0)?wind_table[w].hTE:NULL;
  1904.           if ((event->modifiers & cmdKey) != 0 && c != 3 )
  1905.           { long res;
  1906.             if (c == '=') c = '+'; else if (c == '/') c = '?';
  1907.             if (hTE != NULL) eTeEditMenuUpdate( hTE, menus[editM] );
  1908.             res = MenuKey( c );
  1909.             if( HiWord( res ) != 0 )
  1910.               return handle_menu( res, w );
  1911.             if( (hTE != NULL) && (c >= 0) && (c <= 31) )
  1912.             {    check_TEKey( c, hTE, 0, event );
  1913.                 inval_msgrect( w );
  1914.             }
  1915.             break;
  1916.           }
  1917.           if (hTE == NULL) break;
  1918. #if LISPmodeP
  1919.           if( ( event->modifiers & controlKey ) != 0 )
  1920.           { eEditCommand( hTE, c, event->modifiers, wind_table[w].bold_input );
  1921.               eMaybeSmudgeWindow( w, hTE );
  1922.               inval_msgrect( w );
  1923.           }
  1924. #endif
  1925.           else if( ( c == 127 /* del fwd */ )  || ( c <= 31 ) )
  1926.           { if( ( c == 3 /*enter*/ ) || (( c == '\r' /*cr*/ ) && ((event->modifiers & optionKey) != 0 )))
  1927.             { short id = (wind_table[w].is_file != 0) ? interaction_id : w;
  1928.               long sel_sta;
  1929.               long sel_end;
  1930.               long sel_len;
  1931. #if EndOfInputP
  1932.               if( event->message >> 24 == 0xee) end_of_input = 1;
  1933. #endif
  1934.               if( (**hTE).selActive ) {
  1935.                   sel_sta = eTeChPosToOffset( hTE, (**hTE).selStart );
  1936.                   sel_end = eTeChPosToOffset( hTE, (**hTE).selEnd );
  1937.               }
  1938.               else
  1939.               { extern void eTeGetRun( eRec **hE, long *sta, long *end );
  1940.                 if ( w == interaction_id )
  1941.                 { long writePos;
  1942.                   eTeGetRun( hTE, &sel_sta, &sel_end );
  1943.                   // try to prevent multiple input of the same text
  1944.                   writePos = eTeChPosToOffset( hTE, (**hTE).writeChPos );
  1945.                   if( sel_sta < writePos && writePos <= sel_end )
  1946.                     sel_sta = writePos;
  1947.                 }
  1948.                 else
  1949. #if LISPmodeP
  1950.                 { sel_end = eTeChPosToOffset( hTE, (**hTE).caretChPos );
  1951.                   sel_sta = balance_bwd( wind_table[w].hTE, 0, 1 );
  1952.                   if (sel_sta < 0) sel_sta = sel_end;
  1953.                 }
  1954. #else
  1955.                   sel_end = sel_sta = eTeChPosToOffset( hTE, (**hTE).caretChPos );
  1956. #endif
  1957.               }
  1958.               eTeSetSelect( hTE, sel_end, sel_end );
  1959.               sel_len = sel_end - sel_sta;
  1960.               HLock((**hTE).hText);
  1961. #ifndef EndOfInputP
  1962. #define end_of_input 0
  1963. #endif
  1964.               if (sel_len > 0)
  1965.                 put_input( id, *((**hTE).hText) + sel_sta, sel_len, !end_of_input, 0, 1 );
  1966.               else
  1967.                 put_input( id, NULL, 0, !end_of_input, 0, 1 ); /*  not done yet!?  12Sep92  e  */
  1968.               HUnlock((**hTE).hText);
  1969.             }
  1970.             else if (c == 9) /*tab*/
  1971.             { eTabCommand( hTE, event->modifiers, wind_table[w].bold_input );
  1972.               eMaybeSmudgeWindow( w, hTE );
  1973.               inval_msgrect( w );
  1974.             }
  1975.             else if ( c == '\b' /*bs*/ // don't bs over writeChPos
  1976.                       && (**hTE).writeChPos.v == (**hTE).caretChPos.v
  1977.                       && (**hTE).writeChPos.h == (**hTE).caretChPos.h
  1978.                     )
  1979.             { SysBeep(3); // add a progressive Alert!
  1980.             }
  1981.             else
  1982.             { check_TEKey( c, hTE, wind_table[w].bold_input, event );
  1983.               if ((c == '\r') && (**hTE).autoInd)
  1984.                 eTabCommand( hTE, optionKey, wind_table[w].bold_input );
  1985.               eMaybeSmudgeWindow( w, hTE );
  1986.               inval_msgrect( w );
  1987.               if ( (c=='\r' /*cr*/) || (c=='\b' /*bs*/) ) eTeShowCaret( hTE );
  1988.             }
  1989.           }
  1990.           else
  1991.           { 
  1992. #if LISPmodeP
  1993.               if (!check_TEKey( c, hTE, wind_table[w].bold_input, event ))
  1994.                 if (c == ')')
  1995.                 { long open_paren = balance_bwd( wind_table[w].hTE, 0, 0 );
  1996.                   if (open_paren >= 0)
  1997.                   { long now;
  1998.                     long selstart = eTeChPosToOffset( hTE, (**hTE).caretChPos );
  1999.                     eTeSetSelect( hTE, open_paren, open_paren+1 );
  2000.                     eTeShowCaret( hTE );
  2001.                     now = TickCount();
  2002.                     while ((TickCount()-now)<10) ;
  2003.                     while (!EventAvail(everyEvent,event) && ((TickCount()-now)<30)) ;
  2004.                     eTeSetSelect( hTE, selstart, selstart );
  2005.                   }
  2006.                 }
  2007. #else
  2008.             check_TEKey( c, hTE, wind_table[w].bold_input, event );
  2009. #endif
  2010.             eMaybeSmudgeWindow( w, hTE );
  2011.             inval_msgrect( w );
  2012.             eTeShowCaret( hTE );
  2013.           }
  2014.         }
  2015.         break;
  2016.       case activateEvt:
  2017.         gCursRgnOK = false;
  2018.           handle_activate( (WindowPtr)event->message, ((event->modifiers & activeFlag) != 0) );
  2019.         break;
  2020.       case updateEvt: 
  2021.         if ((w = wptr_to_id( (WindowPtr)event->message )) >= 0)
  2022.         { update_window(w);
  2023.         }
  2024.         else
  2025.         { GrafPtr port = (WindowPtr)event->message;
  2026.           SetPort( port );
  2027.           BeginUpdate( port );
  2028.           EndUpdate( port );
  2029.         }
  2030.         break;
  2031.       case osEvt:
  2032.         if( *(char *)(&event->message) == suspendResumeMessage )
  2033.         { gCursRgnOK = false; /* Suspend/resume is also an activate/deactivate. */
  2034.           gInBackground = !(event->message & resumeFlag);
  2035.           if( gInBackground ) eTePutScrap();
  2036.           else                  eTeGetScrap();
  2037.           handle_activate( FrontWindow(), !gInBackground );
  2038.         }
  2039.         /* punt mouseMovedMessage */
  2040.         break;
  2041.       case diskEvt:
  2042.         gCursRgnOK = false;                     /* It is not a bad idea to at least call */
  2043.         if (HiWord(event->message) != noErr) /* DIBadMount in response to a diskEvt,  */
  2044.         { Point pt;                             /* so that the user can format a floppy. */
  2045.           SetPt( &pt, kDILeft, kDITop );
  2046.           DIBadMount( pt, event->message );
  2047.         }
  2048.         break;
  2049.       case kHighLevelEvent:
  2050.         AEProcessAppleEvent(event);
  2051.         if (gDoQuit) os_quit();
  2052.         break;
  2053.       default: ;
  2054.     }
  2055.   }
  2056.   return 1;
  2057. }
  2058.  
  2059. long os_get_next_event( EventRecord *event )
  2060. { long result = 0;
  2061.   GrafPtr save;
  2062.   GetPort( &save );
  2063.   if (do_tasks())
  2064.   { beg_mf_time();
  2065.     // if (gHasWNE)
  2066.       { result = (long)( gInBackground ? gWaitTicksBG
  2067.                                          : (long )( (gWaitTicksFG > gMaxSleep) ? gMaxSleep
  2068.                                                                                 : gWaitTicksFG) );
  2069.       result = WaitNextEvent( everyEvent, event, result, gCursorRgn );
  2070.     }
  2071.     // else
  2072.     // { SystemTask();
  2073.     //   result = GetNextEvent( everyEvent, event );
  2074.     // }
  2075.     end_mf_time();
  2076.   }
  2077.   SetPort( save );
  2078.   return result;
  2079. }
  2080.  
  2081. long os_handle_event( EventRecord *event )
  2082. { long result;
  2083.   GrafPtr save;
  2084.   GetPort( &save );
  2085.   result = handle_event( event );
  2086.   SetPort( save );
  2087.   return result;
  2088. }
  2089.  
  2090. void os_event_check( void )
  2091. { EventRecord event;
  2092.   os_get_next_event( &event );
  2093.   os_handle_event( &event );
  2094. #if USE_EVENTCHK_TIMER
  2095.   next_eventchk_ticks = 0;
  2096. #else
  2097.   next_eventchk_ticks = LMGetTicks() + TicksBetweenEventChecks;
  2098. #endif
  2099.   if ( interrupted ) { interrupted = 0; raise(SIGINT); }
  2100. }
  2101.  
  2102. void os_quit()
  2103. #if ANSIquitP
  2104.   exit(0);
  2105. #else
  2106.   wind_end();
  2107. #if USE_EVENTCHK_TIMER
  2108.   cancel_eck_timer();
  2109. #endif
  2110.   ExitToShell();
  2111. #endif
  2112. }
  2113.  
  2114. /* ******* console io ******* */
  2115.  
  2116. static GrowZoneUPP mem_full_errUPP;
  2117.  
  2118. static short main_internal( )
  2119. { short i;
  2120.   MaxApplZone();
  2121.   for (i = 0; i < 10; i++)
  2122.         MoreMasters();
  2123.   /* CouldAlert( ok_alertID ); */
  2124.   mem_full_errUPP = NewGrowZoneProc(mem_full_err);
  2125.   SetGrowZone( mem_full_errUPP );
  2126.  
  2127.   wind_begin();
  2128.  
  2129. #if ANSIquitP
  2130.   atexit(wind_quit);
  2131. #endif
  2132.  
  2133.   SetCursor( current_cursor );
  2134.  
  2135.   ParamText1( "\p" );
  2136.  
  2137. #if USE_EVENTCHK_TIMER
  2138.   init_eck_timer();
  2139. #endif
  2140.  
  2141.   return 0;
  2142. }
  2143.  
  2144. static short console_initialized = 0;
  2145.  
  2146. WindowPeek os_console_new( unsigned char *name )
  2147. { short id;
  2148.   WindowPeek wp;
  2149.   if( !console_initialized )
  2150.   { main_internal();
  2151.     console_initialized = 1;
  2152.   }
  2153.   id = wind_open( name, FALSE, FALSE, TRUE );
  2154.   if( id < 0 ) return (WindowPeek )0;
  2155.   interaction_id = id;
  2156.   delWindMenuItem( interaction_id );
  2157.   wp = (WindowPeek )wind_table[id].wptr;
  2158.   wp->refCon = (long )id;
  2159.   return(wp);
  2160. }
  2161.  
  2162. long os_console_chars_ready(WindowPeek wp)
  2163. {  short id = wp->refCon;
  2164.    return wind_table[id].len - wind_table[id].pos;
  2165. }
  2166.  
  2167. long os_console_read( WindowPeek wp, unsigned char *ptr, long cnt )
  2168. #if ReadHangsP
  2169.   long result;
  2170.   do
  2171.   { result = os_console_read_nohang( wp, ptr, cnt );
  2172.   } while (result == 0);
  2173.   return result;
  2174. #else
  2175.   return os_console_read_nohang( wp, ptr, cnt );
  2176. #endif
  2177. }
  2178.  
  2179. long os_console_read_nohang( WindowPeek wp, unsigned char *ptr, long cnt )
  2180. { long result = 0;
  2181.   GrafPtr save;
  2182.   GetPort( &save );
  2183.   if( cnt > 0 )
  2184.   { register unsigned char *p1 = ptr;
  2185.     short id = wp->refCon;
  2186.     EventRecord event;
  2187.     do
  2188.     { os_get_next_event( &event );
  2189.       os_handle_event( &event );
  2190.       if( interrupted )
  2191.         goto ocr_done;
  2192.       else
  2193.       { register unsigned char *p2 = (unsigned char *)wind_table[id].buf + wind_table[id].pos;
  2194.         register long len = wind_table[id].len - wind_table[id].pos;
  2195.         register short i = 0;
  2196.         if (len > cnt) len = cnt;
  2197.         cnt = len; /* nohang */
  2198.         while ( i < len )
  2199.         { register unsigned char c = p2[i++];
  2200.           if (c == '\r')
  2201.           {
  2202.             if (XlateRETURN != 0) c = '\n';
  2203.             len = i; /* to exit inner loop */
  2204.             cnt = i; /* to exit outer loop */
  2205.           }
  2206.           *p1++ = c;
  2207.         }
  2208.         wind_table[id].pos += i;
  2209.         cnt -= i;
  2210.         result += i;
  2211.       }
  2212. #if EndOfInputP
  2213.       if( end_of_input )
  2214.       {
  2215.         // end_of_input = 0;
  2216.         goto ocr_done;
  2217.       }
  2218. #endif
  2219.     } while( cnt > 0 );
  2220.   }
  2221. ocr_done:
  2222.   SetPort( save );
  2223.   return result;
  2224. }
  2225.  
  2226. long os_console_write( WindowPeek wp, unsigned char *ptr, long cnt)
  2227. { long result = 0;
  2228.   GrafPtr save;
  2229.   short id = (short )wp->refCon;
  2230.  
  2231.   GetPort( &save );
  2232.  
  2233.   if (!(wp->visible))
  2234.     select_and_show( (WindowPtr )wp );
  2235.  
  2236.   if (XlateRETURN)
  2237.   {
  2238.     register unsigned char *p1 = ptr, *p2 = ptr+cnt;
  2239.     register short len = wind_table[id].out_len;
  2240.     register unsigned char *p3;
  2241.     if( wind_table[id].out_buf == NULL )
  2242.     { wind_table[id].out_buf = NewHandle( OUT_BUF_LEN );
  2243.       if( wind_table[id].out_buf == NULL )
  2244.       { SysBeep(10);
  2245.         return result;
  2246.       }
  2247.     }
  2248.     HLock( wind_table[id].out_buf );
  2249.     p3 = (unsigned char *)*wind_table[id].out_buf;
  2250.  
  2251.     while( p1 < p2 )
  2252.     { register unsigned char c = *p1++;
  2253.       if (c == '\n') { p3[len++] = '\r'; goto output; }
  2254.       p3[len++] = c;
  2255.       if (len == OUT_BUF_LEN)
  2256.       { output:
  2257.         if( check_TEWrite( (char *)p3, (long)len, wind_table[id].hTE, 0 ) ) goto werror;
  2258.         wind_table[id].out_len = 0;
  2259.         len = 0;
  2260.       }
  2261.     }
  2262.     wind_table[id].out_len = len;
  2263.     result = cnt;
  2264. werror:
  2265.     SetPort( save );
  2266.     HUnlock( wind_table[id].out_buf );
  2267.   }
  2268.   else
  2269.   {
  2270.     if( check_TEWrite( (char *)ptr, (long)cnt, wind_table[id].hTE, 0 ) == 0 )
  2271.       result = cnt;
  2272.   }
  2273.   return result;
  2274. }
  2275.  
  2276. long os_console_close( WindowPeek wp )
  2277. { long result = 0;
  2278.   GrafPtr save;
  2279.   short id = (short )wp->refCon;
  2280.   GetPort( &save );
  2281.   if( id < 0 )
  2282.     result = -1;
  2283.   else
  2284.     wind_close( id );
  2285.   SetPort( save );
  2286.   return result;
  2287. }
  2288.  
  2289. /*--------------------------------------------------------------------------*/
  2290.  
  2291. /* Used to check for any unread required parameters. Returns true if we
  2292. ** missed at least one. */
  2293.  
  2294. static Boolean    MissedAnyParameters(AppleEvent *message)
  2295. {
  2296.     OSErr        err;
  2297.     DescType    ignoredActualType;
  2298.     AEKeyword    missedKeyword;
  2299.     Size        ignoredActualSize;
  2300.     EventRecord    event;
  2301.  
  2302.     err = AEGetAttributePtr(    /* SEE IF PARAMETERS ARE ALL USED UP.          */
  2303.         message,                /* AppleEvent to check.                          */
  2304.         keyMissedKeywordAttr,    /* Look for unread parameters.                  */
  2305.         typeWildCard,            /* So we can see what type we missed, if any. */
  2306.         &ignoredActualType,        /* What it would have been if not coerced.      */
  2307.         (Ptr)&missedKeyword,    /* Data area.  (Keyword not handled.)          */
  2308.         sizeof(missedKeyword),    /* Size of data area.                          */
  2309.         &ignoredActualSize        /* Actual data size.                          */
  2310.     );
  2311.  
  2312. /* No error means that we found some unused parameters. */
  2313.  
  2314.     if (err == noErr) {
  2315.         event.message = *(long *) &ignoredActualType;
  2316.         event.where = *(Point *) &missedKeyword;
  2317.         err = errAEEventNotHandled;
  2318.     }
  2319.  
  2320. /* errAEDescNotFound means that there are no more parameters.  If we get
  2321. ** an error code other than that, flag it. */
  2322.  
  2323.     return(err != errAEDescNotFound);
  2324. }
  2325.  
  2326. #if ( CREATOR == 'Moml' )
  2327.  
  2328. static void get_app_name( void )
  2329. {
  2330.   //unsigned char *CurApName = LMGetCurApName();
  2331.   ProcessInfoRec pir;
  2332.   ProcessSerialNumber psn;
  2333.   char      path[512];
  2334.   short     w;
  2335.   
  2336.   psn.highLongOfPSN = 0;
  2337.   psn.lowLongOfPSN = kCurrentProcess;
  2338.   pir.processInfoLength = sizeof(pir);
  2339.   pir.processName = 0;
  2340.   pir.processAppSpec = &appFSS;
  2341.   GetProcessInformation( &psn, &pir );
  2342.   w = getfullpath( appFSS.vRefNum, appFSS.parID, appFSS.name, path, 511, 1 );
  2343.   e_setenv( "PATH_TRANSLATED", path, 0 );
  2344.   if( image_name == NULL && strcmp( ".app", &path[w-4] ) == 0 && w < 510 )
  2345.   { // make image name from app name: foo.app => foo.image
  2346.     strcpy( &path[w-3], "image" );
  2347.     image_name = malloc( w + 3 );
  2348.     if( image_name ) strncpy( image_name, path, w + 3 );
  2349.   }
  2350.     gMadeAppFSS = true;
  2351. }
  2352.  
  2353. #else
  2354. static void get_app_name( void )
  2355. {
  2356. }
  2357. #endif
  2358.  
  2359. static OSErr    OpenDocEventHandler(AppleEvent *message, AppleEvent *reply, short mode)
  2360. {
  2361.   #pragma unused( reply )
  2362.     OSErr        err;
  2363.     OSErr        err2;
  2364.     AEDesc        theDesc;
  2365.     FSSpec        theFSS;
  2366.     short        loop;
  2367.     long        numFilesToOpen;
  2368.     AEKeyword    ignoredKeyWord;
  2369.     DescType    ignoredType;
  2370.     Size        ignoredSize;
  2371.     char path[512];
  2372.     short w;
  2373.     FInfo theFInfo;
  2374.  
  2375.   if( ! gMadeAppFSS ) get_app_name( );
  2376.  
  2377.     theDesc.dataHandle = nil;
  2378.         /* Make sure disposing of the descriptors is okay in all cases.
  2379.         ** This will not be necessary after 7.0b3, since the calls that
  2380.         ** attempt to create the descriptors will nil automatically
  2381.         ** upon failure. */
  2382.  
  2383.     if ( (err = AEGetParamDesc( message, keyDirectObject, typeAEList, &theDesc )) != 0 )
  2384.         return(err);
  2385.  
  2386.     if ( ! MissedAnyParameters( message ) ) {
  2387.  
  2388. /* Got all the parameters we need.  Now, go through the direct object,
  2389. ** see what type it is, and parse it up. */
  2390.  
  2391.         err = AECountItems(&theDesc, &numFilesToOpen);
  2392.         if (!err)
  2393.         {    /* We have numFilesToOpen that need opening, as either a window
  2394.             ** or to be printed.  Go to it... */
  2395.  
  2396.             for (loop = 1; ((loop <= numFilesToOpen) && (!err)); ++loop)
  2397.             {    err = AEGetNthPtr(        /* GET NEXT IN THE LIST...         */
  2398.                     &theDesc,            /* List of file names.             */
  2399.                     loop,                /* Item # in the list.             */
  2400.                     typeFSS,            /* Item is of type FSSpec.         */
  2401.                     &ignoredKeyWord,    /* Returned keyword -- we know.  */
  2402.                     &ignoredType,        /* Returned type -- we know.     */
  2403.                     (Ptr)&theFSS,        /* Where to put the FSSpec info. */
  2404.                     sizeof(theFSS),        /* Size of the FSSpec info.         */
  2405.                     &ignoredSize        /* Actual size -- we know.         */
  2406.                 );
  2407.                 if (err) break;
  2408.  
  2409.                 FSpGetFInfo( &theFSS, &theFInfo );
  2410.                 if ( theFInfo.fdType != 'TEXT' )
  2411.                 { 
  2412. #ifdef PFILmode
  2413.                   if( theFInfo.fdType == 'FILi' ) pfil_ae_load( &theFSS );
  2414.                   else
  2415. #endif
  2416. #if ( CREATOR == 'Moml' )
  2417.                   w = getfullpath( theFSS.vRefNum, theFSS.parID, theFSS.name, path, 511, 1 );
  2418.                   if( !been_there_done_that && theFInfo.fdType == 'BINA' && theFInfo.fdCreator == 'Moml' )
  2419.                   {
  2420.                     been_there_done_that = true;
  2421.                     image_name = malloc( w + 1 );
  2422.                     if( image_name ) strncpy( image_name, path, w + 1 );
  2423.                   }
  2424.                   else
  2425. #elif ( CREATOR == 's48e' )
  2426.                   char *cmnd = "vm -i ";
  2427.                   w = getfullpath( theFSS.vRefNum, theFSS.parID, theFSS.name, path, 511, 1 );
  2428.                   if ( ( theFInfo.fdType == 'BINA' ) && w )
  2429.                   {
  2430.                     check_TEInsert( cmnd, 6, wind_table[interaction_id].hTE, 1 );
  2431.                     check_TEInsert( path, w, wind_table[interaction_id].hTE, 1 );
  2432.                     put_input( interaction_id, cmnd, 6, 0, 0, 1 );
  2433.                     put_input( interaction_id, path, w, 1, 0, 0 );
  2434.                   }
  2435.                   else
  2436. #else
  2437.           #pragma unused( path )
  2438. #endif
  2439.                   SysBeep( 3 );
  2440.                   continue;
  2441.                 }
  2442.                 gPrintPage = mode;
  2443.                     /* Open the window off-screen if we are printing.
  2444.                     ** We use the gPrintPage global to flag this.  Normally, the
  2445.                     ** gPrintPage global is to tell ImageDocument if we are imaging
  2446.                     ** to the window or to paper.  We don't need it for this yet,
  2447.                     ** as we can't image the document until it is opened.  DoNewWindow()
  2448.                     ** uses gPrintPage as a flag to open the window off-screen, but
  2449.                     ** visible, so that PrintMonitor can use the title of the window
  2450.                     ** as the document name that is being printed. */
  2451.                 
  2452.                 if ( 1 ) /* was ( w ); moved getfullpath inside bin case 18Jul96 e */
  2453.                 {    
  2454.                     w = edit( &theFSS, 0L, 0L, 0L );
  2455.  
  2456.                     if ( gPrintPage && w >= 0 )
  2457.                     {
  2458.                         err  = eTePrint( wind_table[w].hTE, (mode == 2), (loop == 1),
  2459.                                          wind_table[w].fss.name );
  2460.                         mode = 1;    /* No interaction mode (mode == 2) only valid
  2461.                                     ** for the first printed document. */
  2462.                         wind_close( w );
  2463.                     }
  2464.                 }
  2465.                 else err = errAEEventNotHandled;     /* file pathname too long */
  2466.             }
  2467.             if (gPrintPage)
  2468.             {    eTePrint( nil, false, false, nil );  /* cleanup */
  2469.                 gPrintPage = 0;                      /* back to normal */
  2470.             }
  2471.         }
  2472.     }
  2473.     err2 = AEDisposeDesc(&theDesc);
  2474.     return(err ? err : err2);
  2475. }
  2476.  
  2477. static Boolean install_aehandler( AEEventClass cl, AEEventID id, ProcPtr p )
  2478. { OSErr    err;
  2479.   AEEventHandlerUPP upp = NewAEEventHandlerProc(p);
  2480.   
  2481.   if ( upp == NULL ) err = memFullErr;
  2482.   else err = AEInstallEventHandler( cl, id, upp, 0L, false );
  2483.   if (err)
  2484.   { io_err(err);
  2485.     return false;
  2486.   }
  2487.   return true;
  2488. }
  2489.  
  2490. static pascal OSErr    DoAEOpenApplication( AppleEvent *message, AppleEvent *reply, long refcon )
  2491. {
  2492.     #pragma unused( message, reply, refcon )
  2493.     get_app_name( );
  2494.     return(noErr);
  2495. }
  2496.  
  2497. static pascal OSErr    DoAEOpenDocuments( AppleEvent *message, AppleEvent *reply, long refcon )
  2498. {
  2499.     #pragma unused( refcon )
  2500.   gCursRgnOK = false;
  2501.     return( OpenDocEventHandler( message, reply, 0 ) ); /* 0 means regular open document */
  2502. }
  2503.  
  2504. #define kTimeOutInTicks (60 * 30)    /* 30 second timeout. */
  2505.  
  2506. static pascal OSErr    DoAEPrintDocuments(AppleEvent *message, AppleEvent *reply, long refcon)
  2507. {
  2508.     #pragma unused( refcon )
  2509.     short                openMode;
  2510.     ProcessSerialNumber    cpsn, fpsn;
  2511.     Boolean                procsSame;
  2512.  
  2513.   gCursRgnOK = false;
  2514.     openMode = 1;
  2515.     if (!AEInteractWithUser(kTimeOutInTicks, nil, nil))
  2516.         ++openMode;
  2517.  
  2518.     GetCurrentProcess(&cpsn);        /* We may have been moved to the front. */
  2519.     GetFrontProcess(&fpsn);
  2520.     SameProcess(&cpsn, &fpsn, &procsSame);
  2521.     gInBackground = !procsSame;
  2522.  
  2523.     return( OpenDocEventHandler( message, reply, openMode ) );
  2524.   /* openMode is either 1 or 2, depending if user interaction is okay. */
  2525. }
  2526.  
  2527. static pascal OSErr    DoAEQuitApplication( AppleEvent *message, AppleEvent *reply, long refcon )
  2528. {
  2529.     #pragma unused( message, reply, refcon )
  2530.   gCursRgnOK = false;
  2531.     gDoQuit = 1;
  2532.     wind_quit();
  2533.     return( gDoQuit ? noErr : errAEEventNotHandled );
  2534. }
  2535.  
  2536. static OSErr DoScriptAsFile( FSSpec *theFSS )
  2537. {
  2538.     OSErr err = noErr;
  2539.     short len;
  2540.     char  path[512];
  2541.     
  2542.     if( (len = getfullpath( theFSS->vRefNum, theFSS->parID, theFSS->name, path, 511, 1 )) != 0 )
  2543.     {
  2544.         put_input( interaction_id, dosc_open_str, dosc_open_str_sz, 0, 0, 1 );
  2545.         put_input( interaction_id, path, len, 0, 0, 0 );
  2546.         put_input( interaction_id, dosc_clos_str, dosc_clos_str_sz, 1, 0, 0 );
  2547.     }
  2548.     else err = errAEEventNotHandled;
  2549.     return err;
  2550. }
  2551.  
  2552. #ifdef DoSCRIPT
  2553. AppleEvent  gAEEvent;
  2554. AppleEvent  gAEReply;
  2555. int         gAESuspn;
  2556. #endif
  2557.  
  2558. static pascal OSErr DoAEDoScript( AppleEvent *theAEEvent, AppleEvent *theAEReply, long *theRefCon)
  2559. {
  2560.     #pragma unused( theRefCon )
  2561.     OSErr        theErr;
  2562.     DescType    typeCode;
  2563.     Size        sizeOfParam, actualSize;
  2564.     char        ourScriptText[256];
  2565.     FSSpec        ourScriptFSpec;
  2566.  
  2567.     /* Get the script to run */ 
  2568.  
  2569.     theErr = AESizeOfParam( theAEEvent, keyDirectObject, &typeCode, &sizeOfParam);
  2570.     if (theErr != noErr)
  2571.     {    /*
  2572.             If we fail here just return the error. We don't need to do any clean up since 
  2573.             we've allocated nothing on the heap yet.  The Apple Event Manager automatically 
  2574.             adds the error number to the reply as keyErrorNumber for non zero handler returns.
  2575.         */
  2576.         return theErr;
  2577.     }
  2578.     else if ((typeCode == typeChar) || (typeCode == typeStyledText) || (typeCode == typeIntlText))
  2579.     {
  2580.         theErr = AEGetParamPtr( theAEEvent, keyDirectObject, typeChar, &typeCode,
  2581.                                  (Ptr)ourScriptText, sizeof(ourScriptText), &actualSize);
  2582.         if (theErr == noErr)
  2583.             if ( MissedAnyParameters( theAEEvent ) )
  2584.                 theErr = errAEEventNotHandled;
  2585.             else
  2586.             { check_TEInsert( ourScriptText, actualSize, wind_table[interaction_id].hTE, 1 );
  2587.               put_input( interaction_id, ourScriptText, actualSize, 1, 0, 1 );
  2588.             }
  2589.     }
  2590.     else if (typeCode == typeAlias)
  2591.     {
  2592.         theErr = AEGetParamPtr( theAEEvent, keyDirectObject, typeFSS, &typeCode,
  2593.                                 (Ptr)&ourScriptFSpec, sizeof(ourScriptFSpec), &actualSize);
  2594.         if ( theErr == noErr )
  2595.             if ( MissedAnyParameters( theAEEvent ) )
  2596.                 theErr = errAEEventNotHandled;
  2597.             else theErr = DoScriptAsFile( &ourScriptFSpec );
  2598.     }
  2599.     else theErr = errAEEventNotHandled;
  2600. #ifdef DoSCRIPT
  2601.     if ( theErr == noErr )
  2602.     {
  2603.     gAEEvent = *theAEEvent;
  2604.     gAEReply = *theAEReply;
  2605.     gAESuspn = 1;
  2606.     gReceivedAE = -1;
  2607.     return AESuspendTheCurrentEvent( theAEEvent );
  2608.     }
  2609. #else
  2610. #pragma unused( theAEEvent, theAEReply, theRefCon )
  2611. #endif
  2612.     return theErr;
  2613. }
  2614.  
  2615. #ifdef DoSCRIPT
  2616. static pascal OSErr DoAEwww2( AppleEvent *theAEEvent, AppleEvent *theAEReply, long *theRefCon)
  2617. {
  2618.   #pragma unused( theAEEvent, theRefCon )
  2619.   OSErr     theErr = noErr;
  2620.   //char      ourScriptText[256];
  2621.  
  2622.   if( gAESuspn )
  2623.   {
  2624.     TeHANDLE hTE = wind_table[interaction_id].hTE;
  2625.     char *txt;
  2626.     int len = eTeTextLength( hTE );
  2627.     HLock( (**hTE).hText );
  2628.     txt = *((**hTE).hText);
  2629.     theErr = AEPutParamPtr( theAEReply, keyDirectObject, typeChar, (Ptr)txt, len);
  2630.     // sprintf( ourScriptText+1, "www2: %d", err );
  2631.     // ourScriptText[0] = strlen(ourScriptText+1);
  2632.     // DebugStr( (unsigned char *)ourScriptText );
  2633.     HUnlock( (**hTE).hText );
  2634.     gAESuspn = 0;
  2635.   }
  2636.   return theErr;
  2637. }
  2638. #endif
  2639.  
  2640. #if 0
  2641. static pascal OSErr DoAEwww( AppleEvent *theAEEvent, AppleEvent *theAEReply, long *theRefCon)
  2642. {
  2643.   OSErr        theErr;
  2644.   DescType    typeCode;
  2645.   Size        sizeOfParam, actualSize;
  2646.   char        ourScriptText[256];
  2647.   FSSpec        ourScriptFSpec;
  2648.  
  2649.   theErr = AEGetParamPtr( theAEEvent, keyDirectObject, typeChar, &typeCode,
  2650.                              (Ptr)ourScriptText, sizeof(ourScriptText), &actualSize);
  2651.   if (theErr == noErr)
  2652.   { check_TEInsert( ourScriptText, actualSize, wind_table[interaction_id].hTE, 1 );
  2653.     put_input( interaction_id, ourScriptText, actualSize, 1, 0, 1 );
  2654.   }
  2655.   gAEEvent = *theAEEvent;
  2656.   gAEReply = *theAEReply;
  2657.   gAESuspn = 1;
  2658.   return AESuspendTheCurrentEvent( theAEEvent );
  2659. }
  2660. #endif
  2661.  
  2662. #ifdef DoSCRIPT
  2663. OSErr finish_AEDoScript( void )
  2664. {
  2665.   if( gAESuspn )
  2666.   {
  2667.     int i;
  2668.     //  char ourScriptText[256];
  2669.   AEEventHandlerUPP upp = NewAEEventHandlerProc(DoAEwww2);
  2670.     OSErr err = AEResumeTheCurrentEvent( &gAEEvent, &gAEReply, upp, 0 );
  2671.     //  sprintf( ourScriptText+1, "www1: %d %x %x %x", err, gAEEvent, gAEReply, upp );
  2672.     //  ourScriptText[0] = strlen(ourScriptText+1);
  2673.     //  DebugStr( (unsigned char *)ourScriptText );
  2674.     if( gAESuspn && err == noErr ) 
  2675.       for( i = 0; gAESuspn && i < 10; i++ ) os_event_check();
  2676.     return err;
  2677.   }
  2678.   return errAEEventNotHandled;
  2679. }
  2680. #endif
  2681.  
  2682.  
  2683. #ifdef PFILmode
  2684.  
  2685. extern int pfil_ae_eval( char *in_buf, int in_siz, char* ou_buf, int ou_siz );
  2686.  
  2687. static pascal OSErr DoAEDoEval( AppleEvent *theAEEvent, AppleEvent *theAEReply, long *theRefCon)
  2688. {
  2689.     OSErr        theErr;
  2690.     DescType    typeCode;
  2691.     Size        sizeOfParam, actualSize;
  2692.     char        inScriptText[256];
  2693.     char        ouScriptText[256];
  2694.     FSSpec        ourScriptFSpec;
  2695.  
  2696.     /* Get the script to run */ 
  2697.  
  2698.     theErr = AESizeOfParam( theAEEvent, keyDirectObject, &typeCode, &sizeOfParam);
  2699.     if (theErr != noErr)
  2700.     {    return theErr;
  2701.     }
  2702.     else if ((typeCode == typeChar) || (typeCode == typeStyledText) || (typeCode == typeIntlText))
  2703.     {
  2704.         theErr = AEGetParamPtr( theAEEvent, keyDirectObject, typeChar, &typeCode,
  2705.                                  (Ptr)inScriptText, sizeof(inScriptText), &actualSize);
  2706.         if (theErr == noErr)
  2707.             if ( MissedAnyParameters( theAEEvent ) )
  2708.                 theErr = errAEEventNotHandled;
  2709.     }
  2710.     else if (typeCode == typeAlias)
  2711.     {
  2712.         theErr = AEGetParamPtr( theAEEvent, keyDirectObject, typeFSS, &typeCode,
  2713.                                 (Ptr)&ourScriptFSpec, sizeof(ourScriptFSpec), &actualSize);
  2714.         if ( theErr == noErr )
  2715.             if ( MissedAnyParameters( theAEEvent ) )
  2716.                 theErr = errAEEventNotHandled;
  2717.             else theErr = errAEEventNotHandled; /* DoScriptAsFile( &ourScriptFSpec ); */
  2718.     }
  2719.     else theErr = errAEEventNotHandled;
  2720.  
  2721.     if ( theErr == noErr )
  2722.     {
  2723.         actualSize = pfil_ae_eval( inScriptText, actualSize,
  2724.                                    ouScriptText, sizeof(ouScriptText) );
  2725.         theErr = AEPutParamPtr( theAEReply, keyDirectObject, typeChar,
  2726.                                  (Ptr)ouScriptText, actualSize);
  2727.     }
  2728.     return theErr;
  2729. }
  2730.  
  2731. #endif
  2732.  
  2733. static void init_ae()
  2734. {
  2735.     long    result;
  2736.  
  2737.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &result) ? false : result != 0);
  2738.  
  2739.     if (gHasAppleEvents)
  2740.          install_aehandler( kCoreEventClass, kAEOpenApplication, (ProcPtr )DoAEOpenApplication )
  2741.       && install_aehandler( kCoreEventClass, kAEOpenDocuments, (ProcPtr )DoAEOpenDocuments )
  2742.       && install_aehandler( kCoreEventClass, kAEPrintDocuments, (ProcPtr )DoAEPrintDocuments )
  2743.       && install_aehandler( kCoreEventClass, kAEQuitApplication, (ProcPtr )DoAEQuitApplication )
  2744.       && install_aehandler( kAEMiscStandards, kAEDoScript, (ProcPtr )DoAEDoScript )
  2745.       // && install_aehandler( 'WWWΩ', 'sdoc', (ProcPtr )DoAEwww )
  2746. #ifdef PFILmode
  2747.       && install_aehandler( kAEMiscStandards, (OSType )'eval', (ProcPtr )DoAEDoEval )
  2748. #endif
  2749.     ;
  2750. }
  2751.  
  2752. /*--------------------------------------------------------------------------*/
  2753.  
  2754.