/* mswstuff.c - ms-windows specific routines */
#include <dos.h>
#include <signal.h>
#include <mem.h>
#include <dir.h>
#include <time.h>
#include <float.h>
#include <sys/stat.h>
#include "xlisp.h"
#include "xlstat.h"
#include "xlgraph.h"
#include "wxlisp.h"
#include "ledit.h"
#include "winutils.h"
#include "version.h"
#define LBSIZE 200
/* external variables */
extern FILEP tfp;
extern int errno;
extern int Exiting;
extern char *iniFile;
extern LVAL s_event_queue, s_in_callback;
/* local variables */
static char lbuf[LBSIZE];
static int lindex;
static int lcount;
#ifdef XLISP_ONLY
static long rseed = 1L;
#endif
static char *xfgets _((char *s, int n));
static void errcatch(int);
char *stackbase;
int xlisp_mono;
/* osinit - initialize */
void osinit(banner)
char *banner;
{
#ifdef STSZ
stackbase = (char *)&banner; /* find base of stack */
#endif
GetPrivateProfileString("Graphics", "COLOR", "", buf, STRMAX, iniFile);
if (! stricmp(buf, "off") || ! stricmp(buf, "no") || getenv("XLISPMONO"))
xlisp_mono = TRUE;
else
xlisp_mono = FALSE;
sprintf(lbuf, "%s\n",banner);
TTYPutStr(lbuf);
sprintf(lbuf, "XLISP-STAT Release %d.%d.%d%s.\n",
XLS_MAJOR_RELEASE, XLS_MINOR_RELEASE, XLS_SUBMINOR_RELEASE,
XLS_RELEASE_STATUS);
TTYPutStr(lbuf);
TTYPutStr("Copyright (c) 1989-1999, by Luke Tierney.\n\n");
lposition = 0;
lindex = 0;
lcount = 0;
#ifndef MinGW32
_control87(MCW_EM, MCW_EM);
#endif
signal(SIGABRT, errcatch);
signal(SIGFPE, errcatch);
signal(SIGILL, errcatch);
signal(SIGSEGV, errcatch);
}
/* osfinish - clean up before returning to the operating system */
void osfinish()
{
CONTEXT cntxt;
xlbegin(&cntxt,CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL,(LVAL)1);
if (XL_SETJMP(cntxt.c_jmpbuf))
exit(0); /*** this probably needs to be done differently */
if (s_breakenable != NULL) setvalue(s_breakenable, NIL);
#ifdef CONDITIONS
if (s_condition_hook != NULL) setvalue(s_condition_hook, NIL);
#endif /* CONDITIONS */
Exiting = TRUE;
PostQuitMessage(0);
ExitXLS();
}
/* xoserror - print an error message */
void xoserror(msg)
char *msg;
{
WarningBox(msg);
}
# ifdef XLISP_ONLY
/* osrand - return a random number between 0 and n-1 */
int osrand(n)
int n;
{
long k1;
/* make sure we don't get stuck at zero */
if (rseed == 0L) rseed = 1L;
/* algorithm taken from Dr. Dobbs Journal, November 1985, page 91 */
k1 = rseed / 127773L;
if ((rseed = 16807L * (rseed - k1 * 127773L) - k1 * 2836L) < 0L)
rseed += 2147483647L;
/* return a random number between 0 and n-1 */
return ((int)(rseed % (long)n));
}
#endif /* XLISP_ONLY */
#ifdef MinGW32
int truename(char *name, char *rname)
{
if (GetFullPathName(name, FNAMEMAX + 1, rname, NULL) == 0)
return FALSE;
else {
char *p;
/* lowercase the whole string */
for (p = rname; *p != 0; p++)
if (isupper(*p))
*p = (char) tolower(*p);
return TRUE;
}
}
#else
int truename(char *name, char *rname)
{
int i;
char *cp;
int drive; /* drive letter */
char pathbuf[FNAMEMAX+1]; /* copy of path part of name */
char curdir[FNAMEMAX+1]; /* current directory of drive */
char *fname; /* pointer to file name part of name */
/* use backslashes consistantly */
for (cp = name; (cp = strchr(cp, '/')) != NULL; *cp = '\\') ;
/* parse any drive specifier */
if ((cp = strrchr(name, ':')) != NULL) {
if (cp != name+1 || !isalpha(*name)) return FALSE;
drive = toupper(*name);
name = cp+1; /* name now excludes drivespec */
}
else {
drive = 'A' + getdisk();
}
/* check for absolute path (good news!) */
if (*name == '\\') {
sprintf(rname,"%c:%s",drive,name);
}
else {
strcpy(pathbuf, name);
if ((cp = strrchr(pathbuf, '\\')) != NULL) { /* path present */
cp[1] = 0;
fname = strrchr(name, '\\') + 1;
}
else {
pathbuf[0] = 0;
fname = name;
}
/* get the current directory of the selected drive */
if (getcurdir(drive - 'A' + 1, curdir))
return FALSE; /* invalid drive */
/* peel off "..\"s */
while (strncmp(pathbuf, "..\\", 3) == 0) {
if (*curdir == 0) return FALSE; /* already at root */
strcpy(pathbuf, pathbuf+3);
if ((cp=strrchr(curdir, '\\')) != NULL)
*cp = 0; /* peel one depth of directories */
else
*curdir = 0; /* peeled back to root */
}
/* allow for a ".\" */
if (strncmp(pathbuf, ".\\", 2) == 0)
strcpy(pathbuf, pathbuf+2);
/* final name is drive:\curdir\pathbuf\fname */
if (strlen(pathbuf)+strlen(curdir)+strlen(fname)+4 > FNAMEMAX)
return FALSE;
if (*curdir)
sprintf(rname, "%c:\\%s\\%s%s", drive, curdir, pathbuf, fname);
else
sprintf(rname, "%c:\\%s%s", drive, pathbuf, fname);
}
/* lowercase the whole string */
for (cp = rname; (i = *cp) != 0; cp++) {
if (isupper(i)) *cp = (char) tolower(i);
}
return TRUE;
}
#endif
int getslot(VOID)
{
int i=0;
for (; i < FTABSIZE; i++) /* look for available slot */
if (filetab[i].fp == NULL) return i;
gc(); /* is this safe??????? */
for (i=0; i < FTABSIZE; i++) /* try again -- maybe one has been freed */
if (filetab[i].fp == NULL) return i;
xlfail("too many open files");
return 0; /* never returns */
}
FILEP osaopen(const char *name, const char *mode)
{
int i=getslot();
char namebuf[FNAMEMAX+1];
FILE *fp;
if (!truename((char *)name, namebuf))
strcpy(namebuf, name); /* should not happen */
if ((filetab[i].tname = malloc(strlen(namebuf)+1)) == NULL) {
xlfail("insufficient memory");
}
if ((fp = fopen(name,mode)) == NULL) {
free(filetab[i].tname);
return CLOSED;
}
filetab[i].fp = fp;
strcpy(filetab[i].tname, namebuf);
/* calculate mode to re-open file */
if (mode[0]=='w') {
strcpy(filetab[i].reopenmode, "r+");
if (mode[strlen(mode)-1]=='b') strcat(filetab[i].reopenmode, "b");
}
else strcpy(filetab[i].reopenmode, mode);
return i;
}
FILEP osbopen(const char *name, const char *mode)
{
char bmode[10];
strcpy(bmode,mode); strcat(bmode,"b");
return osaopen(name, bmode);
}
VOID osclose(FILEP f)
{
fclose(filetab[f].fp);
free(filetab[f].tname);
filetab[f].tname = NULL;
filetab[f].fp = NULL;
}
/* ostgetc - get a character from the terminal */
int ostgetc()
{
while(--lcount < 0 ) {
if ( xfgets(lbuf,LBSIZE) == NULL )
return( EOF );
lcount = strlen( lbuf );
if (tfp!=CLOSED) OSWRITE(lbuf,1,lcount,tfp);
lindex = 0;
lposition = 0;
}
return( lbuf[lindex++] );
}
LOCAL char *xfgets(s, n)
char *s;
int n;
{
int c;
char *cs;
cs = s;
while (--n > 0 && (c = TTYGetC()) != EOF) {
*cs++ = (char) c;
if (c == '\n') break;
}
if (c == EOF && cs==s) return(NULL);
*cs++ = '\0';
return(s);
}
/* ostputc - put a character to the terminal */
void ostputc(ch)
int ch;
{
if (ch == '\n') lposition = 0;
else lposition++;
if (tfp != CLOSED) OSPUTC(ch,tfp);
TTYPutC(ch);
}
/* osflush - flush the terminal input buffer */
void osflush()
{
TTYFlush();
lindex = lcount = 0;
}
VOID osforce(fp)
FILEP fp;
{
if (fp == CONSOLE)
TTYFlush();
else
fflush(filetab[fp].fp);
}
void ossymbols()
{
statsymbols();
}
void osfinit()
{
}
#ifdef max
#undef max
#endif
int max(x, y)
int x, y;
{
return((x > y) ? x : y);
}
#ifdef min
#undef min
#endif
int min(x, y)
int x, y;
{
return((x < y) ? x : y);
}
LVAL string2stream(char *s)
{
LVAL stream, newustream();
xlsave1(stream);
stream = newustream();
for (; *s != '\0'; s++) xlputc(stream, *s);
xlpop();
return(stream);
}
LVAL readevalstream(LVAL stream)
{
LVAL expr, oldenv, oldfenv, val;
CONTEXT cntxt;
if (! ustreamp(stream)) xlfail("not a ustream");
/* protect some pointers */
xlstkcheck(4);
xlprotect(stream);
xlsave(expr);
xlsave(oldenv);
xlsave(oldfenv);
/* set the lexical environment to null */
oldenv = xlenv; xlenv = NIL;
oldfenv = xlfenv; xlfenv = NIL;
val = NIL;
/* read and evaluate each expression in the stream */
xlbegin(&cntxt,CF_ERROR,s_true);
if (! XL_SETJMP(cntxt.c_jmpbuf)) {
while (xlread(stream,&expr,FALSE,FALSE)) {
val = xleval(expr);
}
}
xlend(&cntxt);
/* reset the environment */
xlenv = oldenv;
xlfenv = oldfenv;
xlpopn(4);
return val;
}
static void errcatch(int sig)
{
signal(sig, errcatch);
switch(sig) {
case SIGABRT: xlfail("Abnormal termination signal -- time to bail out");
case SIGFPE: xlfail("Floating point exception.");
case SIGILL: xlfail("Illegal instruction -- time to bail out");
case SIGSEGV: xlfail("Segment violation -- time to bail out");
default: xexit();
}
}
#if defined(__TURBOC__) && (__TURBOC__ >= 0x0400)
int _FARFUNC _matherr (struct exception *e)
#pragma argsused
{
return 1;
}
#else
int __cdecl matherr(struct exception *e)
{
return(1);
}
#endif
void osreset()
{
#ifndef NOGRAPHICS
MSWResetMenus();
MSWResetDialogs();
MSWResetGraphics();
#endif /* NOGRAPHICS */
}
#ifdef NOGRAPHICS
set_gc_cursor() {}
#endif /* NOGRAPHICS */
#ifndef HZ
#define HZ 60
#endif
unsigned long ticks_per_second() { return((unsigned long) HZ); }
unsigned long real_tick_count()
{
return((unsigned long) ((HZ / CLK_TCK) * clock()));
}
unsigned long run_tick_count()
{
return real_tick_count();
}
unsigned long system_tick_count()
{
return((unsigned long) (time((unsigned long *) NULL)));
}
int renamebackup(char *name)
#pragma argsused
{
return(TRUE);
}
/* xgetwd - builtin function GET-WORKING-DIRECTORY */
LVAL xgetwd()
{
xllastarg();
if (! getcwd(buf, FNAMEMAX))
return NIL;
else
return cvstring(buf);
}
/* xsetwd - builtin function SET-WORKING-DIRECTORY */
LVAL xsetwd()
{
char *dir = getstring(xlgastring());
xllastarg();
if (chdir(dir))
return NIL;
else
return s_true;
}
VOID disable_interrupts() {}
VOID enable_interrupts() {}
int osmtime(fname, mtime)
char *fname;
time_t *mtime;
{
struct stat s;
if (stat(fname, &s))
return -1;
*mtime = s.st_mtime;
return 0;
}
/* internal version of directory function */
/***** probably needs to be protected by check that dirent is available */
/***** need to drop non-files, i.e. directories, using stat() call */
#include <dirent.h>
LVAL dirlist P1C(char *, name)
{
LVAL val;
DIR *dir;
disable_interrupts();
xlsave1(val);
val = NIL;
if ((dir = opendir(name))) {
struct dirent *dentry;
while ((dentry = readdir(dir)))
val = cons(cvstring(dentry->d_name), val);
closedir(dir);
}
xlpop();
enable_interrupts();
return val;
}
void get_directory(char *s)
{
int n;
char *dir = getenv("XLISPLIB");
if (dir == NULL) dir = "";
strcpy(s, dir);
n = strlen(s);
if (n > 0 && s[n - 1] != '\\')
strcat(s, "\\");
}
int MSWAnyEventsQueued()
{
LVAL queue = getvalue(s_event_queue);
return consp(queue) ? TRUE : FALSE;
}
void MSWDoEventQueue(void)
{
LVAL task, queue, oldenv, oldfenv, olddenv;
queue = getvalue(s_event_queue);
if (consp(queue)) {
olddenv = xldenv;
xldbind(s_in_callback, s_true);
/* set the lexical environment to null */
xlstkcheck(2);
xlsave(oldenv);
xlsave(oldfenv);
oldenv = xlenv; xlenv = NIL;
oldfenv = xlfenv; xlfenv = NIL;
task = car(queue);
setvalue(s_event_queue, cdr(queue));
xleval(task);
/* reset the environment */
xlenv = oldenv;
xlfenv = oldfenv;
xlpopn(2);
xlunbind(olddenv);
}
}
#ifdef BIGNUMS
/* We need this because the one that Borland supplies doesn't work for
exp values out of range */
unsigned char infp[8] = {0,0,0,0,0,0,0xf0, 0x7f};
unsigned char infn[8] = {0,0,0,0,0,0,0xf0, 0xff};
double myldexp(double val, int exp) {
if (exp > DBL_MAX_EXP)
return (val > 0 ? *(double *)&infp : *(double *)&infn);
if (exp < DBL_MIN_EXP) return 0.0;
return ldexp(val, exp);
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1