Shell.mod 23 KB

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