[project @ 1999-10-15 22:35:04 by andy]
[ghc-hetmet.git] / ghc / interpreter / hugs.c
1
2 /* --------------------------------------------------------------------------
3  * Command interpreter
4  *
5  * The Hugs 98 system is Copyright (c) Mark P Jones, Alastair Reid, the
6  * Yale Haskell Group, and the Oregon Graduate Institute of Science and
7  * Technology, 1994-1999, All rights reserved.  It is distributed as
8  * free software under the license in the file "License", which is
9  * included in the distribution.
10  *
11  * $RCSfile: hugs.c,v $
12  * $Revision: 1.13 $
13  * $Date: 1999/10/15 22:35:04 $
14  * ------------------------------------------------------------------------*/
15
16 #include <setjmp.h>
17 #include <ctype.h>
18 #include <stdio.h>
19
20 #include "prelude.h"
21 #include "storage.h"
22 #include "command.h"
23 #include "backend.h"
24 #include "connect.h"
25 #include "errors.h"
26 #include "version.h"
27 #include "link.h"
28
29 #include "Rts.h"
30 #include "RtsAPI.h"
31 #include "Schedule.h"
32
33
34 Bool haskell98 = TRUE;                  /* TRUE => Haskell 98 compatibility*/
35
36 #if EXPLAIN_INSTANCE_RESOLUTION
37 Bool showInstRes = FALSE;
38 #endif
39 #if MULTI_INST
40 Bool multiInstRes = FALSE;
41 #endif
42
43 /* --------------------------------------------------------------------------
44  * Local function prototypes:
45  * ------------------------------------------------------------------------*/
46
47 static Void   local initialize        Args((Int,String []));
48 static Void   local promptForInput    Args((String));
49 static Void   local interpreter       Args((Int,String []));
50 static Void   local menu              Args((Void));
51 static Void   local guidance          Args((Void));
52 static Void   local forHelp           Args((Void));
53 static Void   local set               Args((Void));
54 static Void   local changeDir         Args((Void));
55 static Void   local load              Args((Void));
56 static Void   local project           Args((Void));
57 static Void   local readScripts       Args((Int));
58 static Void   local whatScripts       Args((Void));
59 static Void   local editor            Args((Void));
60 static Void   local find              Args((Void));
61 static Bool   local startEdit         Args((Int,String));
62 static Void   local runEditor         Args((Void));
63 static Void   local setModule         Args((Void));
64 static Module local findEvalModule    Args((Void));
65 static Void   local evaluator         Args((Void));
66 static Void   local stopAnyPrinting   Args((Void));
67 static Void   local showtype          Args((Void));
68 static String local objToStr          Args((Module, Cell));
69 static Void   local info              Args((Void));
70 static Void   local printSyntax       Args((Name));
71 static Void   local showInst          Args((Inst));
72 static Void   local describe          Args((Text));
73 static Void   local listNames         Args((Void));
74
75 static Void   local toggleSet         Args((Char,Bool));
76 static Void   local togglesIn         Args((Bool));
77 static Void   local optionInfo        Args((Void));
78 #if USE_REGISTRY || HUGS_FOR_WINDOWS
79 static String local optionsToStr      Args((Void));
80 #endif
81 static Void   local readOptions       Args((String));
82 static Bool   local processOption     Args((String));
83 static Void   local setHeapSize       Args((String));
84 static Int    local argToInt          Args((String));
85
86 static Void   local loadProject       Args((String));
87 static Void   local clearProject      Args((Void));
88 static Bool   local addScript         Args((Int));
89 static Void   local forgetScriptsFrom Args((Script));
90 static Void   local setLastEdit       Args((String,Int));
91 static Void   local failed            Args((Void));
92 static String local strCopy           Args((String));
93 static Void   local browseit          Args((Module,String));
94 static Void   local browse            Args((Void));
95
96 /* --------------------------------------------------------------------------
97  * Machine dependent code for Hugs interpreter:
98  * ------------------------------------------------------------------------*/
99
100 #include "machdep.c"
101 #ifdef WANT_TIMER
102 #include "timer.c"
103 #endif
104
105 /* --------------------------------------------------------------------------
106  * Local data areas:
107  * ------------------------------------------------------------------------*/
108
109 static Bool   printing     = FALSE;     /* TRUE => currently printing value*/
110 static Bool   showStats    = FALSE;     /* TRUE => print stats after eval  */
111 static Bool   listScripts  = TRUE;      /* TRUE => list scripts after loading*/
112 static Bool   addType      = FALSE;     /* TRUE => print type with value   */
113 static Bool   useDots      = RISCOS;    /* TRUE => use dots in progress    */
114 static Bool   quiet        = FALSE;     /* TRUE => don't show progress     */
115 static Bool   lastWasObject = FALSE;
116        Bool   preludeLoaded = FALSE;
117        Bool   optimise      = FALSE;
118
119 typedef 
120    struct { 
121       String modName;                   /* Module name                     */
122       Bool   details;             /* FALSE => remaining fields are invalid */
123       String path;                      /* Path to module                  */
124       String srcExt;                    /* ".hs" or ".lhs" if fromSource   */
125       Time   lastChange;                /* Time of last change to script   */
126       Bool   fromSource;                /* FALSE => load object code       */
127       Bool   postponed;                 /* Indicates postponed load        */
128       Bool   objLoaded;
129       Long   size;
130       Long   oSize;
131    }
132    ScriptInfo;
133
134 static Void   local makeStackEntry    Args((ScriptInfo*,String));
135 static Void   local addStackEntry     Args((String));
136
137 static ScriptInfo scriptInfo[NUM_SCRIPTS];
138
139 static Int    numScripts;               /* Number of scripts loaded        */
140 static Int    nextNumScripts;
141 static Int    namesUpto;                /* Number of script names set      */
142 static Bool   needsImports;             /* set to TRUE if imports required */
143        String scriptFile;               /* Name of current script (if any) */
144
145
146
147 static Text   evalModule  = 0;          /* Name of module we eval exprs in */
148 static String currProject = 0;          /* Name of current project file    */
149 static Bool   projectLoaded = FALSE;    /* TRUE => project file loaded     */
150
151 static Bool   autoMain   = FALSE;
152 static String lastEdit   = 0;           /* Name of script to edit (if any) */
153 static Int    lastEdLine = 0;           /* Editor line number (if possible)*/
154 static String prompt     = 0;           /* Prompt string                   */
155 static Int    hpSize     = DEFAULTHEAP; /* Desired heap size               */
156        String hugsEdit   = 0;           /* String for editor command       */
157        String hugsPath   = 0;           /* String for file search path     */
158
159 #if REDIRECT_OUTPUT
160 static Bool disableOutput = FALSE;      /* redirect output to buffer?      */
161 #endif
162
163 String bool2str ( Bool b )
164 {
165    if (b) return "Yes"; else return "No ";
166 }
167
168 void ppSmStack ( String who )
169 {
170    int i, j;
171 return;
172    fflush(stdout);fflush(stderr);
173    printf ( "\n" );
174    printf ( "ppSmStack %s:  numScripts = %d   namesUpto = %d  needsImports = %s\n",
175             who, numScripts, namesUpto, bool2str(needsImports) );
176    assert (namesUpto >= numScripts);
177    printf ( "     Det FrS Pst ObL           Module Ext   Size ModTime  Path\n" );
178    for (i = namesUpto-1; i >= 0; i--) {
179       printf ( "%c%2d: %3s %3s %3s %3s %16s %-4s %5ld %8lx %s\n",
180                (i==numScripts ? '*' : ' '),
181                i, bool2str(scriptInfo[i].details), 
182                   bool2str(scriptInfo[i].fromSource),
183                   bool2str(scriptInfo[i].postponed), 
184                   bool2str(scriptInfo[i].objLoaded),
185                   scriptInfo[i].modName, 
186                   scriptInfo[i].fromSource ? scriptInfo[i].srcExt : "",
187                   scriptInfo[i].size, 
188                   scriptInfo[i].lastChange,
189                   scriptInfo[i].path
190              );
191    }
192    //   printf ( "\n" );
193    fflush(stdout);fflush(stderr);
194 ppScripts();
195 ppModules();
196    printf ( "\n" );
197 }
198
199 /* --------------------------------------------------------------------------
200  * Hugs entry point:
201  * ------------------------------------------------------------------------*/
202
203 #ifndef NO_MAIN /* we omit main when building the "Hugs server" */
204  
205 Main main Args((Int, String []));       /* now every func has a prototype  */
206
207 Main main(argc,argv)
208 int  argc;
209 char *argv[]; {
210 #ifdef HAVE_CONSOLE_H /* Macintosh port */
211     _ftype = 'TEXT';
212     _fcreator = 'R*ch';       /*  // 'KAHL';      //'*TEX';       //'ttxt'; */
213
214     console_options.top = 50;
215     console_options.left = 20;
216
217     console_options.nrows = 32;
218     console_options.ncols = 80;
219
220     console_options.pause_atexit = 1;
221     console_options.title = "\pHugs";
222
223     console_options.procID = 5;
224     argc = ccommand(&argv);
225 #endif
226
227     CStackBase = &argc;                 /* Save stack base for use in gc   */
228
229     /* Try and figure out an absolute path to the executable, so
230        we can make a reasonable guess about where the default
231        libraries (Prelude etc) are.
232     */
233     setDefaultLibDir ( argv[0] );
234
235     /* If first arg is +Q or -Q, be entirely silent, and automatically run
236        main after loading scripts.  Useful for running the nofib suite.    */
237     if (argc > 1 && (strcmp(argv[1],"+Q") == 0 || strcmp(argv[1],"-Q")==0)) {
238        autoMain = TRUE;
239        hugsEnableOutput(0);
240     }
241
242     Printf("__   __ __  __  ____   ___      _________________________________________\n");
243     Printf("||   || ||  || ||  || ||__      Hugs 98: Based on the Haskell 98 standard\n");
244     Printf("||___|| ||__|| ||__||  __||     Copyright (c) 1994-1999\n");
245     Printf("||---||         ___||           World Wide Web: http://haskell.org/hugs\n");
246     Printf("||   ||                         Report bugs to: hugs-bugs@haskell.org\n");
247     Printf("||   || Version: %s _________________________________________\n\n",HUGS_VERSION);
248
249 #if SYMANTEC_C
250     Printf("   Ported to Macintosh by Hans Aberg, compiled " __DATE__ ".\n\n");
251 #endif
252     FlushStdout();
253     interpreter(argc,argv);
254     Printf("[Leaving Hugs]\n");
255     everybody(EXIT);
256     shutdownHaskell();
257     FlushStdout();
258     fflush(stderr);
259     exit(0);
260     MainDone();
261 }
262
263 #endif
264
265 /* --------------------------------------------------------------------------
266  * Initialization, interpret command line args and read prelude:
267  * ------------------------------------------------------------------------*/
268
269 static Void local initialize(argc,argv)/* Interpreter initialization       */
270 Int    argc;
271 String argv[]; {
272     Script i;
273     String proj        = 0;
274     char argv_0_orig[1000];
275
276     setLastEdit((String)0,0);
277     lastEdit      = 0;
278     scriptFile    = 0;
279     numScripts    = 0;
280     namesUpto     = 1;
281
282 #if HUGS_FOR_WINDOWS
283     hugsEdit      = strCopy(fromEnv("EDITOR","c:\\windows\\notepad.exe"));
284 #elif SYMANTEC_C
285     hugsEdit      = "";
286 #else
287     hugsEdit      = strCopy(fromEnv("EDITOR",NULL));
288 #endif
289     hugsPath      = strCopy(HUGSPATH);
290     readOptions("-p\"%s> \" -r$$");
291 #if USE_REGISTRY
292     projectPath   = strCopy(readRegChildStrings(HKEY_LOCAL_MACHINE,ProjectRoot,
293                                                 "HUGSPATH", PATHSEP, ""));
294     readOptions(readRegString(HKEY_LOCAL_MACHINE,HugsRoot,"Options",""));
295     readOptions(readRegString(HKEY_CURRENT_USER, HugsRoot,"Options",""));
296 #endif /* USE_REGISTRY */
297     readOptions(fromEnv("STGHUGSFLAGS",""));
298
299    strncpy(argv_0_orig,argv[0],1000);   /* startupHaskell mangles argv[0] */
300    startupHaskell (argc,argv);
301    argc = prog_argc; argv = prog_argv;
302
303     namesUpto = numScripts = 0;
304     addStackEntry("Prelude");
305
306    for (i=1; i<argc; ++i) {            /* process command line arguments  */
307         if (strcmp(argv[i], "--")==0) break;
308         if (strcmp(argv[i],"+")==0 && i+1<argc) {
309             if (proj) {
310                 ERRMSG(0) "Multiple project filenames on command line"
311                 EEND;
312             } else {
313                 proj = argv[++i];
314             }
315         } else if (argv[i] && argv[i][0]/* workaround for /bin/sh silliness*/
316                  && !processOption(argv[i])) {
317             addStackEntry(argv[i]);
318         }
319     }
320
321 #ifdef DEBUG
322     DEBUG_LoadSymbols(argv_0_orig);
323 #endif
324
325
326
327 #if 0
328     if (!scriptName[0]) {
329         Printf("Prelude not found on current path: \"%s\"\n",
330                hugsPath ? hugsPath : "");
331         fatal("Unable to load prelude");
332     }
333 #endif
334
335     if (haskell98) {
336         Printf("Haskell 98 mode: Restart with command line option -98 to enable extensions\n\n");
337     } else {
338         Printf("Hugs mode: Restart with command line option +98 for Haskell 98 mode\n\n");
339     }
340  
341     everybody(INSTALL);
342     evalModule = findText("");      /* evaluate wrt last module by default */
343     if (proj) {
344         if (namesUpto>1) {
345             fprintf(stderr,
346                     "\nUsing project file, ignoring additional filenames\n");
347         }
348         loadProject(strCopy(proj));
349     }
350     readScripts(0);
351 }
352
353 /* --------------------------------------------------------------------------
354  * Command line options:
355  * ------------------------------------------------------------------------*/
356
357 struct options {                        /* command line option toggles     */
358     char   c;                           /* table defined in main app.      */
359     int    h98;
360     String description;
361     Bool   *flag;
362 };
363 extern struct options toggle[];
364
365 static Void local toggleSet(c,state)    /* Set command line toggle         */
366 Char c;
367 Bool state; {
368     Int i;
369     for (i=0; toggle[i].c; ++i)
370         if (toggle[i].c == c) {
371             *toggle[i].flag = state;
372             return;
373         }
374     ERRMSG(0) "Unknown toggle `%c'", c
375     EEND;
376 }
377
378 static Void local togglesIn(state)      /* Print current list of toggles in*/
379 Bool state; {                           /* given state                     */
380     Int count = 0;
381     Int i;
382     for (i=0; toggle[i].c; ++i)
383         if (*toggle[i].flag == state && (!haskell98 || toggle[i].h98)) {
384             if (count==0)
385                 Putchar((char)(state ? '+' : '-'));
386             Putchar(toggle[i].c);
387             count++;
388         }
389     if (count>0)
390         Putchar(' ');
391 }
392
393 static Void local optionInfo() {        /* Print information about command */
394     static String fmts = "%-5s%s\n";    /* line settings                   */
395     static String fmtc = "%-5c%s\n";
396     Int    i;
397
398     Printf("TOGGLES: groups begin with +/- to turn options on/off resp.\n");
399     for (i=0; toggle[i].c; ++i) {
400         if (!haskell98 || toggle[i].h98) {
401             Printf(fmtc,toggle[i].c,toggle[i].description);
402         }
403     }
404
405     Printf("\nOTHER OPTIONS: (leading + or - makes no difference)\n");
406     Printf(fmts,"hnum","Set heap size (cannot be changed within Hugs)");
407     Printf(fmts,"pstr","Set prompt string to str");
408     Printf(fmts,"rstr","Set repeat last expression string to str");
409     Printf(fmts,"Pstr","Set search path for modules to str");
410     Printf(fmts,"Estr","Use editor setting given by str");
411     Printf(fmts,"cnum","Set constraint cutoff limit");
412 #if USE_PREPROCESSOR  && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
413     Printf(fmts,"Fstr","Set preprocessor filter to str");
414 #endif
415
416     Printf("\nCurrent settings: ");
417     togglesIn(TRUE);
418     togglesIn(FALSE);
419     Printf("-h%d",heapSize);
420     Printf(" -p");
421     printString(prompt);
422     Printf(" -r");
423     printString(repeatStr);
424     Printf(" -c%d",cutoff);
425     Printf("\nSearch path     : -P");
426     printString(hugsPath);
427 #if 0
428 ToDo
429     if (projectPath!=NULL) {
430         Printf("\nProject Path    : %s",projectPath);
431     }
432 #endif
433     Printf("\nEditor setting  : -E");
434     printString(hugsEdit);
435 #if USE_PREPROCESSOR  && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
436     Printf("\nPreprocessor    : -F");
437     printString(preprocessor);
438 #endif
439     Printf("\nCompatibility   : %s", haskell98 ? "Haskell 98 (+98)"
440                                                : "Hugs Extensions (-98)");
441     Putchar('\n');
442 }
443
444 #if USE_REGISTRY || HUGS_FOR_WINDOWS
445 #define PUTC(c)                         \
446     *next++=(c)
447
448 #define PUTS(s)                         \
449     strcpy(next,s);                     \
450     next+=strlen(next)
451
452 #define PUTInt(optc,i)                  \
453     sprintf(next,"-%c%d",optc,i);       \
454     next+=strlen(next)
455
456 #define PUTStr(c,s)                     \
457     next=PUTStr_aux(next,c,s)
458
459 static String local PUTStr_aux Args((String,Char, String));
460
461 static String local PUTStr_aux(next,c,s)
462 String next;
463 Char   c;
464 String s; {
465     if (s) { 
466         String t = 0;
467         sprintf(next,"-%c\"",c); 
468         next+=strlen(next);      
469         for(t=s; *t; ++t) {
470             PUTS(unlexChar(*t,'"'));
471         }
472         next+=strlen(next);      
473         PUTS("\" ");
474     }
475     return next;
476 }
477
478 static String local optionsToStr() {          /* convert options to string */
479     static char buffer[2000];
480     String next = buffer;
481
482     Int i;
483     for (i=0; toggle[i].c; ++i) {
484         PUTC(*toggle[i].flag ? '+' : '-');
485         PUTC(toggle[i].c);
486         PUTC(' ');
487     }
488     PUTS(haskell98 ? "+98 " : "-98 ");
489     PUTInt('h',hpSize);  PUTC(' ');
490     PUTStr('p',prompt);
491     PUTStr('r',repeatStr);
492     PUTStr('P',hugsPath);
493     PUTStr('E',hugsEdit);
494     PUTInt('c',cutoff);  PUTC(' ');
495 #if USE_PREPROCESSOR  && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
496     PUTStr('F',preprocessor);
497 #endif
498     PUTC('\0');
499     return buffer;
500 }
501 #endif /* USE_REGISTRY */
502
503 #undef PUTC
504 #undef PUTS
505 #undef PUTInt
506 #undef PUTStr
507
508 static Void local readOptions(options)         /* read options from string */
509 String options; {
510     String s;
511     if (options) {
512         stringInput(options);
513         while ((s=readFilename())!=0) {
514             if (*s && !processOption(s)) {
515                 ERRMSG(0) "Option string must begin with `+' or `-'"
516                 EEND;
517             }
518         }
519     }
520 }
521
522 static Bool local processOption(s)      /* process string s for options,   */
523 String s; {                             /* return FALSE if none found.     */
524     Bool state;
525
526     if (s[0]=='-')
527         state = FALSE;
528     else if (s[0]=='+')
529         state = TRUE;
530     else
531         return FALSE;
532
533     while (*++s)
534         switch (*s) {
535             case 'Q' : break;                           /* already handled */
536
537             case 'p' : if (s[1]) {
538                            if (prompt) free(prompt);
539                            prompt = strCopy(s+1);
540                        }
541                        return TRUE;
542
543             case 'r' : if (s[1]) {
544                            if (repeatStr) free(repeatStr);
545                            repeatStr = strCopy(s+1);
546                        }
547                        return TRUE;
548
549             case 'P' : {
550                            String p = substPath(s+1,hugsPath ? hugsPath : "");
551                            if (hugsPath) free(hugsPath);
552                            hugsPath = p;
553                            return TRUE;
554                        }
555
556             case 'E' : if (hugsEdit) free(hugsEdit);
557                        hugsEdit = strCopy(s+1);
558                        return TRUE;
559
560 #if USE_PREPROCESSOR  && (defined(HAVE_POPEN) || defined(HAVE__POPEN))
561             case 'F' : if (preprocessor) free(preprocessor);
562                        preprocessor = strCopy(s+1);
563                        return TRUE;
564 #endif
565
566             case 'h' : setHeapSize(s+1);
567                        return TRUE;
568
569             case 'D' : /* hack */
570                 {
571                     extern void setRtsFlags( int x );
572                     setRtsFlags(argToInt(s+1));
573                     return TRUE;
574                 }
575
576             default  : if (strcmp("98",s)==0) {
577                            if (heapBuilt() && ((state && !haskell98) ||
578                                                (!state && haskell98))) {
579                                FPrintf(stderr,"Haskell 98 compatibility cannot be changed while the interpreter is running\n");
580                            } else {
581                                haskell98 = state;
582                            }
583                            return TRUE;
584                        } else {
585                            toggleSet(*s,state);
586                        }
587                        break;
588         }
589     return TRUE;
590 }
591
592 static Void local setHeapSize(s) 
593 String s; {
594     if (s) {
595         hpSize = argToInt(s);
596         if (hpSize < MINIMUMHEAP)
597             hpSize = MINIMUMHEAP;
598         else if (MAXIMUMHEAP && hpSize > MAXIMUMHEAP)
599             hpSize = MAXIMUMHEAP;
600         if (heapBuilt() && hpSize != heapSize) {
601             /* ToDo: should this use a message box in winhugs? */
602 #if USE_REGISTRY
603             FPrintf(stderr,"Change to heap size will not take effect until you rerun Hugs\n");
604 #else
605             FPrintf(stderr,"Cannot change heap size\n");
606 #endif
607         } else {
608             heapSize = hpSize;
609         }
610     }
611 }
612
613 static Int local argToInt(s)            /* read integer from argument str  */
614 String s; {
615     Int    n = 0;
616     String t = s;
617
618     if (*s=='\0' || !isascii((int)(*s)) || !isdigit((int)(*s))) {
619         ERRMSG(0) "Missing integer in option setting \"%s\"", t
620         EEND;
621     }
622
623     do {
624         Int d = (*s++) - '0';
625         if (n > ((MAXPOSINT - d)/10)) {
626             ERRMSG(0) "Option setting \"%s\" is too large", t
627             EEND;
628         }
629         n     = 10*n + d;
630     } while (isascii((int)(*s)) && isdigit((int)(*s)));
631
632     if (*s=='K' || *s=='k') {
633         if (n > (MAXPOSINT/1000)) {
634             ERRMSG(0) "Option setting \"%s\" is too large", t
635             EEND;
636         }
637         n *= 1000;
638         s++;
639     }
640
641 #if MAXPOSINT > 1000000                 /* waste of time on 16 bit systems */
642     if (*s=='M' || *s=='m') {
643         if (n > (MAXPOSINT/1000000)) {
644             ERRMSG(0) "Option setting \"%s\" is too large", t
645             EEND;
646         }
647         n *= 1000000;
648         s++;
649     }
650 #endif
651
652 #if MAXPOSINT > 1000000000
653     if (*s=='G' || *s=='g') {
654         if (n > (MAXPOSINT/1000000000)) {
655             ERRMSG(0) "Option setting \"%s\" is too large", t
656             EEND;
657         }
658         n *= 1000000000;
659         s++;
660     }
661 #endif
662
663     if (*s!='\0') {
664         ERRMSG(0) "Unwanted characters after option setting \"%s\"", t
665         EEND;
666     }
667
668     return n;
669 }
670
671 /* --------------------------------------------------------------------------
672  * Print Menu of list of commands:
673  * ------------------------------------------------------------------------*/
674
675 static struct cmd cmds[] = {
676  {":?",      HELP},   {":cd",   CHGDIR},  {":also",    ALSO},
677  {":type",   TYPEOF}, {":!",    SYSTEM},  {":load",    LOAD},
678  {":reload", RELOAD}, {":gc",   COLLECT}, {":edit",    EDIT},
679  {":quit",   QUIT},   {":set",  SET},     {":find",    FIND},
680  {":names",  NAMES},  {":info", INFO},    {":project", PROJECT},
681  {":dump",   DUMP},   {":ztats", STATS},
682  {":module",SETMODULE}, 
683  {":browse", BROWSE},
684 #if EXPLAIN_INSTANCE_RESOLUTION
685  {":xplain", XPLAIN},
686 #endif
687  {":version", PNTVER},
688  {"",      EVAL},
689  {0,0}
690 };
691
692 static Void local menu() {
693     Printf("LIST OF COMMANDS:  Any command may be abbreviated to :c where\n");
694     Printf("c is the first character in the full name.\n\n");
695     Printf(":load <filenames>   load modules from specified files\n");
696     Printf(":load               clear all files except prelude\n");
697     Printf(":also <filenames>   read additional modules\n");
698     Printf(":reload             repeat last load command\n");
699     Printf(":project <filename> use project file\n");
700     Printf(":edit <filename>    edit file\n");
701     Printf(":edit               edit last module\n");
702     Printf(":module <module>    set module for evaluating expressions\n");
703     Printf("<expr>              evaluate expression\n");
704     Printf(":type <expr>        print type of expression\n");
705     Printf(":?                  display this list of commands\n");
706     Printf(":set <options>      set command line options\n");
707     Printf(":set                help on command line options\n");
708     Printf(":names [pat]        list names currently in scope\n");
709     Printf(":info <names>       describe named objects\n");
710     Printf(":browse <modules>   browse names defined in <modules>\n");
711 #if EXPLAIN_INSTANCE_RESOLUTION
712     Printf(":xplain <context>   explain instance resolution for <context>\n");
713 #endif
714     Printf(":find <name>        edit module containing definition of name\n");
715     Printf(":!command           shell escape\n");
716     Printf(":cd dir             change directory\n");
717     Printf(":gc                 force garbage collection\n");
718     Printf(":version            print Hugs version\n");
719     Printf(":dump <name>        print STG code for named fn\n");
720 #ifdef CRUDE_PROFILING
721     Printf(":ztats <name>       print reduction stats\n");
722 #endif
723     Printf(":quit               exit Hugs interpreter\n");
724 }
725
726 static Void local guidance() {
727     Printf("Command not recognised.  ");
728     forHelp();
729 }
730
731 static Void local forHelp() {
732     Printf("Type :? for help\n");
733 }
734
735 /* --------------------------------------------------------------------------
736  * Setting of command line options:
737  * ------------------------------------------------------------------------*/
738
739 struct options toggle[] = {             /* List of command line toggles    */
740     {'s', 1, "Print no. reductions/cells after eval", &showStats},
741     {'t', 1, "Print type after evaluation",           &addType},
742     {'g', 1, "Print no. cells recovered after gc",    &gcMessages},
743     {'l', 1, "Literate modules as default",           &literateScripts},
744     {'e', 1, "Warn about errors in literate modules", &literateErrors},
745     {'.', 1, "Print dots to show progress",           &useDots},
746     {'q', 1, "Print nothing to show progress",        &quiet},
747     {'w', 1, "Always show which modules are loaded",  &listScripts},
748     {'k', 1, "Show kind errors in full",              &kindExpert},
749     {'o', 0, "Allow overlapping instances",           &allowOverlap},
750     {'O', 1, "Optimise (improve?) generated code",    &optimise},
751
752
753 #if DEBUG_CODE
754     {'D', 1, "Debug: show generated code",            &debugCode},
755 #endif
756 #if EXPLAIN_INSTANCE_RESOLUTION
757     {'x', 1, "Explain instance resolution",           &showInstRes},
758 #endif
759 #if MULTI_INST
760     {'m', 0, "Use multi instance resolution",         &multiInstRes},
761 #endif
762 #if DEBUG_CODE
763     {'D', 1, "Debug: show generated G code",          &debugCode},
764 #endif
765 #if DEBUG_SHOWSC
766     {'S', 1, "Debug: show generated SC code",         &debugSC},
767 #endif
768 #if 0
769     {'f', 1, "Terminate evaluation on first error",   &failOnError},
770     {'u', 1, "Use \"show\" to display results",       &useShow},
771     {'i', 1, "Chase imports while loading modules",   &chaseImports}, 
772 #endif
773     {0,   0, 0,                                       0}
774 };
775
776 static Void local set() {               /* change command line options from*/
777     String s;                           /* Hugs command line               */
778
779     if ((s=readFilename())!=0) {
780         do {
781             if (!processOption(s)) {
782                 ERRMSG(0) "Option string must begin with `+' or `-'"
783                 EEND;
784             }
785         } while ((s=readFilename())!=0);
786 #if USE_REGISTRY
787         writeRegString("Options", optionsToStr());
788 #endif
789     }
790     else
791         optionInfo();
792 }
793
794 /* --------------------------------------------------------------------------
795  * Change directory command:
796  * ------------------------------------------------------------------------*/
797
798 static Void local changeDir() {         /* change directory                */
799     String s = readFilename();
800     if (s && chdir(s)) {
801         ERRMSG(0) "Unable to change to directory \"%s\"", s
802         EEND;
803     }
804 }
805
806 /* --------------------------------------------------------------------------
807  * Loading project and script files:
808  * ------------------------------------------------------------------------*/
809
810 static Void local loadProject(s)        /* Load project file               */
811 String s; {
812     clearProject();
813     currProject = s;
814     projInput(currProject);
815     scriptFile = currProject;
816     forgetScriptsFrom(1);
817     while ((s=readFilename())!=0)
818         addStackEntry(s);
819     if (namesUpto<=1) {
820         ERRMSG(0) "Empty project file"
821         EEND;
822     }
823     scriptFile    = 0;
824     projectLoaded = TRUE;
825 }
826
827 static Void local clearProject() {      /* clear name for current project  */
828     if (currProject)
829         free(currProject);
830     currProject   = 0;
831     projectLoaded = FALSE;
832 #if HUGS_FOR_WINDOWS
833     setLastEdit((String)0,0);
834 #endif
835 }
836
837
838
839 static Void local makeStackEntry ( ScriptInfo* ent, String iname )
840 {
841    Bool   ok, fromObj;
842    Bool   sAvail, iAvail, oAvail;
843    Time   sTime,  iTime,  oTime;
844    Long   sSize,  iSize,  oSize;
845    String path,   sExt;
846
847    ok = findFilesForModule (
848            iname,
849            &path,
850            &sExt,
851            &sAvail, &sTime, &sSize,
852            &iAvail, &iTime, &iSize,
853            &oAvail, &oTime, &oSize
854         );
855    if (!ok) {
856       ERRMSG(0) 
857         /* "Can't file source or object+interface for module \"%s\"", */
858          "Can't file source for module \"%s\"",
859          iname
860       EEND;
861    }
862    /* findFilesForModule should enforce this */
863    if (!(sAvail || (oAvail && iAvail))) 
864       internal("chase");
865    /* Load objects in preference to sources if both are available */
866    /* 11 Oct 99: disable object loading in the interim.
867       Will probably only reinstate when HEP becomes available.
868    fromObj = sAvail
869                 ? (oAvail && iAvail && timeEarlier(sTime,oTime))
870                 : TRUE;
871    */
872    fromObj = FALSE;
873
874    /* ToDo: namesUpto overflow */
875    ent->modName     = strCopy(iname);
876    ent->details     = TRUE;
877    ent->path        = path;
878    ent->fromSource  = !fromObj;
879    ent->srcExt      = sExt;
880    ent->postponed   = FALSE;
881    ent->lastChange  = sTime; /* ToDo: is this right? */
882    ent->size        = fromObj ? iSize : sSize;
883    ent->oSize       = fromObj ? oSize : 0;
884    ent->objLoaded   = FALSE;
885 }
886
887
888
889 static Void nukeEnding( String s )
890 {
891     Int l = strlen(s);
892     if (l > 2 && strncmp(s+l-2,".o"  ,3)==0) s[l-2] = 0; else
893     if (l > 3 && strncmp(s+l-3,".hi" ,3)==0) s[l-3] = 0; else
894     if (l > 3 && strncmp(s+l-3,".hs" ,3)==0) s[l-3] = 0; else
895     if (l > 4 && strncmp(s+l-4,".lhs",4)==0) s[l-4] = 0; else
896     if (l > 4 && strncmp(s+l-4,".dll",4)==0) s[l-4] = 0; else
897     if (l > 4 && strncmp(s+l-4,".DLL",4)==0) s[l-4] = 0;
898 }
899
900 static Void local addStackEntry(s)     /* Add script to list of scripts    */
901 String s; {                            /* to be read in ...                */
902     String s2;
903     Bool   found;
904     Int    i;
905
906     if (namesUpto>=NUM_SCRIPTS) {
907         ERRMSG(0) "Too many module files (maximum of %d allowed)",
908                   NUM_SCRIPTS
909         EEND;
910     }
911
912     s = strCopy(s);
913     nukeEnding(s);
914     for (s2 = s; *s2; s2++)
915        if (*s2 == SLASH && *(s2+1)) s = s2+1;
916
917     found = FALSE;
918     for (i = 0; i < namesUpto; i++)
919        if (strcmp(scriptInfo[i].modName,s)==0)
920           found = TRUE;
921
922     if (!found) {
923        makeStackEntry ( &scriptInfo[namesUpto], strCopy(s) );
924        namesUpto++;
925     }
926     free(s);
927 }
928
929 /* Return TRUE if no imports were needed; FALSE otherwise. */
930 static Bool local addScript(stacknum)   /* read single file                */
931 Int stacknum; {
932    static char name[FILENAME_MAX+1];
933    Int len = scriptInfo[stacknum].size;
934
935 #if HUGS_FOR_WINDOWS                    /* Set clock cursor while loading  */
936     allowBreak();
937     SetCursor(LoadCursor(NULL, IDC_WAIT));
938 #endif
939
940     //   setLastEdit(name,0);
941
942    nameObj[0] = 0;
943    strcpy(name, scriptInfo[stacknum].path);
944    strcat(name, scriptInfo[stacknum].modName);
945    if (scriptInfo[stacknum].fromSource)
946       strcat(name, scriptInfo[stacknum].srcExt); else
947       strcat(name, ".hi");
948
949    scriptFile = name;
950
951    if (scriptInfo[stacknum].fromSource) {
952       if (lastWasObject) finishInterfaces();
953       lastWasObject = FALSE;
954       Printf("Reading script \"%s\":\n",name);
955       needsImports = FALSE;
956       parseScript(name,len);
957       if (needsImports) return FALSE;
958       checkDefns();
959       typeCheckDefns();
960       compileDefns();
961    } else {
962       Printf("Reading  iface \"%s\":\n", name);
963       scriptFile = name;
964       needsImports = FALSE;
965
966       // set nameObj for the benefit of openGHCIface
967       strcpy(nameObj, scriptInfo[stacknum].path);
968       strcat(nameObj, scriptInfo[stacknum].modName);
969       strcat(nameObj, DLL_ENDING);
970       sizeObj = scriptInfo[stacknum].oSize;
971
972       loadInterface(name,len);
973       scriptFile = 0;
974       lastWasObject = TRUE;
975       if (needsImports) return FALSE;
976    }
977  
978    scriptFile = 0;
979    preludeLoaded = TRUE;
980    return TRUE;
981 }
982
983
984 Bool chase(imps)                        /* Process list of import requests */
985 List imps; {
986     Int    dstPosn;
987     ScriptInfo tmp;
988     Int    origPos  = numScripts;       /* keep track of original position */
989     String origName = scriptInfo[origPos].modName;
990     for (; nonNull(imps); imps=tl(imps)) {
991         String iname = textToStr(textOf(hd(imps)));
992         Int    i     = 0;
993         for (; i<namesUpto; i++)
994             if (strcmp(scriptInfo[i].modName,iname)==0)
995                 break;
996         //fprintf(stderr, "import name = %s   num = %d\n", iname, i );
997
998         if (i<namesUpto) {
999            /* We should have filled in the details of each module
1000               the first time we hear about it.
1001            */
1002            assert(scriptInfo[i].details);
1003         }
1004
1005         if (i>=origPos) {               /* Neither loaded or queued        */
1006             String theName;
1007             Time   theTime;
1008             Bool   thePost;
1009             Bool   theFS;
1010
1011             needsImports = TRUE;
1012             if (scriptInfo[origPos].fromSource)
1013                scriptInfo[origPos].postponed  = TRUE;
1014
1015             if (i==namesUpto) {         /* Name not found (i==namesUpto)   */
1016                  /* Find out where it lives, whether source or object, etc */
1017                makeStackEntry ( &scriptInfo[i], iname );
1018                namesUpto++;
1019             }
1020             else 
1021             if (scriptInfo[i].postponed && scriptInfo[i].fromSource) {
1022                                         /* Check for recursive dependency  */
1023                 ERRMSG(0)
1024                   "Recursive import dependency between \"%s\" and \"%s\"",
1025                   scriptInfo[origPos].modName, iname
1026                 EEND;
1027             }
1028             /* Move stack entry i to somewhere below origPos.  If i denotes 
1029              * an object, destination is immediately below origPos.  
1030              * Otherwise, it's underneath the queue of objects below origPos.
1031              */
1032             dstPosn = origPos-1;
1033             if (scriptInfo[i].fromSource)
1034                while (!scriptInfo[dstPosn].fromSource && dstPosn > 0)
1035                   dstPosn--;
1036
1037             dstPosn++;
1038             tmp = scriptInfo[i];
1039             for (; i > dstPosn; i--) scriptInfo[i] = scriptInfo[i-1];
1040             scriptInfo[dstPosn] = tmp;
1041             if (dstPosn < nextNumScripts) nextNumScripts = dstPosn;
1042             origPos++;
1043         }
1044     }
1045     return needsImports;
1046 }
1047
1048 static Void local forgetScriptsFrom(scno)/* remove scripts from system     */
1049 Script scno; {
1050     Script i;
1051 #if 0
1052     for (i=scno; i<namesUpto; ++i)
1053         if (scriptName[i])
1054             free(scriptName[i]);
1055 #endif
1056     dropScriptsFrom(scno-1);
1057     namesUpto = scno;
1058     if (numScripts>namesUpto)
1059         numScripts = scno;
1060 }
1061
1062 /* --------------------------------------------------------------------------
1063  * Commands for loading and removing script files:
1064  * ------------------------------------------------------------------------*/
1065
1066 static Void local load() {           /* read filenames from command line   */
1067     String s;                        /* and add to list of scripts waiting */
1068                                      /* to be read                         */
1069     while ((s=readFilename())!=0)
1070         addStackEntry(s);
1071     readScripts(1);
1072 }
1073
1074 static Void local project() {          /* read list of script names from   */
1075     String s;                          /* project file                     */
1076
1077     if ((s=readFilename()) || currProject) {
1078         if (!s)
1079             s = strCopy(currProject);
1080         else if (readFilename()) {
1081             ERRMSG(0) "Too many project files"
1082             EEND;
1083         }
1084         else
1085             s = strCopy(s);
1086     }
1087     else {
1088         ERRMSG(0) "No project filename specified"
1089         EEND;
1090     }
1091     loadProject(s);
1092     readScripts(1);
1093 }
1094
1095 static Void local readScripts(n)        /* Reread current list of scripts, */
1096 Int n; {                                /* loading everything after and    */
1097     Time timeStamp;                     /* including the first script which*/
1098     Long fileSize;                      /* has been either changed or added*/
1099     static char name[FILENAME_MAX+1];
1100
1101     lastWasObject = FALSE;
1102     ppSmStack("readscripts-begin");
1103 #if HUGS_FOR_WINDOWS
1104     SetCursor(LoadCursor(NULL, IDC_WAIT));
1105 #endif
1106
1107 #if 0
1108     for (; n<numScripts; n++) {         /* Scan previously loaded scripts  */
1109         ppSmStack("readscripts-loop1");
1110         getFileInfo(scriptName[n], &timeStamp, &fileSize);
1111         if (timeChanged(timeStamp,lastChange[n])) {
1112             dropScriptsFrom(n-1);
1113             numScripts = n;
1114             break;
1115         }
1116     }
1117     for (; n<NUM_SCRIPTS; n++)          /* No scripts have been postponed  */
1118         postponed[n] = FALSE;           /* at this stage                   */
1119     numScripts = 0;
1120
1121     while (numScripts<namesUpto) {      /* Process any remaining scripts   */
1122         ppSmStack("readscripts-loop2");
1123         getFileInfo(scriptName[numScripts], &timeStamp, &fileSize);
1124         timeSet(lastChange[numScripts],timeStamp);
1125         if (numScripts>0)               /* no new script for prelude       */
1126             startNewScript(scriptName[numScripts]);
1127         if (addScript(scriptName[numScripts],fileSize))
1128             numScripts++;
1129         else
1130             dropScriptsFrom(numScripts-1);
1131     }
1132 #endif
1133
1134     interface(RESET);
1135
1136     for (; n<numScripts; n++) {
1137         ppSmStack("readscripts-loop2");
1138         strcpy(name, scriptInfo[n].path);
1139         strcat(name, scriptInfo[n].modName);
1140         if (scriptInfo[n].fromSource)
1141            strcat(name, scriptInfo[n].srcExt); else
1142            strcat(name, ".hi");  //ToDo: should be .o
1143         getFileInfo(name,&timeStamp, &fileSize);
1144         if (timeChanged(timeStamp,scriptInfo[n].lastChange)) {
1145            dropScriptsFrom(n-1);
1146            numScripts = n;
1147            break;
1148         }
1149     }
1150     for (; n<NUM_SCRIPTS; n++)
1151         scriptInfo[n].postponed = FALSE;
1152
1153     //numScripts = 0;
1154
1155     while (numScripts < namesUpto) {
1156 ppSmStack ( "readscripts-loop2" );
1157
1158        if (scriptInfo[numScripts].fromSource) {
1159
1160           if (numScripts>0)
1161               startNewScript(scriptInfo[numScripts].modName);
1162           nextNumScripts = NUM_SCRIPTS; //bogus initialisation
1163           if (addScript(numScripts)) {
1164              numScripts++;
1165 assert(nextNumScripts==NUM_SCRIPTS);
1166           }
1167           else
1168              dropScriptsFrom(numScripts-1);
1169
1170        } else {
1171       
1172           if (scriptInfo[numScripts].objLoaded) {
1173              numScripts++;
1174           } else {
1175              scriptInfo[numScripts].objLoaded = TRUE;
1176              /* new */
1177              if (numScripts>0)
1178                  startNewScript(scriptInfo[numScripts].modName);
1179              /* end */
1180              nextNumScripts = NUM_SCRIPTS;
1181              if (addScript(numScripts)) {
1182                 numScripts++;
1183 assert(nextNumScripts==NUM_SCRIPTS);
1184              } else {
1185                 //while (!scriptInfo[numScripts].fromSource && numScripts > 0)
1186                 //   numScripts--;
1187                 //if (scriptInfo[numScripts].fromSource)
1188                 //   numScripts++;
1189                 numScripts = nextNumScripts;
1190 assert(nextNumScripts<NUM_SCRIPTS);
1191              }
1192           }
1193        }
1194 if (numScripts==namesUpto) ppSmStack( "readscripts-final") ;
1195     }
1196
1197     finishInterfaces();
1198
1199     { Int  m     = namesUpto-1;
1200       Text mtext = findText(scriptInfo[m].modName);
1201       setCurrModule(mtext);
1202       evalModule = mtext;
1203     }
1204
1205     
1206
1207     if (listScripts)
1208         whatScripts();
1209     if (numScripts<=1)
1210         setLastEdit((String)0, 0);
1211     ppSmStack("readscripts-end  ");
1212 }
1213
1214 static Void local whatScripts() {       /* list scripts in current session */
1215     int i;
1216     Printf("\nHugs session for:");
1217     if (projectLoaded)
1218         Printf(" (project: %s)",currProject);
1219     for (i=0; i<numScripts; ++i)
1220       Printf("\n%s%s",scriptInfo[i].path, scriptInfo[i].modName);
1221     Putchar('\n');
1222 }
1223
1224 /* --------------------------------------------------------------------------
1225  * Access to external editor:
1226  * ------------------------------------------------------------------------*/
1227
1228 static Void local editor() {            /* interpreter-editor interface    */
1229     String newFile  = readFilename();
1230     if (newFile) {
1231         setLastEdit(newFile,0);
1232         if (readFilename()) {
1233             ERRMSG(0) "Multiple filenames not permitted"
1234             EEND;
1235         }
1236     }
1237     runEditor();
1238 }
1239
1240 static Void local find() {              /* edit file containing definition */
1241 #if 0
1242 This just plain wont work no more.
1243 ToDo: Fix!
1244     String nm = readFilename();         /* of specified name               */
1245     if (!nm) {
1246         ERRMSG(0) "No name specified"
1247         EEND;
1248     }
1249     else if (readFilename()) {
1250         ERRMSG(0) "Multiple names not permitted"
1251         EEND;
1252     }
1253     else {
1254         Text t;
1255         Cell c;
1256         setCurrModule(findEvalModule());
1257         startNewScript(0);
1258         if (nonNull(c=findTycon(t=findText(nm)))) {
1259             if (startEdit(tycon(c).line,scriptName[scriptThisTycon(c)])) {
1260                 readScripts(1);
1261             }
1262         } else if (nonNull(c=findName(t))) {
1263             if (startEdit(name(c).line,scriptName[scriptThisName(c)])) {
1264                 readScripts(1);
1265             }
1266         } else {
1267             ERRMSG(0) "No current definition for name \"%s\"", nm
1268             EEND;
1269         }
1270     }
1271 #endif
1272 }
1273
1274 static Void local runEditor() {         /* run editor on script lastEdit   */
1275     if (startEdit(lastEdLine,lastEdit)) /* at line lastEdLine              */
1276         readScripts(1);
1277 }
1278
1279 static Void local setLastEdit(fname,line)/* keep name of last file to edit */
1280 String fname;
1281 Int    line; {
1282     if (lastEdit)
1283         free(lastEdit);
1284     lastEdit = strCopy(fname);
1285     lastEdLine = line;
1286 #if HUGS_FOR_WINDOWS
1287     DrawStatusLine(hWndMain);           /* Redo status line                */
1288 #endif
1289 }
1290
1291 /* --------------------------------------------------------------------------
1292  * Read and evaluate an expression:
1293  * ------------------------------------------------------------------------*/
1294
1295 static Void local setModule(){/*set module in which to evaluate expressions*/
1296     String s = readFilename();
1297     if (!s) s = "";              /* :m clears the current module selection */
1298     evalModule = findText(s);
1299     setLastEdit(fileOfModule(findEvalModule()),0);
1300 }
1301
1302 static Module local findEvalModule() { /*Module in which to eval expressions*/
1303     Module m = findModule(evalModule); 
1304     if (isNull(m))
1305         m = lastModule();
1306     return m;
1307 }
1308
1309 static Void local evaluator() {        /* evaluate expr and print value    */
1310     Type  type, bd;
1311     Kinds ks   = NIL;
1312
1313     setCurrModule(findEvalModule());
1314     scriptFile = 0;
1315     startNewScript(0);                 /* Enables recovery of storage      */
1316                                        /* allocated during evaluation      */
1317     parseExp();
1318     checkExp();
1319     defaultDefns = evalDefaults;
1320     type         = typeCheckExp(TRUE);
1321     if (isPolyType(type)) {
1322         ks = polySigOf(type);
1323         bd = monotypeOf(type);
1324     }
1325     else
1326         bd = type;
1327
1328     if (whatIs(bd)==QUAL) {
1329         ERRMSG(0) "Unresolved overloading" ETHEN
1330         ERRTEXT   "\n*** Type       : "    ETHEN ERRTYPE(type);
1331         ERRTEXT   "\n*** Expression : "    ETHEN ERREXPR(inputExpr);
1332         ERRTEXT   "\n"
1333         EEND;
1334     }
1335   
1336 #ifdef WANT_TIMER
1337     updateTimers();
1338 #endif
1339
1340 #if 1
1341     if (typeMatches(type,ap(typeIO,typeUnit))) {
1342         inputExpr = ap(nameRunIO,inputExpr);
1343         evalExp();
1344         Putchar('\n');
1345     } else {
1346         Cell d = provePred(ks,NIL,ap(classShow,bd));
1347         if (isNull(d)) {
1348             ERRMSG(0) "Cannot find \"show\" function for:" ETHEN
1349             ERRTEXT   "\n*** expression : "   ETHEN ERREXPR(inputExpr);
1350             ERRTEXT   "\n*** of type    : "   ETHEN ERRTYPE(type);
1351             ERRTEXT   "\n"
1352             EEND;
1353         }
1354         inputExpr = ap2(findName(findText("show")),d,inputExpr);
1355         inputExpr = ap(findName(findText("putStr")), inputExpr);
1356         inputExpr = ap(nameRunIO, inputExpr);
1357
1358         evalExp(); printf("\n");
1359         if (addType) {
1360             printf(" :: ");
1361             printType(stdout,type);
1362             Putchar('\n');
1363         }
1364     }
1365
1366 #else
1367
1368    printf ( "result type is " );
1369    printType ( stdout, type );
1370    printf ( "\n" );
1371    evalExp();
1372    printf ( "\n" );
1373
1374 #endif
1375
1376 }
1377
1378 static Void local stopAnyPrinting() {  /* terminate printing of expression,*/
1379     if (printing) {                    /* after successful termination or  */
1380         printing = FALSE;              /* runtime error (e.g. interrupt)   */
1381         Putchar('\n');
1382         if (showStats) {
1383 #define plural(v)   v, (v==1?"":"s")
1384             Printf("%lu cell%s",plural(numCells));
1385             if (numGcs>0)
1386                 Printf(", %u garbage collection%s",plural(numGcs));
1387             Printf(")\n");
1388 #undef plural
1389         }
1390         FlushStdout();
1391         garbageCollect();
1392     }
1393 }
1394
1395 /* --------------------------------------------------------------------------
1396  * Print type of input expression:
1397  * ------------------------------------------------------------------------*/
1398
1399 static Void local showtype() {         /* print type of expression (if any)*/
1400     Cell type;
1401
1402     setCurrModule(findEvalModule());
1403     startNewScript(0);                 /* Enables recovery of storage      */
1404                                        /* allocated during evaluation      */
1405     parseExp();
1406     checkExp();
1407     defaultDefns = evalDefaults;
1408     type = typeCheckExp(FALSE);
1409     printExp(stdout,inputExpr);
1410     Printf(" :: ");
1411     printType(stdout,type);
1412     Putchar('\n');
1413 }
1414
1415
1416 static Void local browseit(mod,t)
1417 Module mod; 
1418 String t; {
1419 #if 0
1420   /* AJG: DISABLED FOR NOW */
1421     if (nonNull(mod)) {
1422         Cell cs;
1423         Printf("module %s where\n",textToStr(module(mod).text));
1424         for (cs = module(mod).names; nonNull(cs); cs=tl(cs)) {
1425             Name nm = hd(cs);
1426             /* only look at things defined in this module */
1427             if (name(nm).mod == mod) {
1428                 /* unwanted artifacts, like lambda lifted values,
1429                    are in the list of names, but have no types */
1430                 if (nonNull(name(nm).type)) {
1431                     printExp(stdout,nm);
1432                     Printf(" :: ");
1433                     printType(stdout,name(nm).type);
1434                     if (isCfun(nm)) {
1435                         Printf("  -- data constructor");
1436                     } else if (isMfun(nm)) {
1437                         Printf("  -- class member");
1438                     } else if (isSfun(nm)) {
1439                         Printf("  -- selector function");
1440                     }
1441                     if (name(nm).primDef) {
1442                         Printf("   -- primitive");
1443                     }
1444                     Printf("\n");
1445                 }
1446             }
1447         }
1448     } else {
1449       if (isNull(mod)) {
1450         Printf("Unknown module %s\n",t);
1451       }
1452     }
1453 #endif
1454 }
1455
1456 static Void local browse() {            /* browse modules                  */
1457     Int    count = 0;                   /* or give menu of commands        */
1458     String s;
1459
1460     setCurrModule(findEvalModule());
1461     startNewScript(0);                  /* for recovery of storage         */
1462     for (; (s=readFilename())!=0; count++) {
1463         browseit(findModule(findText(s)),s);
1464     }
1465     if (count == 0) {
1466         whatScripts();
1467     }
1468 }
1469
1470 #if EXPLAIN_INSTANCE_RESOLUTION
1471 static Void local xplain() {         /* print type of expression (if any)*/
1472     Cell type;
1473     Cell d;
1474     Bool sir = showInstRes;
1475
1476     setCurrModule(findEvalModule());
1477     startNewScript(0);                 /* Enables recovery of storage      */
1478                                        /* allocated during evaluation      */
1479     parseContext();
1480     checkContext();
1481     showInstRes = TRUE;
1482     d = provePred(NIL,NIL,hd(inputContext));
1483     if (isNull(d)) {
1484         fprintf(stdout, "not Sat\n");
1485     } else {
1486         fprintf(stdout, "Sat\n");
1487     }
1488     showInstRes = sir;
1489 }
1490 #endif
1491
1492 /* --------------------------------------------------------------------------
1493  * Enhanced help system:  print current list of scripts or give information
1494  * about an object.
1495  * ------------------------------------------------------------------------*/
1496
1497 static String local objToStr(m,c)
1498 Module m;
1499 Cell   c; {
1500 #if 1 || DISPLAY_QUANTIFIERS
1501     static char newVar[60];
1502     switch (whatIs(c)) {
1503         case NAME  : if (m == name(c).mod) {
1504                          sprintf(newVar,"%s", textToStr(name(c).text));
1505                      } else {
1506                          sprintf(newVar,"%s.%s",
1507                                         textToStr(module(name(c).mod).text),
1508                                         textToStr(name(c).text));
1509                      }
1510                      break;
1511
1512         case TYCON : if (m == tycon(c).mod) {
1513                          sprintf(newVar,"%s", textToStr(tycon(c).text));
1514                      } else {
1515                          sprintf(newVar,"%s.%s",
1516                                         textToStr(module(tycon(c).mod).text),
1517                                         textToStr(tycon(c).text));
1518                      }
1519                      break;
1520
1521         case CLASS : if (m == cclass(c).mod) {
1522                          sprintf(newVar,"%s", textToStr(cclass(c).text));
1523                      } else {
1524                          sprintf(newVar,"%s.%s",
1525                                         textToStr(module(cclass(c).mod).text),
1526                                         textToStr(cclass(c).text));
1527                      }
1528                      break;
1529
1530         default    : internal("objToStr");
1531     }
1532     return newVar;
1533 #else
1534     static char newVar[33];
1535     switch (whatIs(c)) {
1536         case NAME  : sprintf(newVar,"%s", textToStr(name(c).text));
1537                      break;
1538
1539         case TYCON : sprintf(newVar,"%s", textToStr(tycon(c).text));
1540                      break;
1541
1542         case CLASS : sprintf(newVar,"%s", textToStr(cclass(c).text));
1543                      break;
1544
1545         default    : internal("objToStr");
1546     }
1547     return newVar;
1548 #endif
1549 }
1550
1551 extern Name nameHw;
1552
1553 static Void local dumpStg( void ) {       /* print STG stuff                 */
1554     String s;
1555     Text   t;
1556     Name   n;
1557     Int    i;
1558     Cell   v;                           /* really StgVar */
1559     setCurrModule(findEvalModule());
1560     startNewScript(0);
1561     for (; (s=readFilename())!=0;) {
1562         t = findText(s);
1563         v = n = NIL;
1564         /* find the name while ignoring module scopes */
1565         for (i=NAMEMIN; i<nameHw; i++)
1566            if (name(i).text == t) n = i;
1567
1568         /* perhaps it's an "idNNNNNN" thing? */
1569         if (isNull(n) &&
1570             strlen(s) >= 3 && 
1571             s[0]=='i' && s[1]=='d' && isdigit(s[2])) {
1572            v = 0;
1573            i = 2;
1574            while (isdigit(s[i])) {
1575               v = v * 10 + (s[i]-'0');
1576               i++;
1577            }
1578            v = -v;
1579            n = nameFromStgVar(v);
1580         }
1581
1582         if (isNull(n) && whatIs(v)==STGVAR) {
1583            Printf ( "\n{- `%s' has no nametable entry -}\n", s );
1584            Printf ( "{- stgSize of body is %d -}\n\n", stgSize(stgVarBody(v)));
1585            printStg(stderr, v );
1586         } else
1587         if (isNull(n)) {
1588            Printf ( "Unknown reference `%s'\n", s );
1589         } else
1590         if (!isName(n)) {
1591            Printf ( "Not a Name: `%s'\n", s );
1592         } else
1593         if (isNull(name(n).stgVar)) {
1594            Printf ( "Doesn't have a STG tree: %s\n", s );
1595         } else {
1596            Printf ( "\n{- stgVar of `%s' is id%d -}\n", s, -name(n).stgVar);
1597            Printf ( "{- stgSize of body is %d -}\n\n", 
1598                     stgSize(stgVarBody(name(n).stgVar)));
1599            printStg(stderr, name(n).stgVar);
1600         }
1601     }
1602 }
1603
1604 static Void local info() {              /* describe objects                */
1605     Int    count = 0;                   /* or give menu of commands        */
1606     String s;
1607
1608     setCurrModule(findEvalModule());
1609     startNewScript(0);                  /* for recovery of storage         */
1610     for (; (s=readFilename())!=0; count++) {
1611         describe(findText(s));
1612     }
1613     if (count == 0) {
1614         whatScripts();
1615     }
1616 }
1617
1618
1619 static Void local describe(t)           /* describe an object              */
1620 Text t; {
1621     Tycon  tc  = findTycon(t);
1622     Class  cl  = findClass(t);
1623     Name   nm  = findName(t);
1624
1625     if (nonNull(tc)) {                  /* as a type constructor           */
1626         Type t = tc;
1627         Int  i;
1628         Inst in;
1629         for (i=0; i<tycon(tc).arity; ++i) {
1630             t = ap(t,mkOffset(i));
1631         }
1632         Printf("-- type constructor");
1633         if (kindExpert) {
1634             Printf(" with kind ");
1635             printKind(stdout,tycon(tc).kind);
1636         }
1637         Putchar('\n');
1638         switch (tycon(tc).what) {
1639             case SYNONYM      : Printf("type ");
1640                                 printType(stdout,t);
1641                                 Printf(" = ");
1642                                 printType(stdout,tycon(tc).defn);
1643                                 break;
1644
1645             case NEWTYPE      :
1646             case DATATYPE     : {   List cs = tycon(tc).defn;
1647                                     if (tycon(tc).what==DATATYPE) {
1648                                         Printf("data ");
1649                                     } else {
1650                                         Printf("newtype ");
1651                                     }
1652                                     printType(stdout,t);
1653                                     Putchar('\n');
1654                                     mapProc(printSyntax,cs);
1655                                     if (hasCfun(cs)) {
1656                                         Printf("\n-- constructors:");
1657                                     }
1658                                     for (; hasCfun(cs); cs=tl(cs)) {
1659                                         Putchar('\n');
1660                                         printExp(stdout,hd(cs));
1661                                         Printf(" :: ");
1662                                         printType(stdout,name(hd(cs)).type);
1663                                     }
1664                                     if (nonNull(cs)) {
1665                                         Printf("\n-- selectors:");
1666                                     }
1667                                     for (; nonNull(cs); cs=tl(cs)) {
1668                                         Putchar('\n');
1669                                         printExp(stdout,hd(cs));
1670                                         Printf(" :: ");
1671                                         printType(stdout,name(hd(cs)).type);
1672                                     }
1673                                 }
1674                                 break;
1675
1676             case RESTRICTSYN  : Printf("type ");
1677                                 printType(stdout,t);
1678                                 Printf(" = <restricted>");
1679                                 break;
1680         }
1681         Putchar('\n');
1682         if (nonNull(in=findFirstInst(tc))) {
1683             Printf("\n-- instances:\n");
1684             do {
1685                 showInst(in);
1686                 in = findNextInst(tc,in);
1687             } while (nonNull(in));
1688         }
1689         Putchar('\n');
1690     }
1691
1692     if (nonNull(cl)) {                  /* as a class                      */
1693         List  ins = cclass(cl).instances;
1694         Kinds ks  = cclass(cl).kinds;
1695         if (nonNull(ks) && isNull(tl(ks)) && hd(ks)==STAR) {
1696             Printf("-- type class");
1697         } else {
1698             Printf("-- constructor class");
1699             if (kindExpert) {
1700                 Printf(" with arity ");
1701                 printKinds(stdout,ks);
1702             }
1703         }
1704         Putchar('\n');
1705         mapProc(printSyntax,cclass(cl).members);
1706         Printf("class ");
1707         if (nonNull(cclass(cl).supers)) {
1708             printContext(stdout,cclass(cl).supers);
1709             Printf(" => ");
1710         }
1711         printPred(stdout,cclass(cl).head);
1712 #if 0
1713         /* AJG: commented out for now */
1714         if (nonNull(cclass(cl).fds)) {
1715             List   fds = cclass(cl).fds;
1716             String pre = " | ";
1717             for (; nonNull(fds); fds=tl(fds)) {
1718                 Printf(pre);
1719                 printFD(stdout,hd(fds));
1720                 pre = ", ";
1721             }
1722         }
1723 #endif
1724         if (nonNull(cclass(cl).members)) {
1725             List ms = cclass(cl).members;
1726             Printf(" where");
1727             do {
1728                 Type t = monotypeOf(name(hd(ms)).type);
1729                 Printf("\n  ");
1730                 printExp(stdout,hd(ms));
1731                 Printf(" :: ");
1732                 if (isNull(tl(fst(snd(t))))) {
1733                     t = snd(snd(t));
1734                 } else {
1735                     t = ap(QUAL,pair(tl(fst(snd(t))),snd(snd(t))));
1736                 }
1737                 printType(stdout,t);
1738                 ms = tl(ms);
1739             } while (nonNull(ms));
1740         }
1741         Putchar('\n');
1742         if (nonNull(ins)) {
1743             Printf("\n-- instances:\n");
1744             do {
1745                 showInst(hd(ins));
1746                 ins = tl(ins);
1747             } while (nonNull(ins));
1748         }
1749         Putchar('\n');
1750     }
1751
1752     if (nonNull(nm)) {                  /* as a function/name              */
1753         printSyntax(nm);
1754         printExp(stdout,nm);
1755         Printf(" :: ");
1756         if (nonNull(name(nm).type)) {
1757             printType(stdout,name(nm).type);
1758         } else {
1759             Printf("<unknown type>");
1760         }
1761
1762         if (isCfun(nm)) {
1763             Printf("  -- data constructor");
1764         } else if (isMfun(nm)) {
1765             Printf("  -- class member");
1766         } else if (isSfun(nm)) {
1767             Printf("  -- selector function");
1768         }
1769         Printf("\n\n");
1770     }
1771
1772
1773     if (isNull(tc) && isNull(cl) && isNull(nm)) {
1774         Printf("Unknown reference `%s'\n",textToStr(t));
1775     }
1776 }
1777
1778 static Void local printSyntax(nm)
1779 Name nm; {
1780     Syntax sy = syntaxOf(nm);
1781     Text   t  = name(nm).text;
1782     String s  = textToStr(t);
1783     if (sy != defaultSyntax(t)) {
1784         Printf("infix");
1785         switch (assocOf(sy)) {
1786             case LEFT_ASS  : Putchar('l'); break;
1787             case RIGHT_ASS : Putchar('r'); break;
1788             case NON_ASS   : break;
1789         }
1790         Printf(" %i ",precOf(sy));
1791         if (isascii((int)(*s)) && isalpha((int)(*s))) {
1792             Printf("`%s`",s);
1793         } else {
1794             Printf("%s",s);
1795         }
1796         Putchar('\n');
1797     }
1798 }
1799
1800 static Void local showInst(in)          /* Display instance decl header    */
1801 Inst in; {
1802     Printf("instance ");
1803     if (nonNull(inst(in).specifics)) {
1804         printContext(stdout,inst(in).specifics);
1805         Printf(" => ");
1806     }
1807     printPred(stdout,inst(in).head);
1808     Putchar('\n');
1809 }
1810
1811 /* --------------------------------------------------------------------------
1812  * List all names currently in scope:
1813  * ------------------------------------------------------------------------*/
1814
1815 static Void local listNames() {         /* list names matching optional pat*/
1816     String pat   = readFilename();
1817     List   names = NIL;
1818     Int    width = getTerminalWidth() - 1;
1819     Int    count = 0;
1820     Int    termPos;
1821     Module mod   = findEvalModule();
1822
1823     if (pat) {                          /* First gather names to list      */
1824         do {
1825             names = addNamesMatching(pat,names);
1826         } while ((pat=readFilename())!=0);
1827     } else {
1828         names = addNamesMatching((String)0,names);
1829     }
1830     if (isNull(names)) {                /* Then print them out             */
1831         ERRMSG(0) "No names selected"
1832         EEND;
1833     }
1834     for (termPos=0; nonNull(names); names=tl(names)) {
1835         String s = objToStr(mod,hd(names));
1836         Int    l = strlen(s);
1837         if (termPos+1+l>width) { 
1838             Putchar('\n');       
1839             termPos = 0;         
1840         } else if (termPos>0) {  
1841             Putchar(' ');        
1842             termPos++;           
1843         }
1844         Printf("%s",s);
1845         termPos += l;
1846         count++;
1847     }
1848     Printf("\n(%d names listed)\n", count);
1849 }
1850
1851 /* --------------------------------------------------------------------------
1852  * print a prompt and read a line of input:
1853  * ------------------------------------------------------------------------*/
1854
1855 static Void local promptForInput(moduleName)
1856 String moduleName; {
1857     char promptBuffer[1000];
1858 #if 1
1859     /* This is portable but could overflow buffer */
1860     sprintf(promptBuffer,prompt,moduleName);
1861 #else
1862     /* Works on ANSI C - but pre-ANSI compilers return a pointer to
1863      * promptBuffer instead.
1864      */
1865     if (sprintf(promptBuffer,prompt,moduleName) >= 1000) {
1866         /* Reset prompt to a safe default to avoid an infinite loop */
1867         free(prompt);
1868         prompt = strCopy("? ");
1869         internal("Combined prompt and evaluation module name too long");
1870     }
1871 #endif
1872     if (autoMain)
1873        stringInput("main\0"); else
1874        consoleInput(promptBuffer);
1875 }
1876
1877 /* --------------------------------------------------------------------------
1878  * main read-eval-print loop, with error trapping:
1879  * ------------------------------------------------------------------------*/
1880
1881 static jmp_buf catch_error;             /* jump buffer for error trapping  */
1882
1883 static Void local interpreter(argc,argv)/* main interpreter loop           */
1884 Int    argc;
1885 String argv[]; {
1886     Int errorNumber = setjmp(catch_error);
1887
1888     if (errorNumber && autoMain) {
1889        fprintf(stderr, "hugs +Q: compilation failed -- can't run `main'\n" );
1890        exit(1);
1891     }
1892
1893     breakOn(TRUE);                      /* enable break trapping           */
1894     if (numScripts==0) {                /* only succeeds on first time,    */
1895         if (errorNumber)                /* before prelude has been loaded  */
1896             fatal("Unable to load prelude");
1897         initialize(argc,argv);
1898         forHelp();
1899     }
1900
1901     for (;;) {
1902         Command cmd;
1903         everybody(RESET);               /* reset to sensible initial state */
1904         dropScriptsFrom(numScripts-1);  /* remove partially loaded scripts */
1905                                         /* not counting prelude as a script*/
1906
1907         promptForInput(textToStr(module(findEvalModule()).text));
1908
1909         cmd = readCommand(cmds, (Char)':', (Char)'!');
1910 #ifdef WANT_TIMER
1911         updateTimers();
1912 #endif
1913         switch (cmd) {
1914             case EDIT   : editor();
1915                           break;
1916             case FIND   : find();
1917                           break;
1918             case LOAD   : clearProject();
1919                           forgetScriptsFrom(1);
1920                           load();
1921                           break;
1922             case ALSO   : clearProject();
1923                           forgetScriptsFrom(numScripts);
1924                           load();
1925                           break;
1926             case RELOAD : readScripts(1);
1927                           break;
1928             case PROJECT: project();
1929                           break;
1930             case SETMODULE :
1931                           setModule();
1932                           break;
1933             case EVAL   : evaluator();
1934                           break;
1935             case TYPEOF : showtype();
1936                           break;
1937             case BROWSE : browse();
1938                           break;
1939 #if EXPLAIN_INSTANCE_RESOLUTION
1940             case XPLAIN : xplain();
1941                           break;
1942 #endif
1943             case NAMES  : listNames();
1944                           break;
1945             case HELP   : menu();
1946                           break;
1947             case BADCMD : guidance();
1948                           break;
1949             case SET    : set();
1950                           break;
1951             case STATS:
1952 #ifdef CRUDE_PROFILING
1953                           cp_show();
1954 #endif
1955                           break;
1956             case SYSTEM : if (shellEsc(readLine()))
1957                               Printf("Warning: Shell escape terminated abnormally\n");
1958                           break;
1959             case CHGDIR : changeDir();
1960                           break;
1961             case INFO   : info();
1962                           break;
1963             case PNTVER: Printf("-- Hugs Version %s\n",
1964                                  HUGS_VERSION);
1965                           break;
1966             case DUMP   : dumpStg();
1967                           break;
1968             case QUIT   : return;
1969             case COLLECT: consGC = FALSE;
1970                           garbageCollect();
1971                           consGC = TRUE;
1972                           Printf("Garbage collection recovered %d cells\n",
1973                                  cellsRecovered);
1974                           break;
1975             case NOCMD  : break;
1976         }
1977 #ifdef WANT_TIMER
1978         updateTimers();
1979         Printf("Elapsed time (ms): %ld (user), %ld (system)\n",
1980                millisecs(userElapsed), millisecs(systElapsed));
1981 #endif
1982         if (autoMain) break;
1983     }
1984     breakOn(FALSE);
1985 }
1986
1987 /* --------------------------------------------------------------------------
1988  * Display progress towards goal:
1989  * ------------------------------------------------------------------------*/
1990
1991 static Target currTarget;
1992 static Bool   aiming = FALSE;
1993 static Int    currPos;
1994 static Int    maxPos;
1995 static Int    charCount;
1996
1997 Void setGoal(what, t)                  /* Set goal for what to be t        */
1998 String what;
1999 Target t; {
2000     if (quiet) return;
2001     currTarget = (t?t:1);
2002     aiming     = TRUE;
2003     if (useDots) {
2004         currPos = strlen(what);
2005         maxPos  = getTerminalWidth() - 1;
2006         Printf("%s",what);
2007     }
2008     else
2009         for (charCount=0; *what; charCount++)
2010             Putchar(*what++);
2011     FlushStdout();
2012 }
2013
2014 Void soFar(t)                          /* Indicate progress towards goal   */
2015 Target t; {                            /* has now reached t                */
2016     if (quiet) return;
2017     if (useDots) {
2018         Int newPos = (Int)((maxPos * ((long)t))/currTarget);
2019
2020         if (newPos>maxPos)
2021             newPos = maxPos;
2022
2023         if (newPos>currPos) {
2024             do
2025                 Putchar('.');
2026             while (newPos>++currPos);
2027             FlushStdout();
2028         }
2029         FlushStdout();
2030     }
2031 }
2032
2033 Void done() {                          /* Goal has now been achieved       */
2034     if (quiet) return;
2035     if (useDots) {
2036         while (maxPos>currPos++)
2037             Putchar('.');
2038         Putchar('\n');
2039     }
2040     else
2041         for (; charCount>0; charCount--) {
2042             Putchar('\b');
2043             Putchar(' ');
2044             Putchar('\b');
2045         }
2046     aiming = FALSE;
2047     FlushStdout();
2048 }
2049
2050 static Void local failed() {           /* Goal cannot be reached due to    */
2051     if (aiming) {                      /* errors                           */
2052         aiming = FALSE;
2053         Putchar('\n');
2054         FlushStdout();
2055     }
2056 }
2057
2058 /* --------------------------------------------------------------------------
2059  * Error handling:
2060  * ------------------------------------------------------------------------*/
2061
2062 Void errHead(l)                        /* print start of error message     */
2063 Int l; {
2064     failed();                          /* failed to reach target ...       */
2065     stopAnyPrinting();
2066     FPrintf(errorStream,"ERROR");
2067
2068     if (scriptFile) {
2069         FPrintf(errorStream," \"%s\"", scriptFile);
2070         setLastEdit(scriptFile,l);
2071         if (l) FPrintf(errorStream," (line %d)",l);
2072         scriptFile = 0;
2073     }
2074     FPrintf(errorStream,": ");
2075     FFlush(errorStream);
2076 }
2077
2078 Void errFail() {                        /* terminate error message and     */
2079     Putc('\n',errorStream);             /* produce exception to return to  */
2080     FFlush(errorStream);                /* main command loop               */
2081     longjmp(catch_error,1);
2082 }
2083
2084 Void errAbort() {                       /* altern. form of error handling  */
2085     failed();                           /* used when suitable error message*/
2086     stopAnyPrinting();                  /* has already been printed        */
2087     errFail();
2088 }
2089
2090 Void internal(msg)                      /* handle internal error           */
2091 String msg; {
2092 #if HUGS_FOR_WINDOWS
2093     char buf[300];
2094     wsprintf(buf,"INTERNAL ERROR: %s",msg);
2095     MessageBox(hWndMain, buf, appName, MB_ICONHAND | MB_OK);
2096 #endif
2097     failed();
2098     stopAnyPrinting();
2099     Printf("INTERNAL ERROR: %s\n",msg);
2100     FlushStdout();
2101     longjmp(catch_error,1);
2102 }
2103
2104 Void fatal(msg)                         /* handle fatal error              */
2105 String msg; {
2106 #if HUGS_FOR_WINDOWS
2107     char buf[300];
2108     wsprintf(buf,"FATAL ERROR: %s",msg);
2109     MessageBox(hWndMain, buf, appName, MB_ICONHAND | MB_OK);
2110 #endif
2111     FlushStdout();
2112     Printf("\nFATAL ERROR: %s\n",msg);
2113     everybody(EXIT);
2114     exit(1);
2115 }
2116
2117 sigHandler(breakHandler) {              /* respond to break interrupt      */
2118 #if HUGS_FOR_WINDOWS
2119     MessageBox(GetFocus(), "Interrupted!", appName, MB_ICONSTOP | MB_OK);
2120 #endif
2121     Hilite();
2122     Printf("{Interrupted!}\n");
2123     Lolite();
2124     breakOn(TRUE);  /* reinstall signal handler - redundant on BSD systems */
2125                     /* but essential on POSIX (and other?) systems         */
2126     everybody(BREAK);
2127     failed();
2128     stopAnyPrinting();
2129     FlushStdout();
2130     clearerr(stdin);
2131     longjmp(catch_error,1);
2132     sigResume;/*NOTREACHED*/
2133 }
2134
2135 /* --------------------------------------------------------------------------
2136  * Read value from environment variable or registry:
2137  * ------------------------------------------------------------------------*/
2138
2139 String fromEnv(var,def)         /* return value of:                        */
2140 String var;                     /*     environment variable named by var   */
2141 String def; {                   /* or: default value given by def          */
2142     String s = getenv(var);     
2143     return (s ? s : def);
2144 }
2145
2146 /* --------------------------------------------------------------------------
2147  * String manipulation routines:
2148  * ------------------------------------------------------------------------*/
2149
2150 static String local strCopy(s)         /* make malloced copy of a string   */
2151 String s; {
2152     if (s && *s) {
2153         char *t, *r;
2154         if ((t=(char *)malloc(strlen(s)+1))==0) {
2155             ERRMSG(0) "String storage space exhausted"
2156             EEND;
2157         }
2158         for (r=t; (*r++ = *s++)!=0; ) {
2159         }
2160         return t;
2161     }
2162     return NULL;
2163 }
2164
2165 /* --------------------------------------------------------------------------
2166  * Compiler output
2167  * We can redirect compiler output (prompts, error messages, etc) by
2168  * tweaking these functions.
2169  * ------------------------------------------------------------------------*/
2170
2171 #if REDIRECT_OUTPUT && !HUGS_FOR_WINDOWS
2172
2173 #ifdef HAVE_STDARG_H
2174 #include <stdarg.h>
2175 #else
2176 #include <varargs.h>
2177 #endif
2178
2179 /* ----------------------------------------------------------------------- */
2180
2181 #define BufferSize 10000              /* size of redirected output buffer  */
2182
2183 typedef struct _HugsStream {
2184     char buffer[BufferSize];          /* buffer for redirected output      */
2185     Int  next;                        /* next space in buffer              */
2186 } HugsStream;
2187
2188 static Void   local vBufferedPrintf  Args((HugsStream*, const char*, va_list));
2189 static Void   local bufferedPutchar  Args((HugsStream*, Char));
2190 static String local bufferClear      Args((HugsStream *stream));
2191
2192 static Void local vBufferedPrintf(stream, fmt, ap)
2193 HugsStream* stream;
2194 const char* fmt;
2195 va_list     ap; {
2196     Int spaceLeft = BufferSize - stream->next;
2197     char* p = &stream->buffer[stream->next];
2198     Int charsAdded = vsnprintf(p, spaceLeft, fmt, ap);
2199     if (0 <= charsAdded && charsAdded < spaceLeft) 
2200         stream->next += charsAdded;
2201 #if 1 /* we can either buffer the first n chars or buffer the last n chars */
2202     else
2203         stream->next = 0;
2204 #endif
2205 }
2206
2207 static Void local bufferedPutchar(stream, c)
2208 HugsStream *stream;
2209 Char        c; {
2210     if (BufferSize - stream->next >= 2) {
2211         stream->buffer[stream->next++] = c;
2212         stream->buffer[stream->next] = '\0';
2213     }
2214 }    
2215
2216 static String local bufferClear(stream)
2217 HugsStream *stream; {
2218     if (stream->next == 0) {
2219         return "";
2220     } else {
2221         stream->next = 0;
2222         return stream->buffer;
2223     }
2224 }
2225
2226 /* ----------------------------------------------------------------------- */
2227
2228 static HugsStream outputStreamH;
2229 /* ADR note: 
2230  * We rely on standard C semantics to initialise outputStreamH.next to 0.
2231  */
2232
2233 Void hugsEnableOutput(f) 
2234 Bool f; {
2235     disableOutput = !f;
2236 }
2237
2238 String hugsClearOutputBuffer() {
2239     return bufferClear(&outputStreamH);
2240 }
2241
2242 #ifdef HAVE_STDARG_H
2243 Void hugsPrintf(const char *fmt, ...) {
2244     va_list ap;                    /* pointer into argument list           */
2245     va_start(ap, fmt);             /* make ap point to first arg after fmt */
2246     if (!disableOutput) {
2247         vprintf(fmt, ap);
2248     } else {
2249         vBufferedPrintf(&outputStreamH, fmt, ap);
2250     }
2251     va_end(ap);                    /* clean up                             */
2252 }
2253 #else
2254 Void hugsPrintf(fmt, va_alist) 
2255 const char *fmt;
2256 va_dcl {
2257     va_list ap;                    /* pointer into argument list           */
2258     va_start(ap);                  /* make ap point to first arg after fmt */
2259     if (!disableOutput) {
2260         vprintf(fmt, ap);
2261     } else {
2262         vBufferedPrintf(&outputStreamH, fmt, ap);
2263     }
2264     va_end(ap);                    /* clean up                             */
2265 }
2266 #endif
2267
2268 Void hugsPutchar(c)
2269 int c; {
2270     if (!disableOutput) {
2271         putchar(c);
2272     } else {
2273         bufferedPutchar(&outputStreamH, c);
2274     }
2275 }
2276
2277 Void hugsFlushStdout() {
2278     if (!disableOutput) {
2279         fflush(stdout);
2280     }
2281 }
2282
2283 Void hugsFFlush(fp)
2284 FILE* fp; {
2285     if (!disableOutput) {
2286         fflush(fp);
2287     }
2288 }
2289
2290 #ifdef HAVE_STDARG_H
2291 Void hugsFPrintf(FILE *fp, const char* fmt, ...) {
2292     va_list ap;             
2293     va_start(ap, fmt);      
2294     if (!disableOutput) {
2295         vfprintf(fp, fmt, ap);
2296     } else {
2297         vBufferedPrintf(&outputStreamH, fmt, ap);
2298     }
2299     va_end(ap);             
2300 }
2301 #else
2302 Void hugsFPrintf(FILE *fp, const char* fmt, va_list)
2303 FILE* fp;
2304 const char* fmt;
2305 va_dcl {
2306     va_list ap;             
2307     va_start(ap);      
2308     if (!disableOutput) {
2309         vfprintf(fp, fmt, ap);
2310     } else {
2311         vBufferedPrintf(&outputStreamH, fmt, ap);
2312     }
2313     va_end(ap);             
2314 }
2315 #endif
2316
2317 Void hugsPutc(c, fp)
2318 int   c;
2319 FILE* fp; {
2320     if (!disableOutput) {
2321         putc(c,fp);
2322     } else {
2323         bufferedPutchar(&outputStreamH, c);
2324     }
2325 }
2326     
2327 #endif /* REDIRECT_OUTPUT && !HUGS_FOR_WINDOWS */
2328 /* --------------------------------------------------------------------------
2329  * Send message to each component of system:
2330  * ------------------------------------------------------------------------*/
2331
2332 Void everybody(what)            /* send command `what' to each component of*/
2333 Int what; {                     /* system to respond as appropriate ...    */
2334     machdep(what);              /* The order of calling each component is  */
2335     storage(what);              /* important for the INSTALL command       */
2336     substitution(what);
2337     input(what);
2338     translateControl(what);
2339     linkControl(what);
2340     staticAnalysis(what);
2341     deriveControl(what);
2342     typeChecker(what);
2343     compiler(what);   
2344     codegen(what);
2345     optimiser(what);
2346 }
2347
2348 /* --------------------------------------------------------------------------
2349  * Hugs for Windows code (WinMain and related functions)
2350  * ------------------------------------------------------------------------*/
2351
2352 #if HUGS_FOR_WINDOWS
2353 #include "winhugs.c"
2354 #endif