Shell.mod 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. MODULE Shell ;
  2. (* TP3 main-menu shell. Draws the Turbo Pascal 3.0 screen with ANSI
  3. escapes and dispatches on the same command letters as the original
  4. (TPSRC4 kmenu / kcmdtab). Editor, compiler and interpreter are
  5. placeholders for now; the shell logic (files, directory, options,
  6. save/load with .BAK) mirrors the original closely. *)
  7. FROM Term IMPORT
  8. Open, Close, ClrScr, GotoXY, PutCh, PutStr, PutCard, PutLongCard,
  9. ScrnWide, Marked, Normal, GetCh, Beep ;
  10. FROM Posix IMPORT
  11. read, write, open, close, unlink, rename,
  12. getcwd, chdir, opendir, readdir, closedir, statvfs,
  13. Dir, dirent, statvfsbuf ;
  14. FROM Compiler IMPORT Compile, CodeBytes, DataBytes ;
  15. FROM Editor IMPORT Run, GotoOffset ;
  16. FROM TextBuf IMPORT
  17. TextLimit, Clear, Length, CharAt, InsertCh ;
  18. FROM SYSTEM IMPORT ADR, ADDRESS, BYTE ;
  19. CONST
  20. O_RDONLY = 0 ; (* linux *)
  21. VAR
  22. drive : CHAR ;
  23. workName : ARRAY [0..255] OF CHAR ;
  24. mainName : ARRAY [0..255] OF CHAR ;
  25. changed : BOOLEAN ;
  26. codeDest : CARDINAL ; (* 0=Memory, 1=COM, 2=CHN *)
  27. errNo, errPos : CARDINAL ;
  28. minCode, minData, minStack, maxStack : CARDINAL ;
  29. paramLine : ARRAY [0..255] OF CHAR ;
  30. (* ------------------------------------------------------------------ *)
  31. (* string helpers *)
  32. (* ------------------------------------------------------------------ *)
  33. PROCEDURE StrLen (VAR s : ARRAY OF CHAR) : CARDINAL ;
  34. VAR i : CARDINAL ;
  35. BEGIN
  36. i := 0 ;
  37. WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO
  38. INC (i)
  39. END ;
  40. RETURN i
  41. END StrLen ;
  42. PROCEDURE StrClear (VAR s : ARRAY OF CHAR) ;
  43. BEGIN
  44. s [0] := 0C
  45. END StrClear ;
  46. PROCEDURE StrCopy (VAR dst : ARRAY OF CHAR ; src : ARRAY OF CHAR) ;
  47. VAR i : CARDINAL ;
  48. BEGIN
  49. i := 0 ;
  50. LOOP
  51. IF i > HIGH (dst) THEN
  52. dst [HIGH (dst)] := 0C ;
  53. EXIT
  54. END ;
  55. IF i > HIGH (src) THEN
  56. dst [i] := 0C ;
  57. EXIT
  58. END ;
  59. IF src [i] = 0C THEN
  60. dst [i] := 0C ;
  61. EXIT
  62. END ;
  63. dst [i] := src [i] ;
  64. INC (i)
  65. END
  66. END StrCopy ;
  67. PROCEDURE StrAppend (VAR dst : ARRAY OF CHAR ; suffix : ARRAY OF CHAR) ;
  68. VAR i, j : CARDINAL ;
  69. BEGIN
  70. i := StrLen (dst) ;
  71. j := 0 ;
  72. LOOP
  73. IF i > HIGH (dst) THEN
  74. EXIT
  75. END ;
  76. IF j > HIGH (suffix) THEN
  77. dst [i] := 0C ;
  78. EXIT
  79. END ;
  80. IF suffix [j] = 0C THEN
  81. dst [i] := 0C ;
  82. EXIT
  83. END ;
  84. dst [i] := suffix [j] ;
  85. INC (i) ;
  86. INC (j)
  87. END
  88. END StrAppend ;
  89. PROCEDURE StrEq (VAR a, b : ARRAY OF CHAR) : BOOLEAN ;
  90. VAR i : CARDINAL ;
  91. BEGIN
  92. i := 0 ;
  93. LOOP
  94. IF (i > HIGH (a)) OR (i > HIGH (b)) THEN
  95. RETURN FALSE
  96. END ;
  97. IF (a [i] = 0C) AND (b [i] = 0C) THEN
  98. RETURN TRUE
  99. END ;
  100. IF a [i] # b [i] THEN
  101. RETURN FALSE
  102. END ;
  103. INC (i)
  104. END ;
  105. RETURN FALSE
  106. END StrEq ;
  107. PROCEDURE Upper (ch : CHAR) : CHAR ;
  108. BEGIN
  109. IF (ch >= "a") AND (ch <= "z") THEN
  110. RETURN CHR (ORD (ch) - (ORD ("a") - ORD ("A")))
  111. END ;
  112. RETURN ch
  113. END Upper ;
  114. PROCEDURE CrLf ;
  115. BEGIN
  116. PutCh (CHR (13)) ;
  117. PutCh (CHR (10))
  118. END CrLf ;
  119. PROCEDURE GetCwd (VAR buf : ARRAY OF CHAR) ;
  120. VAR i : CARDINAL ;
  121. BEGIN
  122. IF getcwd (ADR (buf), 4096) = NIL THEN
  123. buf [0] := 0C
  124. END
  125. END GetCwd ;
  126. (* ------------------------------------------------------------------ *)
  127. (* marks one command letter then prints the rest of the label *)
  128. (* ------------------------------------------------------------------ *)
  129. PROCEDURE Key (letter, rest : ARRAY OF CHAR) ;
  130. BEGIN
  131. Marked ;
  132. PutCh (letter [0]) ;
  133. Normal ;
  134. PutStr (rest)
  135. END Key ;
  136. (* ------------------------------------------------------------------ *)
  137. (* input line editing (no echo from termios): CR or LF ends the line, *)
  138. (* backspace deletes the last char, the result is stored 0C-terminated*)
  139. (* ------------------------------------------------------------------ *)
  140. PROCEDURE ReadLine (VAR s : ARRAY OF CHAR) : CARDINAL ;
  141. VAR len : CARDINAL ;
  142. ch : CHAR ;
  143. BEGIN
  144. StrClear (s) ;
  145. len := 0 ;
  146. LOOP
  147. GetCh (ch) ;
  148. IF (ch = CHR (13)) OR (ch = CHR (10)) THEN
  149. PutCh (CHR (13)) ;
  150. PutCh (CHR (10)) ;
  151. EXIT
  152. ELSIF (ch = CHR (8)) OR (ch = CHR (127)) THEN
  153. IF len > 0 THEN
  154. DEC (len) ;
  155. PutStr (" ") (* backspace over the char *)
  156. END
  157. ELSIF ch = CHR (27) THEN
  158. (* ESC: cancel the current edit *)
  159. EXIT
  160. ELSIF (ch >= " ") AND (ch <= "~") AND (len < HIGH (s)) THEN
  161. s [len] := ch ;
  162. INC (len) ;
  163. PutCh (ch)
  164. END
  165. END ;
  166. s [len] := 0C ;
  167. RETURN len
  168. END ReadLine ;
  169. PROCEDURE Pause ;
  170. VAR ch : CHAR ;
  171. BEGIN
  172. Beep ;
  173. GetCh (ch)
  174. END Pause ;
  175. PROCEDURE WaitEsc ;
  176. VAR ch : CHAR ;
  177. BEGIN
  178. LOOP
  179. GetCh (ch) ;
  180. IF (ch = CHR (27)) OR (ch = "q") OR (ch = "Q") THEN
  181. EXIT
  182. END
  183. END
  184. END WaitEsc ;
  185. (* return true if the user confirms with Y / y *)
  186. PROCEDURE Confirm (prompt : ARRAY OF CHAR) : BOOLEAN ;
  187. VAR ch : CHAR ;
  188. BEGIN
  189. PutStr (prompt) ;
  190. GetCh (ch) ;
  191. IF (ch = "y") OR (ch = "Y") THEN
  192. CrLf ;
  193. RETURN TRUE
  194. END ;
  195. CrLf ;
  196. RETURN FALSE
  197. END Confirm ;
  198. (* ------------------------------------------------------------------ *)
  199. (* file name handling *)
  200. (* ------------------------------------------------------------------ *)
  201. (* Does the name contain a '.' ? *)
  202. PROCEDURE HasExt (VAR s : ARRAY OF CHAR) : BOOLEAN ;
  203. VAR i : CARDINAL ;
  204. BEGIN
  205. i := 0 ;
  206. WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO
  207. IF s [i] = "." THEN
  208. RETURN TRUE
  209. END ;
  210. INC (i)
  211. END ;
  212. RETURN FALSE
  213. END HasExt ;
  214. (* replaces the current work file, appending .PAS when needed *)
  215. PROCEDURE SetWorkName (VAR s : ARRAY OF CHAR) ;
  216. BEGIN
  217. StrCopy (workName, s) ;
  218. IF NOT HasExt (workName) THEN
  219. StrAppend (workName, ".PAS")
  220. END
  221. END SetWorkName ;
  222. (* ------------------------------------------------------------------ *)
  223. (* buffered save of the work file: .BAK = old version, then ^Z *)
  224. (* ------------------------------------------------------------------ *)
  225. PROCEDURE SaveWorkFile ;
  226. VAR fd : INTEGER ;
  227. path : ARRAY [0..511] OF CHAR ;
  228. w : LONGINT ;
  229. i : CARDINAL ;
  230. msg : ARRAY [0..255] OF CHAR ;
  231. b : BYTE ;
  232. BEGIN
  233. IF StrLen (workName) = 0 THEN
  234. PutStr (" ...work file not set") ;
  235. CrLf ;
  236. Pause ;
  237. RETURN
  238. END ;
  239. StrClear (msg) ;
  240. StrAppend (msg, "Saving A:") ;
  241. StrAppend (msg, workName) ;
  242. PutStr (msg) ;
  243. StrClear (path) ;
  244. StrAppend (path, workName) ;
  245. StrAppend (path, ".BAK") ;
  246. w := unlink (ADR (path)) ; (* drop old backup *)
  247. StrClear (path) ;
  248. StrAppend (path, workName) ;
  249. StrAppend (path, ".BAK") ;
  250. StrClear (msg) ;
  251. StrAppend (msg, workName) ;
  252. w := rename (ADR (msg), ADR (path)) ; (* old version -> .BAK *)
  253. StrClear (path) ;
  254. StrAppend (path, workName) ;
  255. fd := open (ADR (path), 1 + 512 + 64, 420) ; (* O_WRONLY|O_TRUNC|O_CREAT, 0644 *)
  256. IF fd < 0 THEN
  257. CrLf ;
  258. PutStr (" ...cannot create file") ;
  259. Pause ;
  260. RETURN
  261. END ;
  262. i := 0 ;
  263. WHILE i < Length () DO
  264. IF CharAt (i) = CHR (13) THEN
  265. b := CHR (13) ;
  266. w := write (fd, ADR (b), 1) ;
  267. b := CHR (10) ;
  268. w := write (fd, ADR (b), 1)
  269. ELSE
  270. b := VAL (BYTE, ORD (CharAt (i))) ;
  271. w := write (fd, ADR (b), 1)
  272. END ;
  273. INC (i)
  274. END ;
  275. b := CHR (26) ; (* EOF marker ^Z, TP3 style *)
  276. w := write (fd, ADR (b), 1) ;
  277. w := close (fd) ;
  278. changed := FALSE ;
  279. CrLf
  280. END SaveWorkFile ;
  281. (* ------------------------------------------------------------------ *)
  282. (* load a file into the text buffer; stop at ^Z or TextLimit *)
  283. (* ------------------------------------------------------------------ *)
  284. PROCEDURE LoadWorkFile ;
  285. VAR fd : INTEGER ;
  286. path : ARRAY [0..511] OF CHAR ;
  287. k : LONGINT ;
  288. b : BYTE ;
  289. prevCR, tooBig : BOOLEAN ;
  290. BEGIN
  291. StrClear (path) ;
  292. StrAppend (path, workName) ;
  293. fd := open (ADR (path), O_RDONLY, 0) ;
  294. IF fd < 0 THEN
  295. PutStr ("New File") ;
  296. CrLf ;
  297. Clear ;
  298. changed := FALSE ;
  299. Pause ;
  300. RETURN
  301. END ;
  302. tooBig := FALSE ;
  303. prevCR := FALSE ;
  304. Clear ;
  305. LOOP
  306. IF Length () >= TextLimit THEN
  307. tooBig := TRUE ;
  308. EXIT
  309. END ;
  310. k := read (fd, ADR (b), 1) ;
  311. IF k # 1 THEN
  312. EXIT
  313. END ;
  314. IF b = CHR (26) THEN
  315. EXIT
  316. ELSIF b = CHR (10) THEN
  317. IF NOT prevCR THEN
  318. InsertCh (Length (), CHR (13)) (* lone LF -> CR *)
  319. END ;
  320. prevCR := FALSE
  321. ELSIF b = CHR (13) THEN
  322. InsertCh (Length (), CHR (13)) ;
  323. prevCR := TRUE
  324. ELSE
  325. InsertCh (Length (), CHR (ORD (b))) ;
  326. prevCR := FALSE
  327. END
  328. END ;
  329. k := close (fd) ;
  330. IF tooBig THEN
  331. PutStr ("File too big") ;
  332. CrLf
  333. END ;
  334. changed := FALSE ;
  335. Pause
  336. END LoadWorkFile ;
  337. (* ------------------------------------------------------------------ *)
  338. (* directory listing (kdir) *)
  339. (* ------------------------------------------------------------------ *)
  340. PROCEDURE MatchMask (VAR m, n : ARRAY OF CHAR) : BOOLEAN ;
  341. VAR mi, ni, saveMi, saveNi : CARDINAL ;
  342. isAll : BOOLEAN ;
  343. BEGIN
  344. (* DOS-style: "*.*" and "*" mean "everything" *)
  345. isAll := TRUE ;
  346. mi := 0 ;
  347. WHILE (mi <= HIGH (m)) AND (m [mi] # 0C) DO
  348. IF NOT ((m [mi] = "*") OR (m [mi] = ".")) THEN
  349. isAll := FALSE
  350. END ;
  351. INC (mi)
  352. END ;
  353. IF isAll THEN
  354. RETURN TRUE
  355. END ;
  356. mi := 0 ;
  357. ni := 0 ;
  358. saveMi := 0 ;
  359. saveNi := 0 ;
  360. LOOP
  361. (* mask exhausted *)
  362. IF (mi <= HIGH (m)) AND (m [mi] = "*") THEN
  363. saveMi := mi ;
  364. WHILE (mi <= HIGH (m)) AND (m [mi] = "*") DO
  365. INC (mi)
  366. END ;
  367. IF mi > HIGH (m) THEN
  368. RETURN TRUE
  369. END ;
  370. saveNi := ni
  371. ELSIF (mi > HIGH (m)) OR (m [mi] = 0C) THEN
  372. RETURN (ni <= HIGH (n)) AND (n [ni] = 0C)
  373. ELSIF (ni <= HIGH (n)) AND (n [ni] # 0C) AND
  374. (Upper (m [mi]) = Upper (n [ni])) THEN
  375. INC (mi) ;
  376. INC (ni)
  377. ELSIF saveMi > 0 THEN
  378. INC (saveNi) ;
  379. IF saveNi > HIGH (n) THEN
  380. RETURN FALSE
  381. END ;
  382. ni := saveNi ;
  383. mi := saveMi + 1
  384. ELSIF (ni > HIGH (n)) OR (n [ni] = 0C) THEN
  385. RETURN FALSE
  386. ELSE
  387. RETURN FALSE
  388. END
  389. END ;
  390. RETURN FALSE
  391. END MatchMask ;
  392. PROCEDURE DirCmd ;
  393. VAR mask : ARRAY [0..255] OF CHAR ;
  394. d : Dir ;
  395. p : POINTER TO dirent ;
  396. count : CARDINAL ;
  397. freeK : LONGCARD ;
  398. sv : statvfsbuf ;
  399. i : CARDINAL ;
  400. w : INTEGER ;
  401. BEGIN
  402. PutStr ("Dir mask: ") ;
  403. IF ReadLine (mask) = 0 THEN
  404. StrCopy (mask, "*.*")
  405. END ;
  406. CrLf ;
  407. d := opendir (ADR (".")) ;
  408. IF d = NIL THEN
  409. PutStr ("No files") ;
  410. CrLf ;
  411. Pause ;
  412. RETURN
  413. END ;
  414. count := 0 ;
  415. LOOP
  416. p := readdir (d) ;
  417. IF p = NIL THEN
  418. EXIT
  419. END ;
  420. IF (p^.d_name [0] # ".") AND
  421. (MatchMask (mask, p^.d_name)) THEN
  422. INC (count) ;
  423. PutStr (p^.d_name) ;
  424. i := 1 + (12 - StrLen (p^.d_name) MOD 12) ;
  425. IF i > 12 THEN
  426. i := 12
  427. END ;
  428. ScrnWide (i)
  429. END
  430. END ;
  431. w := closedir (d) ;
  432. CrLf ;
  433. IF count = 0 THEN
  434. PutStr ("No files") ;
  435. CrLf
  436. END ;
  437. IF statvfs (ADR ("."), ADR (sv)) = 0 THEN
  438. freeK := (sv.f_bavail * sv.f_frsize) DIV 1024 ;
  439. PutLongCard (freeK) ;
  440. PutStr ("k bytes free") ;
  441. CrLf
  442. END ;
  443. Pause
  444. END DirCmd ;
  445. (* ------------------------------------------------------------------ *)
  446. (* main menu *)
  447. (* ------------------------------------------------------------------ *)
  448. PROCEDURE DrawMenu ;
  449. VAR cwd : ARRAY [0..4095] OF CHAR ;
  450. freeB : CARDINAL ;
  451. i : CARDINAL ;
  452. BEGIN
  453. ClrScr ;
  454. GotoXY (1, 1) ;
  455. Key ("L", "ogged drive: ") ;
  456. PutCh (drive) ;
  457. GetCwd (cwd) ;
  458. GotoXY (2, 1) ;
  459. Key ("A", "ctive directory: ") ;
  460. PutStr (cwd) ;
  461. GotoXY (4, 1) ;
  462. Key ("W", "ork file: A:") ;
  463. PutStr (workName) ;
  464. GotoXY (5, 1) ;
  465. Key ("M", "ain file: A:") ;
  466. PutStr (mainName) ;
  467. GotoXY (7, 1) ;
  468. Key ("E", "dit ") ;
  469. Key ("C", "ompile ") ;
  470. Key ("R", "un ") ;
  471. Key ("S", "ave") ;
  472. GotoXY (9, 1) ;
  473. Key ("D", "ir ") ;
  474. Key ("Q", "uit compiler ") ;
  475. Key ("O", "ptions") ;
  476. GotoXY (11, 1) ;
  477. PutStr ("Text: ") ;
  478. PutCard (Length ()) ;
  479. PutStr (" bytes") ;
  480. freeB := TextLimit - Length ();
  481. GotoXY (12, 1) ;
  482. PutStr ("Free: ") ;
  483. PutCard (freeB) ;
  484. PutStr (" bytes") ;
  485. GotoXY (14, 1) ;
  486. Marked ;
  487. PutCh (">") ;
  488. Normal
  489. END DrawMenu ;
  490. (* ------------------------------------------------------------------ *)
  491. (* command handlers *)
  492. (* ------------------------------------------------------------------ *)
  493. PROCEDURE CmdLogDrive ;
  494. VAR nm : ARRAY [0..255] OF CHAR ;
  495. ln : CARDINAL ;
  496. BEGIN
  497. ClrScr ;
  498. GotoXY (1, 1) ;
  499. PutStr ("New drive: ") ;
  500. ln := ReadLine (nm) ;
  501. IF ln = 1 THEN
  502. drive := Upper (nm [0]) ;
  503. IF (drive < "A") OR (drive > "P") THEN
  504. drive := "A"
  505. END
  506. ELSIF ln > 1 THEN
  507. (* treat as a directory instead (linux has no real drives) *)
  508. IF chdir (ADR (nm)) # 0 THEN
  509. PutStr ("File not found") ;
  510. CrLf ;
  511. Pause
  512. END
  513. END
  514. END CmdLogDrive ;
  515. PROCEDURE CmdActDir ;
  516. VAR nm : ARRAY [0..255] OF CHAR ;
  517. BEGIN
  518. ClrScr ;
  519. GotoXY (1, 1) ;
  520. PutStr ("New directory: ") ;
  521. IF ReadLine (nm) > 0 THEN
  522. IF chdir (ADR (nm)) # 0 THEN
  523. PutStr ("File not found") ;
  524. CrLf ;
  525. Pause
  526. END
  527. END
  528. END CmdActDir ;
  529. PROCEDURE CmdWorkFile ;
  530. VAR nm : ARRAY [0..255] OF CHAR ;
  531. txtTitle : ARRAY [0..511] OF CHAR ;
  532. BEGIN
  533. ClrScr ;
  534. GotoXY (1, 1) ;
  535. PutStr ("Work file name: ") ;
  536. IF ReadLine (nm) > 0 THEN
  537. IF changed THEN
  538. CrLf ;
  539. PutStr (" ") ;
  540. IF Confirm ("Save current work file now (Y/N) ?") THEN
  541. SaveWorkFile
  542. END
  543. END ;
  544. ClrScr ;
  545. GotoXY (1, 1) ;
  546. SetWorkName (nm) ;
  547. StrClear (txtTitle) ;
  548. StrAppend (txtTitle, "Loading A:") ;
  549. StrAppend (txtTitle, workName) ;
  550. PutStr (txtTitle) ;
  551. CrLf ;
  552. LoadWorkFile
  553. END
  554. END CmdWorkFile ;
  555. PROCEDURE CmdMainFile ;
  556. VAR nm : ARRAY [0..255] OF CHAR ;
  557. BEGIN
  558. ClrScr ;
  559. GotoXY (1, 1) ;
  560. PutStr ("Main file name: ") ;
  561. IF ReadLine (nm) > 0 THEN
  562. StrCopy (mainName, nm) ;
  563. IF NOT HasExt (mainName) THEN
  564. StrAppend (mainName, ".PAS")
  565. END
  566. END
  567. END CmdMainFile ;
  568. PROCEDURE CmdCompile ;
  569. BEGIN
  570. ClrScr ;
  571. GotoXY (1, 1) ;
  572. IF Compile (errNo, errPos) THEN
  573. PutStr ("Compiled OK - code ") ;
  574. PutCard (CodeBytes ()) ;
  575. PutStr (" bytes, data ") ;
  576. PutCard (DataBytes ()) ;
  577. PutStr (" bytes (TP3 option O not yet run)") ;
  578. CrLf ;
  579. PutStr ("press ESC to return to the editor") ;
  580. CrLf ;
  581. WaitEsc
  582. ELSE
  583. PutStr ("TP3-style error ") ;
  584. PutCard (errNo) ;
  585. PutStr (" at relative pos ") ;
  586. PutCard (errPos) ;
  587. CrLf ;
  588. PutStr ("press ESC, then the editor opens on the error") ;
  589. CrLf ;
  590. WaitEsc ;
  591. (* TP3 kcwait: waitesc ; BX:=txerrpos ; DEC BX ; JMP editor2.
  592. Net cursor position = txbeg + txerrpos, i.e. errPos here. *)
  593. GotoOffset (errPos) ;
  594. CmdEditor
  595. END
  596. END CmdCompile ;
  597. PROCEDURE CmdRun ;
  598. BEGIN
  599. ClrScr ;
  600. GotoXY (1, 1) ;
  601. PutStr ("Interpreter pending - compiled code is in memory") ;
  602. CrLf ;
  603. PutStr ("(TP3 option R / debugger not yet wired)") ;
  604. CrLf ;
  605. WaitEsc
  606. END CmdRun ;
  607. PROCEDURE CmdEditor ;
  608. VAR edChanged : BOOLEAN ;
  609. BEGIN
  610. IF StrLen (workName) = 0 THEN
  611. (* kgetfn: no work file yet -> prompt just like W does *)
  612. CmdWorkFile ;
  613. IF StrLen (workName) = 0 THEN
  614. RETURN
  615. END
  616. END ;
  617. edChanged := FALSE ;
  618. Run (drive, workName, edChanged) ;
  619. IF edChanged THEN
  620. changed := TRUE
  621. END
  622. END CmdEditor ;
  623. (* ------------------------------------------------------------------ *)
  624. (* TP3 "Options" submenu (optmenu) *)
  625. (* ------------------------------------------------------------------ *)
  626. PROCEDURE PutHex (n : CARDINAL) ;
  627. VAR dig : ARRAY [0..7] OF CHAR ;
  628. i, d : CARDINAL ;
  629. BEGIN
  630. i := 0 ;
  631. LOOP
  632. d := n MOD 16 ;
  633. IF d < 10 THEN
  634. dig [i] := CHR (ORD ("0") + d)
  635. ELSE
  636. dig [i] := CHR (ORD ("A") + d - 10)
  637. END ;
  638. n := n DIV 16 ;
  639. INC (i) ;
  640. IF (n = 0) OR (i = 8) THEN
  641. EXIT
  642. END
  643. END ;
  644. WHILE i > 0 DO
  645. DEC (i) ;
  646. PutCh (dig [i])
  647. END
  648. END PutHex ;
  649. PROCEDURE OptionsMenu ;
  650. VAR ch : CHAR ;
  651. s : ARRAY [0..255] OF CHAR ;
  652. done : BOOLEAN ;
  653. BEGIN
  654. done := FALSE ;
  655. REPEAT
  656. ClrScr ;
  657. GotoXY (1, 1) ;
  658. Marked ; PutCh ("M") ; Normal ;
  659. PutStr ("emory ") ;
  660. Marked ; PutCh ("C") ; Normal ;
  661. PutStr ("OM ") ;
  662. Marked ; PutCh ("H") ; Normal ;
  663. PutStr ("CHN") ;
  664. CrLf ;
  665. PutStr (" ") ;
  666. IF codeDest = 1 THEN
  667. PutStr ("Compile -> COM")
  668. ELSIF codeDest = 2 THEN
  669. PutStr ("Compile -> CHN")
  670. ELSE
  671. PutStr ("Compile -> Memory")
  672. END ;
  673. CrLf ;
  674. PutStr ("Text: ") ;
  675. PutCard (Length ()) ;
  676. PutStr (" Code: ") ;
  677. PutHex (minCode) ;
  678. PutStr (" Data: ") ;
  679. PutHex (minData) ;
  680. PutStr (" Stack: ") ;
  681. PutHex (minStack) ;
  682. CrLf ;
  683. PutStr ("Command line Params: ") ;
  684. PutStr (paramLine) ;
  685. CrLf ;
  686. Marked ; PutCh ("F") ; Normal ;
  687. PutStr ("ind run-time error ") ;
  688. Marked ; PutCh ("Q") ; Normal ;
  689. PutStr ("uit") ;
  690. CrLf ;
  691. CrLf ;
  692. Marked ; PutCh (">") ; Normal ;
  693. GetCh (ch) ;
  694. ch := Upper (ch) ;
  695. CASE ch OF
  696. | "M" : codeDest := 0
  697. | "C" : codeDest := 1
  698. | "H" : codeDest := 2
  699. | "O" :
  700. ClrScr ; GotoXY (1,1) ;
  701. PutStr ("Min Code Segment (hex): ") ;
  702. IF ReadLine (s) > 0 THEN minCode := 0 END
  703. | "D" :
  704. ClrScr ; GotoXY (1,1) ;
  705. PutStr ("Min Data Segment (hex): ") ;
  706. IF ReadLine (s) > 0 THEN minData := 0 END
  707. | "I" :
  708. ClrScr ; GotoXY (1,1) ;
  709. PutStr ("Min Free Dyn Mem / Stack (hex): ") ;
  710. IF ReadLine (s) > 0 THEN minStack := 0 END
  711. | "A" :
  712. ClrScr ; GotoXY (1,1) ;
  713. PutStr ("Max Free Dyn Mem / Stack (hex): ") ;
  714. IF ReadLine (s) > 0 THEN maxStack := 0 END
  715. | "P" :
  716. ClrScr ; GotoXY (1,1) ;
  717. PutStr ("Command line Params: ") ;
  718. IF ReadLine (paramLine) > 0 THEN
  719. (* keep the parameter string *)
  720. END
  721. | "F" :
  722. ClrScr ; GotoXY (1,1) ;
  723. PutStr ("Find run-time error address (hex) : ") ;
  724. IF ReadLine (s) > 0 THEN
  725. PutStr ("Searching ... (not implemented)") ;
  726. CrLf ;
  727. Pause
  728. END
  729. | "Q" :
  730. done := TRUE
  731. ELSE
  732. (* ignore *)
  733. END
  734. UNTIL done
  735. END OptionsMenu ;
  736. (* ------------------------------------------------------------------ *)
  737. PROCEDURE terminal ;
  738. VAR ch : CHAR ;
  739. BEGIN
  740. Open ;
  741. drive := "A" ;
  742. codeDest := 0 ;
  743. minCode := 0 ; minData := 0 ; minStack := 0 ; maxStack := 0 ;
  744. StrClear (workName) ;
  745. StrClear (mainName) ;
  746. StrClear (paramLine) ;
  747. Clear ;
  748. changed := FALSE ;
  749. LOOP
  750. DrawMenu ;
  751. GetCh (ch) ;
  752. ch := Upper (ch) ;
  753. CASE ch OF
  754. | "L" : CmdLogDrive
  755. | "A" : CmdActDir
  756. | "W" : CmdWorkFile
  757. | "M" : CmdMainFile
  758. | "E" : CmdEditor
  759. | "C" : CmdCompile
  760. | "R" : CmdRun
  761. | "S" :
  762. IF StrLen (workName) > 0 THEN
  763. SaveWorkFile ;
  764. Pause
  765. END
  766. | "D" : DirCmd
  767. | "O" : OptionsMenu
  768. | "Q" :
  769. IF changed THEN
  770. CrLf ;
  771. IF Confirm ("Work file not saved. Save (Y/N) ?") THEN
  772. SaveWorkFile
  773. END
  774. END ;
  775. Close ;
  776. (* gm2 -fiso: a bare HALT aborts (SIGABRT, shell status 134);
  777. an explicit HALT (0) exits cleanly with status 0. *)
  778. HALT (0)
  779. ELSE
  780. (* any other key: redraw the menu, like TP3 *)
  781. END
  782. END
  783. END terminal ;
  784. BEGIN
  785. terminal
  786. END Shell.