/* -------------------------------------------------------------------------- * hugs.c: Copyright (c) Mark P Jones 1991-1998. All rights reserved. * See NOTICE for details and conditions of use etc... * Hugs version 1.3b, January 1998 * * Command interpreter * ------------------------------------------------------------------------*/ #include "prelude.h" #include "storage.h" #include "command.h" #include "connect.h" #include "errors.h" #include #include /* -------------------------------------------------------------------------- * Local function prototypes: * ------------------------------------------------------------------------*/ static Void local initialize Args((Int,String [])); static Void local interpreter Args((Int,String [])); static Void local menu Args((Void)); static Void local guidance Args((Void)); static Void local forHelp Args((Void)); static Void local set Args((Void)); static Void local changeDir Args((Void)); static Void local load Args((Void)); static Void local project Args((Void)); static Void local readScripts Args((Int)); static Void local whatFiles Args((Void)); static Void local editor Args((Void)); static Void local find Args((Void)); static Void local runEditor Args((Void)); static Void local evaluator Args((Void)); static Void local stopAnyPrinting Args((Void)); static Void local showtype Args((Void)); static Void local info Args((Void)); static Void local showInst Args((Inst)); static Void local describe Args((Text)); static Void local listNames Args((Void)); static Void local toggleSet Args((Char,Bool)); static Void local togglesIn Args((Bool)); static Void local optionInfo Args((Void)); static Bool local processOption Args((String)); static Int local argToInt Args((String)); static Void local loadProject Args((String)); static Void local clearProject Args((Void)); static Void local addScriptName Args((String,Bool)); static Bool local addScript Args((String,Long)); static Void local forgetScriptsFrom Args((Module)); static Void local setLastEdit Args((String,Int)); static Void local failed Args((Void)); static String local strCopy Args((String)); /* -------------------------------------------------------------------------- * Machine dependent code for Hugs interpreter: * ------------------------------------------------------------------------*/ #include "machdep.c" #ifdef WANT_TIMER #include "timer.c" #endif /* -------------------------------------------------------------------------- * Local data areas: * ------------------------------------------------------------------------*/ static Bool printing = FALSE; /* TRUE => currently printing value*/ static Bool showStats = FALSE; /* TRUE => print stats after eval */ static Bool listFiles = TRUE; /* TRUE => list files after loading*/ static Bool addType = FALSE; /* TRUE => print type with value */ static Bool useShow = TRUE; /* TRUE => use Text/show printer */ static Bool chaseImports = TRUE; /* TRUE => chase imports on load */ static Bool useDots = RISCOS; /* TRUE => use dots in progress */ static String scriptName[NUM_SCRIPTS]; /* Script file names */ static Time lastChange[NUM_SCRIPTS]; /* Time of last change to file */ static Bool postponed[NUM_SCRIPTS]; /* Indicates postponed load */ /* static */ Int numScripts; /* Number of scripts loaded */ static Int namesUpto; /* Number of script names set */ static Bool needsImports; /* set to TRUE if imports required */ static String scriptFile; /* Name of current script (if any) */ static String currProject = 0; /* Name of current project file */ static Bool projectLoaded = FALSE; /* TRUE => project file loaded */ static String lastEdit = 0; /* Name of file to edit (if any) */ static Int lastLine = 0; /* Editor line number (if possible)*/ static String prompt = 0; /* Prompt string */ String hugsEdit = 0; /* String for editor command */ String hugsPath = 0; /* String for file search path */ /* -------------------------------------------------------------------------- * Hugs entry point: * ------------------------------------------------------------------------*/ #ifndef NO_MAIN /* we omit main when building rohugs */ Main main Args((Int, String [])); /* now every func has a prototype */ Main main(argc,argv) int argc; char *argv[]; { gArgc = argc; gArgv = argv; CStackBase = &argc; /* Save stack base for use in gc */ /* The startup banner now includes my name. Hugs is provided free of */ /* charge. I ask however that you show your appreciation for the many */ /* hours of work involved by retaining my name in the banner. Thanks! */ printf(" __ , ___ ___ ___ ___ __________ __________\n"); printf("/_/ / / / / / / / / / _______/ / _______/ The O'Haskell User's\n"); printf(" / /___/ / / / / / / / _____ / /______ Gofer System\n"); printf(" / ____ / / / / / / / /_ / /______ /\n"); printf(" / / / / / /___/ / / /___/ / _______/ / Version 0.5\n"); printf(" /__/ /__/ /_________/ /_________/ /_________/ Jan 2001\n\n"); printf(" Copyright (c) Mark P Jones, Johan Nordlander,\n"); printf(" Bj"OE"rn von Sydow, Magnus Carlsson,\n"); printf(" Oregon Graduate Institute, Chalmers University of Technology, 1994-2001.\n\n"); fflush(stdout); interpreter(argc,argv); printf("[Leaving O'Hugs]\n"); everybody(EXIT); exit(0); MainDone } #endif /* -------------------------------------------------------------------------- * Initialization, interpret command line args and read prelude: * ------------------------------------------------------------------------*/ static Void local initialize(argc,argv)/* Interpreter initialization */ Int argc; String argv[]; { Module i; String proj = 0; setLastEdit((String)0,0); lastEdit = 0; scriptFile = 0; numScripts = 0; namesUpto = 1; #if MACWP hugsPath = strCopy("{OHUGS}lib;{OHUGS}libhugs"); prompt = strCopy("? "); repeatStr = strCopy("$$"); #else #if !MSWIN hugsPath = strCopy(fromEnv("OHUGSPATH",NULL)); hugsEdit = strCopy(fromEnv("OHUGSEDIT",fromEnv("EDITOR",NULL))); prompt = strCopy("? "); repeatStr = strCopy("$$"); #endif #endif for (i=1; i1) fprintf(stderr, "\nUsing project file, ignoring additional filenames\n"); loadProject(strCopy(proj)); } readScripts(0); } /* -------------------------------------------------------------------------- * Command line options: * ------------------------------------------------------------------------*/ struct options { /* command line option toggles */ char c; /* table defined in main app. */ String description; Bool *flag; }; extern struct options toggle[]; static Void local toggleSet(c,state) /* Set command line toggle */ Char c; Bool state; { Int i; for (i=0; toggle[i].c; ++i) if (toggle[i].c == c) { *toggle[i].flag = state; return; } ERRMSG(0) "Unknown toggle `%c'", c EEND; } static Void local togglesIn(state) /* Print current list of toggles in*/ Bool state; { /* given state */ Int count = 0; Int i; for (i=0; toggle[i].c; ++i) if (*toggle[i].flag == state) { if (count==0) putchar(state ? '+' : '-'); putchar(toggle[i].c); count++; } if (count>0) putchar(' '); } static Void local optionInfo() { /* Print information about command */ static String fmts = "%-5s%s\n"; /* line settings */ static String fmtc = "%-5c%s\n"; Int i; printf("TOGGLES: groups begin with +/- to turn options on/off resp.\n"); for (i=0; toggle[i].c; ++i) printf(fmtc,toggle[i].c,toggle[i].description); printf("\nOTHER OPTIONS: (leading + or - makes no difference)\n"); printf(fmts,"hnum","Set heap size (cannot be changed within O'Hugs)"); printf(fmts,"pstr","Set prompt string to str"); printf(fmts,"rstr","Set repeat last expression string to str"); printf(fmts,"Pstr","Set search path for script files to str"); printf(fmts,"Estr","Use editor setting given by str"); printf("\nCurrent settings: "); togglesIn(TRUE); togglesIn(FALSE); printf("-h%d",heapSize); printf(" -p"); printString(prompt); printf(" -r"); printString(repeatStr); printf("\nSearch path : -P"); printString(hugsPath); printf("\nEditor setting : -E"); printString(hugsEdit); putchar('\n'); } static Bool local processOption(s) /* process string s for options, */ String s; { /* return FALSE if none found. */ Bool state; if (s[0]=='-') state = FALSE; else if (s[0]=='+') state = TRUE; else return FALSE; while (*++s) switch (*s) { case 'p' : if (s[1]) { if (prompt) free(prompt); prompt = strCopy(s+1); } return TRUE; case 'r' : if (s[1]) { if (repeatStr) free(repeatStr); repeatStr = strCopy(s+1); } return TRUE; case 'P' : if (hugsPath) free(hugsPath); hugsPath = strCopy(s+1); return TRUE; case 'E' : if (hugsEdit) free(hugsEdit); hugsEdit = strCopy(s+1); return TRUE; case 'h' : if (heapBuilt()) { ERRMSG(0) "Cannot change heap size" EEND; } heapSize = argToInt(s); if (heapSizeMAXIMUMHEAP) heapSize = MAXIMUMHEAP; return TRUE; default : toggleSet(*s,state); break; } return TRUE; } static Int local argToInt(s) /* read integer from argument str */ String s; { Int n = 0; String t = s++; if (*s=='\0' || !isascii(*s) || !isdigit(*s)) { ERRMSG(0) "Missing integer in option setting \"%s\"", t EEND; } do { Int d = (*s++) - '0'; if (n > ((MAXPOSINT - d)/10)) { ERRMSG(0) "Option setting \"%s\" is too large", t EEND; } n = 10*n + d; } while (isascii(*s) && isdigit(*s)); if (*s=='K' || *s=='k') { if (n > (MAXPOSINT/1000)) { ERRMSG(0) "Option setting \"%s\" is too large", t EEND; } n *= 1000; s++; } if (*s!='\0') { ERRMSG(0) "Unwanted characters after option setting \"%s\"", t EEND; } return n; } /* -------------------------------------------------------------------------- * Print Menu of list of commands: * ------------------------------------------------------------------------*/ static struct cmd cmds[] = { {":?", HELP}, {":cd", CHGDIR}, {":also", ALSO}, {":type", TYPEOF}, {":!", SYSTEM}, {":load", LOAD}, {":reload", RELOAD}, {":gc", COLLECT}, {":edit", EDIT}, {":quit", QUIT}, {":set", SET}, {":find", FIND}, {":names", NAMES}, {":info", INFO}, {":project", PROJECT}, {"", EVAL}, {0,0} }; static Void local menu() { printf("LIST OF COMMANDS: Any command may be abbreviated to :c where\n"); printf("c is the first character in the full name.\n\n"); printf(":load load scripts from specified files\n"); printf(":load clear all files except prelude\n"); printf(":also read additional script files\n"); printf(":reload repeat last load command\n"); printf(":project use project file\n"); printf(":edit edit file\n"); printf(":edit edit last file\n"); printf(" evaluate expression\n"); printf(":type print type of expression\n"); printf(":? display this list of commands\n"); printf(":set set command line options\n"); printf(":set help on command line options\n"); printf(":names [pat] list names currently in scope\n"); printf(":info describe named objects\n"); printf(":find edit file containing definition of name\n"); printf(":!command shell escape\n"); printf(":cd dir change directory\n"); printf(":gc force garbage collection\n"); printf(":quit exit O'Hugs interpreter\n"); } static Void local guidance() { printf("Command not recognised. "); forHelp(); } static Void local forHelp() { printf("Type :? for help\n"); } /* -------------------------------------------------------------------------- * Setting of command line options: * ------------------------------------------------------------------------*/ struct options toggle[] = { /* List of command line toggles */ {'s', "Print no. reductions/cells after eval", &showStats}, {'t', "Print type after evaluation", &addType}, {'f', "Terminate evaluation on first error", &failOnError}, {'g', "Print no. cells recovered after gc", &gcMessages}, {'l', "Literate scripts as default", &literateScripts}, {'e', "Warn about errors in literate scripts", &literateErrors}, {'.', "Print dots to show progress", &useDots}, {'w', "Always show which files loaded", &listFiles}, {'k', "Show kind errors in full", &kindExpert}, {'u', "Use \"show\" to display results", &useShow}, {'i', "Chase imports while loading files", &chaseImports}, {0, 0, 0} }; static Void local set() { /* change command line options from*/ String s; /* Hugs command line */ if (s=readFilename()) { do { if (!processOption(s)) { ERRMSG(0) "Option string must begin with `+' or `-'" EEND; } } while (s=readFilename()); } else optionInfo(); } /* -------------------------------------------------------------------------- * Change directory command: * ------------------------------------------------------------------------*/ static Void local changeDir() { /* change directory */ String s = readFilename(); if (s && chdir(s)) { ERRMSG(0) "Unable to change to directory \"%s\"", s EEND; } } /* -------------------------------------------------------------------------- * Loading project and script files: * ------------------------------------------------------------------------*/ static Void local loadProject(s) /* Load project file */ String s; { clearProject(); currProject = s; projInput(currProject); scriptFile = currProject; forgetScriptsFrom(1); while (s=readFilename()) addScriptName(s,TRUE); if (namesUpto<=1) { ERRMSG(0) "Empty project file" EEND; } scriptFile = 0; projectLoaded = TRUE; } static Void local clearProject() { /* clear name for current project */ if (currProject) free(currProject); currProject = 0; projectLoaded = FALSE; #if MSWIN setLastEdit((String)0,0); #endif } static Void local addScriptName(s,sch) /* Add script to list of files */ String s; /* to be read in ... */ Bool sch; { /* TRUE => requires pathname search*/ if (namesUpto>=NUM_SCRIPTS) { ERRMSG(0) "Too many script files (maximum of %d allowed)", NUM_SCRIPTS EEND; } else scriptName[namesUpto++] = strCopy(sch ? findPathname(NULL,s) : s); } static Bool local addScript(fname,len) /* read single script file */ String fname; /* name of script file */ Long len; { /* length of script file */ scriptFile = fname; #if MSWIN /* Set clock cursor while loading */ allowBreak(); SetCursor(LoadCursor(NULL, IDC_WAIT)); #endif #ifndef NO_MAIN printf("Reading script file \"%s\":\n",fname); #endif setLastEdit(fname,0); needsImports = FALSE; parseScript(fname,len); /* process script file */ if (needsImports) return FALSE; checkDefns(); typeCheckDefns(); compileDefns(); scriptFile = 0; return TRUE; } Bool chase(imps) /* Process list of import requests */ List imps; { if (chaseImports) { Int origPos = numScripts; /* keep track of original position */ String origName = scriptName[origPos]; for (; nonNull(imps); imps=tl(imps)) { String iname = findPathname(origName,textToStr(textOf(hd(imps)))); Int i = 0; for (; i=origPos) { /* Neither loaded or queued */ String theName; Time theTime; Bool thePost; postponed[origPos] = TRUE; needsImports = TRUE; if (i>=namesUpto) /* Name not found (i==namesUpto) */ addScriptName(iname,FALSE); else if (postponed[i]) {/* Check for recursive dependency */ ERRMSG(0) "Recursive import dependency between \"%s\" and \"%s\"", scriptName[origPos], iname EEND; } /* Right rotate section of tables between numScripts and i so * that i ends up with other imports in front of orig. script */ theName = scriptName[i]; thePost = postponed[i]; timeSet(theTime,lastChange[i]); for (; i>numScripts; i--) { scriptName[i] = scriptName[i-1]; postponed[i] = postponed[i-1]; timeSet(lastChange[i],lastChange[i-1]); } scriptName[numScripts] = theName; postponed[numScripts] = thePost; timeSet(lastChange[numScripts],theTime); origPos++; } } return needsImports; } return FALSE; } static Void local forgetScriptsFrom(scno)/* remove scripts from system */ Module scno; { Module i; for (i=scno; inamesUpto) numScripts = scno; } /* -------------------------------------------------------------------------- * Commands for loading and removing script files: * ------------------------------------------------------------------------*/ static Void local load() { /* read filenames from command line */ String s; /* and add to list of files waiting */ /* to be read */ while (s=readFilename()) addScriptName(s,TRUE); readScripts(1); } static Void local project() { /* read list of file names from */ String s; /* project file */ if ((s=readFilename()) || currProject) { if (!s) s = strCopy(currProject); else if (readFilename()) { ERRMSG(0) "Too many project files" EEND; } else s = strCopy(s); } else { ERRMSG(0) "No project filename specified" EEND; } loadProject(s); readScripts(1); } static Void local readScripts(n) /* Reread current list of scripts, */ Int n; { /* loading everything after and */ Time timeStamp; /* including the first script which*/ Long fileSize; /* has been either changed or added*/ #if MSWIN SetCursor(LoadCursor(NULL, IDC_WAIT)); #endif for (; n0) /* no new module for prelude */ startNewModule(); if (addScript(scriptName[numScripts],fileSize)) numScripts++; else dropModulesFrom(numScripts-1); } if (listFiles) whatFiles(); if (numScripts<=1) setLastEdit((String)0, 0); } static Void local whatFiles() { /* list files in current session */ int i; printf("\nO'Hugs session for:"); if (projectLoaded) printf(" (project: %s)",currProject); for (i=0; i0) printf(", %u garbage collection%s",plural(numberGcs)); printf(")\n"); #undef plural } fflush(stdout); } } /* -------------------------------------------------------------------------- * Print type of input expression: * ------------------------------------------------------------------------*/ static Void local showtype() { /* print type of expression (if any)*/ Cell type; startNewModule(); /* Enables recovery of storage */ /* allocated during evaluation */ parseExp(); checkExp(); defaultDefns = evalDefaults; type = typeCheckExp(FALSE); printExp(stdout,inputExpr); printf(" :: "); printType(stdout,type); putchar('\n'); } /* -------------------------------------------------------------------------- * Enhanced help system: print current list of scripts or give information * about an object. * ------------------------------------------------------------------------*/ static Void local info() { /* describe objects */ Int count = 0; /* or give menu of commands */ String s; startNewModule(); /* for recovery of storage */ for (; s=readFilename(); count++) describe(findText(s)); if (count == 0) whatFiles(); } static Void local describe(t) /* describe an object */ Text t; { Tycon tc = findTycon(t); Class cl = findClass(t); Name nm = findName(t); if (nonNull(tc)) { /* as a type constructor */ Type t = satTycon(tc); Inst in; printf("-- type constructor"); if (kindExpert) { printf(" (kind "); printKind(stdout,tycon(tc).kind); putchar(')'); } if (nonNull(tycon(tc).variance)) { printf(" (variance "); printVariance(stdout,tycon(tc).variance); putchar(')'); } putchar('\n'); switch (tycon(tc).what) { case SYNONYM : printf("type "); printType(stdout,t); printf(" = "); printType(stdout,tycon(tc).defn); break; case STRUCTTYPE : case NEWTYPE : case DATATYPE : { List cs; List axs = tycon(tc).axioms; if (tycon(tc).what==DATATYPE) printf("data "); else if (tycon(tc).what==STRUCTTYPE) printf("struct "); else printf("newtype "); printType(stdout,t); printAxioms(stdout,tc); if (tycon(tc).what==STRUCTTYPE) printf("\n\n-- selectors:"); else printf("\n\n-- constructors:"); for (; nonNull(axs); axs=tl(axs)) { Tycon h = getHead(monoType(hd(axs))); for (cs=tycon(h).defn; nonNull(cs); cs=tl(cs)) { putchar('\n'); printExp(stdout,hd(cs)); printf(" :: "); printType(stdout,liftedType(hd(cs),tc)); } } for (cs=tycon(tc).defn; nonNull(cs); cs=tl(cs)) { putchar('\n'); printExp(stdout,hd(cs)); printf(" :: "); printType(stdout,name(hd(cs)).type); } } break; case PRIMTYPE : printf("type "); printType(stdout,t); printAxioms(stdout,tc); printf(" -- primitive"); break; case RESTRICTSYN : printf("type "); printType(stdout,t); printf(" = "); break; } putchar('\n'); if (nonNull(in=findFirstInst(tc))) { printf("\n-- instances:\n"); do { showInst(in); in = findNextInst(tc,in); } while (nonNull(in)); } putchar('\n'); } if (nonNull(cl)) { /* as a class */ List ins = cclass(cl).instances; if (cclass(cl).sig==STAR) printf("-- type class"); else { printf("-- constructor class"); if (kindExpert) { printf(" with instances of kind "); printKind(stdout,cclass(cl).sig); } } printf("\nclass "); if (nonNull(cclass(cl).supers)) { List cs = cclass(cl).supers; if (nonNull(tl(cs))) { putchar('('); for (;;) { printf("%s a",textToStr(cclass(hd(cs)).text)); if (nonNull(cs=tl(cs))) printf(", "); else break; } putchar(')'); } else printf("%s a",textToStr(cclass(hd(cs)).text)); printf(" => "); } printf("%s a",textToStr(cclass(cl).text)); if (nonNull(cclass(cl).members)) { List ms = cclass(cl).members; printf(" where"); do { Type t = monoTypeOf(name(hd(ms)).type); printf("\n "); printExp(stdout,hd(ms)); printf(" :: "); if (isNull(tl(fst(snd(t))))) t = snd(snd(t)); else t = ap(QUAL,pair(tl(fst(snd(t))),snd(snd(t)))); printType(stdout,t); ms = tl(ms); } while (nonNull(ms)); } putchar('\n'); if (nonNull(ins)) { printf("\n-- instances:\n"); do { showInst(hd(ins)); ins = tl(ins); } while (nonNull(ins)); } putchar('\n'); } if (nonNull(nm)) { /* as a function/name */ printExp(stdout,nm); printf(" :: "); if (nonNull(name(nm).type)) { /* we have to run the type checker */ inputExpr = nm; /* to convert GTC type to HTC form */ printType(stdout,typeCheckExp(FALSE)); } else printf(""); if (isCfun(nm) && isStructSel(nm)) printf(" -- struct selector"); else if (isCfun(nm)) printf(" -- data constructor"); else if (isMfun(nm)) printf(" -- class member"); if (name(nm).primDef) printf(" -- primitive"); printf("\n\n"); } if (isalpha(textToStr(t)[0]) && nonNull(findName(mkStructSel(t)))) describe(mkStructSel(t)); else if (isNull(tc) && isNull(cl) && isNull(nm)) { printf("Unknown reference `%s'\n",textToStr(t)); } } static Void local showInst(in) /* Display instance decl header */ Inst in; { printf("instance "); if (nonNull(inst(in).specifics)) { printContext(stdout,inst(in).specifics); printf(" => "); } printPred(stdout,makeInstPred(in)); putchar('\n'); } /* -------------------------------------------------------------------------- * List all names currently in scope: * ------------------------------------------------------------------------*/ static Void local listNames() { /* list names matching optional pat*/ String pat = readFilename(); List names = NIL; Int width = getTerminalWidth() - 1; Int count = 0; Int termPos; if (pat) /* First gather names to list */ do names = addNamesMatching(pat,names); while (pat=readFilename()); else names = addNamesMatching((String)0,names); if (isNull(names)) { /* Then print them out */ ERRMSG(0) "No names selected" EEND; } for (termPos=0; nonNull(names); names=tl(names)) { String s = textToStr(name(hd(names)).text); Int l = strlen(s); if (termPos+1+l>width) { putchar('\n'); termPos = 0; } else if (termPos>0) { putchar(' '); termPos++; } printf("%s",s); termPos += l; count++; } printf("\n(%d names listed)\n", count); } /* -------------------------------------------------------------------------- * main read-eval-print loop, with error trapping: * ------------------------------------------------------------------------*/ static jmp_buf catch_error; /* jump buffer for error trapping */ static Void local interpreter(argc,argv)/* main interpreter loop */ Int argc; String argv[]; { Int errorNumber = setjmp(catch_error); breakOn(TRUE); /* enable break trapping */ if (numScripts==0) { /* only succeeds on first time, */ if (errorNumber) /* before prelude has been loaded */ fatal("Unable to load prelude"); initialize(argc,argv); forHelp(); } for (;;) { Command cmd; everybody(RESET); /* reset to sensible initial state */ dropModulesFrom(numScripts-1); /* remove partially loaded scripts */ /* not counting prelude as a module*/ consoleInput(prompt); cmd = readCommand(cmds, (Char)':', (Char)'!'); #ifdef WANT_TIMER updateTimers(); #endif switch (cmd) { case EDIT : editor(); break; case FIND : find(); break; case LOAD : clearProject(); forgetScriptsFrom(1); load(); break; case ALSO : clearProject(); forgetScriptsFrom(numScripts); load(); break; case RELOAD : readScripts(1); break; case PROJECT: project(); break; case EVAL : evaluator(); break; case TYPEOF : showtype(); break; case NAMES : listNames(); break; case HELP : menu(); break; case BADCMD : guidance(); break; case SET : set(); break; case SYSTEM : shellEsc(readLine()); break; case CHGDIR : changeDir(); break; case INFO : info(); break; case QUIT : return; case COLLECT: consGC = FALSE; garbageCollect(); consGC = TRUE; printf("Garbage collection recovered %d cells\n", cellsRecovered); break; case NOCMD : break; } #ifdef WANT_TIMER updateTimers(); printf("Elapsed time (ms): %ld (user), %ld (system)\n", millisecs(userElapsed), millisecs(systElapsed)); #endif } } /* -------------------------------------------------------------------------- * Display progress towards goal: * ------------------------------------------------------------------------*/ static Target currTarget; static Bool aiming = FALSE; static Int currPos; static Int maxPos; static Int charCount; Void setGoal(what, t) /* Set goal for what to be t */ String what; Target t; { #ifdef NO_MAIN return; #endif currTarget = (t?t:1); aiming = TRUE; if (useDots) { currPos = strlen(what); maxPos = getTerminalWidth() - 1; printf("%s",what); } else for (charCount=0; *what; charCount++) putchar(*what++); fflush(stdout); } Void soFar(t) /* Indicate progress towards goal */ Target t; { /* has now reached t */ #ifdef NO_MAIN return; #endif if (useDots) { Int newPos = (Int)((maxPos * ((long)t))/currTarget); if (newPos>maxPos) newPos = maxPos; if (newPos>currPos) { do putchar('.'); while (newPos>++currPos); fflush(stdout); } fflush(stdout); } } Void done() { /* Goal has now been achieved */ #ifdef NO_MAIN return; #endif if (useDots) { while (maxPos>currPos++) putchar('.'); putchar('\n'); aiming = FALSE; } else for (; charCount>0; charCount--) { putchar('\b'); putchar(' '); putchar('\b'); } fflush(stdout); } static Void local failed() { /* Goal cannot be reached due to */ if (aiming) { /* errors */ aiming = FALSE; putchar('\n'); fflush(stdout); } } /* -------------------------------------------------------------------------- * Error handling: * ------------------------------------------------------------------------*/ Void errHead(l) /* print start of error message */ Int l; { failed(); /* failed to reach target ... */ stopAnyPrinting(); fprintf(errorStream,"ERROR"); if (scriptFile) { fprintf(errorStream," \"%s\"", scriptFile); setLastEdit(scriptFile,l); if (l) fprintf(errorStream," (line %d)",l); scriptFile = 0; } fprintf(errorStream,": "); fflush(errorStream); } Void errFail() { /* terminate error message and */ putc('\n',errorStream); /* produce exception to return to */ fflush(errorStream); /* main command loop */ longjmp(catch_error,1); } Void errAbort() { /* altern. form of error handling */ failed(); /* used when suitable error message*/ stopAnyPrinting(); /* has already been printed */ errFail(); } Void internal(msg) /* handle internal error */ String msg; { #if MSWIN char buf[300]; wsprintf(buf,"INTERNAL ERROR: %s",msg); MessageBox(hWndMain, buf, appName, MB_ICONHAND | MB_OK); #endif failed(); stopAnyPrinting(); fprintf(errorStream,"INTERNAL ERROR: %s\n",msg); fflush(errorStream); longjmp(catch_error,1); } Void fatal(msg) /* handle fatal error */ String msg; { #if MSWIN char buf[300]; wsprintf(buf,"FATAL ERROR: %s",msg); MessageBox(hWndMain, buf, appName, MB_ICONHAND | MB_OK); #endif fflush(stdout); printf("\nFATAL ERROR: %s\n",msg); everybody(EXIT); exit(1); } sigHandler(breakHandler) { /* respond to break interrupt */ #ifdef NO_MAIN fprintf(stderr,"Interrupted!\n"); doexit(1); #endif #if MSWIN MessageBox(GetFocus(), "Interrupted!", appName, MB_ICONSTOP | MB_OK); #endif Hilite printf("{Interrupted!}\n"); Lolite breakOn(TRUE); everybody(BREAK); failed(); stopAnyPrinting(); fflush(stdout); longjmp(catch_error,1); sigResume;/*NOTREACHED*/ } /* -------------------------------------------------------------------------- * Read value from environment variable: * ------------------------------------------------------------------------*/ String fromEnv(var,def) /* return value of: */ String var; /* environment variable named by var */ String def; { /* or: default value given by def */ String s = getenv(var); return (s ? s : def); } /* -------------------------------------------------------------------------- * String manipulation routines: * ------------------------------------------------------------------------*/ static String local strCopy(s) /* make malloced copy of a string */ String s; { if (s && *s) { char *t, *r; if ((t=(char *)malloc(strlen(s)+1))==0) { ERRMSG(0) "String storage space exhausted" EEND; } for (r=t; *r++ = *s++; ) ; return t; } return NULL; } /* -------------------------------------------------------------------------- * Send message to each component of system: * ------------------------------------------------------------------------*/ Void everybody(what) /* send command `what' to each component of*/ Int what; { /* system to respond as appropriate ... */ machdep(what); /* The order of calling each component is */ storage(what); /* important for the INSTALL command */ input(what); staticAnalysis(what); typeChecker(what); compiler(what); machine(what); builtIn(what); } /*-------------------------------------------------------------------------*/