| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007 |
- MODULE Shell ;
- (* TP3 main-menu shell. Draws the Turbo Pascal 3.0 screen with ANSI
- escapes and dispatches on the same command letters as the original
- (TPSRC4 kmenu / kcmdtab). Editor, compiler and interpreter are
- placeholders for now; the shell logic (files, directory, options,
- save/load with .BAK) mirrors the original closely. *)
- FROM Term IMPORT
- Open, Close, ClrScr, GotoXY, PutCh, PutStr, PutCard, PutLongCard,
- ScrnWide, Marked, Normal, GetCh, Beep ;
- FROM Posix IMPORT
- read, write, open, close, unlink, rename,
- getcwd, chdir, opendir, readdir, closedir, statvfs,
- Dir, dirent, statvfsbuf ;
- FROM Compiler IMPORT Compile, CodeBytes, DataBytes, ImageBytes, ImageByteAt ;
- FROM Linker IMPORT LinkSize, WriteCom ;
- FROM Editor IMPORT Run, GotoOffset ;
- FROM TextBuf IMPORT
- TextLimit, Clear, Length, CharAt, InsertCh ;
- (* The 86 suffix on these three is not decoration: ISO Modula-2 has neither
- import renaming nor a procedure-local import, so every import in this
- module shares one flat namespace, and `Clear' and `Run' were already
- TextBuf's and Editor's. Exec86.def's header records the same fact from
- the other side. *)
- FROM Exec86 IMPORT Clear86, Poke86, Run86 ;
- FROM SYSTEM IMPORT ADR, ADDRESS, BYTE ;
- CONST
- O_RDONLY = 0 ; (* linux *)
- VAR
- drive : CHAR ;
- workName : ARRAY [0..255] OF CHAR ;
- mainName : ARRAY [0..255] OF CHAR ;
- changed : BOOLEAN ;
- codeDest : CARDINAL ; (* 0=Memory, 1=COM, 2=CHN *)
- errNo, errPos : CARDINAL ;
- minCode, minData, minStack, maxStack : CARDINAL ;
- paramLine : ARRAY [0..255] OF CHAR ;
- (* ------------------------------------------------------------------ *)
- (* string helpers *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE StrLen (VAR s : ARRAY OF CHAR) : CARDINAL ;
- VAR i : CARDINAL ;
- BEGIN
- i := 0 ;
- WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO
- INC (i)
- END ;
- RETURN i
- END StrLen ;
- PROCEDURE StrClear (VAR s : ARRAY OF CHAR) ;
- BEGIN
- s [0] := 0C
- END StrClear ;
- PROCEDURE StrCopy (VAR dst : ARRAY OF CHAR ; src : ARRAY OF CHAR) ;
- VAR i : CARDINAL ;
- BEGIN
- i := 0 ;
- LOOP
- IF i > HIGH (dst) THEN
- dst [HIGH (dst)] := 0C ;
- EXIT
- END ;
- IF i > HIGH (src) THEN
- dst [i] := 0C ;
- EXIT
- END ;
- IF src [i] = 0C THEN
- dst [i] := 0C ;
- EXIT
- END ;
- dst [i] := src [i] ;
- INC (i)
- END
- END StrCopy ;
- PROCEDURE StrAppend (VAR dst : ARRAY OF CHAR ; suffix : ARRAY OF CHAR) ;
- VAR i, j : CARDINAL ;
- BEGIN
- i := StrLen (dst) ;
- j := 0 ;
- LOOP
- IF i > HIGH (dst) THEN
- EXIT
- END ;
- IF j > HIGH (suffix) THEN
- dst [i] := 0C ;
- EXIT
- END ;
- IF suffix [j] = 0C THEN
- dst [i] := 0C ;
- EXIT
- END ;
- dst [i] := suffix [j] ;
- INC (i) ;
- INC (j)
- END
- END StrAppend ;
- PROCEDURE StrEq (VAR a, b : ARRAY OF CHAR) : BOOLEAN ;
- VAR i : CARDINAL ;
- BEGIN
- i := 0 ;
- LOOP
- IF (i > HIGH (a)) OR (i > HIGH (b)) THEN
- RETURN FALSE
- END ;
- IF (a [i] = 0C) AND (b [i] = 0C) THEN
- RETURN TRUE
- END ;
- IF a [i] # b [i] THEN
- RETURN FALSE
- END ;
- INC (i)
- END ;
- RETURN FALSE
- END StrEq ;
- PROCEDURE Upper (ch : CHAR) : CHAR ;
- BEGIN
- IF (ch >= "a") AND (ch <= "z") THEN
- RETURN CHR (ORD (ch) - (ORD ("a") - ORD ("A")))
- END ;
- RETURN ch
- END Upper ;
- PROCEDURE CrLf ;
- BEGIN
- PutCh (CHR (13)) ;
- PutCh (CHR (10))
- END CrLf ;
- PROCEDURE GetCwd (VAR buf : ARRAY OF CHAR) ;
- VAR i : CARDINAL ;
- BEGIN
- IF getcwd (ADR (buf), 4096) = NIL THEN
- buf [0] := 0C
- END
- END GetCwd ;
- (* ------------------------------------------------------------------ *)
- (* marks one command letter then prints the rest of the label *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE Key (letter, rest : ARRAY OF CHAR) ;
- BEGIN
- Marked ;
- PutCh (letter [0]) ;
- Normal ;
- PutStr (rest)
- END Key ;
- (* ------------------------------------------------------------------ *)
- (* input line editing (no echo from termios): CR or LF ends the line, *)
- (* backspace deletes the last char, the result is stored 0C-terminated*)
- (* ------------------------------------------------------------------ *)
- PROCEDURE ReadLine (VAR s : ARRAY OF CHAR) : CARDINAL ;
- VAR len : CARDINAL ;
- ch : CHAR ;
- BEGIN
- StrClear (s) ;
- len := 0 ;
- LOOP
- GetCh (ch) ;
- IF (ch = CHR (13)) OR (ch = CHR (10)) THEN
- PutCh (CHR (13)) ;
- PutCh (CHR (10)) ;
- EXIT
- ELSIF (ch = CHR (8)) OR (ch = CHR (127)) THEN
- IF len > 0 THEN
- DEC (len) ;
- PutStr ("[D [D") (* backspace over the char *)
- END
- ELSIF ch = CHR (27) THEN
- (* ESC: cancel the current edit *)
- EXIT
- ELSIF (ch >= " ") AND (ch <= "~") AND (len < HIGH (s)) THEN
- s [len] := ch ;
- INC (len) ;
- PutCh (ch)
- END
- END ;
- s [len] := 0C ;
- RETURN len
- END ReadLine ;
- PROCEDURE Pause ;
- VAR ch : CHAR ;
- BEGIN
- Beep ;
- GetCh (ch)
- END Pause ;
- PROCEDURE WaitEsc ;
- VAR ch : CHAR ;
- BEGIN
- LOOP
- GetCh (ch) ;
- IF (ch = CHR (27)) OR (ch = "q") OR (ch = "Q") THEN
- EXIT
- END
- END
- END WaitEsc ;
- (* return true if the user confirms with Y / y *)
- PROCEDURE Confirm (prompt : ARRAY OF CHAR) : BOOLEAN ;
- VAR ch : CHAR ;
- BEGIN
- PutStr (prompt) ;
- GetCh (ch) ;
- IF (ch = "y") OR (ch = "Y") THEN
- CrLf ;
- RETURN TRUE
- END ;
- CrLf ;
- RETURN FALSE
- END Confirm ;
- (* ------------------------------------------------------------------ *)
- (* file name handling *)
- (* ------------------------------------------------------------------ *)
- (* Does the name contain a '.' ? *)
- PROCEDURE HasExt (VAR s : ARRAY OF CHAR) : BOOLEAN ;
- VAR i : CARDINAL ;
- BEGIN
- i := 0 ;
- WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO
- IF s [i] = "." THEN
- RETURN TRUE
- END ;
- INC (i)
- END ;
- RETURN FALSE
- END HasExt ;
- (* replaces the current work file, appending .PAS when needed *)
- PROCEDURE SetWorkName (VAR s : ARRAY OF CHAR) ;
- BEGIN
- StrCopy (workName, s) ;
- IF NOT HasExt (workName) THEN
- StrAppend (workName, ".PAS")
- END
- END SetWorkName ;
- (* The .COM name for the current work file: the same path with .COM.
- TP3 derives the output name the same way (it hands the destination to the
- overlay loader with the extension swapped), so FOO.PAS links to FOO.COM
- in whatever directory the source lives, not to the current directory.
- The dot is found by scanning for the LAST one, not the first: a Pascal
- path may well contain a directory component with a dot in it, and taking
- the first would truncate the directory and write the .COM somewhere else. *)
- PROCEDURE ComName (VAR dst : ARRAY OF CHAR) ;
- VAR i, dot : CARDINAL ;
- BEGIN
- IF StrLen (workName) = 0 THEN
- StrClear (dst) ;
- RETURN
- END ;
- StrCopy (dst, workName) ;
- dot := 0 ;
- i := 0 ;
- WHILE (i <= HIGH (workName)) AND (workName [i] # 0C) DO
- IF workName [i] = "." THEN
- dot := i
- END ;
- INC (i)
- END ;
- IF dot = 0 THEN
- (* no extension at all - just append *)
- StrCopy (dst, workName) ;
- StrAppend (dst, ".COM")
- ELSE
- (* cut at the dot, then append *)
- i := dot ;
- WHILE (i <= HIGH (dst)) DO
- dst [i] := 0C ;
- INC (i)
- END ;
- StrAppend (dst, ".COM")
- END
- END ComName ;
- (* ------------------------------------------------------------------ *)
- (* buffered save of the work file: .BAK = old version, then ^Z *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE SaveWorkFile ;
- VAR fd : INTEGER ;
- path : ARRAY [0..511] OF CHAR ;
- w : LONGINT ;
- i : CARDINAL ;
- msg : ARRAY [0..255] OF CHAR ;
- b : BYTE ;
- BEGIN
- IF StrLen (workName) = 0 THEN
- PutStr (" ...work file not set") ;
- CrLf ;
- Pause ;
- RETURN
- END ;
- StrClear (msg) ;
- StrAppend (msg, "Saving A:") ;
- StrAppend (msg, workName) ;
- PutStr (msg) ;
- StrClear (path) ;
- StrAppend (path, workName) ;
- StrAppend (path, ".BAK") ;
- w := unlink (ADR (path)) ; (* drop old backup *)
- StrClear (path) ;
- StrAppend (path, workName) ;
- StrAppend (path, ".BAK") ;
- StrClear (msg) ;
- StrAppend (msg, workName) ;
- w := rename (ADR (msg), ADR (path)) ; (* old version -> .BAK *)
- StrClear (path) ;
- StrAppend (path, workName) ;
- fd := open (ADR (path), 1 + 512 + 64, 420) ; (* O_WRONLY|O_TRUNC|O_CREAT, 0644 *)
- IF fd < 0 THEN
- CrLf ;
- PutStr (" ...cannot create file") ;
- Pause ;
- RETURN
- END ;
- i := 0 ;
- WHILE i < Length () DO
- IF CharAt (i) = CHR (13) THEN
- b := CHR (13) ;
- w := write (fd, ADR (b), 1) ;
- b := CHR (10) ;
- w := write (fd, ADR (b), 1)
- ELSE
- b := VAL (BYTE, ORD (CharAt (i))) ;
- w := write (fd, ADR (b), 1)
- END ;
- INC (i)
- END ;
- b := CHR (26) ; (* EOF marker ^Z, TP3 style *)
- w := write (fd, ADR (b), 1) ;
- w := close (fd) ;
- changed := FALSE ;
- CrLf
- END SaveWorkFile ;
- (* ------------------------------------------------------------------ *)
- (* load a file into the text buffer; stop at ^Z or TextLimit *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE LoadWorkFile ;
- VAR fd : INTEGER ;
- path : ARRAY [0..511] OF CHAR ;
- k : LONGINT ;
- b : BYTE ;
- prevCR, tooBig : BOOLEAN ;
- BEGIN
- StrClear (path) ;
- StrAppend (path, workName) ;
- fd := open (ADR (path), O_RDONLY, 0) ;
- IF fd < 0 THEN
- PutStr ("New File") ;
- CrLf ;
- Clear ;
- changed := FALSE ;
- Pause ;
- RETURN
- END ;
- tooBig := FALSE ;
- prevCR := FALSE ;
- Clear ;
- LOOP
- IF Length () >= TextLimit THEN
- tooBig := TRUE ;
- EXIT
- END ;
- k := read (fd, ADR (b), 1) ;
- IF k # 1 THEN
- EXIT
- END ;
- IF b = CHR (26) THEN
- EXIT
- ELSIF b = CHR (10) THEN
- IF NOT prevCR THEN
- InsertCh (Length (), CHR (13)) (* lone LF -> CR *)
- END ;
- prevCR := FALSE
- ELSIF b = CHR (13) THEN
- InsertCh (Length (), CHR (13)) ;
- prevCR := TRUE
- ELSE
- InsertCh (Length (), CHR (ORD (b))) ;
- prevCR := FALSE
- END
- END ;
- k := close (fd) ;
- IF tooBig THEN
- PutStr ("File too big") ;
- CrLf
- END ;
- changed := FALSE ;
- Pause
- END LoadWorkFile ;
- (* ------------------------------------------------------------------ *)
- (* directory listing (kdir) *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE MatchMask (VAR m, n : ARRAY OF CHAR) : BOOLEAN ;
- VAR mi, ni, saveMi, saveNi : CARDINAL ;
- isAll : BOOLEAN ;
- BEGIN
- (* DOS-style: "*.*" and "*" mean "everything" *)
- isAll := TRUE ;
- mi := 0 ;
- WHILE (mi <= HIGH (m)) AND (m [mi] # 0C) DO
- IF NOT ((m [mi] = "*") OR (m [mi] = ".")) THEN
- isAll := FALSE
- END ;
- INC (mi)
- END ;
- IF isAll THEN
- RETURN TRUE
- END ;
- mi := 0 ;
- ni := 0 ;
- saveMi := 0 ;
- saveNi := 0 ;
- LOOP
- (* mask exhausted *)
- IF (mi <= HIGH (m)) AND (m [mi] = "*") THEN
- saveMi := mi ;
- WHILE (mi <= HIGH (m)) AND (m [mi] = "*") DO
- INC (mi)
- END ;
- IF mi > HIGH (m) THEN
- RETURN TRUE
- END ;
- saveNi := ni
- ELSIF (mi > HIGH (m)) OR (m [mi] = 0C) THEN
- RETURN (ni <= HIGH (n)) AND (n [ni] = 0C)
- ELSIF (ni <= HIGH (n)) AND (n [ni] # 0C) AND
- (Upper (m [mi]) = Upper (n [ni])) THEN
- INC (mi) ;
- INC (ni)
- ELSIF saveMi > 0 THEN
- INC (saveNi) ;
- IF saveNi > HIGH (n) THEN
- RETURN FALSE
- END ;
- ni := saveNi ;
- mi := saveMi + 1
- ELSIF (ni > HIGH (n)) OR (n [ni] = 0C) THEN
- RETURN FALSE
- ELSE
- RETURN FALSE
- END
- END ;
- RETURN FALSE
- END MatchMask ;
- PROCEDURE DirCmd ;
- VAR mask : ARRAY [0..255] OF CHAR ;
- d : Dir ;
- p : POINTER TO dirent ;
- count : CARDINAL ;
- freeK : LONGCARD ;
- sv : statvfsbuf ;
- i : CARDINAL ;
- w : INTEGER ;
- BEGIN
- PutStr ("Dir mask: ") ;
- IF ReadLine (mask) = 0 THEN
- StrCopy (mask, "*.*")
- END ;
- CrLf ;
- d := opendir (ADR (".")) ;
- IF d = NIL THEN
- PutStr ("No files") ;
- CrLf ;
- Pause ;
- RETURN
- END ;
- count := 0 ;
- LOOP
- p := readdir (d) ;
- IF p = NIL THEN
- EXIT
- END ;
- IF (p^.d_name [0] # ".") AND
- (MatchMask (mask, p^.d_name)) THEN
- INC (count) ;
- PutStr (p^.d_name) ;
- i := 1 + (12 - StrLen (p^.d_name) MOD 12) ;
- IF i > 12 THEN
- i := 12
- END ;
- ScrnWide (i)
- END
- END ;
- w := closedir (d) ;
- CrLf ;
- IF count = 0 THEN
- PutStr ("No files") ;
- CrLf
- END ;
- IF statvfs (ADR ("."), ADR (sv)) = 0 THEN
- freeK := (sv.f_bavail * sv.f_frsize) DIV 1024 ;
- PutLongCard (freeK) ;
- PutStr ("k bytes free") ;
- CrLf
- END ;
- Pause
- END DirCmd ;
- (* ------------------------------------------------------------------ *)
- (* main menu *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE DrawMenu ;
- VAR cwd : ARRAY [0..4095] OF CHAR ;
- freeB : CARDINAL ;
- i : CARDINAL ;
- BEGIN
- ClrScr ;
- GotoXY (1, 1) ;
- Key ("L", "ogged drive: ") ;
- PutCh (drive) ;
- GetCwd (cwd) ;
- GotoXY (2, 1) ;
- Key ("A", "ctive directory: ") ;
- PutStr (cwd) ;
- GotoXY (4, 1) ;
- Key ("W", "ork file: A:") ;
- PutStr (workName) ;
- GotoXY (5, 1) ;
- Key ("M", "ain file: A:") ;
- PutStr (mainName) ;
- GotoXY (7, 1) ;
- Key ("E", "dit ") ;
- Key ("C", "ompile ") ;
- Key ("R", "un ") ;
- Key ("S", "ave") ;
- GotoXY (9, 1) ;
- Key ("D", "ir ") ;
- Key ("Q", "uit compiler ") ;
- Key ("O", "ptions") ;
- GotoXY (11, 1) ;
- PutStr ("Text: ") ;
- PutCard (Length ()) ;
- PutStr (" bytes") ;
- freeB := TextLimit - Length ();
- GotoXY (12, 1) ;
- PutStr ("Free: ") ;
- PutCard (freeB) ;
- PutStr (" bytes") ;
- GotoXY (14, 1) ;
- Marked ;
- PutCh (">") ;
- Normal
- END DrawMenu ;
- (* ------------------------------------------------------------------ *)
- (* command handlers *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE CmdLogDrive ;
- VAR nm : ARRAY [0..255] OF CHAR ;
- ln : CARDINAL ;
- BEGIN
- ClrScr ;
- GotoXY (1, 1) ;
- PutStr ("New drive: ") ;
- ln := ReadLine (nm) ;
- IF ln = 1 THEN
- drive := Upper (nm [0]) ;
- IF (drive < "A") OR (drive > "P") THEN
- drive := "A"
- END
- ELSIF ln > 1 THEN
- (* treat as a directory instead (linux has no real drives) *)
- IF chdir (ADR (nm)) # 0 THEN
- PutStr ("File not found") ;
- CrLf ;
- Pause
- END
- END
- END CmdLogDrive ;
- PROCEDURE CmdActDir ;
- VAR nm : ARRAY [0..255] OF CHAR ;
- BEGIN
- ClrScr ;
- GotoXY (1, 1) ;
- PutStr ("New directory: ") ;
- IF ReadLine (nm) > 0 THEN
- IF chdir (ADR (nm)) # 0 THEN
- PutStr ("File not found") ;
- CrLf ;
- Pause
- END
- END
- END CmdActDir ;
- PROCEDURE CmdWorkFile ;
- VAR nm : ARRAY [0..255] OF CHAR ;
- txtTitle : ARRAY [0..511] OF CHAR ;
- BEGIN
- ClrScr ;
- GotoXY (1, 1) ;
- PutStr ("Work file name: ") ;
- IF ReadLine (nm) > 0 THEN
- IF changed THEN
- CrLf ;
- PutStr (" ") ;
- IF Confirm ("Save current work file now (Y/N) ?") THEN
- SaveWorkFile
- END
- END ;
- ClrScr ;
- GotoXY (1, 1) ;
- SetWorkName (nm) ;
- StrClear (txtTitle) ;
- StrAppend (txtTitle, "Loading A:") ;
- StrAppend (txtTitle, workName) ;
- PutStr (txtTitle) ;
- CrLf ;
- LoadWorkFile
- END
- END CmdWorkFile ;
- PROCEDURE CmdMainFile ;
- VAR nm : ARRAY [0..255] OF CHAR ;
- BEGIN
- ClrScr ;
- GotoXY (1, 1) ;
- PutStr ("Main file name: ") ;
- IF ReadLine (nm) > 0 THEN
- StrCopy (mainName, nm) ;
- IF NOT HasExt (mainName) THEN
- StrAppend (mainName, ".PAS")
- END
- END
- END CmdMainFile ;
- PROCEDURE CmdCompile ;
- VAR comPath : ARRAY [0..255] OF CHAR ;
- BEGIN
- ClrScr ;
- GotoXY (1, 1) ;
- IF Compile (errNo, errPos) THEN
- PutStr ("Compiled OK - code ") ;
- PutCard (CodeBytes ()) ;
- PutStr (" bytes, data ") ;
- PutCard (DataBytes ()) ;
- CrLf ;
- (* Destination, as TP3's Options submenu sets it: 0 = Memory (the
- debugger runs the code in place), 1 = .COM, 2 = .CHN.
- Until now the choice was displayed and then ignored, which was a
- fidelity gap: selecting COM did nothing at all. *)
- CASE codeDest OF
- | 0 :
- PutStr ("Destination: Memory (code left in the buffer)") ;
- CrLf
- | 2 :
- (* .CHN is Turbo Pascal's TBIOS overlay format; the original
- wrote it with its own overlay loader. Refuse rather than
- pretend - the user's next R would not find anything. *)
- PutStr ("Destination: .CHN is not implemented") ;
- CrLf
- ELSE
- PutStr ("Destination: .COM") ;
- CrLf ;
- ComName (comPath) ;
- IF WriteCom (comPath) THEN
- PutStr (" wrote ") ;
- PutStr (comPath) ;
- PutStr (" ") ;
- PutCard (LinkSize ()) ;
- PutStr (" bytes (image ") ;
- PutCard (ImageBytes ()) ;
- PutStr (")")
- ELSE
- (* WriteCom unlinked any partial file, so there is no half
- file to clean up here. *)
- PutStr (" could not write ") ;
- PutStr (comPath) ;
- PutStr (" - disk error?")
- END ;
- CrLf
- END ;
- PutStr ("press ESC to return to the editor") ;
- CrLf ;
- WaitEsc
- ELSE
- PutStr ("TP3-style error ") ;
- PutCard (errNo) ;
- PutStr (" at relative pos ") ;
- PutCard (errPos) ;
- CrLf ;
- PutStr ("press ESC, then the editor opens on the error") ;
- CrLf ;
- WaitEsc ;
- (* TP3 kcwait: waitesc ; BX:=txerrpos ; DEC BX ; JMP editor2.
- Net cursor position = txbeg + txerrpos, i.e. errPos here. *)
- GotoOffset (errPos) ;
- CmdEditor
- END
- END CmdCompile ;
- PROCEDURE CmdRun ;
- (* TP3's `R': compile, then run what came out.
- The original has no separate loader here - krungo runs the image where it
- already is, in the same 64 KB, at the address DOS would give a .COM.
- Exec86 has the same shape: the linked image is poked into the
- interpreter's own 64 KB at 0100H and executed in this process, with no
- file written, so R does the same thing whether Destination is Memory or
- .COM.
- The guest's output goes to this process's fd 1 through the runtime's
- INT 21h AH=02/09/08, and it lands between our two status lines rather
- than being collected and replayed: Term writes one byte per write(2) and
- buffers nothing, so the two streams stay in order.
- Clear86, Poke86 and Run86 are module-level imports like everything else
- here; the suffix is explained where they are imported. *)
- VAR
- status, exitCode, i, n : CARDINAL ;
- steps : LONGCARD ;
- BEGIN
- ClrScr ;
- GotoXY (1, 1) ;
- IF NOT Compile (errNo, errPos) THEN
- PutStr ("TP3-style error ") ;
- PutCard (errNo) ;
- PutStr (" at relative pos ") ;
- PutCard (errPos) ;
- CrLf ;
- PutStr ("press ESC, then the editor opens on the error") ;
- CrLf ;
- WaitEsc ;
- GotoOffset (errPos) ;
- CmdEditor ;
- RETURN
- END ;
- PutStr ("Compiled OK - code ") ;
- PutCard (CodeBytes ()) ;
- PutStr (" bytes, data ") ;
- PutCard (DataBytes ()) ;
- CrLf ;
- (* LinkSize, not ImageBytes: the .COM DOS would load is the image padded
- out to cover the whole data area, and the globals the program is about
- to use live in that padding. ImageByteAt answers 0 past the end of the
- image, which is exactly the zero fill the padding is made of. *)
- n := LinkSize () ;
- Clear86 ;
- i := 0 ;
- WHILE i < n DO
- Poke86 (0100H + i, ORD (ImageByteAt (i))) ;
- INC (i)
- END ;
- PutStr ("running ") ;
- PutCard (n) ;
- PutStr (" bytes at 0100h") ;
- CrLf ;
- CrLf ;
- status := Run86 (exitCode, steps) ;
- CrLf ;
- CASE status OF
- | 0 :
- PutStr ("program terminated (INT 21h AH=4Ch, code ") ;
- PutCard (exitCode) ;
- PutStr (")")
- | 1 :
- PutStr ("interpreter fault - diagnostic above")
- | 2 :
- PutStr ("step limit reached - runaway loop?")
- ELSE
- PutStr ("unexpected status ") ;
- PutCard (status)
- END ;
- CrLf ;
- PutStr ("steps executed: ") ;
- PutLongCard (steps) ;
- CrLf ;
- PutStr ("press ESC to return to the editor") ;
- CrLf ;
- WaitEsc
- END CmdRun ;
- PROCEDURE CmdEditor ;
- VAR edChanged : BOOLEAN ;
- BEGIN
- IF StrLen (workName) = 0 THEN
- (* kgetfn: no work file yet -> prompt just like W does *)
- CmdWorkFile ;
- IF StrLen (workName) = 0 THEN
- RETURN
- END
- END ;
- edChanged := FALSE ;
- Run (drive, workName, edChanged) ;
- IF edChanged THEN
- changed := TRUE
- END
- END CmdEditor ;
- (* ------------------------------------------------------------------ *)
- (* TP3 "Options" submenu (optmenu) *)
- (* ------------------------------------------------------------------ *)
- PROCEDURE PutHex (n : CARDINAL) ;
- VAR dig : ARRAY [0..7] OF CHAR ;
- i, d : CARDINAL ;
- BEGIN
- i := 0 ;
- LOOP
- d := n MOD 16 ;
- IF d < 10 THEN
- dig [i] := CHR (ORD ("0") + d)
- ELSE
- dig [i] := CHR (ORD ("A") + d - 10)
- END ;
- n := n DIV 16 ;
- INC (i) ;
- IF (n = 0) OR (i = 8) THEN
- EXIT
- END
- END ;
- WHILE i > 0 DO
- DEC (i) ;
- PutCh (dig [i])
- END
- END PutHex ;
- PROCEDURE OptionsMenu ;
- VAR ch : CHAR ;
- s : ARRAY [0..255] OF CHAR ;
- done : BOOLEAN ;
- BEGIN
- done := FALSE ;
- REPEAT
- ClrScr ;
- GotoXY (1, 1) ;
- Marked ; PutCh ("M") ; Normal ;
- PutStr ("emory ") ;
- Marked ; PutCh ("C") ; Normal ;
- PutStr ("OM ") ;
- Marked ; PutCh ("H") ; Normal ;
- PutStr ("CHN") ;
- CrLf ;
- PutStr (" ") ;
- IF codeDest = 1 THEN
- PutStr ("Compile -> COM")
- ELSIF codeDest = 2 THEN
- PutStr ("Compile -> CHN")
- ELSE
- PutStr ("Compile -> Memory")
- END ;
- CrLf ;
- PutStr ("Text: ") ;
- PutCard (Length ()) ;
- PutStr (" Code: ") ;
- PutHex (minCode) ;
- PutStr (" Data: ") ;
- PutHex (minData) ;
- PutStr (" Stack: ") ;
- PutHex (minStack) ;
- CrLf ;
- PutStr ("Command line Params: ") ;
- PutStr (paramLine) ;
- CrLf ;
- Marked ; PutCh ("F") ; Normal ;
- PutStr ("ind run-time error ") ;
- Marked ; PutCh ("Q") ; Normal ;
- PutStr ("uit") ;
- CrLf ;
- CrLf ;
- Marked ; PutCh (">") ; Normal ;
- GetCh (ch) ;
- ch := Upper (ch) ;
- CASE ch OF
- | "M" : codeDest := 0
- | "C" : codeDest := 1
- | "H" : codeDest := 2
- | "O" :
- ClrScr ; GotoXY (1,1) ;
- PutStr ("Min Code Segment (hex): ") ;
- IF ReadLine (s) > 0 THEN minCode := 0 END
- | "D" :
- ClrScr ; GotoXY (1,1) ;
- PutStr ("Min Data Segment (hex): ") ;
- IF ReadLine (s) > 0 THEN minData := 0 END
- | "I" :
- ClrScr ; GotoXY (1,1) ;
- PutStr ("Min Free Dyn Mem / Stack (hex): ") ;
- IF ReadLine (s) > 0 THEN minStack := 0 END
- | "A" :
- ClrScr ; GotoXY (1,1) ;
- PutStr ("Max Free Dyn Mem / Stack (hex): ") ;
- IF ReadLine (s) > 0 THEN maxStack := 0 END
- | "P" :
- ClrScr ; GotoXY (1,1) ;
- PutStr ("Command line Params: ") ;
- IF ReadLine (paramLine) > 0 THEN
- (* keep the parameter string *)
- END
- | "F" :
- ClrScr ; GotoXY (1,1) ;
- PutStr ("Find run-time error address (hex) : ") ;
- IF ReadLine (s) > 0 THEN
- PutStr ("Searching ... (not implemented)") ;
- CrLf ;
- Pause
- END
- | "Q" :
- done := TRUE
- ELSE
- (* ignore *)
- END
- UNTIL done
- END OptionsMenu ;
- (* ------------------------------------------------------------------ *)
- PROCEDURE terminal ;
- VAR ch : CHAR ;
- BEGIN
- Open ;
- drive := "A" ;
- codeDest := 0 ;
- minCode := 0 ; minData := 0 ; minStack := 0 ; maxStack := 0 ;
- StrClear (workName) ;
- StrClear (mainName) ;
- StrClear (paramLine) ;
- Clear ;
- changed := FALSE ;
- LOOP
- DrawMenu ;
- GetCh (ch) ;
- ch := Upper (ch) ;
- CASE ch OF
- | "L" : CmdLogDrive
- | "A" : CmdActDir
- | "W" : CmdWorkFile
- | "M" : CmdMainFile
- | "E" : CmdEditor
- | "C" : CmdCompile
- | "R" : CmdRun
- | "S" :
- IF StrLen (workName) > 0 THEN
- SaveWorkFile ;
- Pause
- END
- | "D" : DirCmd
- | "O" : OptionsMenu
- | "Q" :
- IF changed THEN
- CrLf ;
- IF Confirm ("Work file not saved. Save (Y/N) ?") THEN
- SaveWorkFile
- END
- END ;
- Close ;
- (* gm2 -fiso: a bare HALT aborts (SIGABRT, shell status 134);
- an explicit HALT (0) exits cleanly with status 0. *)
- HALT (0)
- ELSE
- (* any other key: redraw the menu, like TP3 *)
- END
- END
- END terminal ;
- BEGIN
- terminal
- END Shell.
|