* HaskellScript code and recursive directory search provided by
* Daan Leijen (leijen@fwi.uva.nl)
*
- * Hugs 98 is Copyright (c) Mark P Jones, Alastair Reid and the Yale
- * Haskell Group 1994-99, and is distributed as Open Source software
- * under the Artistic License; see the file "Artistic" that is included
- * in the distribution for details.
+ * The Hugs 98 system is Copyright (c) Mark P Jones, Alastair Reid, the
+ * Yale Haskell Group, and the Oregon Graduate Institute of Science and
+ * Technology, 1994-1999, All rights reserved. It is distributed as
+ * free software under the license in the file "License", which is
+ * included in the distribution.
*
* $RCSfile: machdep.c,v $
- * $Revision: 1.5 $
- * $Date: 1999/04/27 10:06:55 $
+ * $Revision: 1.18 $
+ * $Date: 1999/12/20 16:55:27 $
* ------------------------------------------------------------------------*/
#ifdef HAVE_SIGNAL_H
#ifdef HAVE_UNIX_H
#include <unix.h>
#endif
+#if SYMANTEC_C
+int allow_break_count = 0;
+#endif
/* --------------------------------------------------------------------------
* Prototypes for registry reading
#endif
#define HugsRoot ("SOFTWARE\\Haskell\\Hugs\\" HUGS_VERSION "\\")
-#define ProjectRoot ("SOFTWARE\\Haskell\\Hugs\\Projects\\")
+#define ProjectRoot ("SOFTWARE\\Haskell\\Projects\\")
static Bool local createKey Args((HKEY, String, PHKEY, REGSAM));
static Bool local queryValue Args((HKEY, String, String, LPDWORD, LPBYTE, DWORD));
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
+error timeEarlier not defined
#else
typedef time_t Time;
-#define timeChanged(now,thn) (now!=thn)
-#define timeSet(var,tm) var = tm
+#define timeChanged(now,thn) (now!=thn)
+#define timeSet(var,tm) var = tm
+#define timeEarlier(earlier,now) (earlier < now)
#endif
-static Void local getFileInfo Args((String, Time *, Long *));
static Bool local readable Args((String));
+static Void local getFileInfo Args((String, Time *, Long *));
static Void local getFileInfo(f,tm,sz) /* find time stamp and size of file*/
String f;
#if defined HAVE_SYS_STAT_H || defined HAVE_STAT_H || defined HAVE_UNIX_H
struct stat scbuf;
if (!stat(f,&scbuf)) {
- *tm = scbuf.st_mtime;
+ if (tm) *tm = scbuf.st_mtime;
*sz = (Long)(scbuf.st_size);
} else {
- *tm = 0;
+ if (tm) *tm = 0;
*sz = 0;
}
#else /* normally just use stat() */
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) */
+ if (tm) tm->hi = r.r[2] & 0xFF; /* Load address (high byte) */
+ if (tm) tm->lo = r.r[3]; /* Execution address (low 4 bytes) */
} else { /* Not found, or not time-stamped */
- tm->hi = tm->lo = 0;
+ if (tm) tm->hi = tm->lo = 0;
}
*sz = (Long)(r.r[0] == 1 ? r.r[4] : 0);
#endif
}
+Void getFileSize ( String f, Long* sz )
+{
+ getFileInfo ( f, NULL, sz );
+}
+
#if defined HAVE_GETFINFO /* Mac971031 */
/* --------------------------------------------------------------------------
* Define a MacOS version of access():
return (0 == access(f,4));
#elif defined HAVE_SYS_STAT_H || defined HAVE_STAT_H
struct stat scbuf;
+ /* fprintf(stderr, "readable: %s\n", f ); */
return ( !stat(f,&scbuf)
&& (scbuf.st_mode & S_IREAD) /* readable */
&& (scbuf.st_mode & S_IFREG) /* regular file */
# define SLASH '\\'
# define isSLASH(c) ((c)=='\\' || (c)=='/')
# define PATHSEP ';'
+# define PATHSEP_STR ";"
# define DLL_ENDING ".dll"
#elif MAC_FILENAMES
# define SLASH ':'
# define isSLASH(c) ((c)==SLASH)
# define PATHSEP ';'
+# define PATHSEP_STR ";"
/* Mac PEF (Preferred Executable Format) file */
# define DLL_ENDING ".pef"
#else
# define SLASH '/'
# define isSLASH(c) ((c)==SLASH)
# define PATHSEP ':'
-# define DLL_ENDING ".so"
+# define PATHSEP_STR ":"
+# define DLL_ENDING ".u_o"
#endif
static String local hugsdir() { /* directory containing lib/Prelude.hs */
}
}
return dir;
-#elif HAVE_GETMODULEFILENAME && !DOS
+#elif HAVE_GETMODULEFILENAME && !DOS && !__CYGWIN32__
/* On Windows, we can find the binary we're running and it's
* conventional to put the libraries in the same place.
*/
if (dir[0] == '\0') { /* GetModuleFileName must have failed */
return HUGSDIR;
}
- if (slash = strrchr(dir,SLASH)) { /* truncate after directory name */
+ slash = strrchr(dir,SLASH);
+ if (slash) { /* truncate after directory name */
*slash = '\0';
}
}
}
#if HSCRIPT
-static String local hscriptDir() { /* directory containing ?? what Daan? */
+static String local hscriptDir() { /* Directory containing hscript.dll */
static char dir[FILENAME_MAX+1] = "";
if (dir[0] == '\0') { /* not initialised yet */
String s = readRegString(HKEY_LOCAL_MACHINE,HScriptRoot,"InstallDir","");
}
#if HSCRIPT
-static String endings[] = { "", ".hs", ".lhs", ".hsx", ".hash", 0 };
+static String endings[] = { "", ".u_hi", ".hs", ".lhs", ".hsx", ".hash", 0 };
#else
-static String endings[] = { "", ".hs", ".lhs", 0 };
+static String endings[] = { "", ".u_hi", ".hs", ".lhs", 0 };
#endif
static char searchBuf[FILENAME_MAX+1];
static Int searchPos;
searches the base directory and its direct subdirectories for a file
input: searchbuf contains SLASH terminated base directory
- argument s contains the (base) filename
+ argument s contains the (base) filename
output: TRUE: searchBuf contains the full filename
- FALSE: searchBuf is garbage, file not found
+ FALSE: searchBuf is garbage, file not found
*/
}
/* --------------------------------------------------------------------------
+ * New path handling stuff for the Combined System (tm)
+ * ------------------------------------------------------------------------*/
+
+char installDir[N_INSTALLDIR];
+
+/* Sets installDir to $STGHUGSDIR, and ensures there is a trailing
+ slash at the end.
+*/
+void setInstallDir ( String argv_0 )
+{
+ int i;
+ char* r = getenv("STGHUGSDIR");
+ if (!r) {
+ fprintf(stderr,
+ "%s: installation error: environment variable STGHUGSDIR is not set.\n",
+ argv_0 );
+ fprintf(stderr,
+ "%s: pls set it to be the directory where STGHugs98 is installed.\n\n",
+ argv_0 );
+ exit(2);
+
+ }
+
+ if (strlen(r) > N_INSTALLDIR-30 ) {
+ fprintf(stderr,
+ "%s: environment variable STGHUGSDIR is suspiciously long; pls remedy\n\n",
+ argv_0 );
+ exit(2);
+ }
+
+ strcpy ( installDir, r );
+ i = strlen(installDir);
+ if (installDir[i-1] != SLASH) installDir[i++] = SLASH;
+ installDir[i] = 0;
+}
+
+
+Bool findFilesForModule (
+ String modName,
+ String* path,
+ String* sExt,
+ Bool* sAvail, Time* sTime, Long* sSize,
+ Bool* iAvail, Time* iTime, Long* iSize,
+ Bool* oAvail, Time* oTime, Long* oSize
+ )
+{
+ /* Let the module name given be M.
+ For each path entry P,
+ a s(rc) file will be P/M.hs or P/M.lhs
+ an i(nterface) file will be P/M.hi
+ an o(bject) file will be P/M.o
+ If there is a s file or (both i and o files)
+ use P to fill in the path names.
+ Otherwise, move on to the next path entry.
+ If all path entries are exhausted, return False.
+ */
+ Int nPath;
+ Bool literate;
+ String peStart, peEnd;
+ String augdPath; /* .:hugsPath:installDir/GhcPrel:installDir/lib */
+
+ *path = *sExt = NULL;
+ *sAvail = *iAvail = *oAvail = FALSE;
+ *sSize = *iSize = *oSize = 0;
+
+ augdPath = malloc( 2*(10+3+strlen(installDir))
+ +strlen(hugsPath) +10/*paranoia*/);
+ if (!augdPath)
+ internal("moduleNameToFileNames: malloc failed(2)");
+
+ augdPath[0] = 0;
+ strcat(augdPath, ".");
+ strcat(augdPath, PATHSEP_STR);
+
+ strcat(augdPath, hugsPath);
+ strcat(augdPath, PATHSEP_STR);
+
+ if (combined) {
+ strcat(augdPath, installDir);
+ strcat(augdPath, "GhcPrel");
+ strcat(augdPath, PATHSEP_STR);
+ }
+
+ strcat(augdPath, installDir);
+ strcat(augdPath, "lib");
+ strcat(augdPath, PATHSEP_STR);
+
+ /* fprintf ( stderr, "augdpath = `%s'\n", augdPath ); */
+
+ peEnd = augdPath-1;
+ while (1) {
+ /* Advance peStart and peEnd very paranoically, giving up at
+ the first sign of mutancy in the path string.
+ */
+ if (peEnd >= augdPath && !(*peEnd)) { free(augdPath); return FALSE; }
+ peStart = peEnd+1;
+ peEnd = peStart;
+ while (*peEnd && *peEnd != PATHSEP) peEnd++;
+
+ /* Now peStart .. peEnd-1 bracket the next path element. */
+ nPath = peEnd-peStart;
+ if (nPath + strlen(modName) + 10 /*slush*/ > FILENAME_MAX) {
+ ERRMSG(0) "Hugs path \"%s\" contains excessively long component",
+ hugsPath
+ EEND;
+ free(augdPath);
+ return FALSE;
+ }
+
+ strncpy(searchBuf, peStart, nPath);
+ searchBuf[nPath] = 0;
+ if (nPath > 0 && !isSLASH(searchBuf[nPath-1]))
+ searchBuf[nPath++] = SLASH;
+
+ strcpy(searchBuf+nPath, modName);
+ nPath += strlen(modName);
+
+ /* searchBuf now holds 'P/M'. Try out the various endings. */
+ *path = *sExt = NULL;
+ *sAvail = *iAvail = *oAvail = FALSE;
+ *sSize = *iSize = *oSize = 0;
+
+ strcpy(searchBuf+nPath, DLL_ENDING);
+ if (readable(searchBuf)) {
+ *oAvail = TRUE;
+ getFileInfo(searchBuf, oTime, oSize);
+ }
+
+ strcpy(searchBuf+nPath, ".u_hi");
+ if (readable(searchBuf)) {
+ *iAvail = TRUE;
+ getFileInfo(searchBuf, iTime, iSize);
+ }
+
+ strcpy(searchBuf+nPath, ".hs");
+ if (readable(searchBuf)) {
+ *sAvail = TRUE;
+ literate = FALSE;
+ getFileInfo(searchBuf, sTime, sSize);
+ *sExt = ".hs";
+ } else {
+ strcpy(searchBuf+nPath, ".lhs");
+ if (readable(searchBuf)) {
+ *sAvail = TRUE;
+ literate = TRUE;
+ getFileInfo(searchBuf, sTime, sSize);
+ *sExt = ".lhs";
+ }
+ }
+
+ /* Success? */
+ if (*sAvail || (*oAvail && *iAvail)) {
+ nPath -= strlen(modName);
+ *path = malloc(nPath+1);
+ if (!(*path))
+ internal("moduleNameToFileNames: malloc failed(1)");
+ strncpy(*path, searchBuf, nPath);
+ (*path)[nPath] = 0;
+ free(augdPath);
+ return TRUE;
+ }
+
+ }
+
+}
+
+
+/* If the primaryObjectName for is (eg)
+ /foo/bar/PrelSwamp.o
+ and the extraFileName is (eg)
+ swampy_cbits
+ and DLL_ENDING is set to .o
+ return
+ /foo/bar/swampy_cbits.o
+ and set *extraFileSize to its size, or -1 if not avail
+*/
+String getExtraObjectInfo ( String primaryObjectName,
+ String extraFileName,
+ Int* extraFileSize )
+{
+ Time xTime;
+ Long xSize;
+ String xtra;
+
+ Int i = strlen(primaryObjectName)-1;
+ while (i >= 0 && primaryObjectName[i] != SLASH) i--;
+ if (i == -1) return extraFileName;
+ i++;
+ xtra = malloc ( i+3+strlen(extraFileName)+strlen(DLL_ENDING) );
+ if (!xtra) internal("deriveExtraObjectName: malloc failed");
+ strncpy ( xtra, primaryObjectName, i );
+ xtra[i] = 0;
+ strcat ( xtra, extraFileName );
+ strcat ( xtra, DLL_ENDING );
+
+ *extraFileSize = -1;
+ if (readable(xtra)) {
+ getFileInfo ( xtra, &xTime, &xSize );
+ *extraFileSize = xSize;
+ }
+ return xtra;
+}
+
+
+/* --------------------------------------------------------------------------
* Substitute old value of path into empty entries in new path
* eg substPath("a:b:c::d:e","x:y:z") = "a:b:c:x:y:z:d:e"
* ------------------------------------------------------------------------*/
if (terminalEchoReqd) {
return getchar();
} else {
- Int c = getch();
+#if IS_WIN32 && !HUGS_FOR_WINDOWS && !__BORLANDC__
+ /* When reading a character from the console/terminal, we want
+ * to operate in 'raw' mode (to use old UNIX tty parlance) and have
+ * it return when a character is available and _not_ wait until
+ * the next time the user hits carriage return. On Windows platforms,
+ * this _can_ be done by reading directly from the console, using
+ * getch(). However, this doesn't sit well with programming
+ * environments such as Emacs which allow you to create sub-processes
+ * running Hugs, and then communicate with the running interpreter
+ * through its standard input and output handles. If you use getch()
+ * in that setting, you end up trying to read the (unused) console
+ * of the editor itself, through which not a lot of characters is
+ * bound to come out, since the editor communicates input to Hugs
+ * via the standard input handle.
+ *
+ * To avoid this rather unfortunate situation, we use the Win32
+ * console API and re-jig the input properties of the standard
+ * input handle before trying to read a character using stdio's
+ * getchar().
+ *
+ * The 'cost' of this solution is that it is Win32 specific and
+ * won't work with Windows 3.1 + it is kind of ugly and verbose
+ * to have to futz around with the console properties on a
+ * per-char basis. Both of these disadvantages aren't in my
+ * opinion fatal.
+ *
+ * -- sof 5/99
+ */
+ Int c;
+ DWORD mo;
+ HANDLE hIn;
+
+ /* I don't quite understand why, but if the FILE*'s underlying file
+ descriptor is in text mode, we seem to lose the first carriage
+ return.
+ */
+ setmode(fileno(stdin), _O_BINARY);
+ hIn = GetStdHandle(STD_INPUT_HANDLE);
+ GetConsoleMode(hIn, &mo);
+ SetConsoleMode(hIn, mo & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
+ /*
+ * On Win9x, the first time you change the mode (as above) a
+ * raw '\n' is inserted. Since enter maps to a raw '\r', and we
+ * map this (below) to '\n', we can just ignore all *raw* '\n's.
+ */
+ do {
+ c = getc(stdin);
+ } while (c == '\n');
+
+ /* Same as it ever was - revert back state of stdin. */
+ SetConsoleMode(hIn, mo);
+ setmode(fileno(stdin), _O_TEXT);
+#else
+ Int c = getch();
+#endif
return c=='\r' ? '\n' : c; /* slight paranoia about CR-LF */
}
}
}
#endif /* !DONT_PANIC */
+#if IS_WIN32
+BOOL WINAPI consoleHandler(DWORD dwCtrlType) {
+ switch (dwCtrlType) { /* Allows Hugs to be terminated */
+ case CTRL_CLOSE_EVENT : /* from the window's close menu. */
+ ExitProcess(0);
+ }
+ return FALSE;
+}
+#endif
+
static Void local installHandlers() { /* Install handlers for all fatal */
/* signals except SIGINT and SIGBREAK*/
+#if IS_WIN32
+ SetConsoleCtrlHandler(consoleHandler,TRUE);
+#endif
#if !DONT_PANIC && !DOS
# ifdef SIGABRT
signal(SIGABRT,panic);
String ec = editorCmd;
String rd = NULL; /* Set to nonnull to redo ... */
- for (; n>0 && *he && *he!=' '; n--)
+ for (; n>0 && *he && *he!=' ' && *he!='%'; n--)
*ec++ = *he++; /* Copy editor name to buffer */
/* assuming filename ends at space */
#endif /* USE_REGISTRY */
/* --------------------------------------------------------------------------
+ * Things to do with the argv/argc and the env
+ * ------------------------------------------------------------------------*/
+
+int nh_argc ( void )
+{
+ return prog_argc;
+}
+
+int nh_argvb ( int argno, int offset )
+{
+ return (int)(prog_argv[argno][offset]);
+}
+
+/* --------------------------------------------------------------------------
* Machine dependent control:
* ------------------------------------------------------------------------*/
Int what; { /* initialisation etc.. */
switch (what) {
case MARK : break;
- case INSTALL : installHandlers();
+ case POSTPREL: break;
+ case PREPREL : installHandlers();
break;
case RESET :
case BREAK :