home *** CD-ROM | disk | FTP | other *** search
- /* --------------------------------------------------------------------------
- * machdep.c: Copyright (c) Mark P Jones 1991-1994. All rights reserved.
- * See goferite.h for details and conditions of use etc...
- * Gofer version 2.30 March 1994
- *
- * Machine dependent code
- * RISCOS specific code provided by Bryan Scatergood, JBS
- * ------------------------------------------------------------------------*/
-
- #if UNIX
- #include <signal.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #endif
-
- #if (TURBOC | BCC)
- #include <dos.h>
- #include <conio.h>
- #include <io.h>
- #include <stdlib.h>
- #include <mem.h>
- #include <sys\stat.h>
- #include <time.h>
- extern unsigned _stklen = 8000; /* Allocate an 8k stack segment */
- #endif
-
- #if (ZTC | WATCOM)
- #include <stdlib.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #endif
-
- #if DJGPP
- #include <dos.h>
- #include <stdlib.h>
- #include <std.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #endif
-
- #if RISCOS
- #include <assert.h>
- #include <signal.h>
- #include "swis.h"
- #include "os.h"
- #endif
-
- #if ATARI
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #endif
-
- #if (S_AMISAS | R_AMISAS | L_AMISAS)
- #include <exec/types.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <dos.h>
- #ifndef MACHDEP_RUNTIME
- __near long __stack = 25000L;
- unsigned char amigabreak = 0;
- #endif
- #endif
-
- /* --------------------------------------------------------------------------
- * Machine dependent code is used in each of:
- * - The gofer interpreter MACHDEP_GOFER
- * - The gofer compiler MACHDEP_GOFC
- * - The compiler runtime system MACHDEP_RUNTIME
- * In many cases, the the same code is used in each part. The following
- * sections of code are enclosed in suitable #if ... #endif directives to
- * indicate which sections require particular parts of the code. Each of
- * the three systems above defines one of the three symbols on the right
- * above as 1 and then #includes this file. The following directives make
- * sure that the other macros are set to the correct defaults.
- * ------------------------------------------------------------------------*/
-
- #ifndef MACHDEP_GOFER
- #define MACHDEP_GOFER 0
- #endif
- #ifndef MACHDEP_GOFC
- #define MACHDEP_GOFC 0
- #endif
- #ifndef MACHDEP_RUNTIME
- #define MACHDEP_RUNTIME 0
- #endif
-
- /* --------------------------------------------------------------------------
- * Find information about a file:
- * ------------------------------------------------------------------------*/
-
- #if (MACHDEP_GOFER | MACHDEP_GOFC)
- #if RISCOS
- typedef struct { unsigned hi, lo; } Time;
- #define timeChanged(now,thn) (now.hi!=thn.hi || now.lo!=thn.lo)
- #define timeSet(var,tm) var.hi = tm.hi; var.lo = tm.lo
- #else
- typedef time_t Time;
- #define timeChanged(now,thn) (now!=thn)
- #define timeSet(var,tm) var = tm
- #endif
-
- static Void local getFileInfo Args((String, Time *, Long *));
-
- static Void local getFileInfo(s,tm,sz) /* find time stamp and size of file*/
- String s;
- Time *tm;
- Long *sz; {
- #if RISCOS /* get file info for RISCOS -- JBS */
- os_regset r; /* RISCOS PRM p.850 and p.837 */
- r.r[0] = 17; /* Read catalogue, no path */
- r.r[1] = (int)s;
- os_swi(OS_File, &r);
- if(r.r[0] == 1 && (r.r[2] & 0xFFF00000) == 0xFFF00000) {
- tm->hi = r.r[2] & 0xFF; /* Load address (high byte) */
- tm->lo = r.r[3]; /* Execution address (low 4 bytes) */
- }
- else /* Not found, or not time-stamped */
- tm->hi = tm->lo = 0;
- *sz = (Long)(r.r[0] == 1 ? r.r[4] : 0);
- #else /* normally just use stat() */
- static struct stat scbuf;
- stat(s,&scbuf);
- *tm = scbuf.st_mtime;
- *sz = (Long)(scbuf.st_size);
- #endif
- }
- #endif
-
- #if RISCOS /* RISCOS needs access() */
- int access(char *s, int dummy) { /* Give 1 iff cannot access file s */
- os_regset r; /* RISCOS PRM p.850 -- JBS */
- assert(dummy == 0);
- r.r[0] = 17; /* Read catalogue, no path */
- r.r[1] = (int)s;
- os_swi(OS_File, &r);
- return r.r[0] != 1;
- }
-
- int namecmp(char *filename, char *spec){/* For filename extension hacks */
- while(*spec)
- if (tolower(*filename) != *spec++)
- return 0;
- else
- ++filename;
- return *filename == '.';
- }
- #endif
-
- /* --------------------------------------------------------------------------
- * Get time/date stamp for inclusion in compiled files:
- * ------------------------------------------------------------------------*/
-
- #if MACHDEP_GOFC
- #include <time.h>
- String timeString() { /* return time&date string */
- time_t clock; /* must end with '\n' character */
- time(&clock);
- return(ctime(&clock));
- }
- #endif
-
- /* --------------------------------------------------------------------------
- * Garbage collection notification:
- * ------------------------------------------------------------------------*/
-
- #if (MACHDEP_GOFER | MACHDEP_GOFC)
- Bool gcMessages = FALSE; /* TRUE => print GC messages */
-
- Void gcStarted() { /* notify garbage collector start */
- if (gcMessages) {
- printf("{{Gc");
- fflush(stdout);
- }
- }
-
- Void gcScanning() { /* notify garbage collector scans */
- if (gcMessages) {
- putchar(':');
- fflush(stdout);
- }
- }
-
- Void gcRecovered(recovered) /* notify garbage collection done */
- Int recovered; {
- if (gcMessages) {
- printf("%d}}",recovered);
- fflush(stdout);
- }
- }
-
- Cell *CStackBase; /* Retain start of C control stack */
-
- #if RISCOS /* Stack traversal for RISCOS */
-
- /* Warning: The following code is specific to the Acorn ARM under RISCOS
- (and C4). We must explicitly walk back through the stack frames, since
- the stack is extended from the heap. (see PRM pp. 1757). gcCStack must
- not be modified, since the offset '5' assumes that only v1 is used inside
- this function. Hence we do all the real work in gcARM.
- */
-
- #define spreg 13 /* C3 has SP=R13 */
-
- #define previousFrame(fp) ((int *)((fp)[-3]))
- #define programCounter(fp) ((int *)((*(fp)-12) & ~0xFC000003))
- #define isSubSPSP(w) (((w)&dontCare) == doCare)
- #define doCare (0xE24DD000) /* SUB r13,r13,#0 */
- #define dontCare (~0x00100FFF) /* S and # bits */
- #define immediateArg(x) ( ((x)&0xFF) << (((x)&0xF00)>>7) )
-
- static void gcARM(int *fp) {
- int si = *programCounter(fp); /* Save instruction indicates how */
- /* many registers in this frame */
- int *regs = fp - 4;
- if (si & (1<<0)) markWithoutMove(*regs--);
- if (si & (1<<1)) markWithoutMove(*regs--);
- if (si & (1<<2)) markWithoutMove(*regs--);
- if (si & (1<<3)) markWithoutMove(*regs--);
- if (si & (1<<4)) markWithoutMove(*regs--);
- if (si & (1<<5)) markWithoutMove(*regs--);
- if (si & (1<<6)) markWithoutMove(*regs--);
- if (si & (1<<7)) markWithoutMove(*regs--);
- if (si & (1<<8)) markWithoutMove(*regs--);
- if (si & (1<<9)) markWithoutMove(*regs--);
- if (previousFrame(fp)) {
- /* The non-register stack space is for the previous frame is above
- this fp, and not below the previous fp, because of the way stack
- extension works. It seems the only way of discovering its size is
- finding the SUB sp, sp, #? instruction by walking through the code
- following the entry point.
- */
- int *oldpc = programCounter(previousFrame(fp));
- int fsize = 0, i;
- for(i = 1; i < 6; ++i)
- if(isSubSPSP(oldpc[i])) fsize += immediateArg(oldpc[i]) / 4;
- for(i=1; i<=fsize; ++i)
- markWithoutMove(fp[i]);
- }
- }
-
- void gcCStack() {
- int dummy;
- int *fp = 5 + &dummy;
- while (fp) {
- gcARM(fp);
- fp = previousFrame(fp);
- }
- }
-
- #else /* Garbage collection for standard stack machines */
-
- Void gcCStack() { /* Garbage collect elements off */
- Cell stackTop = NIL; /* C stack */
- Cell *ptr = &stackTop;
- #if SMALL_GOFER
- if (((long)(ptr) - (long)(CStackBase))&1)
- fatal("gcCStack");
- #else
- if (((long)(ptr) - (long)(CStackBase))&3)
- fatal("gcCStack");
- #endif
-
- #define StackGrowsDown while (ptr<=CStackBase) markWithoutMove(*ptr++)
- #define StackGrowsUp while (ptr>=CStackBase) markWithoutMove(*ptr--)
- #define GuessDirection if (ptr>CStackBase) StackGrowsUp; else StackGrowsDown
- #if HPUX
- GuessDirection;
- #else
- StackGrowsDown;
- #endif
- #undef StackGrowsDown
- #undef StackGrowsUp
- #undef GuessDirection
- }
- #endif
- #endif
-
- /* --------------------------------------------------------------------------
- * Terminal dependent stuff:
- * ------------------------------------------------------------------------*/
-
- #if (TERMIO_IO | SGTTY_IO | TERMIOS_IO)
-
- #if TERMIO_IO
- #include <termio.h>
- typedef struct termio TermParams;
- #define getTerminal(tp) ioctl(fileno(stdin),TCGETA,&tp)
- #define setTerminal(tp) ioctl(fileno(stdin),TCSETAF,&tp)
- #define noEcho(tp) tp.c_lflag &= ~(ICANON | ECHO); \
- tp.c_cc[VMIN] = 1; \
- tp.c_cc[VTIME] = 0;
- #endif
-
- #if SGTTY_IO
- #include <sgtty.h>
- typedef struct sgttyb TermParams;
- #define getTerminal(tp) ioctl(fileno(stdin),TIOCGETP,&tp)
- #define setTerminal(tp) ioctl(fileno(stdin),TIOCSETP,&tp)
- #if HPUX
- #define noEcho(tp) tp.sg_flags |= RAW; tp.sg_flags &= (~ECHO);
- #else
- #define noEcho(tp) tp.sg_flags |= CBREAK; tp.sg_flags &= (~ECHO);
- #endif
- #endif
-
- #if TERMIOS_IO
- #include <termios.h>
- typedef struct termios TermParams;
- #define getTerminal(tp) tcgetattr(fileno(stdin), &tp)
- #define setTerminal(tp) tcsetattr(fileno(stdin), TCSAFLUSH, &tp)
- #define noEcho(tp) tp.c_lflag &= ~(ICANON | ECHO); \
- tp.c_cc[VMIN] = 1; \
- tp.c_cc[VTIME] = 0;
- #endif
-
- static Bool messedWithTerminal = FALSE;
- static TermParams originalSettings;
-
- Void normalTerminal() { /* restore terminal initial state */
- if (messedWithTerminal)
- setTerminal(originalSettings);
- }
-
- Void noechoTerminal() { /* set terminal into noecho mode */
- TermParams settings;
-
- if (!messedWithTerminal) {
- getTerminal(originalSettings);
- messedWithTerminal = TRUE;
- }
- getTerminal(settings);
- noEcho(settings);
- setTerminal(settings);
- }
-
- #if (MACHDEP_GOFER | MACHDEP_GOFC)
- Int getTerminalWidth() { /* determine width of terminal */
- #ifdef TIOCGWINSZ
- #ifdef _M_UNIX /* SCO Unix 3.2.4 defines TIOCGWINSZ*/
- #include <sys/stream.h> /* Required by sys/ptem.h */
- #include <sys/ptem.h> /* Required to declare winsize */
- #endif
- static struct winsize terminalSize;
- ioctl(fileno(stdout),TIOCGWINSZ,&terminalSize);
- return (terminalSize.ws_col==0)? 80 : terminalSize.ws_col;
- #else
- return 80;
- #endif
- }
- #endif
-
- Int readTerminalChar() { /* read character from terminal */
- return getchar(); /* without echo, assuming that */
- } /* noechoTerminal() is active... */
- #endif
-
- #if DOS_IO
- static Bool terminalEchoReqd = TRUE;
-
- #if (MACHDEP_GOFER | MACHDEP_GOFC)
- #if (S_AMISAS | R_AMISAS | L_AMISAS)
- Int getTerminalWidth() {
- int lm, rm;
- int c;
- static char *nosizecheck = NULL;
- static int check = 1;
-
- /* If the environment variable GOFERNOWIDTH exists,
- * Gofer will abstain from trying to determine the
- * width of the ternminal.
- * Use it if you run Gofer from inside GNU Emacs;
- * the FIFO device used to communicate lies to both
- * isatty() and rawcon() and claims it is interactive.
- */
-
- if (check) {
- /* Only the first time getTerminalWidth() is called */
- nosizecheck = getenv("GOFERNOWIDTH");
- check = 0;
- }
-
- if (!nosizecheck && isatty(fileno(stdin)) > 0 && rawcon(1) == 0) {
- printf("%c%s",0x9B,"0 q"); /* Request window size report. */
- /*
- * Now read the size report.
- * <CSI>1;1;<bottom>;<right>r
- */
- c = getchar();
- for (;;) {
- if (c != 0x9B) { /* <CSI> */
- c = getchar();
- continue;
- }
- if (!isdigit(c = getchar()))
- continue; /* Top margin (not used). */
- while (isdigit(c = getchar()))
- ;
- if (c != ';')
- continue; /* ';' seperator. */
- if (!isdigit(c = getchar()))
- continue; /* Left margin. */
- lm = c - '0';
- while (isdigit(c = getchar()))
- lm = lm * 10 + c - '0';
- if (c != ';')
- continue; /* ';' seperator. */
- if (!isdigit(c = getchar()))
- continue; /* Bottom margin (not used). */
- while (isdigit(c = getchar()))
- ;
- if (c != ';')
- continue; /* ';' seperator. */
- if (!isdigit(c = getchar()))
- continue; /* Right margin. */
- rm = c - '0';
- while (isdigit(c = getchar()))
- rm = rm * 10 + c - '0';
- if (c != ' ')
- continue; /* " r" terminator. */
- if ((c = getchar()) != 'r')
- continue;
- break;
- }
- if (terminalEchoReqd) rawcon(0);
- return rm - lm + 1;
- }
- else
- return 77; /* Anybody's guess... */
- }
- #else
- Int getTerminalWidth() { /* PC screen is fixed 80 chars */
- return 80;
- }
- #endif
- #endif
-
- #if (S_AMISAS | R_AMISAS | L_AMISAS)
-
- Void normalTerminal() { /* restore terminal initial state */
- terminalEchoReqd = TRUE;
- rawcon(0);
- }
-
- Void noechoTerminal() { /* turn terminal echo on/off */
- terminalEchoReqd = FALSE;
- rawcon(1);
- }
-
- Int readTerminalChar() { /* read character from terminal */
- Int c = getchar();
- /*
- * This circumvents a problem with
- * Gofer code like 'run (map toUpper)'
- */
- if (c == 3) { /* Ctrl-C is swallowed raw */
- normalTerminal(); /* turn echo on */
- raise(SIGINT);
- c = '\n'; /* is this reasonable? */
- }
- return c=='\r' ? '\n' : c;
- }
-
- #else
-
- Void normalTerminal() { /* restore terminal initial state */
- terminalEchoReqd = TRUE;
- }
-
- Void noechoTerminal() { /* turn terminal echo on/off */
- terminalEchoReqd = FALSE;
- }
-
- Int readTerminalChar() { /* read character from terminal */
- if (terminalEchoReqd)
- return getchar();
- else {
- Int c = getch();
- return c=='\r' ? '\n' : c;
- }
- }
- #endif
-
- #if RISCOS
- #if (MACHDEP_GOFER | MACHDEP_GOFC)
- Int getTerminalWidth() {
- int dummy, width;
- (void) os_swi3r(OS_ReadModeVariable, -1, 1, 0, &dummy, &dummy, &width);
- return width+1;
- }
- #endif
-
- Void normalTerminal() { /* restore terminal initial state */
- } /* (not yet implemented) */
-
- Void noechoTerminal() { /* turn terminal echo on/off */
- } /* (not yet implemented) */
-
- Int readTerminalChar() { /* read character from terminal */
- return getchar();
- }
- #endif
-
- /* --------------------------------------------------------------------------
- * Interrupt handling:
- * ------------------------------------------------------------------------*/
-
- #if (MACHDEP_GOFER | MACHDEP_GOFC) /* runtime.c provides own version */
- static Bool broken = FALSE;
- static Bool breakReqd = FALSE;
- static sigProto(ignoreBreak);
-
- Bool breakOn(reqd) /* set break trapping on if reqd, */
- Bool reqd; { /* or off otherwise, returning old */
- Bool old = breakReqd;
-
- breakReqd = reqd;
- if (reqd) {
- if (broken) { /* repond to break signal received */
- broken = FALSE; /* whilst break trap disabled */
- sigRaise(breakHandler);
- }
- ctrlbrk(breakHandler);
- }
- else
- ctrlbrk(ignoreBreak);
-
- return old;
- }
-
- static sigHandler(ignoreBreak) { /* record but don't respond to break*/
- ctrlbrk(ignoreBreak);
- broken = TRUE;
- sigResume;
- }
- #endif
-
- /* --------------------------------------------------------------------------
- * Shell escapes:
- * ------------------------------------------------------------------------*/
-
- #if MACHDEP_GOFER
- Int shellEsc(s) /* run a shell command (or shell) */
- String s; {
- #if UNIX
- if (s[0]=='\0')
- s = fromEnv("SHELL","/bin/sh");
- #endif
- return system(s);
- }
-
- #if RISCOS /* RISCOS also needs a chdir() */
- int chdir(char *s) { /* RISCOS PRM p. 885 -- JBS */
- return os_swi2(OS_FSControl + XOS_Bit, 0, (int)s) != NULL;
- }
- #endif
- #endif
-
- /* --------------------------------------------------------------------------
- * Floating point support:
- * ------------------------------------------------------------------------*/
-
- #if HAS_FLOATS
- #if BREAK_FLOATS
- static union {
- Float flVal;
- struct {
- Cell flPart1,flPart2;
- } clVal;
- } fudgeCoerce;
-
- Cell part1Float(fl)
- FloatPro fl; {
- fudgeCoerce.flVal = fl;
- return fudgeCoerce.clVal.flPart1;
- }
-
- Cell part2Float(fl)
- FloatPro fl; {
- fudgeCoerce.flVal = fl;
- return fudgeCoerce.clVal.flPart2;
- }
-
- FloatPro floatFromParts(c1,c2)
- Cell c1, c2; {
- fudgeCoerce.clVal.flPart1 = c1;
- fudgeCoerce.clVal.flPart2 = c2;
- return fudgeCoerce.flVal;
- }
-
- Cell mkFloat(fl)
- FloatPro fl; {
- Cell p1,p2;
- fudgeCoerce.flVal = fl;
- p1 = mkInt(fudgeCoerce.clVal.flPart1);
- p2 = mkInt(fudgeCoerce.clVal.flPart2);
- return pair(FLOATCELL,pair(p1,p2));
- }
-
- FloatPro floatOf(c)
- Cell c; {
- fudgeCoerce.clVal.flPart1 = intOf(fst(snd(c)));
- fudgeCoerce.clVal.flPart2 = intOf(snd(snd(c)));
- return fudgeCoerce.flVal;
- }
-
- #if MACHDEP_RUNTIME & BREAK_FLOATS
- Cell safeMkFloat(fl)
- FloatPro fl; {
- fudgeCoerce.flVal = fl;
- needStack(2);
- pushInt(fudgeCoerce.clVal.flPart2);
- pushInt(fudgeCoerce.clVal.flPart1);
- heap(2);
- mkap();
- topfun(FLOATCELL);
- return pop();
- }
- #endif
-
- #else /* !BREAK_FLOATS */
- static union {
- Float flVal;
- Cell clVal;
- } fudgeCoerce;
-
- Cell mkFloat(fl)
- FloatPro fl; {
- fudgeCoerce.flVal = fl;
- return pair(FLOATCELL,fudgeCoerce.clVal);
- }
-
- FloatPro floatOf(c)
- Cell c; {
- fudgeCoerce.clVal = snd(c);
- return fudgeCoerce.flVal;
- }
- #endif
-
- String floatToString(fl) /* Make sure that floating */
- FloatPro fl; { /* point values print out in */
- static char buffer1[32]; /* a form in which they could*/
- static char buffer2[32]; /* also be entered as floats */
- Int i=0, j=0;
-
- sprintf(buffer1,FloatFMT,fl);
- while (buffer1[i] && strchr("eE.",buffer1[i])==0)
- buffer2[j++] = buffer1[i++];
- if (buffer1[i]!='.') {
- buffer2[j++] = '.';
- buffer2[j++] = '0';
- }
- while (buffer2[j++]=buffer1[i++])
- ;
- return buffer2;
- }
-
- FloatPro stringToFloat(s)
- String s; {
- return atof(s);
- }
- #else
- Cell mkFloat(fl)
- FloatPro fl; {
- internal("mkFloat");
- return 0;/*NOTREACHED*/
- }
-
- FloatPro floatOf(c)
- Cell c; {
- internal("floatOf");
- return 0;/*NOTREACHED*/
- }
-
- String floatToString(fl)
- FloatPro fl; {
- internal("floatToString");
- return "";/*NOTREACHED*/
- }
-
- FloatPro stringToFloat(s)
- String s; {
- internal("stringToFloat");
- return 0;
- }
- #endif
-
- /* --------------------------------------------------------------------------
- * Machine dependent control:
- * ------------------------------------------------------------------------*/
-
- #if (MACHDEP_GOFER | MACHDEP_GOFC)
- #if UNIX
- static sigHandler(panic) { /* exit in a panic, on receipt of */
- everybody(EXIT); /* an unexpected signal */
- fprintf(stderr,"Unexpected signal\n");
- exit(1);
- sigResume;/*NOTREACHED*/
- }
- #endif
-
- Void machdep(what) /* Handle machine specific */
- Int what; { /* initialisation etc.. */
- switch (what) {
- case MARK : break;
- #if UNIX
- case INSTALL :
- #ifdef SIGHUP
- signal(SIGHUP,panic);
- #endif
- #ifdef SIGQUIT
- signal(SIGQUIT,panic);
- #endif
- #ifdef SIGTERM
- signal(SIGTERM,panic);
- #endif
- #ifdef SIGSEGV
- signal(SIGSEGV,panic);
- #endif
- #ifdef SIGBUS
- signal(SIGBUS,panic);
- #endif
- break;
- #endif
- case RESET :
- case BREAK :
- case EXIT : normalTerminal();
- break;
- }
- }
- #endif
-
- /*-------------------------------------------------------------------------*/
-