Annotation of 43BSDTahoe/new/jove/mac.c, revision 1.1

1.1     ! root        1: /***************************************************************************
        !             2:  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
        !             3:  * is 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: #include "tune.h"
        !            12: #ifdef MAC
        !            13: #define _mac 
        !            14: #include <MacTypes.h>
        !            15: #include "jove.h" 
        !            16: #include <QuickDraw.h>
        !            17: #include <WindowMgr.h>
        !            18: #include <FontMgr.h>
        !            19: #include <ListMgr.h>
        !            20: #include <EventMgr.h>
        !            21: #include <ControlMgr.h>
        !            22: #include <DialogMgr.h>
        !            23: #include <ResourceMgr.h>
        !            24: #include <ToolboxUtil.h>
        !            25: #include <HFS.h>
        !            26: #include <StdFilePkg.h>
        !            27: #include <MenuMgr.h>
        !            28: #include <pascal.h>
        !            29: #include <errno.h>
        !            30: #include <SegmentLdr.h>
        !            31: #include "mac.h"
        !            32: #include "termcap.h"
        !            33: 
        !            34: /***************************************************/
        !            35: 
        !            36: /* these normally reside in "tune.c" which we don't use */
        !            37: 
        !            38: char *CmdDb;   /* see InitMac() */
        !            39: char *p_tempfile = ".jrecXXX"; 
        !            40: char *d_tempfile = ".joveXXX";
        !            41: char *Joverc = ".joverc";      
        !            42: 
        !            43: 
        !            44: void putcurs(),curset(),putp(),dellines(),inslines();
        !            45: 
        !            46: 
        !            47: static WindowPtr theScreen;
        !            48: 
        !            49: int
        !            50:        errno,
        !            51:        EventCmd,
        !            52:        Keyonly,
        !            53:        Macmode,
        !            54:        Bufchange,
        !            55:        Modechange,
        !            56:        Windchange;
        !            57: 
        !            58: 
        !            59: 
        !            60: 
        !            61: /* Initialization Routines. */
        !            62: 
        !            63: void InitBinds()
        !            64: {
        !            65:        struct cmd *c;
        !            66:        data_obj **p;
        !            67:        int i;
        !            68:        
        !            69:        p = mainmap;
        !            70:        for(i= 0; i < NCHARS; i++) {
        !            71:                c = (struct cmd *) *p;
        !            72:                c->c_map = F_MAINMAP;
        !            73:                c->c_key = i;
        !            74:                p++;
        !            75:        }
        !            76:        
        !            77:        p = pref1map;
        !            78:        for(i= 0; i < NCHARS; i++) {
        !            79:                c = (struct cmd *) *p;
        !            80:                c->c_map = F_PREF1MAP;
        !            81:                c->c_key = i;
        !            82:                p++;
        !            83:        }
        !            84:        p = pref2map;
        !            85:        for(i= 0; i < NCHARS; i++) {
        !            86:                c = (struct cmd *) *p;
        !            87:                c->c_map = F_PREF2MAP;
        !            88:                c->c_key = i;
        !            89:                p++;
        !            90:        }
        !            91:        
        !            92: }
        !            93: 
        !            94: static WindowPtr window;
        !            95: static Rect r; 
        !            96: static CursHandle cross;
        !            97: 
        !            98: void InitEvents()
        !            99: {
        !           100:        void InitSysMenu();
        !           101:        
        !           102:        window = theScreen;
        !           103:        InitSysMenu();          
        !           104:        SetRect(&r,window->portRect.left,
        !           105:        window->portRect.top,
        !           106:        window->portRect.right - SCROLLWIDTH,
        !           107:        window->portRect.bottom - SCROLLWIDTH);
        !           108:        cross = GetCursor(crossCursor);
        !           109: }
        !           110: 
        !           111: void MacInit()
        !           112: {
        !           113:        char *gethome();
        !           114:        void tn_init();
        !           115: 
        !           116:        tn_init();
        !           117:        getdir();
        !           118:        gethome();      /* before anyone changes it */
        !           119:        CmdDb = malloc(strlen(gethome()) + 10);
        !           120:        strcpy(CmdDb,gethome());
        !           121:        strcat(CmdDb,"/cmds.doc");
        !           122:        InitBinds();
        !           123: }
        !           124: 
        !           125: 
        !           126: /* dummy routines. */
        !           127: 
        !           128: void InitCM()
        !           129: {
        !           130: }
        !           131: 
        !           132: void ResetTerm(){}
        !           133: 
        !           134: void UnsetTerm(s)
        !           135: char *s;
        !           136: {
        !           137: }
        !           138: 
        !           139: 
        !           140: 
        !           141: int dummy(){}
        !           142: 
        !           143: int (*signal(sig,func))()
        !           144: int sig;
        !           145: int (*func)();
        !           146: {
        !           147:        return(&dummy);
        !           148: }
        !           149: dorecover() {}
        !           150: 
        !           151: 
        !           152: /* Surrogate unix-style file i/o routines for Jove. These replace the
        !           153:    routines distributed in the libraries. They work with Jove, but may
        !           154:    not be general enough for other purposes. */
        !           155: 
        !           156: #include <io.h>
        !           157: #define NFILES 10
        !           158: /*
        !           159: #define fsetup(p) {p.ioCompletion = 0; p.ioVRefNum = cur_vol; p.ioDirID = cur_dir;p.ioFVersNum = 0;}
        !           160: #define isetup(p) {p.ioCompletion = 0; p.ioVRefNum = cur_vol;}
        !           161: */
        !           162: 
        !           163: static int cur_vol;    /* Disk or volume number */
        !           164: static long cur_dir;   /* Directory number */
        !           165: static int cur_vref;   /* ugh.. Vref for volume + directory */
        !           166: 
        !           167: struct ftab {
        !           168:        int inuse;      /* 0 = closed 1 = binary 2 = text*/
        !           169:        int refnum;     /* Mac file reference number */
        !           170: } ft[NFILES];
        !           171: 
        !           172: fsetup(p)
        !           173: HParmBlkPtr p;
        !           174: {
        !           175:        bzero(p,sizeof(HParamBlockRec));
        !           176:        p->fileParam.ioVRefNum = cur_vol;
        !           177:        p->fileParam.ioDirID = cur_dir;
        !           178:        p->fileParam.ioFVersNum = 0;
        !           179: }
        !           180: 
        !           181: isetup(p)
        !           182: HIOParam *p;
        !           183: {
        !           184:        bzero(p,sizeof(HIOParam));
        !           185:        p->ioVRefNum = cur_vol;
        !           186: }
        !           187: 
        !           188:        
        !           189: /* Kludge to convert Macintosh error codes to something like Unix. */
        !           190: 
        !           191: static int cvt_err(err)        /* some of these don't make sense... */
        !           192: {
        !           193:        switch(err) {
        !           194:                case noErr: errno = 0; return(0);
        !           195:                case dirFulErr: errno = ENOSPC; break;
        !           196:                case dskFulErr: errno = ENOSPC; break;
        !           197:                case nsvErr: errno = ENOENT; break;
        !           198:                case ioErr: errno = EIO; break;
        !           199:                case bdNamErr: errno = EINVAL; break;
        !           200:                case fnOpnErr: errno = EBADF; break;    /* dubious... */
        !           201:                case eofErr: errno = ESPIPE; break;             /* ditto */
        !           202:                case posErr: errno = ESPIPE; break;
        !           203:                case mFulErr: 
        !           204:                case tmfoErr:
        !           205:                case fnfErr: errno = ENOENT; break;
        !           206:                case wPrErr: errno = EROFS; break;
        !           207:                case fLckdErr: errno = EACCES; break;
        !           208:                case fBsyErr: errno = EBUSY; break;
        !           209:                case dupFNErr: errno = EEXIST; break;
        !           210:                case opWrErr:
        !           211:                case paramErr: errno = EINVAL; break;
        !           212:                case rfNumErr: errno = EBADF; break;
        !           213:                case gfpErr:
        !           214:                case volOffLinErr: errno = ENODEV; break;
        !           215:                case permErr: errno = EACCES; break;
        !           216:                case volOnLinErr: errno = ENODEV; break;
        !           217:                case nsDrvErr: errno = ENODEV; break;
        !           218:                case noMacDskErr: errno = EIO; break;
        !           219:                case extFSErr: errno = EIO; break;
        !           220:                case fsRnErr: 
        !           221:                case badMDBErr:
        !           222:                case wrPermErr: errno = EPERM; break;
        !           223:                default: errno = ENOENT;
        !           224:        }
        !           225:        return(-1);
        !           226: }
        !           227: 
        !           228: static char *cvt_fnm(file)
        !           229: char *file;
        !           230: {
        !           231:        static char nm[255];
        !           232:        char *t;
        !           233: 
        !           234: 
        !           235:        if(*file == '/') strcpy(nm,file + 1); /* full path */
        !           236:        else {
        !           237:                if(index(file + 1, '/') != NULL)
        !           238:                        strcpy(nm,"/"); /* make a partial pathname */
        !           239:                else *nm = '\0';
        !           240:                strcat(nm,file);
        !           241:        }
        !           242:        t = nm;
        !           243:        while(*t) {
        !           244:                if(*t == '/') *t = ':';
        !           245:                t++;
        !           246:        }
        !           247:        return(nm);
        !           248: }
        !           249: 
        !           250: int creat(name,perm)   /* permission mode is irrelevant on a Mac */
        !           251: char *name;
        !           252: {
        !           253:        int fd, err;
        !           254:        char *nm;
        !           255:        HParamBlockRec p;
        !           256: 
        !           257:        nm = cvt_fnm(name);     /* convert filename to Mac type name */
        !           258:        CtoPstr(nm);
        !           259:        for(fd = 0; fd < NFILES && ft[fd].inuse; fd++);
        !           260:        if(fd == NFILES) {
        !           261:                errno = EMFILE;
        !           262:                return(-1);
        !           263:        }
        !           264:        fsetup(&p);     /* try to delete it, whether it is there or not. */
        !           265:        p.fileParam.ioNamePtr = (StringPtr) nm;
        !           266:        if((err = PBHDelete(&p,0)) != noErr && err != fnfErr) return(cvt_err(err));
        !           267:        if(do_creat(&p,nm) != 0) return(-1);
        !           268:        else {
        !           269:                ft[fd].inuse++;
        !           270:                ft[fd].refnum = p.ioParam.ioRefNum;
        !           271:                return(fd + 1);
        !           272:        }
        !           273: }
        !           274: 
        !           275: int open(name,mode)
        !           276: char *name;
        !           277: {
        !           278:        int fd, err;
        !           279:        char *nm;
        !           280:        HParamBlockRec p;
        !           281: 
        !           282:        nm = cvt_fnm(name);     /* convert filename to Mac type name */
        !           283:        CtoPstr(nm);
        !           284:        for(fd = 0; fd < NFILES && ft[fd].inuse; fd++);
        !           285:        if(fd == NFILES) {
        !           286:                errno = EMFILE;
        !           287:                return(-1);
        !           288:        }
        !           289:        fsetup(&p);
        !           290:        if((mode & 3) == O_RDONLY) p.ioParam.ioPermssn = fsRdPerm;
        !           291:        if((mode & 3) == O_WRONLY) p.ioParam.ioPermssn = fsWrPerm;
        !           292:        if((mode & 3) == O_RDWR) p.ioParam.ioPermssn = fsRdWrPerm;
        !           293:        p.ioParam.ioNamePtr = (StringPtr) nm;
        !           294:        p.ioParam.ioMisc = 0;
        !           295:        if((err = PBHOpen(&p,0)) != noErr && err != fnfErr) return(cvt_err(err));
        !           296:        if(err == noErr && mode & O_CREAT && mode & O_EXCL) {
        !           297:                PBClose(&p,0);
        !           298:                errno = EEXIST;
        !           299:                return(-1);
        !           300:        }
        !           301:        if(err == fnfErr) {
        !           302:                if(mode & O_CREAT) {
        !           303:                        if(do_creat(&p,nm) != 0) return(-1);
        !           304:                } else {
        !           305:                        errno = ENOENT;
        !           306:                        return(-1);
        !           307:                }
        !           308:        }
        !           309:        ft[fd].inuse++;
        !           310:        ft[fd].refnum = p.ioParam.ioRefNum;
        !           311:        if(mode & O_APPEND)     p.ioParam.ioPosMode = fsFromLEOF;
        !           312:        else p.ioParam.ioPosMode = fsFromStart;
        !           313:        p.ioParam.ioPosOffset = 0;
        !           314:        if((err = PBSetFPos(&p,0)) != noErr) {
        !           315:                ft[fd].inuse = 0;
        !           316:                return(cvt_err(err));
        !           317:        }
        !           318:        errno = 0;
        !           319:        return(fd + 1);
        !           320: }
        !           321: 
        !           322: static int do_creat(p,nm)
        !           323: HParmBlkPtr p;
        !           324: char *nm;
        !           325: {
        !           326:        int err;
        !           327:        
        !           328:        fsetup(p);
        !           329:        p->fileParam.ioNamePtr = (StringPtr) nm;
        !           330:        if((err = PBHCreate(p,0)) != noErr) return(cvt_err(err));
        !           331:        fsetup(p);
        !           332:        p->fileParam.ioNamePtr = (StringPtr) nm;
        !           333:        p->fileParam.ioFDirIndex = 0;
        !           334:        if((err = PBHGetFInfo(p,0)) != noErr) return(cvt_err(err));
        !           335:        p->fileParam.ioDirID = cur_dir;
        !           336:        p->fileParam.ioFlFndrInfo.fdType = 'TEXT';
        !           337:        p->fileParam.ioFlFndrInfo.fdCreator = 'JV01';
        !           338:        p->fileParam.ioFlFndrInfo.fdFlags = 0;
        !           339:        p->fileParam.ioFVersNum = 0;
        !           340:        if((err = PBHSetFInfo(p,0)) != noErr) return(cvt_err(err));
        !           341:        fsetup(p);
        !           342:        p->ioParam.ioNamePtr = (StringPtr) nm;
        !           343:        p->ioParam.ioPermssn = fsRdWrPerm;
        !           344:        p->ioParam.ioMisc = 0;
        !           345:        if(cvt_err(PBHOpen(p,0))) return(-1);
        !           346:        return(0);
        !           347: }
        !           348: 
        !           349: 
        !           350: int close(fd)
        !           351: {
        !           352:        int err;
        !           353:        HParamBlockRec p;
        !           354: 
        !           355:        fsetup(&p);
        !           356:        p.ioParam.ioRefNum = ft[--fd].refnum;
        !           357:        ft[fd].inuse = 0;
        !           358: /*     if(cvt_err(PBFlushFile(&p,0)) < 0) return(-1);
        !           359:        fsetup(&p); */
        !           360:        if(cvt_err(PBClose(&p,0)) < 0) return(-1);
        !           361:        fsetup(&p);
        !           362:        p.ioParam.ioNamePtr = 0;
        !           363:        if(cvt_err(PBFlushVol(&p,0)) < 0) return(-1);
        !           364: }
        !           365: 
        !           366: int read(fd,buf,n)
        !           367: char *buf;
        !           368: unsigned n;
        !           369: {
        !           370:        int err;
        !           371:        IOParam p;
        !           372:        if(fd == 0) return(con_read(buf,n));
        !           373:        if(ft[--fd].inuse == 0) {
        !           374:                errno = EBADF;
        !           375:                return(-1);
        !           376:        }
        !           377:        isetup(&p);
        !           378:        p.ioRefNum = ft[fd].refnum;
        !           379:        p.ioBuffer = buf;
        !           380:        p.ioReqCount = n;
        !           381:        p.ioPosMode = fsFromMark;
        !           382:        p.ioPosOffset = 0;
        !           383:        if((err = PBRead(&p,0)) != noErr && err != eofErr) {
        !           384:                cvt_err(err);
        !           385:                return(-1);
        !           386:        }
        !           387:        while(n--) {            
        !           388:                if(*buf == '\r') *buf = '\n';   /* convert from Mac style */
        !           389:                buf++;
        !           390:        }
        !           391:        errno = 0;
        !           392:        return(p.ioActCount);
        !           393: }
        !           394: 
        !           395: int write(fd,buf,n)
        !           396: char *buf;
        !           397: unsigned n;
        !           398: {
        !           399:        int err;
        !           400:        IOParam p;
        !           401:        char *obuf, *s;
        !           402:        
        !           403:        if(fd == 0) return(con_write(buf,n));
        !           404:        
        !           405:        s = obuf = malloc(n + 1);
        !           406:        if(obuf == 0)  return(-1);      /* shouldn't happen... */
        !           407:        if(ft[--fd].inuse == 0) {
        !           408:                errno = EBADF;
        !           409:                free(obuf);
        !           410:                return(-1);
        !           411:        }
        !           412:        isetup(&p);
        !           413:        p.ioRefNum = ft[fd].refnum;
        !           414:        p.ioBuffer = obuf;
        !           415:        p.ioReqCount = (long) n;
        !           416:        p.ioPosMode = fsFromMark;
        !           417:        p.ioPosOffset = 0L;
        !           418:        while(n--) {            
        !           419:                if(*buf == '\n') *s = '\r';     /* make it look like Mac files */
        !           420:                else(*s = *buf);
        !           421:                buf++;
        !           422:                s++;
        !           423:        }
        !           424:        if((err = PBWrite(&p,0)) != noErr) {
        !           425:                free(obuf);
        !           426:                return(-1);
        !           427:        }
        !           428:        free(obuf);
        !           429:        return((int) p.ioActCount);
        !           430: }
        !           431: 
        !           432: long lseek(fd,offset,type)     /* The Mac version of this doesn't allocate new space. */
        !           433: long offset;
        !           434: unsigned type;
        !           435: {
        !           436:        int err;
        !           437:        long cur_mark, eof, new_mark;
        !           438:        IOParam p;
        !           439: 
        !           440:        if(ft[--fd].inuse == 0) {
        !           441:                errno = EBADF;
        !           442:                return(-1);
        !           443:        }
        !           444: 
        !           445:        isetup(&p);
        !           446:        p.ioRefNum = ft[fd].refnum;
        !           447:        if((err = PBGetFPos(&p,0)) != noErr) {
        !           448:                cvt_err(err);
        !           449:                return(-1);
        !           450:        }
        !           451:        cur_mark = p.ioPosOffset;
        !           452:        isetup(&p);
        !           453:        p.ioRefNum = ft[fd].refnum;
        !           454:        if((err = PBGetEOF(&p,0)) != noErr) {
        !           455:                cvt_err(err);
        !           456:                return(-1);
        !           457:        }
        !           458:        eof = (long) p.ioMisc;
        !           459:        switch(type) {
        !           460:                case 0 :
        !           461:                        new_mark = offset;
        !           462:                        break;
        !           463:                case 1 :
        !           464:                        new_mark = offset + cur_mark;
        !           465:                        break;
        !           466:                case 2 :
        !           467:                        new_mark = offset + eof;
        !           468:        }
        !           469:        if(new_mark > eof) {            /* need more space in file */
        !           470:                isetup(&p);
        !           471:                p.ioRefNum = ft[fd].refnum;
        !           472:                p.ioMisc = (Ptr) new_mark;
        !           473:                if((err = PBSetEOF(&p,0)) != noErr) {
        !           474:                        cvt_err(err);
        !           475:                        return(-1);
        !           476:                }
        !           477: /*             if((err = PBAllocContig(&p,0)) != noErr) {
        !           478:                        cvt_err(err);
        !           479:                        return(-1);
        !           480:                }*/
        !           481:        }
        !           482:        isetup(&p);
        !           483:        p.ioRefNum = ft[fd].refnum;
        !           484:        p.ioPosOffset = new_mark;
        !           485:        p.ioPosMode = fsFromStart;
        !           486:        if((err = PBSetFPos(&p,0)) != noErr) {
        !           487:                cvt_err(err);
        !           488:                return(-1);
        !           489:        }
        !           490:        errno = 0;
        !           491:        return(p.ioPosOffset);
        !           492: }
        !           493: 
        !           494: int unlink(name)
        !           495: char *name;
        !           496: {      int fd, err;
        !           497:        char *nm;
        !           498:        HParamBlockRec p;
        !           499: 
        !           500:        nm = cvt_fnm(name);     /* convert filename to Mac type name */
        !           501:        CtoPstr(nm);
        !           502:        fsetup(&p);     /* try to delete it, whether it is there or not. */
        !           503:        p.fileParam.ioNamePtr = (StringPtr) nm;
        !           504:        if((err = PBHDelete(&p,0)) != noErr && err != fnfErr) return(cvt_err(err));
        !           505:        return;
        !           506: }
        !           507: 
        !           508: /* Console read and write routines */
        !           509: 
        !           510: static int con_write(buf,size)
        !           511: unsigned  size;
        !           512: char *buf;
        !           513: {
        !           514:        while(size--) putp(*buf++);
        !           515:        return(size);
        !           516: }
        !           517: 
        !           518: static int con_read(buf,size)
        !           519: unsigned size;
        !           520: char *buf;
        !           521: {
        !           522:        unsigned n;
        !           523:        int p;
        !           524: 
        !           525:        
        !           526:        n = 0;
        !           527:        do {
        !           528:                p = rawgetc();
        !           529: #ifdef O_META
        !           530:                if(p & 0x7f) p &= 0x7f;         /* was normal ascii char */
        !           531: #endif
        !           532:                *buf++ = p;
        !           533:                n++;
        !           534:        } while (rawchkc() && n <= size);
        !           535:        return(n);
        !           536: }
        !           537: 
        !           538: 
        !           539: /* This didn't seem to be any place else */
        !           540: 
        !           541: int abs(n)
        !           542: int n;
        !           543: {
        !           544:        return(n >= 0 ? n : -n);
        !           545: 
        !           546: }
        !           547: 
        !           548: /* Simplified stat() routine emulates what is needed most. */
        !           549: 
        !           550: int stat(fname,buf)
        !           551: char *fname;
        !           552: struct stat *buf;
        !           553: {
        !           554:        CInfoPBRec p;
        !           555:        char *nm;
        !           556:        
        !           557:        nm = cvt_fnm(fname);
        !           558:        CtoPstr(nm);
        !           559:        bzero(&p,sizeof(CInfoPBRec));
        !           560:        p.hFileInfo.ioCompletion = 0;
        !           561:        p.hFileInfo.ioNamePtr = (StringPtr) nm;
        !           562:        p.hFileInfo.ioFVersNum = 0;
        !           563:        p.hFileInfo.ioFDirIndex = 0;
        !           564:        p.hFileInfo.ioVRefNum = cur_vol;
        !           565:        p.hFileInfo.ioDirID = cur_dir;
        !           566:        
        !           567:        switch (PBHGetFInfo(&p,0)) {
        !           568:                
        !           569:                case noErr :    errno = 0;
        !           570:                                                break;
        !           571:                case nsvErr:
        !           572:                case paramErr:
        !           573:                case bdNamErr :
        !           574:                case fnfErr:    errno = ENOENT;
        !           575:                                                break;
        !           576:                case ioErr:             errno = EIO;
        !           577:                                                break;
        !           578:                default :               errno = ENOENT;
        !           579:                                                break;
        !           580:        }
        !           581:        buf->st_dev = p.hFileInfo.ioVRefNum + 1;        /* don't want 0 */
        !           582:        buf->st_ino = p.hFileInfo.ioDirID;
        !           583:        buf->st_size = p.hFileInfo.ioFlLgLen;
        !           584:        buf->st_mtime = p.hFileInfo.ioFlMdDat;
        !           585:        buf->st_mode = (p.hFileInfo.ioFlAttrib & 0x10) ? S_IFDIR : 0;
        !           586:        PtoCstr(nm);
        !           587:        return(errno == 0 ? 0 : -1);
        !           588: }
        !           589: 
        !           590: /* Directory related routines. Jove keeps track of the true Volume (disk) number and
        !           591:    directory number, and avoids "Working Directory Reference Numbers", which are
        !           592:    confusing. */
        !           593:    
        !           594: static int getdir()    /* call this only once, during startup. */
        !           595: {
        !           596:        WDPBRec p;
        !           597: 
        !           598:        p.ioCompletion = 0;
        !           599:        p.ioNamePtr = 0;
        !           600:        if(PBHGetVol(&p,0) != noErr) return(-1);        /* BIG trouble */
        !           601:        cur_vol = p.ioWDVRefNum;
        !           602:        cur_dir = p.ioWDDirID;
        !           603:        SFSaveDisk = 0 - cur_vol;       /* these are for SF dialogs */
        !           604:        CurDirStore = cur_dir;
        !           605: }
        !           606: 
        !           607: static int setdir(vol,dir)
        !           608: long dir;
        !           609: {
        !           610:        WDPBRec p;
        !           611: 
        !           612:        p.ioCompletion = 0;
        !           613:        p.ioNamePtr = 0;
        !           614:        p.ioVRefNum = vol;
        !           615:        p.ioWDDirID = dir;
        !           616:        if(PBHSetVol(&p,0) != noErr) return(-1);
        !           617:        cur_vol = vol;
        !           618:        cur_dir = dir;
        !           619:        SFSaveDisk = 0 - vol;   /* these are for SF dialogs */
        !           620:        CurDirStore = dir;
        !           621: 
        !           622: 
        !           623: }
        !           624: 
        !           625: int chdir(dir)
        !           626: char *dir;
        !           627: {
        !           628:        DirInfo d;
        !           629:        WDPBRec p;
        !           630:        char *t;
        !           631:        char *nm; 
        !           632:        
        !           633:        if(strcmp(dir,"/") == 0) return(-1); /* There is no root... */
        !           634:        nm = malloc(strlen(dir) + 2);
        !           635:        if(nm == 0) return(-1);
        !           636:        
        !           637:        strcpy(nm,dir);
        !           638:        t = nm;
        !           639:        while(*t) {
        !           640:                if(*t == '/') *t = ':';
        !           641:                t++;
        !           642:        }
        !           643:        t = nm; 
        !           644:        while(*t == ':') t++;   /*get rid of initial slashes */
        !           645:        strcat(nm,":");
        !           646:        CtoPstr(t);
        !           647: 
        !           648:        d.ioCompletion = 0;                     /* get the directory number */
        !           649:        d.ioNamePtr = (StringPtr) t;
        !           650:        d.ioVRefNum = cur_vol;
        !           651:        d.ioFDirIndex = 0;
        !           652:        d.ioDrDirID = 0;
        !           653:        PBGetCatInfo(&d,0);
        !           654:        free(nm);
        !           655:        if(d.ioResult != noErr || ((d.ioFlAttrib & 0x10) == 0)) return(-1);
        !           656:        if(setdir(d.ioVRefNum,d.ioDrDirID) < 0)return(-1);
        !           657:        return(0);
        !           658: }
        !           659: 
        !           660: /* Scandir returns the number of entries or -1 if the directory cannoot
        !           661:    be opened or malloc fails. */
        !           662: 
        !           663: int scandir(dir, nmptr, qualify, sorter) /* this function has NOT been debugged */
        !           664: char   *dir;
        !           665: char   ***nmptr;
        !           666: int    (*qualify)();
        !           667: int    (*sorter)();
        !           668: {
        !           669:        HParamBlockRec fb;
        !           670:        DirInfo d;
        !           671:        long DirID;
        !           672:        char    **ourarray, *nm, *t, buf[50];
        !           673:        Str255 buf1;
        !           674:        unsigned int    len, nalloc = 10,
        !           675:                        nentries = 0;
        !           676: 
        !           677:        if(strcmp(dir,"/") == 0) return(-1); /* There is no root... */
        !           678:        nm = malloc(strlen(dir) + 2);
        !           679:        if(nm == 0) return(-1);
        !           680:        
        !           681:        strcpy(nm,dir);
        !           682:        t = nm;
        !           683:        while(*t) {
        !           684:                if(*t == '/') *t = ':';
        !           685:                t++;
        !           686:        }
        !           687:        t = nm; 
        !           688:        while(*t == ':') t++;   /*get rid of initial slashes */
        !           689:        strcat(nm,":");
        !           690:        CtoPstr(t);
        !           691: 
        !           692:        d.ioCompletion = 0;                     /* get the directory number */
        !           693:        d.ioNamePtr = (StringPtr) t;
        !           694:        d.ioVRefNum = cur_vol;
        !           695:        d.ioFDirIndex = 0;
        !           696:        d.ioDrDirID = 0;
        !           697:        PBGetCatInfo(&d,0);
        !           698:        free(nm);
        !           699:        fb.fileParam.ioDirID = DirID = d.ioDrDirID;
        !           700:        fb.fileParam.ioCompletion = (long) 0;
        !           701:        fb.fileParam.ioVRefNum = cur_vol;
        !           702:        fb.fileParam.ioFVersNum = 0;
        !           703:        fb.fileParam.ioNamePtr = buf1;
        !           704: 
        !           705:        if ((ourarray = (char **) malloc(nalloc * sizeof (char *))) == 0)
        !           706: memfail:       complain("[Malloc failed: cannot scandir]");
        !           707:        while (1) {
        !           708:                fb.fileParam.ioFDirIndex = nentries;
        !           709:                fb.fileParam.ioVRefNum = cur_vol;
        !           710:                fb.fileParam.ioDirID = DirID;
        !           711:                if(PBHGetFInfo(&fb,0) != noErr) break;  /* we are done, then */
        !           712:                len = (char) *fb.fileParam.ioNamePtr;   /* pascal style string */
        !           713:                strncpy(buf,fb.fileParam.ioNamePtr +1,len);
        !           714:                buf[len] = '\0';
        !           715: 
        !           716:                if (qualify != 0 && (*qualify)(buf) == 0)
        !           717:                        continue;
        !           718:                if (nentries == nalloc) {
        !           719:                        ourarray = (char **) realloc((char *) ourarray, (nalloc += 10) * sizeof (char *));
        !           720:                        if (ourarray == 0)
        !           721:                                goto memfail;
        !           722:                }
        !           723:                ourarray[nentries] = (char *) malloc(strlen(buf)+1);
        !           724:                null_ncpy(ourarray[nentries], buf, strlen(buf));
        !           725:                nentries += 1;
        !           726:        }
        !           727:        if ((nentries + 1) != nalloc)
        !           728:                ourarray = (char **) realloc((char *) ourarray,
        !           729:                                        ((nentries + 1) * sizeof (char *)));
        !           730:        if (sorter != 0)
        !           731:                qsort((char *) ourarray, nentries, sizeof (char **), sorter);
        !           732:        *nmptr = ourarray;
        !           733:        ourarray[nentries] = 0;         /* guaranteed 0 pointer */
        !           734:        return nentries;
        !           735: }
        !           736: 
        !           737: 
        !           738: char *getwd()
        !           739: {
        !           740:        DirInfo d;
        !           741:        static char ret[255];
        !           742:        char nm[50], tmp[255];
        !           743:        
        !           744:        ret[0] = '\0';
        !           745:        d.ioDrDirID = cur_dir;
        !           746:        for(;;) {
        !           747:                d.ioCompletion = 0;
        !           748:                d.ioNamePtr = (StringPtr) nm;
        !           749:                d.ioVRefNum = cur_vol;
        !           750:                d.ioFDirIndex = -1;
        !           751: 
        !           752:                PBGetCatInfo(&d,0);
        !           753:                if(d.ioResult != noErr) return(0);
        !           754:                PtoCstr((char *) nm);
        !           755:                strcpy(tmp,ret);
        !           756:                strcpy(ret,"/");
        !           757:                strcat(ret,nm);
        !           758:                strcat(ret,tmp);
        !           759:                if(d.ioDrDirID == 2) break;     /* home directory */
        !           760:                d.ioDrDirID = d.ioDrParID;
        !           761:        } 
        !           762:        return(ret);
        !           763: }
        !           764: 
        !           765: static char *gethome()         /* this will be startup directory */
        !           766: {
        !           767:        static char *ret = 0;
        !           768:        
        !           769: 
        !           770:        if(ret == 0) {
        !           771:                char *item = getwd();
        !           772:                ret = malloc(strlen(item)+1);
        !           773:                strcpy(ret,item);
        !           774:        }
        !           775:        return(ret);
        !           776: }      
        !           777: 
        !           778:        
        !           779: 
        !           780: /* Routines that put up and manipulate the "About Jove" dialog. */
        !           781: 
        !           782: 
        !           783: /* (ORIGINALLY IN) about_j.c. */
        !           784: 
        !           785: 
        !           786: #define DLOGNAME "\pABOUT_JDLOG"
        !           787: 
        !           788: #define DONE_ITEM 1
        !           789: #define LIST_ITEM 2
        !           790: 
        !           791: 
        !           792: #define DWIDTH 460             /* there should be an easy way to get this */
        !           793: #define DHEIGHT 240            /* from the resource file! */
        !           794: 
        !           795: WindowPtr makedisplay();
        !           796: ListHandle makelist();
        !           797: 
        !           798: 
        !           799: static WindowPtr theWindow;
        !           800: static ListHandle theList;
        !           801: static Rect theListRect;
        !           802: static EventRecord theEvent;
        !           803: 
        !           804: 
        !           805: 
        !           806: static void about_j()
        !           807: {
        !           808:        void do_list(), do_events();
        !           809:        
        !           810:        WindowPtr OldWindow;
        !           811:        
        !           812:        GetPort(&OldWindow);
        !           813:        
        !           814:        if((theWindow = makedisplay()) == 0) return;
        !           815:        SetPort(theWindow);
        !           816:        if(theList = makelist()) {
        !           817:                LActivate(1,theList);
        !           818:                do_list();
        !           819:                ShowWindow(theWindow);
        !           820:                do_events();
        !           821:        }
        !           822:        SetPort(OldWindow);
        !           823:        LDispose(theList);
        !           824:        DisposDialog(theWindow);
        !           825:        
        !           826:        return;
        !           827: }
        !           828:                
        !           829:        
        !           830: static WindowPtr makedisplay()
        !           831: {
        !           832:        static int dlogid = 0;
        !           833:        DialogPtr theDialog;
        !           834:        Handle theHandle;
        !           835:        Handle theResource;
        !           836:        Str255 buf;
        !           837:        long itemType;
        !           838:        Rect theRect;
        !           839:        short dh,dv;    /* to center dialog on the screen */
        !           840:        Str255 nostring;
        !           841:        
        !           842:        if(dlogid == 0) {
        !           843:                if((theResource = GetNamedResource('DLOG',DLOGNAME)) == 0)
        !           844:                        return((WindowPtr) 0);
        !           845:                itemType = 'DLOG';
        !           846:                GetResInfo(theResource,&dlogid,&itemType,buf);
        !           847:        }
        !           848:        
        !           849:        theDialog = GetNewDialog(dlogid,(long) 0,(WindowPtr) -1);
        !           850:        strcpy((char *) nostring,"\p");
        !           851:        ParamText("\pMacJove - Copyright (C) 1986, 1987, 1988 J. Payne, K. Gegenfurtner,",
        !           852:        "\pK. Mitchum. Portions (C) THINK Technologies, Inc.",nostring,nostring);
        !           853:        
        !           854:        dh = screenBits.bounds.left + (screenBits.bounds.right - DWIDTH) / 2;
        !           855:        dv = screenBits.bounds.top  + (screenBits.bounds.bottom - DHEIGHT) / 2;
        !           856:        MoveWindow((WindowPtr)theDialog,dh,dv,0);
        !           857:        ShowWindow((WindowPtr)theDialog);
        !           858:        
        !           859:        
        !           860:        GetDItem(theDialog,LIST_ITEM,&itemType,&theHandle,&theRect);
        !           861:        theListRect = theRect;
        !           862:        theListRect.right -= 15;
        !           863:        ((WindowPtr)theDialog)->txFont = FONT;
        !           864:        ((WindowPtr)theDialog)->txSize = TEXTSIZE;
        !           865:        
        !           866:        return((WindowPtr) theDialog);
        !           867: }
        !           868: 
        !           869: static void do_display()               /* draw necessary controls, lines */
        !           870: {
        !           871:        Rect rViewF;            /* framing rect for list */
        !           872:        int offset;
        !           873:        
        !           874:        rViewF = theListRect;
        !           875:        
        !           876:        rViewF.left--;
        !           877:        rViewF.top--;
        !           878:        rViewF.right++;
        !           879:        rViewF.bottom++;
        !           880:        FrameRect(&rViewF);
        !           881:        
        !           882:        DrawControls(theWindow);
        !           883: 
        !           884: }
        !           885: 
        !           886: static ListHandle makelist()
        !           887: {
        !           888:        Point csize;
        !           889:        Rect dataBounds, rView; /* list boundaries */   
        !           890:        
        !           891:        csize.h = csize.v = 0;
        !           892:        SetRect(&dataBounds,0,0,1,0);   
        !           893:        return(LNew(&theListRect,&dataBounds,csize,0,theWindow,0,0,0,1));
        !           894: }
        !           895: 
        !           896: static void do_list()
        !           897: {
        !           898:        void printbind();
        !           899:        
        !           900:        int row, col;
        !           901:        struct cmd *f;
        !           902:        Str255 buf;
        !           903:        Point theCell;
        !           904: 
        !           905:        theCell.h = 0;
        !           906:        
        !           907:        for(f = commands, row = 0; f->Name; f++, row++) {
        !           908:                LAddRow(1,row,theList);
        !           909:                theCell.v = row;
        !           910: 
        !           911:                printbind(f,buf);
        !           912:                strcat(buf,f->Name);
        !           913:                LSetCell(buf,strlen((char *)buf),theCell,theList);
        !           914:                
        !           915:        }
        !           916: }
        !           917: static void printbind(f,buf)
        !           918: struct cmd *f;
        !           919: char *buf;
        !           920: {      
        !           921:        char c;
        !           922:        
        !           923:        if(f->c_map == 0 || (c = f->c_key) == 0x7f) {
        !           924:                strcpy(buf,"        ");
        !           925:                return;
        !           926:        }
        !           927:        switch(f->c_map) {
        !           928:                case F_MAINMAP :
        !           929:                        strcpy(buf,"     ");
        !           930:                        break;
        !           931:                
        !           932:                case F_PREF1MAP :
        !           933:                        strcpy(buf," ESC ");
        !           934:                        break;
        !           935:                        
        !           936:                case F_PREF2MAP :
        !           937:                        strcpy(buf,"  ^X ");
        !           938:                        break;
        !           939:        }
        !           940:        if(c < ' ') {
        !           941:                buf[5] = '^';           /* control char */
        !           942:                c |= 0x40;
        !           943:        }
        !           944:        else buf[5] = ' ';
        !           945:        if(c >= 'a' && c<= 'z') c &= 0x5f;
        !           946:        buf[6] = c;
        !           947:        buf[7] = ' ';
        !           948:        buf[8] = '\0';
        !           949: }
        !           950: 
        !           951: 
        !           952: 
        !           953: static pascal Boolean ProcFilter(theDialog,event,itemHit)
        !           954: DialogPtr theDialog;
        !           955: EventRecord *event;
        !           956: int *itemHit;
        !           957: {
        !           958:        theEvent = *event;
        !           959:        if(theEvent.what == keyDown && theEvent.message & charCodeMask == '\r') {
        !           960:                *itemHit = 1;
        !           961:                return(TRUE);
        !           962:        }
        !           963:        if(theEvent.what == activateEvt && (WindowPtr) theEvent.message == theWindow) {
        !           964:                LDoDraw(1,theList);
        !           965:                LActivate(1,theList);
        !           966:        }
        !           967:        if(theEvent.what == updateEvt && (WindowPtr) theEvent.message == theWindow) {
        !           968:                BeginUpdate(theWindow);
        !           969:                do_display();
        !           970:                DrawDialog(theWindow);
        !           971:                LUpdate((GrafPtr) theWindow->visRgn,theList);
        !           972:                EndUpdate(theWindow);
        !           973:        }
        !           974: 
        !           975:        return(FALSE);
        !           976: }
        !           977:        
        !           978: 
        !           979: void do_events()
        !           980: {
        !           981:        int item,done;
        !           982:        Point p;
        !           983:        
        !           984:        done = 0;
        !           985:        
        !           986:        while(!done) {
        !           987:                ModalDialog(ProcFilter,&item);
        !           988:                switch(item) {
        !           989:                        case DONE_ITEM :
        !           990:                                done = 1;
        !           991:                        case LIST_ITEM :
        !           992:                                p = theEvent.where;
        !           993:                                GlobalToLocal(&p);
        !           994:                                LClick(p,theEvent.modifiers,theList);
        !           995:                }
        !           996:        }
        !           997: }
        !           998: 
        !           999: /* Window and Control related routines. */
        !          1000: 
        !          1001: /* (ORIGINALLY IN) tcon.c. 
        !          1002:    control handler routines for Jove. K. Mitchum 12/86 */
        !          1003: 
        !          1004: 
        !          1005: #define MINC 0
        !          1006: #define MAXC (int)100
        !          1007: #define INITC 0
        !          1008: #define EVENTLIST (mDownMask | keyDownMask )
        !          1009: 
        !          1010: extern long GetCRefCon();      /* omitted in ControlMgr.h */
        !          1011: 
        !          1012: static Point p;
        !          1013: static intext; /* mouse down in jove text */
        !          1014: 
        !          1015: void docontrols()      /* called from redisplay routines */
        !          1016: {
        !          1017:        void MakeScrollBar(),
        !          1018:                AdjustScrollBar(),
        !          1019:                drawfluff();
        !          1020:        
        !          1021:        Window *w;
        !          1022:        int top;
        !          1023: 
        !          1024:        w = fwind;
        !          1025:        top = 0;
        !          1026:        do {
        !          1027:                if(w->w_control) HideControl(w->w_control);
        !          1028:                w = w->w_next;
        !          1029:        } while (w != fwind);
        !          1030:        w = fwind;
        !          1031:        do {
        !          1032:                w->w_topline = top;
        !          1033:                if(w->w_control) AdjustScrollBar(w);
        !          1034:                else MakeScrollBar(w);
        !          1035:                ShowControl(w->w_control);
        !          1036:                top += w->w_height;
        !          1037:                w = w->w_next;
        !          1038:        } while(w != fwind);
        !          1039:        Windchange = 0;
        !          1040:        drawfluff();
        !          1041: }      
        !          1042: 
        !          1043: 
        !          1044: void MakeScrollBar(w)  /* set up control */
        !          1045: Window *w;
        !          1046: {
        !          1047:        Rect BarRect;
        !          1048:        int wheight, wtop;
        !          1049:        
        !          1050:        WindowPtr window = theScreen;
        !          1051:        wheight = w->w_height;
        !          1052:        wtop = w->w_topline;
        !          1053:        SetRect(&BarRect,window->portRect.right - SCROLLWIDTH + 1,
        !          1054:                window->portRect.top -1 + wtop * HEIGHT,
        !          1055:                window->portRect.right +1,
        !          1056:                window->portRect.top + ((wheight + wtop) * HEIGHT));
        !          1057:                w->w_control = ((char **) NewControl(window,&BarRect,"/psbar",1,INITC,
        !          1058:                MINC,MAXC,scrollBarProc,w));
        !          1059: }
        !          1060: 
        !          1061: void AdjustScrollBar(w)        /* redo existing control */
        !          1062: Window *w;
        !          1063: {
        !          1064:        int wtop,wheight;
        !          1065:        ControlHandle handle;
        !          1066:        WindowPtr window;
        !          1067:        
        !          1068:        handle = (ControlHandle) w->w_control;
        !          1069:        wtop = w->w_topline;
        !          1070:        wheight = w->w_height;
        !          1071:        window = (*handle)->contrlOwner;
        !          1072: 
        !          1073:        if(handle == 0) return;
        !          1074: 
        !          1075:        SizeControl(handle,SCROLLWIDTH,wheight * HEIGHT +1);
        !          1076:        
        !          1077:        MoveControl(handle,window->portRect.right - SCROLLWIDTH + 1,
        !          1078:                window->portRect.top -1 + wtop * HEIGHT);
        !          1079: }
        !          1080: 
        !          1081: void SetScrollBar(handle)      /* set value of the bar */
        !          1082: ControlHandle handle;
        !          1083: { 
        !          1084: 
        !          1085:        SetCtlValue(handle,ltoc());
        !          1086: }
        !          1087: 
        !          1088: 
        !          1089: 
        !          1090: static void dodivider()        /* originally to divide windows, but not enough */
        !          1091:                        /* room in between lines, so just put line at bottom */
        !          1092: {
        !          1093:        WindowPtr window;
        !          1094:        PenState pnState;
        !          1095:        
        !          1096:        window = theScreen;
        !          1097:        GetPenState(&pnState);
        !          1098:        MoveTo(0,((MAXROW) * HEIGHT));
        !          1099:        PenSize(1,1);
        !          1100:        LineTo(window->portRect.right,(MAXROW) * HEIGHT);
        !          1101:        SetPenState(&pnState);
        !          1102:        return;
        !          1103: }
        !          1104: 
        !          1105: static void drawfluff()                /* draw controls and dividers */
        !          1106: {
        !          1107:        WindowPtr window;
        !          1108:        Window *w = fwind;
        !          1109: 
        !          1110:        window = theScreen;
        !          1111:        DrawControls(window);
        !          1112:        
        !          1113:        dodivider();
        !          1114: }      
        !          1115: 
        !          1116: void RemoveScrollBar(w)
        !          1117: Window *w;
        !          1118: {
        !          1119:        if(w->w_control) DisposeControl(w->w_control);
        !          1120:        dodivider();            /* erase the divider */
        !          1121:        w->w_control = 0;
        !          1122: 
        !          1123: }
        !          1124:        
        !          1125: static pascal void DScroll(control,part)
        !          1126: ControlHandle control;
        !          1127: int part;
        !          1128: {
        !          1129:        DownScroll();
        !          1130:        redisplay();
        !          1131: }
        !          1132: 
        !          1133: static pascal void UScroll(control,part)
        !          1134: ControlHandle control;
        !          1135: int part;
        !          1136: {
        !          1137:        UpScroll();
        !          1138:        redisplay();
        !          1139: }
        !          1140: 
        !          1141: static pascal void NPage(control,part)
        !          1142: ControlHandle control;
        !          1143: int part;
        !          1144: {      NextPage();
        !          1145:        redisplay();
        !          1146: }
        !          1147: 
        !          1148: static pascal void PPage(control,part)
        !          1149: ControlHandle control;
        !          1150: int part;
        !          1151: {      PrevPage();
        !          1152:        redisplay();
        !          1153: }
        !          1154: 
        !          1155: static long npos;      /* number of lines in buffer */
        !          1156: 
        !          1157: static int ltoc()      /* calculate ctlvalue for line position */
        !          1158: {
        !          1159:        register long ipos;
        !          1160:        register Line   *lp = curbuf->b_first;
        !          1161: 
        !          1162:        for (npos = 1; lp ; npos++, lp = lp->l_next)  {
        !          1163:                if(lp == curline) ipos = npos;
        !          1164:        }
        !          1165:        return((int) ((ipos * MAXC) / npos));
        !          1166: }
        !          1167: 
        !          1168: static Line *ctol(ctlv)        /* find buffer line for ctlvalue */
        !          1169: int ctlv;
        !          1170: {
        !          1171: extern char *itoa();
        !          1172:        register long ipos;
        !          1173:        register Line   *lp = curbuf->b_first;
        !          1174: 
        !          1175:        ipos = (npos * ctlv)/MAXC;
        !          1176:        while (ipos-- && lp->l_next) lp = lp->l_next;
        !          1177:        return(lp);
        !          1178: }
        !          1179: 
        !          1180: static void doWind(event,window)
        !          1181: EventRecord *event;
        !          1182: WindowPtr window;
        !          1183: {
        !          1184: #define track() TrackControl(whichControl,p,(ProcPtr) 0)
        !          1185: 
        !          1186:        ControlHandle whichControl;
        !          1187:        Window *jwind, *cwind;
        !          1188:        int notcurwind;
        !          1189:        int cpart;      /* control part */
        !          1190:        int oldval,newval,thumb = 0;
        !          1191:        
        !          1192:        p = event->where;
        !          1193:        intext = 0;
        !          1194:        notcurwind = 0;
        !          1195:        GlobalToLocal(&p);
        !          1196:        
        !          1197:        if(event->what == mouseDown) {
        !          1198:                if((cpart = FindControl(p,window,&whichControl)) == 0) return;
        !          1199:                if((jwind = (Window *) (*whichControl)->contrlRfCon) !=  curwind) {
        !          1200:                        notcurwind++;
        !          1201:                        cwind = curwind;
        !          1202:                        SetWind(jwind);
        !          1203:                }
        !          1204:                switch (cpart) {
        !          1205:                        case inUpButton :       TrackControl(whichControl,p,(ProcPtr) DScroll); break;
        !          1206:                        case inDownButton :     TrackControl(whichControl,p,(ProcPtr) UScroll); break;
        !          1207:                        case inPageUp :         TrackControl(whichControl,p,(ProcPtr) PPage); break;
        !          1208:                        case inPageDown :       TrackControl(whichControl,p,(ProcPtr) NPage); break;
        !          1209:                        case inThumb :          if(track()) {
        !          1210:                                                                        newval = GetCtlValue(whichControl);
        !          1211:                                                                                
        !          1212:                                                                        if(newval == MAXC) Eof();
        !          1213:                                                                        else if(newval == MINC) Bof();
        !          1214:                                                                        else SetLine(ctol(newval));
        !          1215:                                                                }
        !          1216:                                                                break;
        !          1217:                                                                        
        !          1218:                }
        !          1219:                if(notcurwind) {
        !          1220:                        SetWind(cwind);
        !          1221:                        redisplay();
        !          1222:                }
        !          1223:                redisplay();    /* again, to set the cursor */
        !          1224:        }
        !          1225:        else {
        !          1226:                if(findtext()) redisplay();
        !          1227:        }
        !          1228: }
        !          1229: 
        !          1230: 
        !          1231: static void doGoAway(event,window)
        !          1232: EventRecord *event;
        !          1233: WindowPtr window;
        !          1234: {
        !          1235:        if(TrackGoAway(window,&event->where) == TRUE) Leave();
        !          1236: }
        !          1237: 
        !          1238: static Window *rtowind(row)    /* return jove window row is in */
        !          1239: int row;
        !          1240: {
        !          1241:        Window *w = fwind;
        !          1242:        
        !          1243:        do {
        !          1244:                if((w->w_topline <= row) && ((w->w_height + w->w_topline) > row))
        !          1245:                        return(w);
        !          1246:                w = w->w_next;
        !          1247:        } while(w != fwind);
        !          1248:        return(0);
        !          1249: }
        !          1250: 
        !          1251: static Line *windtol(w,row)            /* return line for row in window */
        !          1252: Window *w;
        !          1253: int row;
        !          1254: {
        !          1255:        Line *l = w->w_top;
        !          1256:        
        !          1257:        while(row--) if((l = l->l_next) == 0) return(0);
        !          1258:        return(l);
        !          1259: }
        !          1260:        
        !          1261: 
        !          1262: static int findtext()          /* locate and move the point to match the mouse */
        !          1263: {
        !          1264:        int row,col;
        !          1265:        Window *w;
        !          1266:        Line *l;
        !          1267:        ptoxy(p,&row,&col);
        !          1268:        if((w = rtowind(row)) == 0) return(0);
        !          1269:        if(w != curwind) SetWind(w);
        !          1270:        row -= w->w_topline;            /* now have row number in window */
        !          1271:        if(row >= w->w_height -1) return(0);
        !          1272:        if((l = windtol(w,row)) == 0) return(0);
        !          1273:        if(l->l_dline == 0) return(0);
        !          1274:        this_cmd = LINECMD;
        !          1275:        SetLine(l);             /* Curline is in linebuf now */
        !          1276:        if(w->w_flags & W_NUMLINES) col -= 8;   /* adjust for line numbers */
        !          1277:        if(col < 0) col = 0;
        !          1278:        curchar = how_far(curline, col);
        !          1279:        return(1);
        !          1280: }
        !          1281: 
        !          1282:        
        !          1283: static int ptoxy(p,row,col)    /* convert Point to terminal x,y coordinate */
        !          1284: Point p;
        !          1285: int *row,*col;
        !          1286: {
        !          1287:        *row = (p.v / HEIGHT);
        !          1288:        *col = (p.h / WIDTH );
        !          1289:        if((*row > MAXROW) || (*col > MAXCOL)) return(ERROR);
        !          1290:        return(0);
        !          1291: }
        !          1292: 
        !          1293: /* Event-related routines. The Event loop is CheckEvents(), and is called whenever
        !          1294:    a console read occurs or a call to charp(). During certain activities, such as ask(),
        !          1295:    etc. non-keyboard events are ignored. This is set by the variable Keyonly. 
        !          1296:    As an update or activate event generates a call to redisplay(), it is important
        !          1297:    that redisplay() and related routines NOT check for keyboard characters. */
        !          1298:  
        !          1299: /* (ORIGINALLY IN) tevent.c
        !          1300:        event handler for Jove. K Mitchum 12/86 */
        !          1301: 
        !          1302: 
        !          1303: #define SYS_ID 100
        !          1304: #define NOFUNC (void (*)()) 0
        !          1305: #define NEVENTS 16
        !          1306: static int firsttime = 0;
        !          1307: extern void doMouse(),dokeyDown(),doUpdate(),doActivate();
        !          1308: static MenuHandle SysMenu;
        !          1309: static void (*eventlist[])() =
        !          1310: {
        !          1311:        NOFUNC, /* nullEvent */
        !          1312:        doMouse,/* mouseDown */
        !          1313:        doMouse, /* mouseUp */
        !          1314:        dokeyDown, /* keyDown */
        !          1315:        NOFUNC, /* keyUp */
        !          1316:        dokeyDown, /* autoKey */
        !          1317:        doUpdate, /* updateEvt */
        !          1318:        NOFUNC, /* diskEvt */
        !          1319:        doActivate, /* activateEvt */
        !          1320:        NOFUNC, /* not  used */
        !          1321:        NOFUNC, /* networkEvt = 10 */
        !          1322:        NOFUNC, /* driverEvt */
        !          1323:        NOFUNC, /* app1Evt */
        !          1324:        NOFUNC, /* app2Evt */
        !          1325:        NOFUNC, /* app3Evt */
        !          1326:        NOFUNC  /* app4Ev */
        !          1327: };
        !          1328: 
        !          1329: 
        !          1330: static void CheckEvents()
        !          1331: {
        !          1332: #define Ticks (long *) 0x16A
        !          1333: 
        !          1334:        void SetBufMenu(),
        !          1335:                MarkModes();
        !          1336:                
        !          1337:        static EventRecord theEvent;
        !          1338:        static Point Mousep;
        !          1339:        static long time = 0;
        !          1340: 
        !          1341: 
        !          1342:        static void (*fptr)();
        !          1343:        
        !          1344: #define HeapEnd (char **) 0x114
        !          1345: #define ApplLimit (char **) 0x130
        !          1346:        static long freesp = 50000;
        !          1347:        
        !          1348:        if(FrontWindow() == window) {
        !          1349:                GetMouse(&Mousep);
        !          1350:                if(PtInRect(Mousep,&r))
        !          1351:                        SetCursor(*cross);
        !          1352:                else SetCursor(&arrow);
        !          1353:        }
        !          1354:        
        !          1355:        SystemTask();
        !          1356:        if(EventCmd && !Keyonly) return;
        !          1357:        if(Bufchange != 0) SetBufMenu();
        !          1358:        if(Modechange != 0) MarkModes();
        !          1359:        while(GetNextEvent(everyEvent,&theEvent)) {
        !          1360:                if ((theEvent.what < NEVENTS) && (fptr = eventlist[theEvent.what])) {
        !          1361:                        (*fptr)(&theEvent);
        !          1362:                }
        !          1363:                SystemTask();
        !          1364:        }
        !          1365:        if((*ApplLimit - *HeapEnd) < freesp) {
        !          1366:                freesp = (((*ApplLimit - *HeapEnd)/5000) * 5000);
        !          1367:                SysBeep(120);
        !          1368:                s_mess("WARNING: Free memory down to %D bytes",freesp);
        !          1369:                freesp -= 5000;
        !          1370:                if(!Macmode) redisplay();
        !          1371:        }
        !          1372:        if((*Ticks - time) > 3600) {
        !          1373:                time = *Ticks;
        !          1374:                UpdModLine = YES;
        !          1375:                redisplay();
        !          1376:        }
        !          1377: 
        !          1378: }
        !          1379: 
        !          1380: 
        !          1381: static void InitSysMenu()
        !          1382: {
        !          1383:        void InitLocalMenus();
        !          1384:        
        !          1385:        SysMenu = NewMenu(SYS_ID,"\p\24");
        !          1386:        AppendMenu(SysMenu,"\pAbout Jove");
        !          1387:        AddResMenu(SysMenu,'DRVR');
        !          1388:        InsertMenu(SysMenu,0);
        !          1389:        InitLocalMenus();
        !          1390:        DrawMenuBar();
        !          1391: }
        !          1392: 
        !          1393: extern void doWind(),doGoAway(),doSysMenu(),doSysClick();
        !          1394: #define NMEVENTS 7
        !          1395: static void (*mouselist[])() =
        !          1396: {
        !          1397:        NOFUNC, /* inDesk */
        !          1398:        doSysMenu, /* inMenuBar */
        !          1399:        doSysClick, /* inSysWindow */
        !          1400:        doWind, /* inContent */
        !          1401:        NOFUNC, /* inDrag */
        !          1402:        NOFUNC, /* inGrow */
        !          1403:        doGoAway /* inGoAwa */
        !          1404: };
        !          1405: 
        !          1406: 
        !          1407: static void doMouse(event)
        !          1408: EventRecord *event;
        !          1409: {
        !          1410:        WindowPtr theWindow;
        !          1411:        int wpart;
        !          1412:        void (*fptr)();
        !          1413:        
        !          1414:        if(Keyonly) {
        !          1415:                if(event->what == mouseDown) SysBeep(2);
        !          1416:                return;
        !          1417:        }
        !          1418:        wpart = FindWindow(event->where,&theWindow);    
        !          1419:        if ((wpart < NMEVENTS) && (fptr = mouselist[wpart])) {
        !          1420:                (*fptr)(event,theWindow);
        !          1421:        }
        !          1422: 
        !          1423: }
        !          1424: 
        !          1425: static void doSysMenu(event,window)
        !          1426: EventRecord *event;
        !          1427: WindowPtr window;
        !          1428: {
        !          1429:        void ProcMenu();
        !          1430:        
        !          1431:        int Menu,Item;
        !          1432:        long result = MenuSelect(event->where);
        !          1433:        Menu = (result >> 16) & 0xffff;
        !          1434:        Item = result & 0xffff;
        !          1435:        if(Item == 0) return;   /* no choice made */
        !          1436:        
        !          1437:        if(Menu == SYS_ID) {                    /* apple menu */
        !          1438:                Str255 Name;
        !          1439:                GrafPtr Port;
        !          1440:                
        !          1441:                if(Item == 1) about_j();
        !          1442:                else {          
        !          1443:                        GetItem(SysMenu,Item,Name);
        !          1444:                        GetPort(&Port);
        !          1445:                        OpenDeskAcc(Name);
        !          1446:                        SetPort(Port);
        !          1447:                }
        !          1448:        }
        !          1449:        else ProcMenu(Menu,Item);
        !          1450:        HiliteMenu(0);
        !          1451:        EventCmd = 1;
        !          1452: 
        !          1453:        menus_on();
        !          1454:        return;
        !          1455:        
        !          1456: }
        !          1457:                
        !          1458: static void doSysClick(event,window)
        !          1459: EventRecord *event;
        !          1460: WindowPtr window;
        !          1461: {
        !          1462:        SystemClick(event,window);
        !          1463: }              
        !          1464:                
        !          1465:        
        !          1466:        
        !          1467: static void doUpdate(event)
        !          1468: EventRecord *event;
        !          1469: {
        !          1470:        WindowPtr theWindow, oldPort;
        !          1471:        
        !          1472:        theWindow = (WindowPtr) event->message;
        !          1473: 
        !          1474:        if(firsttime == 0) {            
        !          1475:                firsttime++;
        !          1476:                BeginUpdate(theWindow);
        !          1477:                EndUpdate(theWindow);
        !          1478:                return;
        !          1479:        }
        !          1480:                
        !          1481: /*     redisplay(); */
        !          1482:        GetPort(&oldPort);
        !          1483:        SetPort(theWindow);
        !          1484:        BeginUpdate(theWindow);
        !          1485:        if(theWindow == theScreen && Windchange == 0
        !          1486:                && Keyonly == 0) {
        !          1487:                Placur(0,0);
        !          1488:                drawfluff();
        !          1489:                cl_scr(1);
        !          1490:                redisplay();
        !          1491:        }
        !          1492:        EndUpdate(theWindow);
        !          1493: 
        !          1494:        SetPort(oldPort);
        !          1495: }
        !          1496: 
        !          1497: static void doActivate(event)
        !          1498: EventRecord *event;
        !          1499: {
        !          1500:        WindowPtr theWindow;
        !          1501:        ControlHandle control;
        !          1502:        int hilite;
        !          1503:        
        !          1504:        theWindow = (WindowPtr) event->message;
        !          1505:        SetPort(theWindow);
        !          1506:        if(event->modifiers & activeFlag) {
        !          1507:                hilite = 0;
        !          1508:        }
        !          1509:        else hilite = 255;
        !          1510:        for(control = (ControlHandle) (((WindowPeek) theWindow)->controlList);
        !          1511:                 (control != 0); control = (*control)->nextControl) {
        !          1512:                        HiliteControl(control,hilite);
        !          1513:        }
        !          1514: }
        !          1515:                
        !          1516: /* Keyboard routines. The Option key was formerly used as a meta key.
        !          1517:    However, to take advantage of the full (non-ASCII) character set,
        !          1518:    this was removed. The corresponding code is ifdeffed O_META. */
        !          1519:    
        !          1520: /* (ORIGINALLY IN) tkey.c
        !          1521:    keyboard routines for Macintosh. K Mitchum 12/86 */
        !          1522: 
        !          1523: extern jmp_buf auxjmp;
        !          1524: 
        !          1525: static nchars = 0;
        !          1526: static char charbuf[MCHARS];
        !          1527: /* the following kludges a meta key out of the option key by
        !          1528: sending an escape sequence back to the dispatch routines. this is
        !          1529: not elegant but it works, and doesn't alter escape sequences for
        !          1530: those that prefer them. to remap the control or meta keys,
        !          1531: see mackeys.h. */
        !          1532: 
        !          1533: static void dokeyDown(event)
        !          1534: EventRecord *event;
        !          1535: {
        !          1536:        unsigned mods;
        !          1537:        register c;
        !          1538:        static int cptr = 0;
        !          1539:        
        !          1540:        if(MCHARS - nchars < 2) return;
        !          1541:                
        !          1542:        c  = (char)((event->message)&(charCodeMask));
        !          1543: 
        !          1544:        if(c == '`') c = '\033';        /* for those used to escapes */
        !          1545:        
        !          1546:        mods = event->modifiers;
        !          1547: 
        !          1548: #ifdef O_META  
        !          1549:        if (mods & (optionKey | cmdKey)) {
        !          1550: #else
        !          1551:        if (mods & (cmdKey)) {
        !          1552: #endif
        !          1553:                if(mods & shiftKey) 
        !          1554:                        c  = sh_keycodes[(((event->message)&(keyCodeMask))>>8)];
        !          1555:                else    
        !          1556:                        c  = nsh_keycodes[(((event->message)&(keyCodeMask))>>8)];
        !          1557: #ifdef O_META                  
        !          1558:                if(mods & optionKey) {          /* make escape sequence */
        !          1559:                        if(mods & cmdKey) c &= 0x1f;
        !          1560:                        charbuf[cptr++] = '\033';
        !          1561:                        cptr &= NMASK;          /* zero if necessary */
        !          1562:                        nchars++;
        !          1563:                }
        !          1564:                else 
        !          1565: #endif
        !          1566:                {       /* command key (control key) */
        !          1567:                        if((c == '2') || (c == '\\')) c = 0;    /* so we have a null char */
        !          1568:                        if(c != '`') c &= 0x1f;         /* make a control char */
        !          1569:                }
        !          1570:        }
        !          1571:        charbuf[cptr++] = c;
        !          1572:        cptr &= NMASK;
        !          1573:        nchars++;
        !          1574: }
        !          1575: 
        !          1576: static int rawgetc()
        !          1577: {
        !          1578:        static int cptr = 0;
        !          1579:        register c;
        !          1580: 
        !          1581:        if(EventCmd) longjmp(auxjmp,0); 
        !          1582:        while(nchars <= 0) {
        !          1583:                nchars = 0;
        !          1584:                if(EventCmd) longjmp(auxjmp,0);
        !          1585:                CheckEvents();  /* ugh! WAIT for a character */
        !          1586:        }
        !          1587:        nchars--;
        !          1588:        c = charbuf[cptr++];
        !          1589:        cptr &= NMASK;          /* zero if necessary */
        !          1590:        return(c);
        !          1591: }
        !          1592: 
        !          1593: int rawchkc()
        !          1594: {
        !          1595:        if(EventCmd) longjmp(auxjmp,0);
        !          1596:        if(nchars == 0) CheckEvents();  /* this should NOT be necessary! */     
        !          1597:        return(nchars > 0);
        !          1598: }
        !          1599: 
        !          1600: /* Routines for calling the standard file dialogs, when macify is ON. If the user
        !          1601:    changes the directory using the file dialogs, Jove's notion of the current directory
        !          1602:    is updated. */
        !          1603: 
        !          1604:                                
        !          1605: /* (ORIGINALLY IN) tmacf.c. K. Mitchum 12/86.
        !          1606:    Macify routines for jove. */
        !          1607: 
        !          1608: int CurrentVol;                        /* see tfile.c */
        !          1609: 
        !          1610: 
        !          1611: #define TYPES  -1
        !          1612: 
        !          1613: static Point px = {100,100};
        !          1614: static char pmess[] = "\pSave file as: ";
        !          1615: 
        !          1616: static pascal Boolean Ffilter(p)
        !          1617: FileParam *p;
        !          1618: {
        !          1619:        if(p->ioFlFndrInfo.fdType == 'APPL') return TRUE;
        !          1620:        PtoCstr((char *) p->ioNamePtr);
        !          1621:        if(strcmp(p->ioNamePtr,d_tempfile) == 0) {
        !          1622:                CtoPstr((char *) p->ioNamePtr);
        !          1623:                return TRUE;
        !          1624:        }
        !          1625:        CtoPstr((char *) p->ioNamePtr);
        !          1626:        return FALSE;
        !          1627: }
        !          1628: 
        !          1629: static void check_dir()
        !          1630: {
        !          1631:        if(cur_vol != 0 - SFSaveDisk || cur_dir != CurDirStore) {
        !          1632:                setdir(0 - SFSaveDisk, CurDirStore);
        !          1633:                UpdModLine = YES;       /* make sure jove knows the change */
        !          1634:                Modechange++;
        !          1635:                setCWD(getwd());
        !          1636:        }
        !          1637: }
        !          1638: 
        !          1639: char *gfile(namebuf)   /* return a filename to get */
        !          1640: char *namebuf;
        !          1641: {
        !          1642:        SFReply frec;
        !          1643:        char ans[FILESIZE];
        !          1644:        
        !          1645:        SFSaveDisk = 0 - cur_vol;       /* in case a Desk Accessory changed them */
        !          1646:        CurDirStore = cur_dir;
        !          1647:        SFGetFile(px,0L,Ffilter,TYPES,0L,0L,&frec);
        !          1648:        check_dir();    /* see if any change, set if so */
        !          1649:        if(frec.good) {
        !          1650:                EventRecord theEvent;
        !          1651:                while(GetNextEvent(updateMask,&theEvent) == 0);
        !          1652:                doUpdate(&theEvent);
        !          1653:                PtoCstr((char *)frec.fName);
        !          1654:                strcpy(ans,frec.fName);
        !          1655:                CtoPstr((char *)frec.fName);
        !          1656:                PathParse(ans,namebuf);
        !          1657:                return(namebuf);
        !          1658:        }
        !          1659:        return(char *) 0;       
        !          1660: }
        !          1661: 
        !          1662: char *pfile(namebuf)
        !          1663: char *namebuf;
        !          1664: {
        !          1665:        SFReply frec;
        !          1666:        char *t, *nm;
        !          1667:        SFSaveDisk = 0 - cur_vol;       /* in case a Desk Accessory changed them */
        !          1668:        CurDirStore = cur_dir;
        !          1669:        strncpy(namebuf,filename(curbuf),63);
        !          1670:        nm = cvt_fnm(namebuf);
        !          1671:        CtoPstr(nm);
        !          1672:        SFPutFile(px,pmess,nm,0L,&frec);
        !          1673:        check_dir();    /* see if any change, set if so */
        !          1674:        if(frec.good) {
        !          1675:                EventRecord theEvent;
        !          1676:                while(GetNextEvent(updateMask,&theEvent) == 0);
        !          1677:                doUpdate(&theEvent);
        !          1678:                t = (char *)frec.fName;
        !          1679:                PtoCstr((char *)frec.fName);
        !          1680:                while(*t == ':') t++;   /* convert to unix style */
        !          1681:                nm = t;
        !          1682:                while(*nm) {
        !          1683:                        if(*nm == ':') *nm = '/';
        !          1684:                        nm++;
        !          1685:                }
        !          1686:                PathParse(t,namebuf);
        !          1687:                return(namebuf);
        !          1688:        }
        !          1689:        return(char *) 0;       
        !          1690: }      
        !          1691: 
        !          1692: 
        !          1693: /* getArgs() returns an argument list based on documents clicked on by the user. */
        !          1694: 
        !          1695: int getArgs(avp)
        !          1696: char ***avp;
        !          1697: {
        !          1698:        int argc, nargs, type, old_vol;
        !          1699:        long old_dir;
        !          1700:        char **argv;
        !          1701:        char *pathname; 
        !          1702:        AppFile p;
        !          1703:        WDPBRec d;
        !          1704:        
        !          1705:        old_vol = cur_vol;
        !          1706:        old_dir = cur_dir;
        !          1707:        
        !          1708:        CountAppFiles(&type,&nargs);
        !          1709:        if(nargs > 0) { /* files to open... */
        !          1710:                argv = (char **) malloc((nargs + 2) * sizeof(char *)); 
        !          1711:                for(argc = 1; argc <= nargs; argc++) {
        !          1712:                        GetAppFiles(argc,&p);
        !          1713:                        if(type == 0) {
        !          1714:                                PtoCstr((char *)p.fName);
        !          1715:                                d.ioCompletion = 0;
        !          1716:                                d.ioNamePtr = 0;
        !          1717:                                d.ioVRefNum = p.vRefNum;
        !          1718:                                d.ioWDIndex = 0;
        !          1719:                                PBGetWDInfo(&d,0);
        !          1720:                                cur_vol = d.ioWDVRefNum;
        !          1721:                                cur_dir = d.ioWDDirID;
        !          1722:                                pathname = getwd();
        !          1723:                                argv[argc] = malloc(strlen((char *)p.fName) + strlen(pathname) + 2);
        !          1724:                                strcpy(argv[argc],pathname);
        !          1725:                                strcat(argv[argc],"/");
        !          1726:                                strcat(argv[argc],(char *)p.fName);
        !          1727:                        }
        !          1728:                        ClrAppFiles(argc);
        !          1729:                }
        !          1730:                if(type != 0) argc = 1;
        !          1731:        }
        !          1732:        else {
        !          1733:                argv = (char **) malloc(2 * sizeof(char*));
        !          1734:                argc = 1;
        !          1735:        }
        !          1736:        argv[0] = "jove";
        !          1737: 
        !          1738:        argv[argc] = 0;
        !          1739:        *avp = argv;
        !          1740:        cur_dir = old_dir;
        !          1741:        cur_vol = old_vol;      
        !          1742:        return(argc);
        !          1743: }
        !          1744: 
        !          1745: /* Limited version of getenv() */
        !          1746: 
        !          1747: char *getenv(item)
        !          1748: char *item;
        !          1749: {
        !          1750:        char *ret = 0, *str = 0;
        !          1751:        
        !          1752:        if(strcmp(item,"CWD") == 0) str = getwd();
        !          1753:        if(strcmp(item,"HOME") == 0) str = gethome();
        !          1754:        if(str) {
        !          1755:                ret = malloc(strlen(str) + 1);
        !          1756:                strcpy(ret,str);
        !          1757:        }
        !          1758:        return(ret);
        !          1759: }
        !          1760: 
        !          1761: char *mktemp(name)
        !          1762: char *name;
        !          1763: {
        !          1764:        return name;
        !          1765: }
        !          1766: 
        !          1767: 
        !          1768: /* Menu routines. The menus items are set up in a similar manner as keys, and
        !          1769:    are bound prior to runtime. See menumaps.txt, which must be run through setmaps.
        !          1770:    Unlike keys, menu items may be bound to variables, and to buffers. Buffer binding
        !          1771:    is only done at runtime. */ 
        !          1772:                
        !          1773: static void InitLocalMenus()
        !          1774: {
        !          1775:        void InitMenu(),
        !          1776:                make_edits();
        !          1777:        
        !          1778:        int i;
        !          1779:        for(i = 0; i < NMENUS; i++) {
        !          1780:                InitMenu(&Menus[i]);
        !          1781:                if(i == 0) make_edits(Menus[i].menu_id + 1);
        !          1782:        }
        !          1783: }
        !          1784: 
        !          1785: static void InitMenu(M)
        !          1786: struct menu *M;
        !          1787: {
        !          1788:        int i;
        !          1789:        data_obj *d;
        !          1790:        char *name;
        !          1791: 
        !          1792:        if(M->menu_id == 0) return;
        !          1793:        M->Mn = NewMenu(M->menu_id,CtoPstr(M->Name));
        !          1794:        PtoCstr(M->Name);
        !          1795: 
        !          1796:        for(i = 0; i < NMENUITEMS; i++) {
        !          1797:                d = (M->m[i]);
        !          1798:                if(d == 0) break;       /* last item... */ 
        !          1799:                switch (d->Type & TYPEMASK) {
        !          1800:                        case (STRING) : 
        !          1801:                                AppendMenu(M->Mn,CtoPstr(d->Name));
        !          1802:                                PtoCstr(d->Name);
        !          1803:                                break;
        !          1804:                        case (VARIABLE) :
        !          1805:                                SetItemMark(M->Mn,i + 1, 0x12);
        !          1806:                        case (FUNCTION) :
        !          1807:                                CtoPstr(name = ((data_obj *) d)->Name);
        !          1808:                                AppendMenu(M->Mn,name);
        !          1809:                                PtoCstr(name);
        !          1810:                }
        !          1811:        }
        !          1812:        InsertMenu(M->Mn,0);
        !          1813: }
        !          1814: 
        !          1815: static void ProcMenu(menuno,itemno)
        !          1816: int menuno,itemno;
        !          1817: {
        !          1818:        void MacSetVar();
        !          1819:        
        !          1820:        int i;
        !          1821:        data_obj *d;
        !          1822: 
        !          1823:        for(i = 0; i < NMENUS && Menus[i].menu_id != menuno; i++);
        !          1824:        if(i < NMENUS) {        /* found the menu */
        !          1825:                itemno--;
        !          1826:                d = Menus[i].m[itemno];
        !          1827:                switch(d->Type & TYPEMASK) {
        !          1828:                        case FUNCTION :
        !          1829:                                ExecCmd((data_obj *) d);
        !          1830:                                break;
        !          1831:                        case BUFFER :
        !          1832:                                        SetABuf(curbuf);
        !          1833:                                        tiewind(curwind,(Buffer *) d);
        !          1834:                                        SetBuf((Buffer *) d);
        !          1835:                                break;
        !          1836:                        case VARIABLE :
        !          1837:                                        MacSetVar((struct variable *) d,i,itemno);
        !          1838:                                break;
        !          1839:                        default :
        !          1840:                                break;
        !          1841:                }
        !          1842:                
        !          1843:        }
        !          1844: }
        !          1845: 
        !          1846:                
        !          1847: 
        !          1848:                        
        !          1849:        
        !          1850: 
        !          1851: static void make_edits(menu)   /* add dummy edit menu */
        !          1852: int menu;
        !          1853: {
        !          1854:        MenuHandle M;
        !          1855:        int item;
        !          1856:        char *fname;
        !          1857:        
        !          1858:        M = NewMenu((menu),"\pEdit");
        !          1859:        AppendMenu(M,"\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear;Select All;(-;Show Clipboard");
        !          1860:        InsertMenu(M,0);
        !          1861:        DisableItem(M,0);
        !          1862: }
        !          1863: 
        !          1864: void menus_off()
        !          1865: {
        !          1866:        int i;
        !          1867:        
        !          1868:        if(Keyonly || EventCmd) return;
        !          1869:        DisableItem(SysMenu,0);
        !          1870:        for(i = 0; i < NMENUS; i++) 
        !          1871:                if(Menus[i].Mn) DisableItem(Menus[i].Mn,0);
        !          1872:        Keyonly = 1;
        !          1873:        DrawMenuBar();
        !          1874: }
        !          1875: 
        !          1876: void menus_on()
        !          1877: {
        !          1878:        int i;
        !          1879:        
        !          1880:        if(Keyonly == 0) return;
        !          1881:        EnableItem(SysMenu,0);
        !          1882:        for(i = 0; i < NMENUS; i++)
        !          1883:                if(Menus[i].Mn) EnableItem(Menus[i].Mn,0);
        !          1884:        Keyonly = 0;
        !          1885:        DrawMenuBar();
        !          1886: }
        !          1887: 
        !          1888: static char *BufMPrint(b,i)
        !          1889: Buffer *b;
        !          1890: {
        !          1891:        char *p;
        !          1892:        char *nm = filename(b);
        !          1893:        char t[35];
        !          1894:        
        !          1895:        if(strlen(nm) > 30) { 
        !          1896:                strcpy(t,"...");
        !          1897:                strcat(t,nm + strlen(nm) - 30);
        !          1898:        }
        !          1899:        else strcpy(t,nm);
        !          1900:        nm = t;
        !          1901:        while(*nm) {
        !          1902:                switch(*nm) {   /* ugh... these are metacharacter for Menus */
        !          1903:                        case '/' : *nm = ':'; break;
        !          1904:                        case '^' :
        !          1905:                        case '!' :
        !          1906:                        case '<' :
        !          1907:                        case '(' :
        !          1908:                        case ';' : *nm = '.'; break;    /* that will confuse everybody */
        !          1909:                }
        !          1910:                nm++;
        !          1911:        }
        !          1912:        p = sprint("%-2d %-11s \"%-s\"",i,b->b_name,t);
        !          1913:        return(p);
        !          1914: }
        !          1915: 
        !          1916: static void SetBufMenu()
        !          1917: {
        !          1918:        register Buffer *b;
        !          1919:        data_obj *d;
        !          1920:        int i,j,stop;
        !          1921:        struct menu *M;
        !          1922: 
        !          1923:        Bufchange = 0;
        !          1924:        for(i = 0; i < NMENUS && strcmp(Menus[i].Name,"Buffer"); i++);
        !          1925:        if(i < NMENUS) {
        !          1926:                M = &Menus[i];
        !          1927:                for(j = 0; j < NMENUITEMS && (d = Menus[i].m[j]) && (d->Type & TYPEMASK) != BUFFER; j++);
        !          1928:                if(j < NMENUITEMS) {
        !          1929:                        for(i = j, b = world; i < NMENUITEMS && b != 0; i++, b = b->b_next) {
        !          1930:                        
        !          1931:                                if(M->m[i] == 0) 
        !          1932:                                        AppendMenu(M->Mn,CtoPstr(BufMPrint(b,i-j+1)));  /* add the item */
        !          1933:                                else
        !          1934:                                        SetItem(M->Mn,i + 1,CtoPstr(BufMPrint(b,i-j+1)));       /* or change it */
        !          1935:                                M->m[i] = (data_obj *) b;
        !          1936:                        }
        !          1937:                        stop = i;
        !          1938:                          /* out of buffers? */
        !          1939:                        for(;i < NMENUITEMS && M->m[i];i++) {
        !          1940:                                DelMenuItem(M->Mn,stop + 1);    /* take off last item */
        !          1941:                                M->m[i] = 0;
        !          1942:                        }
        !          1943:                }
        !          1944:        }
        !          1945:        return;
        !          1946: }
        !          1947: 
        !          1948: static void MacSetVar(vp,mnu,itm)      /* Set a variable from the menu */
        !          1949: struct variable *vp;   /* Liberally taken from SetVar() in extend.c */
        !          1950: int mnu,itm;
        !          1951: {
        !          1952:        void MarkVar();
        !          1953:        
        !          1954:        char *prompt;
        !          1955: 
        !          1956:        prompt = sprint("Set %s: ", vp->Name);
        !          1957:        switch (vp->v_flags & V_TYPEMASK) {
        !          1958:        case V_BASE10:
        !          1959:        case V_BASE8:
        !          1960:            {
        !          1961:                int     value;
        !          1962: 
        !          1963:                value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10)
        !          1964:                                          ? 10 : 8);
        !          1965:                *(vp->v_value) = value;
        !          1966:                break;
        !          1967:            }
        !          1968:        case V_BOOL:    /* toggle the value */
        !          1969:                *(vp->v_value) = (*vp->v_value == ON ? OFF : ON);
        !          1970:                MarkVar(vp,mnu,itm);
        !          1971:                break;
        !          1972:        case V_FILENAME:
        !          1973:        case V_STRING:
        !          1974:            {
        !          1975:                char    *str;
        !          1976: 
        !          1977:                /* Do_ask() so you can set string to "" if you so desire. */
        !          1978:                str = do_ask("\r\n", (int (*)()) 0, (char *) vp->v_value, prompt);
        !          1979:                if (str == 0)
        !          1980:                        str = NullStr;
        !          1981:                strcpy((char *) vp->v_value, str);
        !          1982:                /* ... and hope there is enough room. */
        !          1983:                break;
        !          1984:            }
        !          1985:        case V_CHAR:
        !          1986:                f_mess(prompt);
        !          1987:                *(vp->v_value) = addgetc();
        !          1988:                break;          
        !          1989:        }
        !          1990: 
        !          1991:        if (vp->v_flags & V_MODELINE)
        !          1992:                UpdModLine = YES;
        !          1993:        if (vp->v_flags & V_CLRSCREEN) ClAndRedraw();
        !          1994:        if (vp->v_flags & V_TTY_RESET) tty_reset(); /* probably none on a Mac */
        !          1995:        return;
        !          1996: }
        !          1997: 
        !          1998: static void MarkModes()
        !          1999: {
        !          2000:        int mnu,itm,checked;
        !          2001:        data_obj *d;
        !          2002:        
        !          2003:        Modechange = 0;
        !          2004:        for(mnu = 0; mnu < NMENUS; mnu++) 
        !          2005:                for(itm = 0; itm < NMENUITEMS; itm++) {
        !          2006:                        if((d = Menus[mnu].m[itm]) == 0) break;
        !          2007:                        if((d->Type & (MAJOR_MODE | MINOR_MODE)) ||
        !          2008:                                 ((d->Type & TYPEMASK) == BUFFER)){
        !          2009:                                if(d->Type & (MAJOR_MODE))
        !          2010:                                        checked = (curbuf->b_major == (d->Type >> 8)) ? 1 : 0;
        !          2011:                                else if(d->Type & (MINOR_MODE))
        !          2012:                                        checked = (curbuf->b_minor & (d->Type >> 8)) ? 1 : 0;
        !          2013:                                else 
        !          2014:                                        checked = (d == (data_obj *) curbuf) ? 1 : 0;
        !          2015:                                CheckItem(Menus[mnu].Mn, itm + 1, checked);
        !          2016:                        }
        !          2017:                }
        !          2018: }
        !          2019:        
        !          2020: void MarkVar(vp,mnu,itm)       /* mark a boolean menu item */
        !          2021: struct variable *vp;
        !          2022: int mnu,itm;
        !          2023: {      
        !          2024:        int checked;
        !          2025:        if(mnu == -1) {         /* we don't know the item... slow */
        !          2026:                int found;
        !          2027:                for(mnu = 0, found = 0; (mnu < NMENUS) && !found; mnu++) {
        !          2028:                        for(itm = 0; (itm < NMENUITEMS); itm++)
        !          2029:                                if((struct variable *) (Menus[mnu].m[itm]) == vp) {
        !          2030:                                        found++;
        !          2031:                                        break;
        !          2032:                                }
        !          2033:                        if(found) break;
        !          2034:                }
        !          2035:                if(!found) return;
        !          2036:        }
        !          2037:        checked = (*(vp->v_value) == ON);
        !          2038:        CheckItem(Menus[mnu].Mn, itm + 1, checked);
        !          2039: }
        !          2040: 
        !          2041: static void MarkAllVar()       /* slow, but only do it once */
        !          2042: {
        !          2043:        int mnu,itm;
        !          2044:        data_obj *d;
        !          2045:        for(mnu = 0; mnu < NMENUS; mnu++) 
        !          2046:                for(itm = 0; itm < NMENUITEMS; itm++) {
        !          2047:                        if((d = Menus[mnu].m[itm]) == 0) break;
        !          2048:                        if((d->Type & TYPEMASK) == VARIABLE)
        !          2049:                                MarkVar((struct variable *)Menus[mnu].m[itm],mnu,itm);
        !          2050:                }
        !          2051: }
        !          2052: 
        !          2053: 
        !          2054: /* Screen routines and driver. The Macinitosh Text Edit routines are not utilized,
        !          2055:    as they are slow and cumbersome for a terminal emulator. Instead, direct QuickDraw
        !          2056:    calls are used. The fastest output is obtained writing a line at a time, rather
        !          2057:    than on a character basis, so the major output routine is writechr(), which takes
        !          2058:    a pascal-style string as an argument. See bufputc() in screen.c. */
        !          2059: 
        !          2060: void Placur(line,col)
        !          2061: int line, col;
        !          2062: {
        !          2063:        CapCol = col;
        !          2064:        CapLine = line;
        !          2065:        putcurs(line,col,ON);
        !          2066: }
        !          2067: 
        !          2068: void NPlacur(line,col)
        !          2069: int line, col;
        !          2070: {
        !          2071:        CapCol = col;
        !          2072:        CapLine = line;
        !          2073:        putcurs(line,col,OFF);
        !          2074: }
        !          2075: 
        !          2076: void i_lines(top, bottom, num)
        !          2077: int top, bottom, num;
        !          2078: {
        !          2079:        Placur(bottom - num + 1, 0);
        !          2080:        dellines(num,bottom);
        !          2081:        Placur(top, 0);
        !          2082:        inslines(num,bottom);
        !          2083: }
        !          2084: 
        !          2085: void d_lines(top, bottom, num)
        !          2086: int top, bottom, num;
        !          2087: {
        !          2088:        Placur(top, 0);
        !          2089:        dellines(num,bottom);
        !          2090:        Placur(bottom + 1 - num, 0);
        !          2091:        inslines(num,bottom);
        !          2092: }
        !          2093: 
        !          2094: 
        !          2095: void clr_page()
        !          2096: {
        !          2097:        void wipescreen();
        !          2098:        
        !          2099:        wipescreen();
        !          2100: }
        !          2101: 
        !          2102: void clr_eoln()
        !          2103: {
        !          2104:        void wipeline();
        !          2105:        
        !          2106:        wipeline();
        !          2107: }
        !          2108: 
        !          2109: void SO_on()
        !          2110: {
        !          2111:        void HLmode();
        !          2112:        
        !          2113:        HLmode(1);
        !          2114: }
        !          2115: 
        !          2116: void SO_off()
        !          2117: {
        !          2118:        void HLmode();
        !          2119:        
        !          2120:        HLmode(0);
        !          2121: }
        !          2122: 
        !          2123:        
        !          2124: /* (ORIGINALLY IN) tn.c   */
        !          2125: /* window driver for MacIntosh using windows. */
        !          2126: /* K. Mitchum 9/86 */
        !          2127: 
        !          2128: 
        !          2129: 
        !          2130: /*#define VARFONT*/
        !          2131: #ifdef VARFONT
        !          2132: static height,width,theight,twidth,descent;
        !          2133: #else
        !          2134: #define height HEIGHT
        !          2135: #define width WIDTH
        !          2136: #define theight THEIGHT
        !          2137: #define twidth TWIDTH 
        !          2138: #define descent DESCENT
        !          2139: #endif
        !          2140: 
        !          2141: static trow,tcol, insert, tattr, cursor;
        !          2142: static Rect cursor_rect;
        !          2143: 
        !          2144: 
        !          2145: static Rect  vRect;
        !          2146: static WindowRecord myWindowRec;
        !          2147: static Rect myBoundsRect;
        !          2148: 
        !          2149: 
        !          2150: #define active() SetPort(theScreen)
        !          2151: /*#define active()*/
        !          2152: #define maxadjust(r) OffsetRect(r,0,2);
        !          2153: static void tn_init()
        !          2154: {
        !          2155:        void INSmode(),
        !          2156:                init_slate();
        !          2157:        
        !          2158:        HLmode(0);
        !          2159:        INSmode(0);
        !          2160:        init_slate();
        !          2161:        ShowPen();
        !          2162: }
        !          2163: 
        !          2164: static void wipescreen()       /* clear and home function */
        !          2165: {
        !          2166:        Rect r;
        !          2167:        
        !          2168:        active();
        !          2169:        SetRect(&r, 0,0,WINDWIDTH,WINDHEIGHT);
        !          2170:        EraseRect(&r);
        !          2171:        cursor = OFF;
        !          2172:        putcurs(0,0);
        !          2173:        drawfluff();
        !          2174: }
        !          2175: 
        !          2176: static void putcurs(row,col,vis)
        !          2177: unsigned row, col, vis;
        !          2178: {
        !          2179: /*     if(row > MAXROW || col > MAXCOL) return(ERROR);*/
        !          2180: /*     if(row != trow || col != tcol) */{
        !          2181:                active();
        !          2182:                curset(OFF);
        !          2183:                if(row == MAXROW)
        !          2184:                        MoveTo(col * width, (row  +1) * height + 2 -descent );
        !          2185:                else
        !          2186:                        MoveTo(col * width, (row  +1) * height - descent);
        !          2187:                trow = row;
        !          2188:                tcol = col;
        !          2189:                curset(vis);
        !          2190:        }
        !          2191: }
        !          2192: 
        !          2193: static void curset(desired)
        !          2194: {
        !          2195:        if(cursor != desired) {
        !          2196:                SetRect(&cursor_rect, tcol * width, (trow) * height , (tcol + 1) * width - 1, (trow +1) * height -1);
        !          2197:                if(trow == MAXROW) maxadjust(&cursor_rect);
        !          2198:                InvertRect(&cursor_rect);
        !          2199:                cursor = desired;
        !          2200:        }
        !          2201: }
        !          2202: 
        !          2203: 
        !          2204: void putp(p)                   /* put one character, advance cursor */
        !          2205: int p;
        !          2206: {
        !          2207:        static Rect r;
        !          2208:        static RgnHandle updateRgn;
        !          2209: 
        !          2210:        active();
        !          2211:        curset(OFF);
        !          2212:        if(insert) {
        !          2213:                updateRgn = NewRgn();
        !          2214:                SetRect(&r, tcol * width, trow * height, WINDWIDTH, (trow +1) * height -1);
        !          2215:                if(trow == MAXROW) maxadjust(&r);
        !          2216:                ScrollRect(&r, width, 0, updateRgn);
        !          2217:                DisposeRgn(updateRgn);
        !          2218:        }
        !          2219:        if(p == '0') p = 0xAF;  /* slashed zero */
        !          2220:        DrawChar(p);
        !          2221:        if(tcol >= MAXCOL) putcurs(trow,MAXCOL);
        !          2222:        else putcurs(trow,tcol +1);
        !          2223: }
        !          2224: 
        !          2225: static void wipeline()
        !          2226: {
        !          2227:                static Rect r;
        !          2228:                
        !          2229:                active();
        !          2230:                cursor = OFF;
        !          2231:                SetRect(&r, tcol * width, trow * height, WINDWIDTH, (trow +1) * height);
        !          2232:                if(trow == MAXROW) maxadjust(&r);
        !          2233:                EraseRect(&r);
        !          2234:                curset(ON);
        !          2235: }
        !          2236: 
        !          2237: static void delchars()
        !          2238: {
        !          2239:                static Rect r;
        !          2240:                static RgnHandle updateRgn;
        !          2241:                
        !          2242:                active();
        !          2243:                curset(OFF);
        !          2244:                updateRgn = NewRgn();
        !          2245:                SetRect(&r, tcol * width, trow * height, twidth - width, (trow +1) * height);
        !          2246:                if(trow == MAXROW) maxadjust(&r);
        !          2247:                ScrollRect(&r, 0 - width, 0, updateRgn);
        !          2248:                DisposeRgn(updateRgn);
        !          2249:                curset(ON);
        !          2250: }
        !          2251: 
        !          2252: static void dellines(n,bot)
        !          2253: int n,bot;
        !          2254: {
        !          2255:        Rect r;
        !          2256:        RgnHandle updateRgn;
        !          2257:        
        !          2258:        updateRgn = NewRgn();
        !          2259:        active();
        !          2260:        curset(OFF);
        !          2261:        SetRect(&r, 0, ((trow) * height), WINDWIDTH, ((bot + 1) * height));
        !          2262:        ScrollRect(&r, 0, 0 - (n * height), updateRgn);
        !          2263:        DisposeRgn(updateRgn);
        !          2264:        putcurs(trow,0);
        !          2265:        
        !          2266: }
        !          2267: 
        !          2268: static void inslines(n,bot)
        !          2269: int n,bot;
        !          2270: {
        !          2271:        Rect r;
        !          2272:        RgnHandle updateRgn;
        !          2273:        
        !          2274:        updateRgn = NewRgn();
        !          2275:        active();
        !          2276:        curset(OFF);    
        !          2277:        SetRect(&r, 0, trow * height, WINDWIDTH, (bot +1) * height);
        !          2278:        ScrollRect(&r, 0, (n * height), updateRgn);
        !          2279:        DisposeRgn(updateRgn);
        !          2280:        putcurs(trow,0);
        !          2281: }
        !          2282:         
        !          2283: static void INSmode(new)
        !          2284: int new;
        !          2285: {
        !          2286:        insert = new;
        !          2287: }
        !          2288: 
        !          2289: static void HLmode(new)
        !          2290: int new;
        !          2291: {
        !          2292:        if(new) tattr = 1;
        !          2293:        else tattr = 0;
        !          2294: }
        !          2295: 
        !          2296: void writechr(start)
        !          2297: char *start;   /* actually, a Str255 type string */
        !          2298: {
        !          2299:        static Rect r;
        !          2300:        static RgnHandle updateRgn;
        !          2301:        register len;
        !          2302:        register char save;
        !          2303:        
        !          2304:        len = (int) start[0];           /* adjusted 6/86 K. M. in td.c*/
        !          2305: 
        !          2306:        active();
        !          2307:        curset(OFF);
        !          2308:        if(insert) {
        !          2309:                updateRgn = NewRgn();
        !          2310:                SetRect(&r, tcol * width, trow * height, twidth - width * len, (trow +1) * height -1);
        !          2311:                if(trow == MAXROW) maxadjust(&r);
        !          2312:                ScrollRect(&r, width * len, 0, updateRgn);
        !          2313:                DisposeRgn(updateRgn);
        !          2314:        }
        !          2315:        DrawString(start);
        !          2316:        
        !          2317:        if(tcol >= MAXCOL) putcurs(trow,MAXCOL);
        !          2318:        else putcurs(trow,tcol +len);
        !          2319: }
        !          2320: 
        !          2321: 
        !          2322: 
        !          2323: static void reset(){}
        !          2324: static void blanks(){}
        !          2325: static void cleanup() {}
        !          2326: 
        !          2327: 
        !          2328: static void init_slate()
        !          2329: {
        !          2330:        FontInfo f;
        !          2331:        
        !          2332:        extern char *version;
        !          2333:        char *Name = "MacJove ";
        !          2334:        char *Title;
        !          2335:        
        !          2336:        InitGraf(&thePort);
        !          2337:        InitWindows();
        !          2338:        InitCursor();
        !          2339:        InitFonts ();
        !          2340:        InitMenus ();
        !          2341:        InitDialogs ((ProcPtr) 0);              /* no restart proc */
        !          2342:        
        !          2343:        tn_left = screenBits.bounds.left + 3;
        !          2344:        tn_top =  screenBits.bounds.top + 40;
        !          2345: 
        !          2346:        tn_rows = (screenBits.bounds.bottom - 3 - tn_top) / HEIGHT;
        !          2347:        tn_cols = (screenBits.bounds.right - 3 - tn_left - SCROLLWIDTH) / WIDTH;
        !          2348:        tn_right = tn_left + tn_cols * WIDTH + SCROLLWIDTH;
        !          2349:        tn_bottom = tn_top + tn_rows * HEIGHT + 2;
        !          2350:        tn_cols++;      /* kludge to get jove to use last col */ 
        !          2351: 
        !          2352:        LI = tn_rows;
        !          2353:        CO = tn_cols;
        !          2354:        MAXROW = tn_rows -1;
        !          2355:        MAXCOL = tn_cols -1;
        !          2356:        
        !          2357:        SetRect(&myBoundsRect,tn_left,tn_top,tn_right,tn_bottom);
        !          2358: 
        !          2359:        Title = sprint("%s%s",Name,version);
        !          2360:        theScreen = NewWindow(&myWindowRec, &myBoundsRect,CtoPstr(Title),
        !          2361:                1,noGrowDocProc,(WindowPtr) -1, 1, (long) 0);
        !          2362: 
        !          2363: 
        !          2364: 
        !          2365:        SetPort(theScreen);
        !          2366: 
        !          2367: /*     SetOrigin(-3,-1);*/
        !          2368:        (theScreen)->txFont = FONT;
        !          2369:        (theScreen)->txSize = TEXTSIZE;
        !          2370:        
        !          2371: #ifdef VARFONT 
        !          2372:        GetFontInfo(&f);
        !          2373:                height = f.ascent+f.descent+f.leading;
        !          2374:                width = f.widMax;
        !          2375:                twidth = width * tn_cols;
        !          2376:                theight = height * tn_rows;
        !          2377:                descent = f.descent;
        !          2378: #endif
        !          2379:        
        !          2380: /*     (theScreen)->lineHeight = height;
        !          2381:        (theScreen)->fontAscent = ASCENT;*/
        !          2382:        theScreen->txMode = patCopy;
        !          2383:        theScreen->pnMode = patCopy;
        !          2384:        PenNormal();
        !          2385:        cursor = OFF;
        !          2386: }
        !          2387: #endif /* MAC */
        !          2388: 
        !          2389: 
        !          2390: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.