executor/src/segment.c

925 lines
23 KiB
C

/* Copyright 1989, 1990, 1995 by Abacus Research and
* Development, Inc. All rights reserved.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_segment[] =
"$Id: segment.c 88 2005-05-25 03:59:37Z ctm $";
#endif
/* Forward declarations in SegmentLdr.h (DO NOT DELETE THIS LINE) */
#include "rsys/common.h"
#include "FileMgr.h"
#include "SegmentLdr.h"
#include "MemoryMgr.h"
#include "ResourceMgr.h"
#include "StdFilePkg.h"
#include "SysErr.h"
#include "FontMgr.h"
#include "OSEvent.h"
#include "WindowMgr.h"
#include "rsys/hfs.h"
#include "rsys/file.h"
#include "rsys/notmac.h"
#include "rsys/glue.h"
#include "rsys/wind.h"
#include "rsys/segment.h"
#include "rsys/host.h"
#include "rsys/vdriver.h"
#include "rsys/executor.h"
#include "rsys/flags.h"
#include "rsys/prefs.h"
#include "rsys/osevent.h"
#include "rsys/cquick.h"
#include "rsys/desk.h"
#include "rsys/dcache.h"
#include "rsys/launch.h"
#include <ctype.h>
#if defined (CYGWIN32)
#include "winfs.h"
/*
* NOTE: I've looked at MINGW32 0.1.3 and the io.h #defines
* X_OK, which we use below. I think Sam uses 0.1.3, even though
* ARDI is currently at 0.1.2.
*/
#if !defined (OLD_MINGWIN32)
#include <io.h> /* needed for X_OK */
#else
#define X_OK 4 /* this is really just to get segment.c to compile */
#endif
#endif
#if defined(MSDOS)
#include "dosevents.h"
#include "vga.h"
#endif /* defined(MSDOS) */
typedef finderinfo *finderinfoptr;
MAKE_HIDDEN(finderinfoptr);
typedef HIDDEN_finderinfoptr *finderinfohand;
PUBLIC int ROMlib_cacheheuristic = FALSE;
#if defined(ONLY_DESTROY_BETWEEN_CODE_SEGMENTS)
static short flush_bypass = 0;
/* This is the total number of code resources accessible to the program.
* If it's zero, we recompute it. Remember to set it to zero whenever
* launching a new program!
*/
typedef struct {
syn68k_addr_t start;
uint32 num_bytes;
} destroy_pair_t;
INTEGER ROMlib_num_code_resources = 0;
static int compar(const void *p1, const void *p2)
{
int retval;
uint32 s1, s2;
s1 = (uint32) ((const destroy_pair_t *) p1)->start;
s2 = (uint32) ((const destroy_pair_t *) p2)->start;
if (s1 < s2)
retval = -1;
else if (s2 < s1)
retval = 1;
else
retval = 0;
return retval;
}
#endif
A0(PUBLIC, void, flushcache)
{
ROMlib_destroy_blocks( (syn68k_addr_t) 0, (uint32) ~0, TRUE );
}
A2(PUBLIC trap, void, HWPriv, LONGINT, d0, LONGINT, a0)
{
static char d_cache_enabled = TRUE, i_cache_enabled = TRUE;
int new_state;
switch (d0) {
case 0: /* Dis/Ena Instr cache */
warning_unimplemented ("Dis/Ena instr cache");
new_state = ((EM_A0 & 0xFFFF) != 0);
EM_A0 = i_cache_enabled;
i_cache_enabled = new_state;
break;
case 1: /* Flush Instr cache */
flushcache();
break;
case 2: /* Dis/Ena Data cache */
warning_unimplemented ("Dis/Ena data cache");
new_state = ((EM_A0 & 0xFFFF) != 0);
EM_A0 = d_cache_enabled;
d_cache_enabled = new_state;
break;
case 3: /* Flush Data cache */
#if 0
flushcache();
#endif
break;
case 4: /* Enable external cache */
warning_unimplemented ("Enable external cache");
break;
case 5: /* Disable external cache */
warning_unimplemented ("Disable external cache");
break;
case 6: /* Flush external cache */
flushcache();
break;
case 9: /* Flush cache range */
ROMlib_destroy_blocks ((syn68k_addr_t) a0, EM_A1, TRUE);
EM_D0 = noErr; /* Maybe we should only touch d0.w? */
break;
default:
warning_unexpected ("d0 = 0x%x", d0);
EM_D0 = hwParamErr; /* Maybe we should only touch d0.w? */
break;
}
}
A1(PUBLIC, char *, ROMlib_undotdot, char *, origp)
{
int dotcount, nleft;
char *p, *oldloc;
boolean_t slashseen_p;
nleft = strlen(origp) + 1;
slashseen_p = FALSE;
dotcount = -1;
for (p = origp; *p; p++, nleft--) {
switch (*p) {
case '/':
switch (dotcount) {
case 0: /* slash slash */
BlockMove((Ptr) p+1, (Ptr) p, (Size) nleft-1);
break;
case 1: /* slash dot slash */
BlockMove((Ptr) p+1, (Ptr) p-1, (Size) nleft-1);
p -= 2;
dotcount = 0;
break;
case 2: /* slash dot dot slash */
for (oldloc = p-4; oldloc >= origp && *oldloc != '/'; --oldloc)
;
if (oldloc < origp)
oldloc = origp + 1;
else
++oldloc;
BlockMove((Ptr) p+1, (Ptr) oldloc, (Size) nleft-1);
p = oldloc - 1;
dotcount = 0;
break;
default:
dotcount = 0;
break;
}
slashseen_p = TRUE;
break;
case '.':
if (slashseen_p)
dotcount++;
break;
default:
slashseen_p = FALSE;
dotcount = -1;
break;
}
}
return origp;
}
PRIVATE void lastcomponent( StringPtr dest, StringPtr src )
{
unsigned char *c, *lastcolon;
int n;
lastcolon = 0;
for (c = src + 1, n = src[0]; --n >= 0; ++c)
if (*c == ':')
lastcolon = c;
if (lastcolon) {
++lastcolon;
n = src[0] - (lastcolon - (src+1));
} else
n = src[0];
dest[0] = n;
memmove(dest+1, lastcolon, n);
}
#if defined (MSDOS) || defined (CYGWIN32)
PRIVATE char *
canonicalize_potential_windows_path (char *uname)
{
char *p;
for (p = uname; *p; ++p)
if (*p == '\\')
*p = '/';
return uname;
}
#endif
PRIVATE boolean_t
full_pathname_p (char *uname)
{
boolean_t retval;
retval = uname[0] == '/';
#if defined (MSDOS) || defined(CYGWIN32)
if (!retval && uname[0] && uname[1] == ':' && uname[2] == '/')
retval = TRUE;
#endif
return retval;
}
PRIVATE uint8
hexval (char c)
{
uint8 retval;
if (c >= '0' && c <= '9')
retval = c - '0';
else if (c >= 'a' && c <= 'f')
retval = c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
retval = c - 'A' + 10;
else
retval = 0;
return retval;
}
/*
* Copies a c string into a pascal string changing occurrances of ::XY
* (where X and Y are hex digits) into the character 0xXY.
*/
PRIVATE void
colon_colon_copy (StringPtr dst, const char *src)
{
StringPtr save_dst;
save_dst = dst;
while (*src)
{
if (src[0] == ':' && src[1] == ':'
&& isxdigit (src[2]) && isxdigit (src[3]))
{
*++dst = (hexval (src[2]) << 4) | hexval (src[3]);
src += 4;
}
else
*++dst = *src++;
}
save_dst[0] = dst - save_dst;
}
/*
* This routine converts the UNIX path path to a pascal string that
* starts with a colon whose individual components have been converted
* from AppleDouble representation to Mac representation. In theory we
* could use this whether or not we were using the netatalk naming convention,
* but since this is a recent addition to ROMlib and since we're about to
* start building 2.1 candidates it makes sense to just use this in the
* unsupported case and continue using the old code with non-netatalk naming.
*/
#define MAC_LOCAL_FROM_UNIX_LOCAL(s) \
({ \
char *_s; \
unsigned char *retval; \
int len; \
int count; \
char *next_slash; \
\
_s = (s); \
len = strlen (_s); \
retval = alloca (len + 2); \
retval[1] = ':'; \
count = 1; \
\
do \
{ \
int component_len, shrinkage; \
\
next_slash = strchr (_s, '/'); \
if (next_slash) \
component_len = next_slash - _s; \
else \
component_len = strlen (_s); \
memcpy (retval+count+1, _s, component_len); \
shrinkage = ROMlib_UNIX7_to_Mac ((char *) retval+count+1, \
component_len); \
count += component_len - shrinkage; \
if (next_slash) \
{ \
_s += component_len + 1; /* skip the '/', too */ \
retval[count+1] = ':'; \
++count; \
} \
} \
while (next_slash); \
\
retval[0] = count; \
retval; \
})
A2(PRIVATE, BOOLEAN, argv_to_appfile, char *, uname, AppFile *, ap)
{
int namelen, pathlen;
unsigned char *path, *p;
VCBExtra *vcbp;
BOOLEAN retval;
INTEGER sysnamelen, totnamelen;
CInfoPBRec cinfo;
WDPBRec wpb;
struct stat sbuf;
#if defined (MSDOS) || defined(CYGWIN32)
uname = canonicalize_potential_windows_path (uname);
#endif
if (uname && Ustat(uname, &sbuf) == 0)
{
if (!full_pathname_p (uname))
{
namelen = strlen (uname);
path = (unsigned char *) ALLOCA(MAXPATHLEN + 1 + namelen + 1);
if (getcwd ((char *) path, MAXPATHLEN))
{
pathlen = strlen ((char *) path);
path[pathlen] = '/';
if (uname[0] == '.' && uname[1] == '/')
BlockMove ((Ptr) uname+2, (Ptr) (path+pathlen+1),
(Size) namelen+1-2);
else
BlockMove ((Ptr) uname, (Ptr) (path+pathlen+1),
(Size) namelen+1);
uname = (char *) path;
#if defined (MSDOS) || defined(CYGWIN32)
uname = canonicalize_potential_windows_path (uname);
#endif
}
else
warning_unexpected ("getwd failed: expect trouble reading "
"resources");
}
ROMlib_automount(uname);
vcbp = (VCBExtra *) ROMlib_vcbbybiggestunixname(uname);
if (vcbp)
{
cinfo.hFileInfo.ioVRefNum = vcbp->vcb.vcbVRefNum;
wpb.ioNamePtr = 0;
sysnamelen = strlen(vcbp->unixname);
if (sysnamelen == 1 + SLASH_CHAR_OFFSET) /* don't remove leading
'/' if that's
all there is */
{
sysnamelen = 0;
uname += SLASH_CHAR_OFFSET;
}
/* NOTE: we can probably skip the following "if" and the else
part and just use the "path = MAC_LOC..." line unconditionally,
but I don't want to possibly introduce a subtle bug at the last
minute before releasing 2.1 final. */
if (apple_double_quote_char == ':')
path = MAC_LOCAL_FROM_UNIX_LOCAL (uname + sysnamelen + 1);
else
{
totnamelen = strlen(uname);
pathlen = totnamelen - sysnamelen + 2; /* count & NUL */
path = alloca(pathlen);
strcpy((char *) path+1, uname + sysnamelen); /* path has count and */
path[0] = pathlen - 2; /* is NUL terminated */
path[1] = ':';
for (p = path; *++p;)
if (*p == '/')
*p = ':';
path[0] -= ROMlib_UNIX7_to_Mac((char *) path+1, path[0]);
}
}
else
path = 0; /* TODO: Some sort of problem here */
}
else
{
int len;
len = strlen (uname);
path = alloca (len + 1);
colon_colon_copy (path, uname);
cinfo.hFileInfo.ioVRefNum = 0;
wpb.ioNamePtr = RM(path);
}
cinfo.hFileInfo.ioNamePtr = RM(path);
cinfo.hFileInfo.ioFDirIndex = CWC (0);
cinfo.hFileInfo.ioDirID = 0;
if ((retval = (PBGetCatInfo(&cinfo, FALSE) == noErr)))
{
ap->fType = cinfo.hFileInfo.ioFlFndrInfo.fdType;
ap->versNum = 0;
wpb.ioVRefNum = cinfo.hFileInfo.ioVRefNum;
wpb.ioWDProcID = TICKX("unix");
wpb.ioWDDirID = cinfo.hFileInfo.ioFlParID;
if (PBOpenWD(&wpb, FALSE) == noErr)
{
ap->vRefNum = wpb.ioVRefNum;
lastcomponent(ap->fName, path);
}
else
{
ap->vRefNum = cinfo.hFileInfo.ioVRefNum;
str255assign(ap->fName, path);
}
}
else
{
warning_unexpected ("%s: unable to get info on `%s'\n", program_name,
uname);
}
return retval;
}
#if defined(NEXTSTEP) && defined(BINCOMPAT)
PUBLIC INTEGER ROMlib_acceptsanotherfile = TRUE;
#endif
PUBLIC int ROMlib_print;
#if !defined (MSDOS) && !defined(CYGWIN32)
#define PATH_SEPARATER ':'
#else
#define PATH_SEPARATER ';'
#endif
A2(PUBLIC, void, ROMlib_seginit, LONGINT, argc, char **, argv) /* INTERNAL */
{
char *path, *firstcolon;
char *fullpathname;
finderinfohand fh;
AppFile app;
INTEGER newcount;
THz saveZone;
fullpathname = 0;
if (Uaccess(argv[0], X_OK) == 0)
fullpathname = argv[0];
else {
for (path = getenv("PATH"); path && path[0];
path = firstcolon ? firstcolon + 1 : 0) {
if ((firstcolon = strchr(path, PATH_SEPARATER)))
*firstcolon = 0;
if (path[0]) {
fullpathname =
(char *) NewPtr(strlen(path) + 1 + strlen(argv[0]) + 1);
sprintf(fullpathname, "%s/%s", path, argv[0]);
} else {
fullpathname = (char *) NewPtr(strlen(argv[0]) + 1);
sprintf(fullpathname, "%s", argv[0]);
}
if (firstcolon)
*firstcolon = PATH_SEPARATER; /* if we don't replace this,
Linux gets confused */
if (Uaccess(fullpathname, X_OK) == 0)
firstcolon = 0; /* this will break us out of the loop */
else {
DisposPtr((Ptr) fullpathname);
fullpathname = 0;
}
}
}
/* NOTE: It's not clear why we're calling argv_to_appfile on fullpathname
below, but argv_to_appfile has enough potential side-effects that I'm
not about to remove it. OTOH, the call to OpenRFPerm will create
a spurious %executor file and then fail, so I've #if 0'd it out. */
if (argv_to_appfile(fullpathname, &app)) {
#if 0
CurApRefNum = CW(OpenRFPerm(app.fName, CW(app.vRefNum), fsCurPerm));
#endif
CurApName[0] = MIN(app.fName[0], sizeof(CurApName)-1);
BlockMove((Ptr) app.fName+1, (Ptr) CurApName+1, (Size) CurApName[0]);
} else {
CurApRefNum = -1;
CurApName[0] = 0;
}
saveZone = TheZone;
TheZone = SysZone;
fh = (finderinfohand)
NewHandle((Size) sizeof(finderinfo) - sizeof(AppFile));
TheZone = saveZone;
AppParmHandle = (Handle) RM(fh);
HxX(fh, count) = 0;
HxX(fh, message) = ROMlib_print ? CWC(appPrint) : CWC(appOpen) ;
if (fullpathname && fullpathname != argv[0])
DisposPtr((Ptr) fullpathname);
#if defined(NEXTSTEP) && defined(BINCOMPAT)
ROMlib_acceptsanotherfile = FALSE;
if (ROMlib_toexec) {
if (ROMlib_toopen)
ROMlib_toexec = *(char **) ROMlib_toexec; /* ick! */
if (argv_to_appfile(ROMlib_toexec, &app)) {
ROMlib_startupscreen = FALSE;
ROMlib_exit = TRUE;
newcount = Hx(fh, count) + 1;
HxX(fh, count) = CW(newcount);
SetHandleSize((Handle) fh,
(char *) &HxX(fh, files)[newcount] - (char *)STARH(fh));
HxX(fh, files)[Hx(fh, count)-1] = app;
}
if (ROMlib_toopen) {
if (argv_to_appfile(ROMlib_toopen, &app)) {
newcount = Hx(fh, count) + 1;
HxX(fh, count) = CW(newcount);
SetHandleSize((Handle) fh,
(char *) &HxX(fh, files)[newcount] - (char *) STARH(fh));
HxX(fh, files)[Hx(fh, count)-1] = app;
}
}
} else
#endif
while (--argc > 0) {
++argv;
if (argv_to_appfile(argv[0], &app)) {
ROMlib_startupscreen = FALSE;
ROMlib_exit = TRUE;
newcount = Hx(fh, count) + 1;
HxX(fh, count) = CW(newcount);
SetHandleSize((Handle) fh,
(char *) &HxX(fh, files)[newcount] - (char *) STARH(fh));
HxX(fh, files)[Hx(fh, count)-1] = app;
}
}
}
A2(PUBLIC, void, CountAppFiles, INTEGER *, messagep,
INTEGER *, countp) /* IMII-57 */
{
if (AppParmHandle)
{
if (messagep)
*messagep = STARH((finderinfohand) MR(AppParmHandle))->message;
if (countp)
*countp = STARH((finderinfohand) MR(AppParmHandle))->count;
}
else
*countp = 0;
}
A2(PUBLIC, void, GetAppFiles, INTEGER, index, AppFile *, filep) /* IMII-58 */
{
*filep = STARH((finderinfohand)MR(AppParmHandle))->files[index-1];
}
A1(PUBLIC, void, ClrAppFiles, INTEGER, index) /* IMII-58 */
{
if (STARH((finderinfohand)MR(AppParmHandle))->files[index-1].fType) {
STARH((finderinfohand)MR(AppParmHandle))->files[index-1].fType = 0;
STARH((finderinfohand)MR(AppParmHandle))->count =
CW(CW(STARH((finderinfohand)MR(AppParmHandle))->count) - 1);
}
}
P3(PUBLIC pascal trap, void, GetAppParms, StringPtr, namep, /* IMII-58 */
INTEGER *, rnp, HIDDEN_Handle *, aphandp)
{
str255assign(namep, CurApName);
*rnp = CurApRefNum;
(*aphandp).p = AppParmHandle;
}
PUBLIC char *ROMlib_errorstring;
PUBLIC char ROMlib_exit = 0;
#if defined(MSDOS)
#include <limits.h>
#endif /* defined(MSDOS) */
#if defined(MSDOS)
PRIVATE void execme(const char *toexec)
{
#if !defined(MSDOS)
execl(toexec, toexec, "-nosplash", (char *) 0);
#else
#if defined(notdef) /* we don't do this, now that we run under Windows */
int i;
i386_registers_t regs;
for (i = 3; i < OPEN_MAX; ++i) /* leave 0, 1, 2 open */
close(i);
regs.l.ebx = (ULONGINT) toexec;
regs.l.ecx = (ULONGINT) "-nosplash";
regs.w.ax = 0xFF10; /* Turbo assist case 16. */
int21(&regs);
#endif
#endif
}
#endif /* defined(MSDOS) */
PUBLIC int ROMlib_nobrowser = 0;
PRIVATE BOOLEAN valid_browser( void )
{
OSErr err;
FInfo finfo;
err = GetFInfo(FinderName, CW(BootDrive), &finfo);
return !ROMlib_nobrowser && err == noErr && finfo.fdType == TICKX("APPL");
}
PRIVATE void launch_browser( void )
{
/* Set the depth to what was specified on the command line;
* if nothing was specified there, set the depth to the maximum
* supported bits per pixel.
*/
SetDepth (MR (MainDevice),
(flag_bpp
? MIN (flag_bpp, vdriver_max_bpp)
: vdriver_max_bpp),
0, 0);
Launch(FinderName, CW(BootDrive));
}
P0(PUBLIC pascal trap, void, ExitToShell)
{
static char beenhere = FALSE;
#if defined(MSDOS)
char *toexec;
#endif
ALLOCABEGIN
#if 1
Point pt;
static SFTypeList applonly = { CLC(T('A','P','P','L')) };
SFReply reply;
char quickbytes[grafSize];
LONGINT tmpA5;
WindowPeek t_w;
int i;
if (ROMlib_mods & optionKey)
ROMlib_exit = TRUE;
/* NOTE: closing drivers is a bad thing in the long run, but for now
we're doing it. We actually do it here *and* in reinitialize_things().
We have to do it here since we want the window taken out of the
windowlist properly, before we hack it out ourself, but we have to
do it in reinitializethings because launch calls that, but doesn't
call exittoshell */
for (i = DESK_ACC_MIN; i <= DESK_ACC_MAX; ++i)
CloseDriver (-i - 1);
empty_timer_queues ();
if (WWExist == EXIST_YES)
{
/* remove global datastructures associated with each window
remaining in the application's window list */
for (t_w = MR (WindowList); t_w; t_w = WINDOW_NEXT_WINDOW (t_w))
pm_window_closed ((WindowPtr) t_w);
}
WindowList = 0;
if (!ROMlib_exit
&& (!beenhere
|| strncmp((char *) CurApName+1,
BROWSER_NAME, CurApName[0]) != 0)) {
beenhere = TRUE;
/* if we call `InitWindows ()', we don't want it shouting
about 32bit uncleanliness, &c */
size_info.application_p = FALSE;
if (QDExist == EXIST_NO) {
a5 = (LONGINT) US_TO_SYN68K(&tmpA5);
CurrentA5 = (Ptr) CL(a5);
InitGraf((Ptr) quickbytes + sizeof(quickbytes) - 4);
}
InitFonts();
FlushEvents( everyEvent, 0 );
if (WWExist == EXIST_NO)
InitWindows();
if (TEScrpHandle == (Handle)CLC(-1) || TEScrpHandle == (Handle)CLC(0))
TEInit();
if (DlgFont == CWC(0) || DlgFont == CWC(-1))
InitDialogs((ProcPtr)0);
InitCursor();
if (valid_browser())
{
/* NOTE: much of the initialization done above isn't really
needed here, but I'd prefer to have the same environment
when we auto-launch browser as when we choose an app
using stdfile */
launch_browser();
}
else
{
pt.h = 100;
pt.v = 100;
SFGetFile(pt, (StringPtr) "", (ProcPtr) 0, 1,
applonly, (ProcPtr) 0, &reply);
if (!reply.good)
ROMlib_exit = 1;
else
{
CurApName[0] = MIN(reply.fName[0], 31);
BlockMove((Ptr) reply.fName+1, (Ptr) CurApName+1,
(Size) CurApName[0]);
Launch(CurApName, CW(reply.vRefNum));
}
}
}
#endif
CloseResFile(0);
ROMlib_OurClose();
dcache_invalidate_all (TRUE);
#if defined (X)
autorepeatonX();
#endif /* X */
#if defined(SUN) && !defined(X) && !defined(NEXTSTEP)
close(_windowfd); /* may be bad choice */
BlockMove(_savebits, _addr, (Size) _nb);
#endif /* SUN && !defined */
#if defined (SCO)
ev_close();
ioctl( 1, (MODESWITCH|_savemode), 0);
restorekb();
#endif /* SCO */
if (ROMlib_errorstring) {
write(2, ROMlib_errorstring, strlen(ROMlib_errorstring));
gui_abort();
}
#if defined(NEXT)
stopprotectingus();
#endif
#if 0
if (FinderName[0]) {
toexec = ALLOCA(FinderName[0]+1);
BlockMove((Ptr) FinderName+1, (Ptr) toexec, (Size) FinderName[0]);
toexec[FinderName[0]] = 0;
execlp(toexec, toexec, (char *) 0);
/* if it fails we'll exit */
}
#endif
#if defined(MSDOS)
#define EXECUTORSUFFIX ".exe" /* This is necessary because of the way go32 */
#else /* works with Executor */
#define EXECUTORSUFFIX ""
#endif
#if defined(MSDOS)
if (!ROMlib_exit) {
toexec = ALLOCA(strlen(ROMlib_startdir) + 1 +
strlen(ROMlib_appname) +
strlen(EXECUTORSUFFIX) + 1);
sprintf(toexec, "%s/%s%s", ROMlib_startdir, ROMlib_appname,
EXECUTORSUFFIX);
execme(toexec);
}
#endif
exit(ROMlib_exit == 1 ? 0 : ROMlib_exit); /* 1 is historically good */
ALLOCAEND /* yeah, right, if exit fails... */
}
#if !defined (BINCOMPAT)
P1(PUBLIC pascal trap, void, UnloadSeg, Ptr, addr) /* INTERNAL */
{
/* NOP */
}
#else /* BINCOMPAT */
#define JMPLINSTR 0x4EF9
#define MOVESPINSTR 0x3F3C
#define LOADSEGTRAP 0xA9F0
P1(PUBLIC pascal trap, void, LoadSeg, INTEGER volatile, segno)
{
Handle newcode;
unsigned short offbytes;
INTEGER taboff, nentries, savenentries;
short *ptr, *saveptr;
#if defined(NEXTSTEP)
if (ROMlib_appbit && !(ROMlib_appbit & ROMlib_whichapps))
ExitToShell();
#endif
ResLoad = -1; /* CricketDraw III's behaviour suggested this */
newcode = GetResource(TICK("CODE"), segno);
HLock(newcode);
taboff = CW(((INTEGER *) STARH(newcode))[0]);
if ((uint16) taboff == 0xA89F) /* magic compressed resource signature */
{
/* We are totally dead here. We almost certainly can't use
* `system_error' to inform the user because the window
* manager probably is not yet running.
*/
ROMlib_launch_failure = (system_version >= 0x700 ?
launch_compressed_ge7 :
launch_compressed_lt7);
C_ExitToShell ();
}
savenentries = nentries = CW(((INTEGER *) STARH(newcode))[1]);
saveptr = ptr = (short *) ((char *) (long) SYN68K_TO_US(a5) + taboff + Cx(CurJTOffset));
while (--nentries >= 0) {
if (ptr[1] != CWC(JMPLINSTR)) {
offbytes = CW(*ptr);
*ptr++ = CW(segno);
*ptr++ = CWC(JMPLINSTR);
*(LONGINT *) ptr =
CL((LONGINT) (long) ((char *) US_TO_SYN68K(STARH(newcode)) + offbytes + 4));
ptr += 2;
} else
ptr += 4;
}
ROMlib_destroy_blocks( (syn68k_addr_t) (long) US_TO_SYN68K(saveptr), 8L * savenentries,
TRUE);
}
#define SEGNOOFP(p) (CW(((INTEGER *)p)[-1]))
A2(PRIVATE, void, unpatch, Ptr, segstart, Ptr, p)
{
INTEGER *ip;
Ptr firstpc;
ip = (INTEGER *) p;
firstpc = MR(*(Ptr *)(p + 2));
ip[1] = ip[-1]; /* the segment number */
ip[-1] = CW(firstpc - segstart - 4);
ip[0] = CWC(MOVESPINSTR);
ip[2] = CWC(LOADSEGTRAP);
}
P1(PUBLIC pascal trap, void, UnloadSeg, Ptr, addr)
{
Ptr p, segstart;
char *top, *bottom;
Handle h;
INTEGER segno;
if (* (INTEGER *) addr == CWC(JMPLINSTR)) {
segno = SEGNOOFP(addr);
h = GetResource(TICK("CODE"), segno);
if (!(*h).p)
LoadResource(h);
segstart = STARH(h);
for (p = addr; SEGNOOFP(p) == segno; p += 8)
unpatch(segstart, p);
bottom = (char *) p;
for (p = addr-8; SEGNOOFP(p) == segno; p -= 8)
unpatch(segstart, p);
top = (char *) p + 6; /* +8 that we didn't zap, -2 that we went
overboard on unpatch (see above) */
ROMlib_destroy_blocks( (syn68k_addr_t) (long) US_TO_SYN68K(top),
bottom - top, FALSE);
HUnlock(h);
HPurge(h);
}
}
#endif /* BINCOMPAT */