home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / jove-4.16-src.tgz / tar.out / bsd / jove / mac.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  58KB  |  2,806 lines

  1. /************************************************************************
  2.  * This program is Copyright (C) 1986-1996 by Jonathan Payne.  JOVE is  *
  3.  * provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is *
  5.  * included in all the files.                                           *
  6.  ************************************************************************/
  7.  
  8.  
  9. /* (C) 1986, 1987, 1988 Ken Mitchum.  This code is intended only for use with Jove. */
  10.  
  11. /* In 1995 December, D. Hugh Redelmeier hacked on the code to make
  12.  * it work again.  The environment was Think C 5.0 under System 7.1.
  13.  *
  14.  * Obligatory excuses:
  15.  * - Hugh is not a Mac expert
  16.  * - Think C 5.0 is quite obsolete (1991)
  17.  * - The only goal was to get the code working, not working well.
  18.  *
  19.  * Known issues:
  20.  * - the keyboard routines were designed for the Mac Plus keyboard.
  21.  *   + "Command" is taken as "Control" and ` is taken as ESC.
  22.  *   + There should be support for a distinct Command keymap
  23.  *     with Mac-like default bindings.
  24.  * - "macify" ought to be extended to find-file and perhaps
  25.  *   other commands
  26.  * - perhaps there are newer MacOS facilities that ought to be
  27.  *   exploited.  Apple Events?
  28.  * - the hacky way the command keystrokes are described in About Jove
  29.  *   ought to be improved.
  30.  * - Highlighting ought to be supported.
  31.  * - Mouse support ought to be better.  For example, selecting text
  32.  *   ought to be at least as well done as under XTerm!
  33.  * - [supposition] Because double-clicking is supported, nothing
  34.  *   is done for a single click until the double-click timeout
  35.  *   happens.  Since the double-click action is a superset of
  36.  *   the single-click action, the single click action ought to
  37.  *   be immediately performed and then augmented if a double-click
  38.  *   happens.
  39.  * - see also comments containing ???
  40.  */
  41.  
  42. #include "tune.h"
  43.  
  44. #ifdef MAC    /* the body is the rest of this file */
  45.  
  46. #include "jove.h"
  47.  
  48. #include <Controls.h>
  49. #include <Desk.h>
  50. #include <Dialogs.h>
  51. #include <Errors.h>
  52. #include <Events.h>
  53. #include <Files.h>
  54. #include <Fonts.h>
  55. #include <Lists.h>
  56. #include <LoMem.h>
  57. #include <Menus.h>
  58. #include <Quickdraw.h>
  59. #include <Resources.h>
  60. #include <SegLoad.h>
  61. #include <StandardFile.h>
  62. #include <ToolUtils.h>
  63. #include <Types.h>
  64. #include <Windows.h>
  65.  
  66. #include <errno.h>
  67. #include <pascal.h>
  68.  
  69. #include "mac.h"
  70. #include "ask.h"
  71. #include "chars.h"
  72. #include "disp.h"
  73. #include "extend.h"
  74. #include "fp.h"    /* for flushscreen() */
  75. #include "commands.h"
  76. #include "fmt.h"
  77. #include "marks.h"
  78. #include "misc.h"
  79. #include "move.h"
  80. #include "screen.h"
  81. #include "scandir.h"
  82. #include "term.h"
  83. #include "vars.h"
  84. #include "version.h"
  85. #include "wind.h"
  86.  
  87. extern struct menu Menus[NMENUS];   /* from menumaps.txt => menumaps.c */
  88.  
  89. private    EventRecord the_Event;
  90.  
  91. private void SetBounds proto((void));
  92. private void Set_std proto((void));
  93. private void Reset_std proto((void));
  94. private bool findtext proto((void));
  95.  
  96.  
  97. /* tn.h Modified for variable screen size 11/21/87. K. Mitchum */
  98.  
  99. #define SCREENSIZE (wc->w_rows * ROWSIZE)
  100. #define FONT monaco
  101. #define TEXTSIZE 9
  102.  
  103. #define HEIGHT 11
  104. #define WIDTH 6
  105. #define DESCENT 2
  106. #define TWIDTH CO * WIDTH
  107. #define THEIGHT LI * HEIGHT
  108.  
  109. /* window specs */
  110.  
  111. #define SCROLLWIDTH 16    /* width of scroll bar control in pixels */
  112. #define WINDWIDTH (wc->w_width - SCROLLWIDTH + 1)    /* local coordinates */
  113. #define WINDHEIGHT (wc->w_height)    /* local coordinates */
  114. #define MAXROW ILI
  115. #define MAXCOL (CO - 1)
  116.  
  117.  
  118. /* for keyboard routines */
  119. #define MCHARS 32    /* length of circular buffer -- must be a power of two */
  120. #define NCHMASK (MCHARS - 1)    /* mask for modulo MCHARS */
  121.  
  122.  
  123. /***************************************************/
  124.  
  125. private void
  126.     putcurs proto((unsigned row, unsigned col, bool vis)),
  127.     curset proto((bool desired)),
  128.     dellines proto((int n, int bot)),
  129.     inslines proto((int n, int bot));
  130.  
  131. private Rect LimitRect;    /* bounds we can't move past */
  132.  
  133. struct wind_config {
  134.     int w_width;    /* pixel width of the Mac window */
  135.     int    w_height;
  136.     int    w_rows;    /* rows of characters which fit the window */
  137.     int    w_cols;
  138. } wc_std, wc_user, *wc;
  139.  
  140. private WindowPtr theScreen;
  141.  
  142. bool
  143.     Windchange,
  144.     EventCmd,
  145.     Keyonly,
  146.     Bufchange,
  147.     Modechange;
  148.  
  149. bool
  150.     Macmode = NO;    /* VAR: use Mac file selector */
  151.  
  152. /* Initialization Routines. */
  153.  
  154. void
  155. getTERM()
  156. {
  157. }
  158.  
  159. /* For each binding, mark the command with the binding.
  160.  * We use it for "About Jove ...".
  161.  * ??? This is faster than using find_binds, but it has problems:
  162.  * - it only notes the last binding of each command
  163.  * - it only reflects the three listed keymaps
  164.  * - it requires a wart on struct cmd
  165.  * - it is MAC-only
  166.  */
  167.  
  168. private void
  169. InitMapBinds(km, kmc)
  170. data_obj    **km;
  171. char    kmc;
  172. {
  173.     ZXchar i;
  174.  
  175.     for (i = 0; i < NCHARS; i++) {
  176.         if (*km != NULL && obj_type(*km) == COMMAND) {
  177.             struct cmd    *c = (struct cmd *) *km;
  178.  
  179.             c->c_map = kmc;
  180.             c->c_key = i;
  181.         }
  182.         km += 1;
  183.     }
  184. }
  185.  
  186. private void
  187. InitBinds()
  188. {
  189.     InitMapBinds(MainKeys, F_MAINMAP);
  190.     InitMapBinds(EscKeys, F_PREF1MAP);
  191.     InitMapBinds(CtlxKeys, F_PREF2MAP);
  192. }
  193.  
  194. private    WindowPtr window;
  195. private    Rect r;
  196. private CursHandle cross;
  197.  
  198. private void InitSysMenu proto((void));
  199.  
  200. void
  201. InitEvents()
  202. {
  203.     window = theScreen;
  204.     InitSysMenu();
  205.     SetRect(&r, window->portRect.left,
  206.         window->portRect.top,
  207.         window->portRect.right - SCROLLWIDTH,
  208.         window->portRect.bottom - SCROLLWIDTH);
  209.     cross = GetCursor(crossCursor);
  210. }
  211.  
  212. private void    tn_init proto((void));
  213. private int    getdir proto((void));
  214.  
  215. void
  216. MacInit()
  217. {
  218.     tn_init();
  219.     getdir();
  220.     strcpy(TmpDir, gethome());
  221.     strcpy(ShareDir, TmpDir);
  222.     InitBinds();
  223. }
  224.  
  225. void
  226. ttysetattr(n)
  227. bool    n;    /* also used as subscript! */
  228. {
  229. }
  230.  
  231. /* Surrogate unix-style file i/o routines for Jove.  These replace the
  232.    routines distributed in the libraries.  They work with Jove, but may
  233.    not be general enough for other purposes. */
  234.  
  235. #define NFILES 10
  236.  
  237. private int cur_vol;    /* Disk or volume number */
  238. private long cur_dir;    /* Directory number */
  239. private int cur_vref;    /* ugh.. Vref for volume + directory */
  240.  
  241. struct ftab {
  242.     bool inuse;
  243.     int refnum;    /* Mac file reference number */
  244. } ft[NFILES];
  245.  
  246. private void
  247. fsetup(p)
  248. HParmBlkPtr p;
  249. {
  250.     byte_zero(p, sizeof(HParamBlockRec));
  251.     p->fileParam.ioVRefNum = cur_vol;
  252.     p->fileParam.ioDirID = cur_dir;
  253.     /* p->fileParam.ioFVersNum = 0; */
  254. }
  255.  
  256. private void
  257. isetup(p)
  258. IOParam *p;
  259. {
  260.     byte_zero(p, sizeof(IOParam));
  261.     p->ioVRefNum = cur_vol;
  262. }
  263.  
  264.  
  265. /* Kludge to convert Macintosh error codes to something like Unix. */
  266.  
  267. private int
  268. cvt_err(err)    /* some of these don't make sense... */
  269. int    err;
  270. {
  271.     switch(err) {
  272.     case noErr:
  273.         errno = 0;
  274.         return 0;
  275.     case dirFulErr:
  276.     case dskFulErr:
  277.         errno = ENOSPC;
  278.         break;
  279.     /* case nsvErr: */
  280.     /* case mFulErr: */
  281.     /* case tmfoErr: */
  282.     /* case fnfErr: */
  283.     default:
  284.         errno = ENOENT;
  285.         break;
  286.     case ioErr:
  287.         errno = EIO;
  288.         break;
  289.     case bdNamErr:
  290.     case opWrErr:
  291.     case paramErr:
  292.         errno = EINVAL;
  293.         break;
  294.     case fnOpnErr:                /* dubious... */
  295.     case rfNumErr:
  296.         errno = EBADF;
  297.         break;
  298.     case eofErr:                /* ditto */
  299.     case posErr:
  300.         errno = /* no longer defined: ESPIPE */ EIO;
  301.         break;
  302.     case wPrErr:
  303.         errno = EROFS;
  304.         break;
  305.     case fLckdErr:
  306.     case permErr:
  307.         errno = EACCES;
  308.         break;
  309.     case fBsyErr:
  310.         errno = EBUSY;
  311.         break;
  312.     case dupFNErr:
  313.         errno = EEXIST;
  314.         break;
  315.     case gfpErr:
  316.     case volOffLinErr:
  317.     case volOnLinErr:
  318.     case nsDrvErr:
  319.         errno = ENODEV;
  320.         break;
  321.     case noMacDskErr:
  322.     case extFSErr:
  323.         errno = EIO;
  324.         break;
  325.     case fsRnErr:
  326.     case badMDBErr:
  327.     case wrPermErr:
  328.         errno = /* no longer defined: EPERM */ EACCES;
  329.         break;
  330.     }
  331.     return -1;
  332. }
  333.  
  334. private StringPtr
  335. cvt_fnm(file)
  336. const char *file;
  337. {
  338.     static char nm[255];
  339.     char *t;
  340.  
  341.     if (*file == '/') {
  342.         strcpy(nm, file + 1);    /* full path */
  343.     } else {
  344.         if (strchr(file + 1, '/') != NULL)
  345.             strcpy(nm, "/");    /* make a partial pathname */
  346.         else
  347.             nm[0] = '\0';
  348.         strcat(nm, file);
  349.     }
  350.     for (t = nm; (t = strchr(t, '/')) != NULL; )
  351.         *t++ = ':';
  352.     return CtoPstr(nm);
  353. }
  354.  
  355. private int do_creat proto((HParmBlkPtr p, StringPtr nm));
  356.  
  357. int
  358. creat(name, perm)    /* permission mode is irrelevant on a Mac */
  359. const char    *name;
  360. int    perm;
  361. {
  362.     int fd, err;
  363.     StringPtr nm;
  364.     HParamBlockRec p;
  365.  
  366.     nm = cvt_fnm(name);    /* convert filename to Mac type name */
  367.     for (fd = 0; ft[fd].inuse; fd++) {
  368.         if (fd == NFILES-1) {
  369.             errno = EMFILE;
  370.             return -1;
  371.         }
  372.     }
  373.     fsetup(&p);    /* try to delete it, whether it is there or not. */
  374.     p.fileParam.ioNamePtr = nm;
  375.     if ((err = PBHDelete(&p, 0)) != noErr && err != fnfErr)
  376.         return cvt_err(err);
  377.     if (do_creat(&p, nm) != 0)
  378.         return -1;
  379.     ft[fd].inuse = YES;
  380.     ft[fd].refnum = p.ioParam.ioRefNum;
  381.     return fd + 1;
  382. }
  383.  
  384. #ifdef USE_PROTOTYPES
  385. int
  386. open(const char *path, int flags, ...)
  387. #else
  388. int
  389. open(path, flags)
  390. const char    *path;
  391. int    flags;
  392. #endif
  393. {
  394.     int fd, err;
  395.     StringPtr nm;
  396.     HParamBlockRec p;
  397.  
  398.     nm = cvt_fnm(path);    /* convert filename to Mac type name */
  399.     for (fd = 0; ft[fd].inuse; fd++) {
  400.         if (fd == NFILES-1) {
  401.             errno = EMFILE;
  402.             return -1;
  403.         }
  404.     }
  405.     fsetup(&p);
  406.     switch (flags & 3) {
  407.     case 0:    /* O_RDONLY */
  408.         p.ioParam.ioPermssn = fsRdPerm;
  409.         break;
  410.     case 1:    /* O_WRONLY */
  411.         p.ioParam.ioPermssn = fsWrPerm;
  412.         break;
  413.     case 2:    /* O_RDWR */
  414.         p.ioParam.ioPermssn = fsRdWrPerm;
  415.         break;
  416.     }
  417.     p.ioParam.ioNamePtr = nm;
  418.     p.ioParam.ioMisc = 0;
  419.     if ((err = PBHOpen(&p, 0)) != noErr)
  420.         return cvt_err(err);
  421.     ft[fd].refnum = p.ioParam.ioRefNum;
  422.     p.ioParam.ioPosMode = fsFromStart;
  423.     p.ioParam.ioPosOffset = 0;
  424.     if ((err = PBSetFPos((ParamBlockRec *) &p, 0)) != noErr)
  425.         return cvt_err(err);
  426.     ft[fd].inuse = YES;
  427.     errno = 0;
  428.     return fd + 1;
  429. }
  430.  
  431. private int
  432. do_creat(p, nm)
  433. HParmBlkPtr p;
  434. StringPtr nm;
  435. {
  436.     int err;
  437.  
  438.     fsetup(p);
  439.     p->fileParam.ioNamePtr = nm;
  440.     if ((err = PBHCreate(p, 0)) != noErr)
  441.         return cvt_err(err);
  442.  
  443.     fsetup(p);
  444.     p->fileParam.ioNamePtr = nm;
  445.     p->fileParam.ioFDirIndex = 0;
  446.     if ((err = PBHGetFInfo(p, 0)) != noErr)
  447.         return cvt_err(err);
  448.  
  449.     p->fileParam.ioDirID = cur_dir;
  450.     p->fileParam.ioFlFndrInfo.fdType = 'TEXT';
  451.     p->fileParam.ioFlFndrInfo.fdCreator = 'JV01';
  452.     p->fileParam.ioFlFndrInfo.fdFlags = 0;
  453.     p->fileParam.ioFVersNum = 0;
  454.     if ((err = PBHSetFInfo(p, 0)) != noErr)
  455.         return cvt_err(err);
  456.  
  457.     fsetup(p);
  458.     p->ioParam.ioNamePtr = nm;
  459.     p->ioParam.ioPermssn = fsRdWrPerm;
  460.     p->ioParam.ioMisc = 0;
  461.     if (cvt_err(PBHOpen(p, 0)))
  462.         return -1;
  463.  
  464.     return 0;
  465. }
  466.  
  467.  
  468. int
  469. close(fd)
  470. int    fd;
  471. {
  472.     int err;
  473.     HParamBlockRec p;
  474.  
  475.     if (!ft[--fd].inuse) {
  476.         errno = EBADF;
  477.         return -1;
  478.     }
  479.  
  480.     fsetup(&p);
  481.     p.ioParam.ioRefNum = ft[fd].refnum;
  482.     ft[fd].inuse = NO;
  483.     if (cvt_err(PBClose((ParamBlockRec *) &p, 0)) < 0)
  484.         return -1;
  485.  
  486.     fsetup(&p);
  487.     p.ioParam.ioNamePtr = NULL;
  488.     if (cvt_err(PBFlushVol((ParamBlockRec *) &p, 0)) < 0)
  489.         return -1;
  490.  
  491.     return 0;
  492. }
  493.  
  494. private SSIZE_T con_read proto((char *buf, size_t size));
  495.  
  496. /* Raw UNIX-like read */
  497.  
  498. SSIZE_T
  499. read(fd, ubuf, n)
  500. int    fd;
  501. UnivPtr    ubuf;
  502. size_t    n;
  503. {
  504.     char    *buf = ubuf;    /* char * is more useful */
  505.     int err;
  506.     IOParam p;
  507.  
  508.     if (fd == 0) {
  509.         return con_read(buf, n);
  510.     } else {
  511.         if (!ft[--fd].inuse) {
  512.             errno = EBADF;
  513.             return -1;
  514.         }
  515.         isetup(&p);
  516.         p.ioRefNum = ft[fd].refnum;
  517.         p.ioBuffer = buf;
  518.         p.ioReqCount = n;
  519.         p.ioPosMode = fsFromMark;
  520.         p.ioPosOffset = 0;
  521.         if ((err = PBRead((ParamBlockRec *)&p, 0)) != noErr && err != eofErr)
  522.             return cvt_err(err);
  523.  
  524.         errno = 0;
  525.         return p.ioActCount;
  526.     }
  527. }
  528.  
  529. /* Raw UNIX-like write */
  530.  
  531. SSIZE_T
  532. write(fd, ubuf, n)
  533. int    fd;
  534. UnivConstPtr    ubuf;
  535. size_t    n;
  536. {
  537.     const char    *buf = ubuf;    /* char * is more convenient */
  538.  
  539.     if (fd == 0) {
  540.         writetext((unsigned char *)buf, n);
  541.         return n;
  542.     } else {
  543.         IOParam p;
  544.         int    err;
  545.         const char    *ebuf = buf + n;
  546.  
  547.         if (!ft[--fd].inuse) {
  548.             errno = EBADF;
  549.             return -1;
  550.         }
  551.         isetup(&p);
  552.         p.ioRefNum = ft[fd].refnum;
  553.         p.ioPosMode = fsFromMark;
  554.         p.ioReqCount = n;
  555.         p.ioBuffer = (Ptr)buf;
  556.         p.ioPosOffset = 0L;    /* bidirectional */
  557.         if ((err = PBWrite((ParamBlockRec *)&p, 0)) != noErr)
  558.             return cvt_err(err);
  559.         return p.ioActCount;
  560.     }
  561. }
  562.  
  563. long
  564. lseek(fd, offset, whence)
  565. int    fd;
  566. long    offset;
  567. int    whence;
  568. {
  569.     int err;
  570.     long cur_mark, leof, new_mark;
  571.     IOParam p;
  572.  
  573.     if (!ft[--fd].inuse) {
  574.         errno = EBADF;
  575.         return -1;
  576.     }
  577.  
  578.     isetup(&p);
  579.     p.ioRefNum = ft[fd].refnum;
  580.     if ((err = PBGetFPos((ParamBlockRec *)&p, 0)) != noErr)
  581.         return cvt_err(err);
  582.  
  583.     cur_mark = p.ioPosOffset;
  584.     isetup(&p);
  585.     p.ioRefNum = ft[fd].refnum;
  586.     if ((err = PBGetEOF((ParamBlockRec *)&p, 0)) != noErr)
  587.         return cvt_err(err);
  588.  
  589.     leof = (long) p.ioMisc;
  590.     switch(whence) {
  591.     case 0:
  592.         new_mark = offset;
  593.         break;
  594.     case 1:
  595.         new_mark = offset + cur_mark;
  596.         break;
  597.     case 2:
  598.         new_mark = offset + leof;
  599.         break;
  600.     default:
  601.         errno = EINVAL;
  602.         return -1;
  603.     }
  604.     if (new_mark > leof) {
  605.         /* need more space in file -- grow it */
  606.         isetup(&p);
  607.         p.ioRefNum = ft[fd].refnum;
  608.         p.ioMisc = (Ptr) new_mark;
  609.         if ((err = PBSetEOF((ParamBlockRec *)&p, 0)) != noErr)
  610.             return cvt_err(err);
  611.     }
  612.     isetup(&p);
  613.     p.ioRefNum = ft[fd].refnum;
  614.     p.ioPosOffset = new_mark;
  615.     p.ioPosMode = fsFromStart;
  616.     if ((err = PBSetFPos((ParamBlockRec *)&p, 0)) != noErr)
  617.         return cvt_err(err);
  618.     errno = 0;
  619.     return p.ioPosOffset;
  620. }
  621.  
  622. /* delete file, if it exists */
  623.  
  624. int
  625. unlink(name)
  626. const char *name;
  627. {
  628.     int fd, err;
  629.     HParamBlockRec p;
  630.  
  631.     fsetup(&p);
  632.     p.fileParam.ioNamePtr = cvt_fnm(name);
  633.     if ((err = PBHDelete(&p, 0)) != noErr && err != fnfErr)
  634.         return cvt_err(err);
  635.     return 0;
  636. }
  637.  
  638. /* Console read routine */
  639.  
  640. private ZXchar rawgetc proto((void));
  641.  
  642. private SSIZE_T
  643. con_read(buf, size)
  644. char *buf;
  645. size_t size;
  646. {
  647.     size_t n;
  648.     ZXchar p;
  649.  
  650.  
  651.     n = 0;
  652.     do {
  653.         p = rawgetc();
  654.         *buf++ = p;
  655.         n++;
  656.     } while (rawchkc() && n <= size);
  657.     return n;
  658. }
  659.  
  660. void
  661. dobell(n)    /* declared in term.h */
  662. int    n;
  663. {
  664.     while (--n >= 0)
  665.         SysBeep(5);
  666.     flushscreen();
  667. }
  668.  
  669. /* Simplified stat() routine emulates what is needed most. */
  670.  
  671. int
  672. stat(fname, buf)
  673. const char *fname;
  674. struct stat *buf;
  675. {
  676.     CInfoPBRec p;
  677.     StringPtr nm;
  678.  
  679.     nm = cvt_fnm(fname);
  680.     byte_zero(&p, sizeof(CInfoPBRec));
  681.     p.hFileInfo.ioCompletion = 0;
  682.     p.hFileInfo.ioNamePtr = nm;
  683.     p.hFileInfo.ioFVersNum = 0;
  684.     p.hFileInfo.ioFDirIndex = 0;
  685.     p.hFileInfo.ioVRefNum = cur_vol;
  686.     p.hFileInfo.ioDirID = cur_dir;
  687.  
  688.     switch (PBGetCatInfo(&p, 0)) {
  689.     case noErr:
  690.         errno = 0;
  691.         buf->st_dev = p.hFileInfo.ioVRefNum + 1;    /* don't want 0 */
  692.         buf->st_ino = p.hFileInfo.ioDirID;
  693.         buf->st_size = p.hFileInfo.ioFlLgLen;
  694.         buf->st_mtime = p.hFileInfo.ioFlMdDat;
  695.         buf->st_mode = (p.hFileInfo.ioFlAttrib & 0x10) ? S_IFDIR : S_IFREG;
  696.         return 0;
  697.     case nsvErr:
  698.     case paramErr:
  699.     case bdNamErr:
  700.     case fnfErr:
  701.         errno = ENOENT;
  702.         break;
  703.     case ioErr:
  704.         errno = EIO;
  705.         break;
  706.     default:
  707.         errno = ENOENT;
  708.         break;
  709.     }
  710.     return -1;
  711. }
  712.  
  713. /* Directory related routines.  Jove keeps track of the true Volume (disk)
  714.    number and directory number, and avoids "Working Directory Reference
  715.    Numbers", which are confusing. */
  716.  
  717. private int
  718. getdir()    /* call this only once, during startup. */
  719. {
  720.     WDPBRec p;
  721.  
  722.     p.ioCompletion = 0;
  723.     p.ioNamePtr = NULL;
  724.     if (PBHGetVol(&p, 0) != noErr)
  725.         return -1;    /* BIG trouble (but caller never checks returned value!) */
  726.     cur_vol = p.ioWDVRefNum;
  727.     cur_dir = p.ioWDDirID;
  728.     SFSaveDisk = 0 - cur_vol;    /* these are for SF dialogs */
  729.     CurDirStore = cur_dir;
  730.     return 0;
  731. }
  732.  
  733. private int
  734. setdir(vol, dir)
  735. int    vol;
  736. long    dir;
  737. {
  738.     WDPBRec p;
  739.  
  740.     p.ioCompletion = 0;
  741.     p.ioNamePtr = NULL;
  742.     p.ioVRefNum = vol;
  743.     p.ioWDDirID = dir;
  744.     if (PBHSetVol(&p, 0) != noErr)
  745.         return -1;
  746.  
  747.     cur_vol = vol;
  748.     cur_dir = dir;
  749.     SFSaveDisk = 0 - vol;    /* these are for SF dialogs */
  750.     CurDirStore = dir;
  751.     return 0;
  752. }
  753.  
  754. private bool
  755. lookupdir(dir, d)
  756. const char    *dir;    /* UNIX-like pathname for directory */
  757. CInfoPBPtr    d;    /* info from directory */
  758. {
  759.     char
  760.         nm[FILESIZE + 1],
  761.         *t;
  762.  
  763.     if (strcmp(dir, ".") == 0)
  764.         getcwd(nm, sizeof(nm) - 1);
  765.     else
  766.         strcpy(nm, dir);
  767.  
  768.     for (t = nm; (t = strchr(t, '/')) != NULL; )
  769.         *t++ = ':';
  770.  
  771.     t = nm;    /* get rid of initial slashes */
  772.     while (*t == ':')
  773.         t++;
  774.  
  775.     strcat(t, ":");    /* force trailing ':', signifying directory */
  776.  
  777.     byte_zero(d, sizeof(*d));
  778.     /* d->dirInfo.ioCompletion = 0; */
  779.     d->dirInfo.ioNamePtr = CtoPstr(t);
  780.     d->dirInfo.ioVRefNum = cur_vol;
  781.     /* d->dirInfo.ioFDirIndex = 0; */
  782.     /* d->dirInfo.ioDrDirID = 0; */
  783.     PBGetCatInfo(d, 0);
  784.     return d->dirInfo.ioResult == noErr
  785.         && (d->dirInfo.ioFlAttrib & 0x10) != 0;
  786. }
  787.  
  788. int
  789. chdir(dir)
  790. const char *dir;
  791. {
  792.     CInfoPBRec d;
  793.  
  794.     if (strcmp(dir, "/") == 0    /* There is no root... */
  795.     || !lookupdir(dir, &d)
  796.     || setdir(d.dirInfo.ioVRefNum, d.dirInfo.ioDrDirID) < 0)
  797.         return -1;
  798.     return 0;
  799. }
  800.  
  801. /* Scandir returns the number of entries or -1 if the directory cannot
  802.    be opened or malloc fails.
  803.    Note: if we ever support RECOVER, this code will have to be moved
  804.    to scandir.c */
  805.  
  806. int
  807. jscandir(dir, nmptr, qualify, sorter)
  808. char    *dir;
  809. char    ***nmptr;
  810. bool    (*qualify) ptrproto((char *));
  811. int    (*sorter) ptrproto((UnivConstPtr, UnivConstPtr));
  812. {
  813.     long DirID;
  814.     char    **ourarray;
  815.     unsigned int    nalloc = 10,
  816.             nentries = 0,
  817.             index = 1;
  818.  
  819.     if (strcmp(dir, "/") == 0) {
  820.         /* we are enumerating volumes */
  821.         DirID = 0;
  822.     } else {
  823.         /* we are enumerating the contents of a volume or directory */
  824.         CInfoPBRec    d;
  825.  
  826.         if (!lookupdir(dir, &d))
  827.             return -1;
  828.         DirID = d.dirInfo.ioDrDirID;
  829.     }
  830.  
  831.     ourarray = (char **) emalloc(nalloc * sizeof (char *));
  832.     for (;;) {
  833.         Str32 name;    /* 31 is limit, but we might add a '/' */
  834.  
  835.         if (DirID == 0) {
  836.             /* we are enumerating volumes */
  837.             ParamBlockRec    d;
  838.  
  839.             byte_zero(&d, sizeof(d));
  840.             d.volumeParam.ioCompletion = 0;
  841.             d.volumeParam.ioNamePtr = name;
  842.             d.volumeParam.ioVRefNum = 0;
  843.             d.volumeParam.ioVolIndex = index++;
  844.             if (PBGetVInfo(&d, 0) != noErr)
  845.                 break;    /* we are done, then */
  846.             PtoCstr(name);
  847. #ifdef DIRECTORY_ADD_SLASH
  848.             /* I *think* this has got to be a volume */
  849.             strcat((char *)name, "/");
  850. #endif
  851.  
  852.         } else {
  853.             /* we are enumerating the contents of a volume or directory */
  854.             CInfoPBRec    d;
  855.  
  856.             byte_zero(&d, sizeof(d));
  857.             d.dirInfo.ioCompletion = 0;
  858.             d.dirInfo.ioNamePtr = name;
  859.             d.dirInfo.ioVRefNum = cur_vol;
  860.             d.dirInfo.ioFDirIndex = index++;
  861.             d.dirInfo.ioDrDirID = DirID;    /* .ioDirID == .ioDrDirID */
  862.             if (PBGetCatInfo(&d, 0) != noErr)
  863.                 break;    /* we are done, then */
  864.             PtoCstr(name);
  865. #ifdef DIRECTORY_ADD_SLASH
  866.             if (d.dirInfo.ioFlAttrib & 0x10)    /* see Inside Mac IV-122 */
  867.                 strcat((char *)name, "/");
  868. #endif
  869.         }
  870.         if (qualify != NULL && !(*qualify)((char *) name))
  871.             continue;
  872.         /* note: test ensures one space left in ourarray for NULL */
  873.         if (nentries+1 == nalloc)
  874.             ourarray = (char **) erealloc((char *) ourarray, (nalloc += 10) * sizeof (char *));
  875.         ourarray[nentries++] = copystr((char *)name);
  876.     }
  877.     ourarray[nentries] = NULL;
  878.  
  879.     if (sorter != NULL)
  880.         qsort((char *) ourarray, nentries, sizeof (char **), sorter);
  881.     *nmptr = ourarray;
  882.  
  883.     return nentries;
  884. }
  885.  
  886.  
  887. char *
  888. getcwd(buf, size)
  889. char    *buf;
  890. size_t    size;
  891. {
  892.     CInfoPBRec d;
  893.     Str31 nm;
  894.     char    *p = buf + size;    /* build from right */
  895.  
  896.     if (p == buf)
  897.         return NULL;    /* not even room for NUL */
  898.  
  899.     *--p = '\0';
  900.  
  901.     for (d.dirInfo.ioDrDirID = cur_dir; ; d.dirInfo.ioDrDirID = d.dirInfo.ioDrParID) {
  902.         d.dirInfo.ioCompletion = 0;
  903.         d.dirInfo.ioNamePtr = nm;
  904.         d.dirInfo.ioVRefNum = cur_vol;
  905.         d.dirInfo.ioFDirIndex = -1;
  906.         PBGetCatInfo(&d, 0);
  907.         if (d.dirInfo.ioResult != noErr)
  908.             return NULL;
  909.  
  910.         if (p - buf <= Length(nm))
  911.             return NULL;    /* insufficient room for / and name */
  912.  
  913.         p -= Length(nm);
  914.         memcpy((UnivPtr)p, (UnivPtr) (nm+1), Length(nm));
  915.         *--p = '/';
  916.  
  917.         if (d.dirInfo.ioDrDirID == 2)
  918.             break;    /* home directory */
  919.     }
  920.     strcpy(buf, p);    /* left justify */
  921.     return buf;
  922. }
  923.  
  924. char *
  925. gethome()        /* this will be startup directory */
  926. {
  927.     static char *ret = NULL;
  928.     char    space[FILESIZE];
  929.  
  930.     if (ret == NULL)
  931.         ret = copystr(getcwd(space, sizeof(space)));
  932.     return ret;
  933. }
  934.  
  935.  
  936.  
  937. /* Routines that put up and manipulate the "About Jove" dialog. */
  938.  
  939.  
  940. /* (ORIGINALLY IN) about_j.c. */
  941.  
  942.  
  943. #define DLOGNAME "\pABOUT_JDLOG"
  944.  
  945. #define DONE_ITEM 1
  946. #define LIST_ITEM 2
  947.  
  948.  
  949. #define DWIDTH 460        /* there should be an easy way to get this */
  950. #define DHEIGHT 240        /* from the resource file! */
  951.  
  952. WindowPtr makedisplay();
  953. ListHandle makelist();
  954.  
  955.  
  956. private WindowPtr theWindow;
  957. private ListHandle theList;
  958. private Rect theListRect;
  959. private EventRecord theEvent;
  960.  
  961.  
  962.  
  963. private void
  964.     do_list proto((void)),
  965.     do_events proto((void));
  966.  
  967. private WindowPtr
  968.     makedisplay proto((void));
  969.  
  970. private ListHandle
  971.     makelist proto((void));
  972.  
  973. private void
  974. about_j()
  975. {
  976.     WindowPtr OldWindow;
  977.  
  978.     GetPort(&OldWindow);
  979.  
  980.     if ((theWindow = makedisplay()) == 0)
  981.         return;
  982.     SetPort(theWindow);
  983.     if (theList = makelist()) {
  984.         LActivate(1, theList);
  985.         do_list();
  986.         ShowWindow(theWindow);
  987.         do_events();
  988.     }
  989.     SetPort(OldWindow);
  990.     LDispose(theList);
  991.     DisposDialog(theWindow);
  992. }
  993.  
  994.  
  995. private WindowPtr
  996. makedisplay()
  997. {
  998.     static short dlogid = 0;
  999.  
  1000.     DialogPtr theDialog;
  1001.     Handle theHandle;
  1002.     Handle theResource;
  1003.     Str255 buf;
  1004.     ResType resType;
  1005.     short itemType;
  1006.     Rect theRect;
  1007.     short dh, dv;    /* to center dialog on the screen */
  1008.     Str255 nostring;
  1009.  
  1010.     if (dlogid == 0) {
  1011.         if ((theResource = GetNamedResource('DLOG', DLOGNAME)) == NULL)
  1012.             return (WindowPtr)NULL;
  1013.         itemType = 'DLOG';
  1014.         GetResInfo(theResource, &dlogid, &resType, buf);
  1015.     }
  1016.  
  1017.     theDialog = GetNewDialog(dlogid, 0L, (WindowPtr) -1);
  1018.     nostring[0] = 0;    /* set length of Pascal String to 0 */
  1019.     ParamText(
  1020.         "\pMacJove - Copyright (C) 1986-1996 J. Payne, K. Gegenfurtner,",
  1021.         "\pK. Mitchum. Portions (C) THINK Technologies, Inc.",
  1022.         nostring, nostring);
  1023.  
  1024.     dh = qd.screenBits.bounds.left + (qd.screenBits.bounds.right - DWIDTH) / 2;
  1025.     dv = qd.screenBits.bounds.top  + (qd.screenBits.bounds.bottom - DHEIGHT) / 2;
  1026.     MoveWindow((WindowPtr)theDialog, dh, dv, 0);
  1027.     ShowWindow((WindowPtr)theDialog);
  1028.  
  1029.  
  1030.     GetDItem(theDialog, LIST_ITEM, &itemType, &theHandle, &theRect);
  1031.     theListRect = theRect;
  1032.     theListRect.right -= 15;
  1033.     ((WindowPtr)theDialog)->txFont = FONT;
  1034.     ((WindowPtr)theDialog)->txSize = TEXTSIZE;
  1035.  
  1036.     return (WindowPtr) theDialog;
  1037. }
  1038.  
  1039. private void
  1040. do_display()        /* draw necessary controls, lines */
  1041. {
  1042.     Rect rViewF;        /* framing rect for list */
  1043.     int offset;
  1044.  
  1045.     rViewF = theListRect;
  1046.  
  1047.     rViewF.left--;
  1048.     rViewF.top--;
  1049.     rViewF.right++;
  1050.     rViewF.bottom++;
  1051.     FrameRect(&rViewF);
  1052.  
  1053.     DrawControls(theWindow);
  1054. }
  1055.  
  1056. private ListHandle
  1057. makelist()
  1058. {
  1059.     Point csize;
  1060.     Rect dataBounds, rView;    /* list boundaries */
  1061.  
  1062.     csize.h = csize.v = 0;
  1063.     SetRect(&dataBounds, 0, 0, 1, 0);
  1064.     return LNew(&theListRect, &dataBounds, csize, 0, theWindow, 0, 0, 0, 1);
  1065. }
  1066.  
  1067. private void
  1068. printbind(f, buf)
  1069. const struct cmd *f;
  1070. char *buf;
  1071. {
  1072.     char c;
  1073.  
  1074.     if (f->c_map == 0 || (c = f->c_key) == 0x7f) {
  1075.         strcpy(buf, "        ");
  1076.         return;
  1077.     }
  1078.     switch(f->c_map) {
  1079.     case F_MAINMAP:
  1080.         strcpy(buf, "     ");
  1081.         break;
  1082.  
  1083.     case F_PREF1MAP:
  1084.         strcpy(buf, " ESC ");
  1085.         break;
  1086.  
  1087.     case F_PREF2MAP:
  1088.         strcpy(buf, "  ^X ");
  1089.         break;
  1090.     }
  1091.     if (c < ' ') {
  1092.         buf[5] = '^';        /* control char */
  1093.         c |= 0x40;
  1094.     } else {
  1095.         buf[5] = ' ';
  1096.     }
  1097.     if ('a' <= c && c <= 'z')
  1098.         c &= 0x5f;
  1099.     buf[6] = c;
  1100.     buf[7] = ' ';
  1101.     buf[8] = '\0';
  1102. }
  1103.  
  1104. private void
  1105. do_list()
  1106. {
  1107.     int row, col;
  1108.     const struct cmd *f;
  1109.     char buf[255];
  1110.     Point theCell;
  1111.  
  1112.     theCell.h = 0;
  1113.  
  1114.     for (f = commands, row = 0; f->Name; f++, row++) {
  1115.         LAddRow(1, row, theList);
  1116.         theCell.v = row;
  1117.  
  1118.         printbind(f, buf);
  1119.         strcat(buf, f->Name);
  1120.         LSetCell(buf, strlen(buf), theCell, theList);
  1121.     }
  1122. }
  1123.  
  1124.  
  1125.  
  1126. private pascal Boolean
  1127. ProcFilter(theDialog, event, itemHit)
  1128. DialogPtr theDialog;
  1129. EventRecord *event;
  1130. short *itemHit;
  1131. {
  1132.     theEvent = *event;
  1133.     if (theEvent.what == keyDown && theEvent.message & charCodeMask == '\r') {
  1134.         *itemHit = 1;
  1135.         return YES;
  1136.     }
  1137.     if (theEvent.what == activateEvt && (WindowPtr) theEvent.message == theWindow) {
  1138.         LDoDraw(1, theList);
  1139.         LActivate(1, theList);
  1140.     }
  1141.     if (theEvent.what == updateEvt && (WindowPtr) theEvent.message == theWindow) {
  1142.         BeginUpdate(theWindow);
  1143.         do_display();
  1144.         DrawDialog(theWindow);
  1145.         LUpdate(theWindow->visRgn, theList);
  1146.         EndUpdate(theWindow);
  1147.     }
  1148.  
  1149.     return NO;
  1150. }
  1151.  
  1152.  
  1153. void
  1154. do_events()
  1155. {
  1156.     short item;
  1157.     bool done = NO;
  1158.     Point p;
  1159.  
  1160.     while (!done) {
  1161.         ModalDialog(ProcFilter, &item);
  1162.         switch(item) {
  1163.         case DONE_ITEM:
  1164.             done = YES;
  1165.             /* ??? fall through? -- DHR */
  1166.         case LIST_ITEM:
  1167.             p = theEvent.where;
  1168.             GlobalToLocal(&p);
  1169.             LClick(p, theEvent.modifiers, theList);
  1170.             break;
  1171.         }
  1172.     }
  1173. }
  1174.  
  1175. /* Window and Control related routines. */
  1176.  
  1177. /* (ORIGINALLY IN) tcon.c.
  1178.    control handler routines for Jove. K. Mitchum 12/86 */
  1179.  
  1180.  
  1181. #define MINC 0
  1182. #define MAXC 100
  1183. #define INITC 0
  1184. #define EVENTLIST (mDownMask | keyDownMask )
  1185.  
  1186. private Point p;
  1187. private bool wc_adjust proto((int, int, struct wind_config *, int));
  1188.  
  1189. private void
  1190.     MakeScrollBar proto((Window *w)),
  1191.     AdjustScrollBar proto((Window *w)),
  1192.     drawfluff proto((void));
  1193.  
  1194. void
  1195. docontrols()    /* called from redisplay routines */
  1196. {
  1197.     Window *w;
  1198.     int top;
  1199.  
  1200.     w = fwind;
  1201.     top = 0;
  1202.     do {
  1203.         if (w->w_control != NULL)
  1204.             HideControl(w->w_control);
  1205.         w = w->w_next;
  1206.     } while (w != fwind);
  1207.     w = fwind;
  1208.     do {
  1209.         w->w_topline = top;
  1210.         if (w->w_control != NULL)
  1211.             AdjustScrollBar(w);
  1212.         else
  1213.             MakeScrollBar(w);
  1214.         ShowControl(w->w_control);
  1215.         top += w->w_height;
  1216.         w = w->w_next;
  1217.     } while (w != fwind);
  1218.     Windchange = NO;
  1219.     drawfluff();
  1220. }
  1221.  
  1222.  
  1223. private void
  1224. MakeScrollBar(w)    /* set up control */
  1225. Window *w;
  1226. {
  1227.     Rect BarRect;
  1228.     int wheight, wtop;
  1229.     WindowPtr window = theScreen;
  1230.  
  1231.     wheight = w->w_height;
  1232.     wtop = w->w_topline;
  1233.     SetRect(&BarRect, window->portRect.right - SCROLLWIDTH + 1,
  1234.         window->portRect.top -2 + wtop * HEIGHT,
  1235.         window->portRect.right +1,
  1236.         window->portRect.top + ((wheight + wtop) * HEIGHT + 1));
  1237.     w->w_control = NewControl(window, &BarRect, "\psbar", 1, INITC,
  1238.         MINC, MAXC, scrollBarProc, (long)w);
  1239. }
  1240.  
  1241. private void
  1242. AdjustScrollBar(w)    /* redo existing control */
  1243. Window *w;
  1244. {
  1245.     ControlHandle handle = w->w_control;;
  1246.  
  1247.     if (handle != NULL) {
  1248.         int    wtop = w->w_topline;
  1249.         int    wheight = w->w_height;
  1250.         WindowPtr    window = (*handle)->contrlOwner;
  1251.  
  1252.         SizeControl(handle, SCROLLWIDTH, wheight * HEIGHT + 1);
  1253.  
  1254.         MoveControl(handle, window->portRect.right - SCROLLWIDTH + 1,
  1255.             window->portRect.top - 1 + wtop * HEIGHT);
  1256.     }
  1257. }
  1258.  
  1259. private int ltoc proto((void));    /* calculate ctlvalue for line position */
  1260.  
  1261. void
  1262. SetScrollBar(w)    /* set value of the bar */
  1263. Window *w;
  1264. {
  1265.     SetCtlValue(w->w_control, ltoc());
  1266. }
  1267.  
  1268. private void
  1269. drawfluff()        /* draw controls and dividers */
  1270. {
  1271.     Window *w = fwind;
  1272.  
  1273.     DrawControls(theScreen);
  1274.     DrawGrowIcon(theScreen);
  1275. }
  1276.  
  1277. void
  1278. RemoveScrollBar(w)
  1279. Window *w;
  1280. {
  1281.     if (w->w_control != NULL)
  1282.         DisposeControl(w->w_control);
  1283.     w->w_control = NULL;
  1284. }
  1285.  
  1286. private pascal void
  1287. DScroll(control, part)
  1288. ControlHandle control;
  1289. int part;
  1290. {
  1291.     DownScroll();
  1292.     redisplay();
  1293. }
  1294.  
  1295. private pascal void
  1296. UScroll(control, part)
  1297. ControlHandle control;
  1298. int part;
  1299. {
  1300.     UpScroll();
  1301.     redisplay();
  1302. }
  1303.  
  1304. private pascal void
  1305. NPage(control, part)
  1306. ControlHandle control;
  1307. int part;
  1308. {    NextPage();
  1309.     redisplay();
  1310. }
  1311.  
  1312. private pascal void
  1313. PPage(control, part)
  1314. ControlHandle control;
  1315. int part;
  1316. {    PrevPage();
  1317.     redisplay();
  1318. }
  1319.  
  1320. private long npos;    /* number of lines in buffer */
  1321.  
  1322. private int
  1323. ltoc()    /* calculate ctlvalue for line position */
  1324. {
  1325.     long ipos = LinesTo(curbuf->b_first, curline) + 1;
  1326.  
  1327.     npos = ipos + LinesTo(curline, (LinePtr)NULL) - 1;
  1328.     return (int) ((ipos * MAXC) / npos);
  1329. }
  1330.  
  1331. private LinePtr
  1332. ctol(ctlv)    /* find buffer line for ctlvalue */
  1333. int ctlv;
  1334. {
  1335.     return next_line(curbuf->b_first, (int) ((npos * ctlv)/MAXC));
  1336. }
  1337.  
  1338. private void
  1339. doWind(event, window)
  1340. EventRecord *event;
  1341. WindowPtr window;
  1342. {
  1343.     p = event->where;
  1344.     GlobalToLocal(&p);
  1345.  
  1346.     if (event->what == mouseDown) {
  1347.         ControlHandle whichControl;
  1348.         Window
  1349.             *jwind,
  1350.             *cwind;
  1351.         bool    notcurwind = NO;
  1352.         int    cpart;    /* control part */
  1353.  
  1354.         if ((cpart = FindControl(p, window, &whichControl)) == 0)
  1355.             return;
  1356.  
  1357.         if ((jwind = (Window *) (*whichControl)->contrlRfCon) != curwind) {
  1358.             notcurwind = YES;
  1359.             cwind = curwind;
  1360.             SetWind(jwind);
  1361.         }
  1362.         switch (cpart) {
  1363.         case inUpButton:
  1364.             TrackControl(whichControl, p, (ProcPtr) DScroll);
  1365.             break;
  1366.         case inDownButton:
  1367.             TrackControl(whichControl, p, (ProcPtr) UScroll);
  1368.             break;
  1369.         case inPageUp:
  1370.             TrackControl(whichControl, p, (ProcPtr) PPage);
  1371.             break;
  1372.         case inPageDown:
  1373.             TrackControl(whichControl, p, (ProcPtr) NPage);
  1374.             break;
  1375.         case inThumb:
  1376.             if (TrackControl(whichControl, p, (ProcPtr)NULL)) {
  1377.                 int    newval = GetCtlValue(whichControl);
  1378.  
  1379.                 if (newval == MAXC)
  1380.                     Eof();
  1381.                 else if (newval == MINC)
  1382.                     Bof();
  1383.                 else
  1384.                     SetLine(ctol(newval));
  1385.             }
  1386.             break;
  1387.         }
  1388.         if (notcurwind) {
  1389.             SetWind(cwind);
  1390.             redisplay();
  1391.         }
  1392.         redisplay();    /* again, to set the cursor */
  1393.     } else {
  1394.         if (findtext())
  1395.             redisplay();
  1396.     }
  1397. }
  1398.  
  1399. #define std_state(w) (*((WStateData **)((WindowPeek)((w)))->dataHandle))->stdState
  1400. #define user_state(w) (*((WStateData **)((WindowPeek)((w)))->dataHandle))->userState
  1401.  
  1402. private void
  1403. doDrag(event, window)
  1404. EventRecord *event;
  1405. WindowPtr window;
  1406. {
  1407.     Rect old_std = std_state(window);
  1408.  
  1409.     DragWindow(window, event->where, &LimitRect);
  1410.     if (wc == &wc_std) {
  1411.         wc_user = wc_std;
  1412.         user_state(theScreen) = std_state(theScreen);
  1413.         ZoomWindow(window, 7, 1);
  1414.         wc = &wc_user;
  1415.         Reset_std();
  1416.     }
  1417. }
  1418.  
  1419. private void
  1420. doGrow(event, window)
  1421. EventRecord *event;
  1422. WindowPtr window;
  1423. {
  1424.     long size;
  1425.  
  1426.     /* zero means user didn't change anything */
  1427.     if ((size = GrowWindow(window, event->where, &LimitRect)) != 0) {
  1428.         if (wc == &wc_std) {
  1429.             wc_user = wc_std;
  1430.             user_state(theScreen) = std_state(theScreen);
  1431.             ZoomWindow(window, 7, 1);
  1432.             wc = &wc_user;
  1433.             Reset_std();
  1434.         }
  1435.         if (wc_adjust(LoWord(size), HiWord(size), wc, 0)) {
  1436.             EraseRect(&window->portRect);
  1437.             SizeWindow(window, wc->w_width, wc->w_height, YES);
  1438.             win_reshape(0);    /* no signals here... */
  1439.         }
  1440.     }
  1441. }
  1442.  
  1443. private void
  1444. doZoomIn(event, window)
  1445. EventRecord *event;
  1446. WindowPtr window;
  1447. {
  1448.     if (TrackBox(window, event->where, 7)) {
  1449.             EraseRect(&window->portRect);
  1450.             ZoomWindow(window, 7, 1);
  1451.             wc = &wc_user;
  1452.             win_reshape(0);    /* we do our own toggle, not ZoomWindow() */
  1453.         }
  1454. }
  1455.  
  1456. private void
  1457. doZoomOut(event, window)
  1458. EventRecord *event;
  1459. WindowPtr window;
  1460. {
  1461.     if (TrackBox(window, event->where, 8)) {
  1462.             EraseRect(&window->portRect);
  1463.             ZoomWindow(window, 8, 1);
  1464.             wc = &wc_std;
  1465.             win_reshape(0);    /* we do our own toggle, not ZoomWindow() */
  1466.         }
  1467. }
  1468.  
  1469. private void
  1470. doGoAway(event, window)
  1471. EventRecord *event;
  1472. WindowPtr window;
  1473. {
  1474.     if (TrackGoAway(window, event->where))
  1475.         Leave();
  1476. }
  1477.  
  1478. private Window *
  1479. rtowind(row)    /* return jove window row is in */
  1480. int row;
  1481. {
  1482.     Window *w = fwind;
  1483.  
  1484.     do {
  1485.         if ((w->w_topline <= row) && ((w->w_height + w->w_topline) > row))
  1486.             return w;
  1487.         w = w->w_next;
  1488.     } while (w != fwind);
  1489.     return NULL;
  1490. }
  1491.  
  1492. private LinePtr
  1493. windtol(w, row)        /* return line for row in window */
  1494. Window *w;
  1495. int row;
  1496. {
  1497.     LinePtr l = w->w_top;
  1498.  
  1499.     while (row-- && l != NULL)
  1500.         l = l->l_next;
  1501.     return l;
  1502. }
  1503.  
  1504. private int    ptoxy proto((Point, int *, int *));    /* convert Point to terminal x, y coordinate */
  1505.  
  1506. private bool
  1507. findtext()        /* locate and move the point to match the mouse */
  1508. {
  1509.     int row, col;
  1510.     int offset;
  1511.     long ticks;
  1512.     EventRecord event;
  1513.     Window *w;
  1514.     LinePtr l;
  1515.  
  1516.     ticks = Ticks;
  1517.     ptoxy(p, &row, &col);
  1518.     if ((w = rtowind(row)) == NULL)
  1519.         return NO;
  1520.  
  1521.     if (w != curwind)
  1522.         SetWind(w);
  1523.     offset = PhysScreen[row].s_offset;    /* account for horizontal scrolling and */
  1524.     offset += SIWIDTH(offset) + W_NUMWIDTH(w);    /* line number */
  1525.     row -= w->w_topline;        /* now have row number in window */
  1526.     if (row >= w->w_height -1)
  1527.         return NO;
  1528.  
  1529.     if ((l = windtol(w, row)) == NULL)
  1530.         return NO;
  1531.  
  1532.     if (l->l_dline == NULL_DADDR)
  1533.         return NO;
  1534.  
  1535.     this_cmd = LINECMD;
  1536.     SetLine(l);        /* Curline is in linebuf now */
  1537.     col -= offset;
  1538.     if (col < 0)
  1539.         col = 0;
  1540.     curchar = how_far(curline, col);
  1541.     do {
  1542.         if (GetNextEvent(mUpMask, &event) && (event.when < ticks + DoubleTime)) {
  1543.             set_mark();
  1544.             break;
  1545.         }
  1546.     } while ((Ticks - ticks) < DoubleTime);
  1547.     return YES;
  1548. }
  1549.  
  1550.  
  1551. private int
  1552. ptoxy(p, row, col)    /* convert Point to terminal x, y coordinate */
  1553. Point p;
  1554. int *row, *col;
  1555. {
  1556.     *row = (p.v / HEIGHT);
  1557.     *col = (p.h / WIDTH );
  1558.     if ((*row > MAXROW) || (*col > MAXCOL))
  1559.         return JMP_ERROR;
  1560.     return 0;
  1561. }
  1562.  
  1563. /* Event-related routines.  The Event loop is CheckEvents(), and is called
  1564.    whenever a console read occurs or a call to charp().  During certain
  1565.    activities, such as ask(), etc. non-keyboard events are ignored.
  1566.    This is set by the variable Keyonly.  As an update or activate event
  1567.    generates a call to redisplay(), it is important that redisplay() and
  1568.    related routines NOT check for keyboard characters. */
  1569.  
  1570. /* (ORIGINALLY IN) tevent.c
  1571.     event handler for Jove. K Mitchum 12/86 */
  1572.  
  1573.  
  1574. #define SYS_ID 100
  1575. #define NOFUNC ((void (*) ptrproto((EventRecord *event)))NULL)
  1576. #define NEVENTS 16
  1577.  
  1578. private void
  1579.     doMouse proto((EventRecord *event)),
  1580.     dokeyDown proto((EventRecord *event)),
  1581.     doUpdate proto((EventRecord *event)),
  1582.     doActivate proto((EventRecord *event));
  1583.  
  1584. private void p_refresh proto((void));
  1585.  
  1586. private MenuHandle SysMenu;
  1587.  
  1588. private void (*eventlist[]) ptrproto((EventRecord *event)) =
  1589. {
  1590.     NOFUNC,    /* nullEvent */
  1591.     doMouse,    /* mouseDown */
  1592.     doMouse,    /* mouseUp */
  1593.     dokeyDown,    /* keyDown */
  1594.     NOFUNC,    /* keyUp */
  1595.     dokeyDown,    /* autoKey */
  1596.     doUpdate,    /* updateEvt */
  1597.     NOFUNC,    /* diskEvt */
  1598.     doActivate,    /* activateEvt */
  1599.     NOFUNC,    /* not  used */
  1600.     NOFUNC,    /* networkEvt = 10 */
  1601.     NOFUNC,    /* driverEvt */
  1602.     NOFUNC,    /* app1Evt */
  1603.     NOFUNC,    /* app2Evt */
  1604.     NOFUNC,    /* app3Evt */
  1605.     NOFUNC    /* app4Ev */
  1606. };
  1607.  
  1608.  
  1609. private void
  1610.     SetBufMenu proto((void)),
  1611.     MarkModes proto((void));
  1612.  
  1613. private void
  1614. CheckEvents()
  1615. {
  1616.     EventRecord theEvent;
  1617.     static long time = 0;
  1618.  
  1619.     static void (*fptr) ptrproto((EventRecord *event));
  1620.  
  1621.     if (FrontWindow() == window) {
  1622.         Point Mousep;
  1623.  
  1624.         GetMouse(&Mousep);
  1625.         if (PtInRect(Mousep, &r))
  1626.             SetCursor(*cross);
  1627.         else
  1628.             SetCursor(&qd.arrow);
  1629.     }
  1630.  
  1631.     SystemTask();
  1632.     if (EventCmd && !Keyonly)
  1633.         return;
  1634.     if (Bufchange)
  1635.         SetBufMenu();
  1636.     if (Modechange)
  1637.         MarkModes();
  1638.     while (GetNextEvent(everyEvent, &theEvent)) {
  1639.         if ((theEvent.what < NEVENTS) && (fptr = eventlist[theEvent.what])) {
  1640.             (*fptr)(&theEvent);
  1641.         }
  1642.         SystemTask();
  1643.     }
  1644.     if (TimeDisplayed && (Ticks - time) > 3600) {
  1645.         time = Ticks;
  1646.         UpdModLine = YES;
  1647.         redisplay();
  1648.     }
  1649. }
  1650.  
  1651. private void InitLocalMenus proto((void));
  1652.  
  1653. private void
  1654. InitSysMenu()
  1655. {
  1656.     SysMenu = NewMenu(SYS_ID, "\p\24");
  1657.     AppendMenu(SysMenu, "\pAbout Jove");
  1658.     AddResMenu(SysMenu, 'DRVR');
  1659.     InsertMenu(SysMenu, 0);
  1660.     InitLocalMenus();
  1661.     DrawMenuBar();
  1662. }
  1663.  
  1664. private void
  1665.     doWind proto((EventRecord *event, WindowPtr window)),
  1666.     doGoAway proto((EventRecord *event, WindowPtr window)),
  1667.     doSysMenu proto((EventRecord *event, WindowPtr window)),
  1668.     doSysClick proto((EventRecord *event, WindowPtr window)),
  1669.     doDrag proto((EventRecord *event, WindowPtr window)),
  1670.     doGrow proto((EventRecord *event, WindowPtr window)),
  1671.     doZoomIn proto((EventRecord *event, WindowPtr window)),
  1672.     doZoomOut proto((EventRecord *event, WindowPtr window));
  1673.  
  1674. #define NMEVENTS 9
  1675.  
  1676. private void (*mouselist[]) ptrproto((EventRecord *event, WindowPtr window)) =
  1677. {
  1678.     (void (*) ptrproto((EventRecord *event, WindowPtr window)))NULL,    /* inDesk */
  1679.     doSysMenu,    /* inMenuBar */
  1680.     doSysClick,    /* inSysWindow */
  1681.     doWind,    /* inContent */
  1682.     doDrag,    /* inDrag */
  1683.     doGrow,    /* inGrow */
  1684.     doGoAway,    /* inGoAway */
  1685.     doZoomIn,    /* inZoomIn */
  1686.     doZoomOut    /* inZoomOut */
  1687. };
  1688.  
  1689.  
  1690. private void
  1691. doMouse(event)
  1692. EventRecord *event;
  1693. {
  1694.     if (Keyonly) {
  1695.         if (event->what == mouseDown)
  1696.             SysBeep(2);
  1697.     } else {
  1698.         WindowPtr theWindow;
  1699.         int wpart = FindWindow(event->where, &theWindow);
  1700.         void (*fptr) ptrproto((EventRecord *event, WindowPtr window));
  1701.  
  1702.         if (wpart < NMEVENTS && (fptr = mouselist[wpart]) != NULL)
  1703.             (*fptr)(event, theWindow);
  1704.     }
  1705. }
  1706.  
  1707. private void ProcMenu proto((int menuno, int itemno));
  1708.  
  1709. private void
  1710. doSysMenu(event, window)
  1711. EventRecord *event;
  1712. WindowPtr window;
  1713. {
  1714.     long result = MenuSelect(event->where);
  1715.     int    Menu = (result >> 16) & 0xffff;
  1716.     int    Item = result & 0xffff;
  1717.  
  1718.     if (Item == 0)
  1719.         return;    /* no choice made */
  1720.  
  1721.     if (Menu == SYS_ID) {            /* apple menu */
  1722.         Str255 Name;
  1723.         GrafPtr Port;
  1724.  
  1725.         if (Item == 1) {
  1726.             about_j();
  1727.         } else {
  1728.             GetItem(SysMenu, Item, Name);
  1729.             GetPort(&Port);
  1730.             OpenDeskAcc(Name);
  1731.             SetPort(Port);
  1732.         }
  1733.     } else {
  1734.         ProcMenu(Menu, Item);
  1735.     }
  1736.     HiliteMenu(0);
  1737.     EventCmd = YES;
  1738.     menus_on();
  1739. }
  1740.  
  1741. private void
  1742. doSysClick(event, window)
  1743. EventRecord *event;
  1744. WindowPtr window;
  1745. {
  1746.     SystemClick(event, window);
  1747. }
  1748.  
  1749.  
  1750. private void
  1751. doUpdate(event)
  1752. EventRecord *event;
  1753. {
  1754.     WindowPtr
  1755.         theWindow = (WindowPtr) event->message,
  1756.         oldPort;
  1757.  
  1758.     GetPort(&oldPort);
  1759.     SetPort(theWindow);
  1760.     BeginUpdate(theWindow);
  1761.     p_refresh();
  1762.     drawfluff();
  1763.     EndUpdate(theWindow);
  1764.     SetPort(oldPort);
  1765. }
  1766.  
  1767. private void
  1768. doActivate(event)
  1769. EventRecord *event;
  1770. {
  1771.     WindowPtr theWindow = (WindowPtr) event->message;
  1772.     ControlHandle control;
  1773.     int hilite;
  1774.  
  1775.     SetPort(theWindow);
  1776.     hilite = (event->modifiers & activeFlag)? 0 : 255;
  1777.     for (control = (ControlHandle) (((WindowPeek) theWindow)->controlList)
  1778.     ; (control != 0); control = (*control)->nextControl)
  1779.     {
  1780.             HiliteControl(control, hilite);
  1781.     }
  1782. }
  1783.  
  1784. /* Keyboard routines. */
  1785.  
  1786. /* Keycodes (from Inside MacIntosh I-251).  This table is ONLY used when
  1787.  * we are trying to make the Option key work as a Meta key.  When we are
  1788.  * doing this, the system-supplied character is wrong, so we retranslate
  1789.  * the key code to a character code.
  1790.  *
  1791.  * Since we only use this table when the character generated by an
  1792.  * option-modified key is greater than DEL, and since the Option
  1793.  * modifier does not so affect keypad keys, we need not provide for
  1794.  * them in this table.
  1795.  *
  1796.  * ??? This may need to be updated to reflect keyboards newer than the Mac+!
  1797.  */
  1798.  
  1799. #define NOKEY '?'
  1800.  
  1801. private char nsh_keycodes[] = {
  1802.     'a','s','d','f','h',                    /* 00 - 04 */
  1803.     'g','z','x','c','v',                    /* 05 - 09 */
  1804.     NOKEY,'b','q','w','e',                    /* 0A - 0E */
  1805.     'r','y','t','1','2',                    /* 0F - 13 */
  1806.     '3','4','6','5','=',                    /* 14 - 18 */
  1807.     '9','7','-','8','0',                    /* 19 - 1D */
  1808.     ']','O','u','[','i',                    /* 1E - 22 */
  1809.     'p',CR,'l','j','\'',                    /* 23 - 27 */
  1810.     'k',';','\\',',','/',                    /* 28 - 2C */
  1811.     'n','m','.','\t',NOKEY,                    /* 2D - 31 */
  1812.     '`',DEL                                    /* 32 - 33*/
  1813. };
  1814.  
  1815. private char sh_keycodes[] = {
  1816.     'A','S','D','F','H',                    /* 00 - 04 */
  1817.     'G','Z','X','C','V',                    /* 05 - 09 */
  1818.     NOKEY,'B','Q','W','E',                    /* 0A - 0E */
  1819.     'R','Y','T','!','@',                    /* 0F - 13 */
  1820.     '#','$','^','%','+',                    /* 14 - 18 */
  1821.     '(','&','_','*',')',                    /* 19 - 1D */
  1822.     '}','O','U','{','I',                    /* 1E - 22 */
  1823.     'P',CR,'L','J','\'',                    /* 23 - 27 */
  1824.     'K',';','|','<','?',                    /* 28 - 2C */
  1825.     'N','M','>','\t',NOKEY,                    /* 2D - 31 */
  1826.     '~',DEL                                    /* 32 - 33 */
  1827. };
  1828.  
  1829. /* (ORIGINALLY IN) tkey.c
  1830.    keyboard routines for Macintosh. K Mitchum 12/86 */
  1831.  
  1832. jmp_buf auxjmp;
  1833.  
  1834. private nchars = 0;
  1835. private char charbuf[MCHARS];
  1836.  
  1837. /* The following kludges a meta key out of the option key by
  1838.    sending an escape sequence back to the dispatch routines.  This is
  1839.    not elegant but it works, and doesn't alter escape sequences for
  1840.    those that prefer them.  To remap the control or meta keys,
  1841.    see mackeys.h. */
  1842.  
  1843. private void
  1844. dokeyDown(event)
  1845. EventRecord *event;
  1846. {
  1847.     unsigned mods;
  1848.     int c;
  1849.     static int cptr = 0;
  1850.  
  1851.     if (MCHARS - nchars < 2)
  1852.         return;
  1853.  
  1854.     c  = event->message & charCodeMask;
  1855.  
  1856.     mods = event->modifiers;
  1857.  
  1858.     if (MetaKey && (mods & optionKey)) {
  1859.         /* Treat the Option key as a Meta key.
  1860.          * We have to "undo" the normal option key effect.
  1861.          * This means that, if the character is greater than DEL
  1862.          * and the code is known to our table, we retranslate the
  1863.          * code into a character.
  1864.          * This seems pretty dubious.  I wonder if "KeyTrans" would
  1865.          * be a better tool.
  1866.          */
  1867.         int    code = (event->message & keyCodeMask) >> 8;
  1868.  
  1869.         if (c > DEL && code < elemsof(sh_keycodes))
  1870.             c  = ((mods & shiftKey)? sh_keycodes : nsh_keycodes)[code];
  1871.  
  1872.         /* jam an ESC prefix */
  1873.         charbuf[cptr++] = ESC;
  1874.         cptr &= NCHMASK;
  1875.         nchars++;
  1876.     }
  1877.  
  1878.     if (mods & (cmdKey | controlKey)) {
  1879.         /* control key (command key is treated as a control key too) */
  1880.         if (c == '@' || c == '2' || c == ' ')
  1881.             c = '\0';    /* so we have a null char */
  1882.         if (c != '`')
  1883.             c = CTL(c);        /* make a control char */
  1884.     } else if (c == '`') {
  1885.         c = ESC;    /* for those used to escapes */
  1886.     }
  1887.  
  1888.     charbuf[cptr++] = c;
  1889.     cptr &= NCHMASK;
  1890.     nchars++;
  1891. }
  1892.  
  1893. private ZXchar
  1894. rawgetc()
  1895. {
  1896.     static int cptr = 0;
  1897.     ZXchar c;
  1898.  
  1899.     if (EventCmd)
  1900.         longjmp(auxjmp, 1);
  1901.  
  1902.     while (nchars <= 0) {
  1903.         nchars = 0;
  1904.         if (EventCmd)
  1905.             longjmp(auxjmp, 1);
  1906.  
  1907.         CheckEvents();    /* ugh! WAIT for a character */
  1908.     }
  1909.     nchars--;
  1910.     c = ZXRC(charbuf[cptr++]);
  1911.     cptr &= NCHMASK;        /* zero if necessary */
  1912.     return c;
  1913. }
  1914.  
  1915. bool
  1916. rawchkc()
  1917. {
  1918.     if (EventCmd)
  1919.         longjmp(auxjmp, 1);
  1920.  
  1921.     if (nchars == 0)
  1922.         CheckEvents();    /* this should NOT be necessary! */
  1923.     return nchars > 0;
  1924. }
  1925.  
  1926. /* Routines for calling the standard file dialogs, when macify is YES.
  1927.    If the user changes the directory using the file dialogs, Jove's notion
  1928.    of the current directory is updated. */
  1929.  
  1930.  
  1931. /* (ORIGINALLY IN) tmacf.c. K. Mitchum 12/86.
  1932.    Macify routines for jove. */
  1933.  
  1934. int CurrentVol;            /* see tfile.c */
  1935.  
  1936. #define TYPES  (-1)
  1937.  
  1938. private Point px = {100, 100};
  1939. private unsigned char pmess[] = "\pSave file as: ";
  1940.  
  1941. private pascal Boolean
  1942. Ffilter(p)
  1943. ParmBlkPtr p;
  1944. {
  1945.     Boolean r;
  1946.     char    *name;
  1947.  
  1948.     if (p->fileParam.ioFlFndrInfo.fdType == 'APPL')
  1949.         return YES;
  1950.  
  1951.     /* Filter out our tempfiles.
  1952.      * ??? the test doesn't check to see if the directories match.
  1953.      */
  1954.     name = PtoCstr(p->fileParam.ioNamePtr);
  1955.     r = strcmp(name, ".joveXXX") == 0
  1956. #ifdef ABBREV
  1957.         || strcmp(name, ".jabbXXX") == 0
  1958. #endif
  1959. #ifdef RECOVER
  1960.         || strcmp(name, ".jrecXXX") == 0
  1961. #endif
  1962.         ;
  1963.     CtoPstr(name);
  1964.     return r;
  1965. }
  1966.  
  1967. private void
  1968. check_dir()
  1969. {
  1970.     if (cur_vol != 0 - SFSaveDisk || cur_dir != CurDirStore) {
  1971.         char    space[FILESIZE];
  1972.  
  1973.         setdir(0 - SFSaveDisk, CurDirStore);
  1974.         UpdModLine = YES;    /* make sure jove knows the change */
  1975.         Modechange = YES;
  1976.         setCWD(getcwd(space, sizeof(space)));
  1977.     }
  1978. }
  1979.  
  1980. char *
  1981. gfile(namebuf)    /* return a filename to get */
  1982. char *namebuf;
  1983. {
  1984.     SFReply frec;
  1985.     char ans[FILESIZE];
  1986.  
  1987.     SFSaveDisk = 0 - cur_vol;    /* in case a Desk Accessory changed them */
  1988.     CurDirStore = cur_dir;
  1989.     SFGetFile(px, 0L, Ffilter, TYPES, 0L, 0L, &frec);
  1990.     check_dir();    /* see if any change, set if so */
  1991.     if (frec.good) {
  1992.         EventRecord theEvent;
  1993.  
  1994.         do; while (GetNextEvent(updateMask, &theEvent) == 0);
  1995.         doUpdate(&theEvent);
  1996.         strcpy(ans, PtoCstr(frec.fName));
  1997.         CtoPstr((char *)frec.fName);
  1998.         PathParse(ans, namebuf);
  1999.         return namebuf;
  2000.     }
  2001.     return NULL;
  2002. }
  2003.  
  2004. char *
  2005. pfile(namebuf)
  2006. char *namebuf;
  2007. {
  2008.     SFReply frec;
  2009.     StringPtr nm;
  2010.  
  2011.     SFSaveDisk = 0 - cur_vol;    /* in case a Desk Accessory changed them */
  2012.     CurDirStore = cur_dir;
  2013.     strncpy(namebuf, filename(curbuf), FILESIZE-1);
  2014.     nm = cvt_fnm(namebuf);
  2015.     SFPutFile(px, pmess, nm, 0L, &frec);
  2016.     check_dir();    /* see if any change, set if so */
  2017.     if (frec.good) {
  2018.         EventRecord theEvent;
  2019.         char *h, *p;
  2020.  
  2021.         do; while (GetNextEvent(updateMask, &theEvent) == 0);
  2022.         doUpdate(&theEvent);
  2023.         h = PtoCstr(frec.fName);
  2024.         while (*h == ':')
  2025.             h++;    /* convert to unix style */
  2026.         for (p = h; (p = strchr(p, ':')) != NULL; )
  2027.             *p++ = '/';
  2028.         PathParse(h, namebuf);
  2029.         return namebuf;
  2030.     }
  2031.     return NULL;
  2032. }
  2033.  
  2034.  
  2035. /* getArgs() returns an argument list based on documents clicked on by the user. */
  2036.  
  2037. int
  2038. getArgs(avp)
  2039. char ***avp;
  2040. {
  2041.     int argc, old_vol;
  2042.     short nargs, type;
  2043.     long old_dir;
  2044.     char **argv;
  2045.     char *pathname;
  2046.     AppFile p;
  2047.     WDPBRec d;
  2048.  
  2049.     old_vol = cur_vol;
  2050.     old_dir = cur_dir;
  2051.  
  2052.     CountAppFiles(&type, &nargs);
  2053.     if (nargs > 0) {    /* files to open... */
  2054.         argv = (char **) emalloc((nargs + 2) * sizeof(char *));
  2055.         for (argc = 1; argc <= nargs; argc++) {
  2056.             GetAppFiles(argc, &p);
  2057.             if (type == 0) {
  2058.                 char    space[FILESIZE];
  2059.  
  2060.                 PtoCstr((StringPtr)p.fName);
  2061.                 d.ioCompletion = 0;
  2062.                 d.ioNamePtr = NULL;
  2063.                 d.ioVRefNum = p.vRefNum;
  2064.                 d.ioWDIndex = 0;
  2065.                 PBGetWDInfo(&d, 0);
  2066.                 cur_vol = d.ioWDVRefNum;
  2067.                 cur_dir = d.ioWDDirID;
  2068.                 pathname = getcwd(space, sizeof(space));
  2069.                 argv[argc] = emalloc(strlen((char *)p.fName) + strlen(pathname) + 2);
  2070.                 strcpy(argv[argc], pathname);
  2071.                 strcat(argv[argc], "/");
  2072.                 strcat(argv[argc], (char *)p.fName);
  2073.             }
  2074.             ClrAppFiles(argc);
  2075.         }
  2076.         if (type != 0)
  2077.             argc = 1;
  2078.     } else {
  2079.         argv = (char **) emalloc(2 * sizeof(char*));
  2080.         argc = 1;
  2081.     }
  2082.     argv[0] = "jove";
  2083.  
  2084.     argv[argc] = NULL;
  2085.     *avp = argv;
  2086.     cur_dir = old_dir;
  2087.     cur_vol = old_vol;
  2088.     return argc;
  2089. }
  2090.  
  2091. char *
  2092. mktemp(name)
  2093. char *name;
  2094. {
  2095.     return name;    /* what, me check? */
  2096. }
  2097.  
  2098.  
  2099. /* Menu routines.  The menus items are set up in a similar manner as keys, and
  2100.    are bound prior to runtime.  See menumaps.txt, which must be run through
  2101.    setmaps.  Unlike keys, menu items may be bound to variables, and to
  2102.    buffers.  Buffer binding is only done at runtime. */
  2103.  
  2104. private void
  2105.     InitMenu proto((struct menu *M)),
  2106.     make_edits proto((int menu));
  2107.  
  2108. private void
  2109. InitLocalMenus()
  2110. {
  2111.     int i;
  2112.  
  2113.     for (i = 0; i < NMENUS; i++) {
  2114.         InitMenu(&Menus[i]);
  2115.         if (i == 0)
  2116.             make_edits(Menus[i].menu_id + 1);
  2117.     }
  2118. }
  2119.  
  2120. private void
  2121. InitMenu(M)
  2122. struct menu *M;
  2123. {
  2124.     int i;
  2125.     StringPtr ps;
  2126.  
  2127.     if (M->menu_id == 0)
  2128.         return;
  2129.  
  2130.     M->Mn = NewMenu(M->menu_id, ps=CtoPstr(M->Name));
  2131.     PtoCstr(ps);
  2132.  
  2133.     for (i = 0; i < NMENUITEMS; i++) {
  2134.         data_obj *d = M->m[i];
  2135.  
  2136.         if (d == NULL)
  2137.             break;    /* last item... */
  2138.  
  2139.         switch (d->Type & TYPEMASK) {
  2140.         case STRING:
  2141.             AppendMenu(M->Mn, ps=CtoPstr(d->Name));
  2142.             PtoCstr(ps);
  2143.             break;
  2144.         case VARIABLE:
  2145.             AppendMenu(M->Mn, ps=CtoPstr(d->Name));
  2146.             PtoCstr(ps);
  2147.             if ((((struct variable *)d)->v_flags & V_TYPEMASK) == V_BOOL
  2148.             && *(bool *)(((struct variable *)d)->v_value))
  2149.                 CheckItem(M->Mn, i + 1, YES);
  2150.             break;
  2151.         case COMMAND:
  2152.             AppendMenu(M->Mn, ps=CtoPstr(d->Name));
  2153.             PtoCstr(ps);
  2154.             break;
  2155.         }
  2156.     }
  2157.     InsertMenu(M->Mn, 0);
  2158. }
  2159.  
  2160. private void    MacSetVar proto((struct variable *vp, int mnu, int itm));
  2161.  
  2162. private void
  2163. ProcMenu(menuno, itemno)
  2164. int menuno, itemno;
  2165. {
  2166.     int i;
  2167.     data_obj *d;
  2168.  
  2169.     for (i = 0; i < NMENUS; i++) {
  2170.         if (Menus[i].menu_id == menuno) {
  2171.             itemno--;
  2172.             d = Menus[i].m[itemno];
  2173.             switch(d->Type & TYPEMASK) {
  2174.             case COMMAND:
  2175.                 ExecCmd((data_obj *) d);
  2176.                 break;
  2177.             case BUFFER:
  2178.                 SetABuf(curbuf);
  2179.                 tiewind(curwind, (Buffer *) d);
  2180.                 SetBuf((Buffer *) d);
  2181.                 break;
  2182.             case VARIABLE:
  2183.                 MacSetVar((struct variable *) d, i, itemno);
  2184.                 break;
  2185.             }
  2186.             break;
  2187.         }
  2188.     }
  2189. }
  2190.  
  2191.  
  2192. private void
  2193. make_edits(menu)    /* add dummy edit menu */
  2194. int menu;
  2195. {
  2196.     MenuHandle M;
  2197.     int item;
  2198.     char *fname;
  2199.  
  2200.     M = NewMenu((menu), "\pEdit");
  2201.     AppendMenu(M,
  2202.         "\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear;Select All;(-;Show Clipboard");
  2203.     InsertMenu(M, 0);
  2204.     DisableItem(M, 0);
  2205. }
  2206.  
  2207. void
  2208. menus_off()
  2209. {
  2210.     int i;
  2211.  
  2212.     if (Keyonly || EventCmd)
  2213.         return;
  2214.  
  2215. #ifdef MENU_DISABLE        /* NOBODY likes this, but it's here if you want it... */
  2216.     DisableItem(SysMenu, 0);
  2217.     for (i = 0; i < NMENUS; i++)
  2218.         if (Menus[i].Mn)
  2219.             DisableItem(Menus[i].Mn, 0);
  2220.     DrawMenuBar();
  2221. #endif
  2222.     Keyonly = YES;
  2223. }
  2224.  
  2225. void
  2226. menus_on()
  2227. {
  2228.     int i;
  2229.  
  2230.     if (!Keyonly)
  2231.         return;
  2232.  
  2233. #ifdef MENU_DISABLE
  2234.     EnableItem(SysMenu, 0);
  2235.     for (i = 0; i < NMENUS; i++)
  2236.         if (Menus[i].Mn)
  2237.             EnableItem(Menus[i].Mn, 0);
  2238.     DrawMenuBar();
  2239. #endif
  2240.     Keyonly = NO;
  2241. }
  2242.  
  2243. private char *
  2244. BufMPrint(b, i)
  2245. Buffer    *b;
  2246. int    i;
  2247. {
  2248.     char *p;
  2249.     char *nm = filename(b);
  2250.     char t[35];
  2251.  
  2252.     if (strlen(nm) > 30) {
  2253.         strcpy(t, "...");
  2254.         strcat(t, nm + strlen(nm) - 30);
  2255.     } else {
  2256.         strcpy(t, nm);
  2257.     }
  2258.     nm = t;
  2259.     while (*nm) {
  2260.         switch(*nm) {    /* ugh... these are metacharacter for Menus */
  2261.         case '/':
  2262.             *nm = ':';
  2263.             break;
  2264.         case '^':
  2265.         case '!':
  2266.         case '<':
  2267.         case '(':
  2268.         case ';':
  2269.             *nm = '.';
  2270.             break;    /* that will confuse everybody */
  2271.         }
  2272.         nm++;
  2273.     }
  2274.     p = sprint("%-2d %-11s \"%-s\"", i, b->b_name, t);
  2275.     return p;
  2276. }
  2277.  
  2278. private void
  2279. SetBufMenu()
  2280. {
  2281.     Buffer *b;
  2282.     int i, j, stop;
  2283.     struct menu *M;
  2284.  
  2285.     Bufchange = NO;
  2286.     for (i = 0; i < NMENUS; i++) {
  2287.         if (strcmp(Menus[i].Name, "Buffer") == 0) {
  2288.             M = &Menus[i];
  2289.             for (j = 0; j < NMENUITEMS; j++) {
  2290.                 data_obj *d = Menus[i].m[j];
  2291.  
  2292.                 if (d == NULL)
  2293.                     break;
  2294.  
  2295.                 if ((d->Type & TYPEMASK) == BUFFER) {
  2296.                     for (i = j, b = world; i < NMENUITEMS && b != NULL; i++, b = b->b_next) {
  2297.  
  2298.                         if (M->m[i] == NULL)
  2299.                             AppendMenu(M->Mn, CtoPstr(BufMPrint(b, i-j+1)));    /* add the item */
  2300.                         else
  2301.                             SetItem(M->Mn, i + 1, CtoPstr(BufMPrint(b, i-j+1)));    /* or change it */
  2302.                         M->m[i] = (data_obj *) b;
  2303.                     }
  2304.                     stop = i;
  2305.                     /* out of buffers? */
  2306.                     for (; i < NMENUITEMS && M->m[i]; i++) {
  2307.                         DelMenuItem(M->Mn, stop + 1);    /* take off last item */
  2308.                         M->m[i] = NULL;
  2309.                     }
  2310.                     break;
  2311.                 }
  2312.             }
  2313.             break;
  2314.         }
  2315.     }
  2316. }
  2317.  
  2318. private void
  2319. MacSetVar(vp, mnu, itm)    /* Set a variable from the menu */
  2320. struct variable *vp;
  2321. int mnu, itm;
  2322. {
  2323.     if ((vp->v_flags & V_TYPEMASK) == V_BOOL) {
  2324.         /* toggle the value */
  2325.         *((bool *) vp->v_value) = !*((bool *) vp->v_value);
  2326.         MarkVar(vp, mnu, itm);
  2327.     } else {
  2328.         char    prompt[128];
  2329.  
  2330.         swritef(prompt, sizeof(prompt), "Set %s: ", vp->Name);
  2331.         vset_aux(vp, prompt);
  2332.     }
  2333. }
  2334.  
  2335. private void
  2336. MarkModes()
  2337. {
  2338.     int mnu, itm;
  2339.     data_obj *d;
  2340.  
  2341.     Modechange = NO;
  2342.     for (mnu = 0; mnu < NMENUS; mnu++) {
  2343.         for (itm = 0; itm < NMENUITEMS; itm++) {
  2344.             if ((d = Menus[mnu].m[itm]) == NULL)
  2345.                 break;
  2346.  
  2347.             if ((d->Type & (MAJOR_MODE | MINOR_MODE))
  2348.             || ((d->Type & TYPEMASK) == BUFFER))
  2349.             {
  2350.                 bool    checked;
  2351.  
  2352.                 if (d->Type & (MAJOR_MODE))
  2353.                     checked = curbuf->b_major == (d->Type >> 8);
  2354.                 else if (d->Type & (MINOR_MODE))
  2355.                     checked = (curbuf->b_minor & (d->Type >> 8)) != 0;
  2356.                 else
  2357.                     checked = d == (data_obj *) curbuf;
  2358.                 CheckItem(Menus[mnu].Mn, itm + 1, checked);
  2359.             }
  2360.         }
  2361.     }
  2362. }
  2363.  
  2364. void
  2365. MarkVar(vp, mnu, itm)    /* mark a boolean menu item */
  2366. const struct variable *vp;
  2367. int mnu, itm;
  2368. {
  2369.     if (mnu == -1) {        /* we don't know the item... slow */
  2370.         for (mnu = 0; ; mnu++) {
  2371.             if (mnu >= NMENUS)
  2372.                 return;    /* not found */
  2373.             for (itm = 0; (itm < NMENUITEMS); itm++) {
  2374.                 if ((struct variable *) (Menus[mnu].m[itm]) == vp)
  2375.                     break;
  2376.             }
  2377.             if (itm < NMENUITEMS)
  2378.                 break;
  2379.         }
  2380.     }
  2381.     CheckItem(Menus[mnu].Mn, itm + 1, *(bool *)vp->v_value);
  2382. }
  2383.  
  2384. /* Screen routines and driver. The Macinitosh Text Edit routines are not utilized,
  2385.    as they are slow and cumbersome for a terminal emulator. Instead, direct QuickDraw
  2386.    calls are used. The fastest output is obtained writing a line at a time, rather
  2387.    than on a character basis, so the major output routine is writechr(), which takes
  2388.    a pascal-style string as an argument. See do_sputc() in screen.c. */
  2389.  
  2390. void
  2391. Placur(line, col)
  2392. int line, col;
  2393. {
  2394.     CapCol = col;
  2395.     CapLine = line;
  2396.     putcurs(line, col, YES);
  2397. }
  2398.  
  2399. void
  2400. NPlacur(line, col)
  2401. int line, col;
  2402. {
  2403.     CapCol = col;
  2404.     CapLine = line;
  2405.     putcurs(line, col, NO);
  2406. }
  2407.  
  2408. void
  2409. i_lines(top, bottom, num)
  2410. int top, bottom, num;
  2411. {
  2412.     Placur(bottom - num + 1, 0);
  2413.     dellines(num, bottom);
  2414.     Placur(top, 0);
  2415.     inslines(num, bottom);
  2416. }
  2417.  
  2418. void
  2419. d_lines(top, bottom, num)
  2420. int top, bottom, num;
  2421. {
  2422.     Placur(top, 0);
  2423.     dellines(num, bottom);
  2424.     Placur(bottom + 1 - num, 0);
  2425.     inslines(num, bottom);
  2426. }
  2427.  
  2428. /* (ORIGINALLY IN) tn.c   */
  2429. /* window driver for MacIntosh using windows. */
  2430. /* K. Mitchum 9/86 */
  2431.  
  2432.  
  2433. /*#define VARFONT*/
  2434. #ifdef VARFONT
  2435. private height, width, theight, twidth, descent;
  2436. #else
  2437. # define height HEIGHT
  2438. # define width WIDTH
  2439. # define theight THEIGHT
  2440. # define twidth TWIDTH
  2441. # define descent DESCENT
  2442. #endif
  2443.  
  2444. private int trow, tcol;
  2445. private bool    cursvis;
  2446. #ifdef NEVER
  2447. private bool insert;
  2448. #endif
  2449. private Rect cursor_rect;
  2450. private char *p_scr, *p_curs;    /* physical screen and cursor */
  2451. private int p_size;
  2452.  
  2453. private Rect  vRect;
  2454. private WindowRecord myWindowRec;
  2455.  
  2456. #define active() SetPort(theScreen)
  2457. #define maxadjust(r) OffsetRect((r), 0, 2)
  2458.  
  2459. private char *
  2460. conv_p_curs(row, col)
  2461. int    row,
  2462.     col;
  2463. {
  2464.     return p_scr + (row * (CO)) + col;
  2465. }
  2466.  
  2467. #ifdef NEVER
  2468. private void
  2469. INSmode(new)
  2470. bool new;
  2471. {
  2472.     insert = new;
  2473. }
  2474. #endif
  2475.  
  2476. void
  2477. SO_effect(new)
  2478. bool new;
  2479. {
  2480.     theScreen->txMode = new? notSrcCopy : srcCopy;
  2481. }
  2482.  
  2483. private void    init_slate proto((void));
  2484.  
  2485. private void
  2486. tn_init()
  2487. {
  2488. #ifdef NEVER
  2489.     INSmode(NO);
  2490. #endif
  2491.     init_slate();
  2492.     SO_off();
  2493.     ShowPen();
  2494. }
  2495.  
  2496. void
  2497. clr_page()    /* clear and home function */
  2498. {
  2499.     Rect r;
  2500.  
  2501.     memset(p_scr, ' ', p_size);
  2502.     active();
  2503.     SetRect(&r, 0, 0, WINDWIDTH, WINDHEIGHT);
  2504.     EraseRect(&r);
  2505.     putcurs(0, 0, NO);    /* ??? "NO" guess by DHR */
  2506.     drawfluff();
  2507. }
  2508.  
  2509. private void
  2510. putcurs(row, col, vis)
  2511. unsigned    row, col;
  2512. bool    vis;
  2513. {
  2514.     active();
  2515.     curset(NO);
  2516.     trow = row;
  2517.     tcol = col;
  2518.     curset(vis);
  2519. }
  2520.  
  2521. private void
  2522. curset(invert)
  2523. bool    invert;
  2524. {
  2525.     int
  2526.         colpix = tcol * width,
  2527.         rowpix = trow * height;
  2528.  
  2529.     if (trow == MAXROW)
  2530.         rowpix += 2;    /* leave space for 2 pixel rule */
  2531.     p_curs = conv_p_curs(trow, tcol);
  2532.     MoveTo(colpix, rowpix + height - descent);
  2533.     DrawChar(*p_curs);
  2534.     cursvis = invert;
  2535.     if (invert) {
  2536.         SetRect(&cursor_rect, colpix, rowpix,
  2537.             colpix + width - 1, rowpix + height - 1);
  2538.         InvertRect(&cursor_rect);
  2539.     }
  2540.     MoveTo(colpix, rowpix + height - descent);
  2541. }
  2542.  
  2543. void
  2544. clr_eoln()
  2545. {
  2546.         Rect r;
  2547.  
  2548.         active();
  2549.         SetRect(&r, tcol * width, trow * height, WINDWIDTH, (trow +1) * height);
  2550.         if (trow == MAXROW)
  2551.             maxadjust(&r);
  2552.         EraseRect(&r);
  2553.         memset(p_curs, ' ', CO - tcol);
  2554.         curset(YES);
  2555. }
  2556.  
  2557. #ifdef NEVER
  2558. private void
  2559. delchars()
  2560. {
  2561.     Rect r;
  2562.     RgnHandle updateRgn;
  2563.  
  2564.     active();
  2565.     curset(NO);
  2566.     updateRgn = NewRgn();
  2567.     SetRect(&r, tcol * width, trow * height, twidth - width, (trow+1) * height);
  2568.     if (trow == MAXROW)
  2569.         maxadjust(&r);
  2570.     ScrollRect(&r, -width, 0, updateRgn);
  2571.     DisposeRgn(updateRgn);
  2572.     BlockMove(p_curs + 1, p_curs, (long) (MAXCOL - tcol));
  2573.     *conv_p_curs(trow, MAXCOL) = ' ';
  2574.     curset(YES);
  2575. }
  2576. #endif /* NEVER */
  2577.  
  2578. private void
  2579. dellines(n, bot)
  2580. int n, bot;
  2581. {
  2582.     RgnHandle updateRgn = NewRgn();
  2583.     Rect r;
  2584.     long len;
  2585.  
  2586.     active();
  2587.     curset(NO);
  2588.     SetRect(&r, 0, ((trow) * height), WINDWIDTH, ((bot + 1) * height));
  2589.     ScrollRect(&r, 0, 0 - (n * height), updateRgn);
  2590.     DisposeRgn(updateRgn);
  2591.     len = ((bot - trow - n + 1) * CO);
  2592.     BlockMove(conv_p_curs(trow + n, 0), conv_p_curs(trow, 0), len);
  2593.     memset(conv_p_curs(bot - n + 1, 0), ' ', n * CO);
  2594.     putcurs(trow, 0, YES);    /* ??? "YES" guess by DHR */
  2595. }
  2596.  
  2597. private void
  2598. inslines(n, bot)
  2599. int n, bot;
  2600. {
  2601.     RgnHandle updateRgn = NewRgn();
  2602.     Rect r;
  2603.     long len;
  2604.  
  2605.     active();
  2606.     curset(NO);
  2607.     SetRect(&r, 0, trow * height, WINDWIDTH, (bot +1) * height);
  2608.     ScrollRect(&r, 0, (n * height), updateRgn);
  2609.     DisposeRgn(updateRgn);
  2610.     len = ((bot - trow - n +1) * CO);
  2611.     BlockMove(conv_p_curs(trow, 0), conv_p_curs(trow + n, 0), len);
  2612.     memset(conv_p_curs(trow, 0), ' ', (n * CO));
  2613.     putcurs(trow, 0, YES);    /* ??? "YES" guess by DHR */
  2614. }
  2615.  
  2616. void
  2617. writetext(str, len)
  2618. const unsigned char *str;
  2619. size_t    len;
  2620. {
  2621.     active();
  2622.     curset(NO);
  2623. #ifdef NEVER
  2624.     if (insert) {
  2625.         RgnHandle updateRgn = NewRgn();
  2626.         Rect r;
  2627.  
  2628.         SetRect(&r, tcol * width, trow * height, twidth - width * len, (trow +1) * height -1);
  2629.         if (trow == MAXROW)
  2630.             maxadjust(&r);
  2631.         ScrollRect(&r, width * len, 0, updateRgn);
  2632.         DisposeRgn(updateRgn);
  2633.     }
  2634. #endif
  2635.     DrawText(str, (short)0, (short)len);
  2636. #ifdef NEVER
  2637.     if (insert)
  2638.         BlockMove(p_curs, p_curs + len, (long) (CO - tcol - len));
  2639. #endif
  2640.     memcpy((UnivPtr)p_curs, (UnivPtr)str, len);
  2641.     putcurs(trow, tcol+len <= MAXCOL? tcol+len : MAXCOL, YES);    /* ??? "YES" guess by DHR */
  2642. }
  2643.  
  2644. private Rect myBoundsRect;
  2645.  
  2646. private void
  2647. init_slate()
  2648. {
  2649.     FontInfo f;
  2650.  
  2651.     char *Name = "Jove ";
  2652.     char *Title;
  2653.  
  2654.     InitGraf(&qd.thePort);
  2655.     InitWindows();
  2656.     InitCursor();
  2657.     InitFonts();
  2658.     InitMenus();
  2659.     InitDialogs((ProcPtr)NULL);        /* no restart proc */
  2660.  
  2661.     /* figure limiting rectangle for window moves */
  2662.     SetRect(&LimitRect,
  2663.         qd.screenBits.bounds.left + 3,
  2664.         qd.screenBits.bounds.top + 20,
  2665.         qd.screenBits.bounds.right - 3,
  2666.         qd.screenBits.bounds.bottom -3);
  2667.  
  2668.     Set_std();
  2669.     SetBounds();
  2670.  
  2671.     /* initialize char array for updates */
  2672.     p_scr = emalloc(p_size = wc_std.w_cols * wc_std.w_rows);    /* only once */
  2673.     p_curs = p_scr;
  2674.  
  2675.     Title = sprint("%s%s", Name, jversion);
  2676.     theScreen = NewWindow(&myWindowRec, &myBoundsRect, CtoPstr(Title),
  2677.         1, 8, (WindowPtr) -1, 1, 0L);
  2678.  
  2679.     /* figure an initial window configuration and adjust it */
  2680.     wc = &wc_std;
  2681.     wc_user = wc_std;    /* initially, only one configuration to toggle */
  2682.     user_state(theScreen) = std_state(theScreen);
  2683.     SetPort(theScreen);
  2684.  
  2685.     theScreen->txFont = FONT;
  2686.     theScreen->txSize = TEXTSIZE;
  2687.  
  2688. #ifdef VARFONT
  2689.     GetFontInfo(&f);
  2690.     height = f.ascent+f.descent+f.leading;
  2691.     width = f.widMax;
  2692.     twidth = width * wc->w_cols;
  2693.     theight = height * wc->w_rows;
  2694.     descent = f.descent;
  2695. #endif
  2696.  
  2697.     theScreen->txMode = srcCopy;
  2698.     theScreen->pnMode = patCopy;
  2699.     PenNormal();
  2700. }
  2701.  
  2702. private void
  2703. p_refresh()
  2704. {
  2705.     int lineno;
  2706.  
  2707.     for (lineno = 0; lineno < LI; lineno++) {
  2708.         char *curs = conv_p_curs(lineno, 0);
  2709.  
  2710.         MoveTo(0, (lineno+1) * height - descent + (lineno == MAXROW? 2 : 0));
  2711.         /* The following kludgy line is to get SO right.  It depends on:
  2712.          * - !defined(HIGHLIGHTING)
  2713.          * - this routine not being called at an inauspicious time
  2714.          *   i.e. in the middle of a SO output.
  2715.          * - the fact that the last line will non-SO so that the text
  2716.          *   mode will be left non-SO.
  2717.          */
  2718.         SO_effect(Screen[lineno].s_effects);
  2719.         DrawText(curs, (short)0, (short)CO);
  2720.     }
  2721.     curset(cursvis);
  2722. }
  2723.  
  2724.  
  2725. private bool
  2726. wc_adjust(w, h, wcf, init)        /* adjust window config to look nice */
  2727. int w, h;
  2728. struct wind_config *wcf;
  2729. int init;
  2730. {
  2731.     static int LIMIT_R, LIMIT_C;
  2732.     int rows, cols;
  2733.  
  2734.     if (init) {
  2735.         LIMIT_R = (h - 4) / HEIGHT;
  2736.         LIMIT_C = (w - SCROLLWIDTH - 1) / WIDTH + 1;
  2737.     }
  2738.     if ((w < WIDTH * 40) ||(h < HEIGHT * 10)    /* too small */
  2739.     || ((rows = (h - 4) / HEIGHT) > LIMIT_R)    /* too big */
  2740.     || ((cols = (w - SCROLLWIDTH - 1) / WIDTH + 1) > LIMIT_C))
  2741.         return NO;
  2742.  
  2743.     wcf->w_rows = rows;
  2744.     wcf->w_cols = cols;
  2745.     wcf->w_width = wcf->w_cols * WIDTH + 1 + SCROLLWIDTH;
  2746.     wcf->w_height = wcf->w_rows * HEIGHT + 4;
  2747.     return YES;
  2748. }
  2749.  
  2750. private int
  2751. getCO()    /* so that jove knows params */
  2752. {
  2753.     return wc->w_cols;
  2754. }
  2755.  
  2756. private int
  2757. getLI()
  2758. {
  2759.     return wc->w_rows;
  2760. }
  2761.  
  2762. void
  2763. ttsize()
  2764. {
  2765.     /* ??? We really ought to wait until the screen is big enough:
  2766.      * at least three lines high (one line each for buffer, mode,
  2767.      * and message) and at least twelve columns wide (eight for
  2768.      * line number, one for content, two for overflow indicators,
  2769.      * and one blank at end).
  2770.      */
  2771.     /* ??? This should be made more like UNIX version */
  2772.     CO = getCO();
  2773.     if (CO > MAXCOLS)
  2774.         CO = MAXCOLS;
  2775.     LI = getLI();
  2776.     Windchange = YES;
  2777.     clr_page();
  2778.     ILI = LI - 1;
  2779. }
  2780.  
  2781. private void
  2782. SetBounds()
  2783. {
  2784.     SetRect(&myBoundsRect,
  2785.         qd.screenBits.bounds.left + 3,
  2786.         qd.screenBits.bounds.top + 40,
  2787.         qd.screenBits.bounds.left + 3 + wc_std.w_width,
  2788.         qd.screenBits.bounds.top + 40 + wc_std.w_height);
  2789. }
  2790.  
  2791. private void
  2792. Set_std()
  2793. {
  2794.     (void) wc_adjust(qd.screenBits.bounds.right - qd.screenBits.bounds.left - 6,
  2795.         qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - 42,
  2796.         &wc_std, 1);
  2797. }
  2798.  
  2799. private void
  2800. Reset_std()
  2801. {
  2802.     Set_std();
  2803.     std_state(theScreen) = myBoundsRect;
  2804. }
  2805. #endif /* MAC */
  2806.