[project @ 1999-11-24 10:38:10 by andy]
[ghc-hetmet.git] / ghc / interpreter / machdep.c
index ebdf4bb..2adcb31 100644 (file)
@@ -6,14 +6,15 @@
  * 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.12 $
+ * $Date: 1999/11/24 10:38:10 $
  * ------------------------------------------------------------------------*/
 
 #ifdef HAVE_SIGNAL_H
@@ -99,6 +100,9 @@ extern unsigned _stklen = 8000;         /* Allocate an 8k stack segment    */
 #ifdef HAVE_UNIX_H
 #include <unix.h>
 #endif
+#if SYMANTEC_C
+int allow_break_count = 0;
+#endif
 
 /* --------------------------------------------------------------------------
  * Prototypes for registry reading
@@ -112,7 +116,7 @@ extern unsigned _stklen = 8000;         /* Allocate an 8k stack segment    */
 #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));
@@ -133,14 +137,16 @@ static String local readRegChildStrings Args((HKEY, String, String, Char, String
 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;
@@ -149,10 +155,10 @@ Long   *sz; {
 #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()        */
@@ -161,15 +167,20 @@ Long   *sz; {
     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():
@@ -210,6 +221,7 @@ String f; {
     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 */
@@ -255,7 +267,7 @@ static Bool   local tryEndings    Args((String));
 # define SLASH                   '/'
 # define isSLASH(c)              ((c)==SLASH)
 # define PATHSEP                 ':'
-# define DLL_ENDING              ".so"
+# define DLL_ENDING              ".o"
 #endif
 
 static String local hugsdir() {     /* directory containing lib/Prelude.hs */
@@ -270,7 +282,7 @@ 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.
      */
@@ -281,7 +293,8 @@ static String local hugsdir() {     /* directory containing lib/Prelude.hs */
         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';
         }
     }
@@ -297,7 +310,7 @@ static String local hugsdir() {     /* directory containing lib/Prelude.hs */
 }
 
 #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","");
@@ -367,9 +380,9 @@ String s; {                     /* a pathname in some appropriate manner.  */
 }
 
 #if HSCRIPT
-static String endings[] = { "", ".hs", ".lhs", ".hsx", ".hash", 0 };
+static String endings[] = { "", ".hi", ".hs", ".lhs", ".hsx", ".hash", 0 };
 #else
-static String endings[] = { "", ".hs", ".lhs", 0 };
+static String endings[] = { "", ".hi", ".hs", ".lhs", 0 };
 #endif
 static char   searchBuf[FILENAME_MAX+1];
 static Int    searchPos;
@@ -413,9 +426,9 @@ String s; {
    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
 */
           
 
@@ -588,6 +601,154 @@ String path; {
 }
 
 /* --------------------------------------------------------------------------
+ * New path handling stuff for the Combined System (tm)
+ * ------------------------------------------------------------------------*/
+
+#define N_DEFAULT_LIBDIR 1000
+char defaultLibDir[N_DEFAULT_LIBDIR];
+
+/* Assumes that getcwd()++argv[0] is the absolute path to the
+   executable.  Basically wrong.
+*/
+void setDefaultLibDir ( String argv_0 )
+{
+   int i;
+   if (argv_0[0] != SLASH) {
+      if (!getcwd(defaultLibDir,N_DEFAULT_LIBDIR-strlen(argv_0)-10)) {
+         ERRMSG(0) "Can't get current working directory"
+         EEND;
+      }
+      i = strlen(defaultLibDir);
+      if (defaultLibDir[i-1] != SLASH) defaultLibDir[i++] = SLASH;
+   } else {
+      i = 0;
+   }
+   strcpy(&defaultLibDir[i],argv_0);
+   i += strlen(argv_0);
+   while (defaultLibDir[i] != SLASH) i--;
+   i++;
+   strcpy(&defaultLibDir[i], "lib");
+   fprintf ( stderr, "default lib dir = %s\n", defaultLibDir ); 
+}
+
+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:defaultLibDir */
+
+   *path = *sExt = NULL;
+   *sAvail = *iAvail = *oAvail = FALSE;
+   *sSize  = *iSize  = *oSize  = 0;
+
+   augdPath = malloc(4+strlen(defaultLibDir)+strlen(hugsPath));
+   if (!augdPath)
+      internal("moduleNameToFileNames: malloc failed(2)");
+   augdPath[0] = '.';
+   augdPath[1] = PATHSEP;
+   augdPath[2] = 0;
+   strcat ( augdPath, hugsPath );
+   augdPath[2+strlen(hugsPath)] = PATHSEP;
+   augdPath[3+strlen(hugsPath)] = 0;
+   strcat(augdPath,defaultLibDir);
+
+   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, ".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;
+      }
+
+   }
+   
+}
+
+
+/* --------------------------------------------------------------------------
  * 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"
  * ------------------------------------------------------------------------*/
@@ -907,7 +1068,61 @@ Int readTerminalChar() {                /* read character from terminal    */
     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    */
     }
 }
@@ -964,8 +1179,21 @@ static sigHandler(panic) {              /* exit in a panic, on receipt of  */
 }
 #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);
@@ -1016,7 +1244,7 @@ String nm; {                            /* or just line may be zero        */
         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 */
 
@@ -1271,6 +1499,20 @@ Int    val; {
 #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:
  * ------------------------------------------------------------------------*/