editor.mod 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. MODULE editor;
  2. (* based on the kilo editor building course*)
  3. (* Step 67 *)
  4. (*** IMPORTS ***)
  5. IMPORT IO, termios, FIO, libc, CharClass, NumberIO, ASCII ;
  6. IMPORT STextIO, Strings, SYSTEM, SplitV1, Storage, MemUtils, ProgramArgs;
  7. FROM SeqFile IMPORT OpenRead, OpenWrite, OpenResults, Close, ChanId, read, write;
  8. FROM IOResult IMPORT ReadResults, ReadResult;
  9. FROM TextIO IMPORT ReadString, ReadRestLine, SkipLine, ReadToken;
  10. FROM Storage IMPORT ALLOCATE;
  11. (*** data ***)
  12. TYPE
  13. (* display buffer *)
  14. abufType = RECORD
  15. b : SYSTEM.ADDRESS;
  16. len : CARDINAL;
  17. END;
  18. abufTypePtr = POINTER TO abufType;
  19. (* line structure : linked list *)
  20. erowPtr = POINTER TO erow;
  21. erow = RECORD
  22. size : CARDINAL;
  23. chars : SYSTEM.ADDRESS;
  24. next, previous : erowPtr;
  25. END;
  26. CONST
  27. KILO_VERSION = "0.0.1";
  28. (* escape sequences length *)
  29. clearScreenStrLen = 4;
  30. cursorHomeStrLen = 3;
  31. tildeStrLen = 3;
  32. requestCursorPosStrLen = 4;
  33. cursorOnStrLen = 6;
  34. cursorOffStrLen = 6;
  35. eraseLineStrLen = 3;
  36. nextLineDownPos1Len = 4;
  37. (* fct key mapping*)
  38. ARROW_LEFT = 1000;
  39. ARROW_RIGHT = 1001;
  40. ARROW_UP = 1002;
  41. ARROW_DOWN = 1003;
  42. HOME_KEY = 1004;
  43. END_KEY = 1005;
  44. PAGE_UP = 1006;
  45. PAGE_DOWN = 1007;
  46. DEL_KEY = 1008;
  47. VAR
  48. editorConfig : RECORD
  49. screenrows : CARDINAL;
  50. screencols : CARDINAL;
  51. posX : CARDINAL;
  52. posY : CARDINAL;
  53. theTermios : termios.TERMIOS;
  54. rows : erowPtr;
  55. lastRow : erowPtr;
  56. numrows : CARDINAL;
  57. rowoff : CARDINAL;
  58. END;
  59. theRow : erow;
  60. theRowPtr : erowPtr;
  61. (* termios*)
  62. c : CHAR;
  63. TCSAFLUSH : INTEGER;
  64. (* Split structure *)
  65. theStructure : SplitV1.Structure;
  66. (* utility *)
  67. i : CARDINAL;
  68. (* escape sequences *)
  69. clearScreenStr : ARRAY [0..3] OF CHAR;
  70. cursorHomeStr : ARRAY [0..2] OF CHAR;
  71. tildeStr : ARRAY [0..2] OF CHAR;
  72. requestCursorPosStr : ARRAY [0..3] OF CHAR;
  73. cursorposStr : ARRAY [0..15] OF CHAR;
  74. cursorOnStr : ARRAY [0..5] OF CHAR;
  75. cursorOffStr : ARRAY [0..5] OF CHAR;
  76. eraseLineStr : ARRAY [0..2] OF CHAR;
  77. nextLineDownPos1 : ARRAY [0..3] OF CHAR;
  78. (* temporary variables *)
  79. tmpString : ARRAY [0..15] OF CHAR;
  80. tmpString1 : ARRAY [0..15] OF CHAR;
  81. tmpString2 : Strings.String1;
  82. cc : Strings.String1;
  83. (* error and information message string *)
  84. message : ARRAY [0..79] OF CHAR;
  85. (* cli arguments *)
  86. theArgChanId : ChanId;
  87. theArgument : ARRAY [0..20] OF CHAR;
  88. theFileName : ARRAY [0..20] OF CHAR;
  89. argumentNumber : CARDINAL;
  90. (******************** Utilities *****************)
  91. PROCEDURE Card2Str ( x : CARDINAL; VAR str : ARRAY OF CHAR);
  92. BEGIN
  93. IF x < 10 THEN
  94. NumberIO.CardToStr(x,1,str);
  95. ELSIF x < 100 THEN
  96. NumberIO.CardToStr(x,2,str);
  97. ELSE
  98. NumberIO.CardToStr(x,3,str);
  99. END;
  100. END Card2Str;
  101. (******************** Buffer ******************)
  102. PROCEDURE abufInit( VAR ptr : abufTypePtr);
  103. BEGIN
  104. Storage.ALLOCATE(ptr,SYSTEM.TSIZE(abufType) );
  105. ptr^.b := NIL;
  106. ptr^.len := 0;
  107. END abufInit;
  108. PROCEDURE abAppend (VAR ptr : abufTypePtr; theSourceAdress: SYSTEM.ADDRESS; theSourceLen : CARDINAL );
  109. BEGIN
  110. IF ptr <> NIL THEN
  111. IF ptr^.b = NIL THEN
  112. Storage.ALLOCATE(ptr^.b,theSourceLen);
  113. ELSE
  114. Storage.REALLOCATE( ptr^.b,ptr^.len + theSourceLen);
  115. END;
  116. MemUtils.MemCopy(theSourceAdress,theSourceLen, SYSTEM.ADDADR(ptr^.b,ptr^.len));
  117. ptr^.len := ptr^.len + theSourceLen;
  118. END;
  119. END abAppend;
  120. PROCEDURE abFree (VAR ptr : abufTypePtr);
  121. BEGIN
  122. Storage.DEALLOCATE(ptr^.b, ptr^.len);
  123. Storage.DEALLOCATE(ptr,SYSTEM.TSIZE(abufType));
  124. END abFree;
  125. (*** Terminal ***)
  126. PROCEDURE CtrlKey(c: CHAR) : CARDINAL;
  127. VAR
  128. n : BITSET;
  129. BEGIN
  130. n := BITSET(ORD(c));
  131. n := n * BITSET(1FH);
  132. RETURN CARDINAL(n)
  133. END CtrlKey;
  134. PROCEDURE die (s : ARRAY OF CHAR);
  135. BEGIN
  136. libc.write(FIO.StdOut,SYSTEM.ADR(cursorHomeStr), cursorHomeStrLen);
  137. libc.write(FIO.StdOut,SYSTEM.ADR(clearScreenStr), clearScreenStrLen);
  138. libc.perror(s);
  139. FOR i := 0 TO Strings.Length(s) DO
  140. IO.Write(s[i])
  141. END;
  142. HALT
  143. END die;
  144. PROCEDURE disablerawMode() : INTEGER;
  145. VAR
  146. result : INTEGER;
  147. BEGIN
  148. IO.BufferedMode(0,TRUE);
  149. IO.BufferedMode(1,TRUE);
  150. result := termios.tcsetattr(FIO.StdIn, TCSAFLUSH, editorConfig.theTermios);
  151. IF result = -1 THEN
  152. editorConfig.theTermios := termios.KillTermios(editorConfig.theTermios);
  153. die("tcsetattr")
  154. ELSE
  155. RETURN result
  156. END;
  157. END disablerawMode;
  158. PROCEDURE enablerawMode;
  159. BEGIN
  160. libc.atexit(disablerawMode);
  161. editorConfig.theTermios := termios.InitTermios();
  162. IF termios.tcgetattr(FIO.StdIn, editorConfig.theTermios) = -1 THEN
  163. die("tcgetattr")
  164. END;
  165. IO.UnBufferedMode(0,TRUE);
  166. IO.UnBufferedMode(1,TRUE);
  167. END enablerawMode;
  168. PROCEDURE editorReadKey() : CARDINAL;
  169. VAR
  170. c : CHAR;
  171. d : CHAR;
  172. num : CARDINAL;
  173. (*
  174. The Home key could be sent as <esc>[1~, <esc>[7~, <esc>[H, or
  175. <esc>OH (this is the letter O followed by H).
  176. Similarly, the End key could be sent as <esc>[4~, <esc>[8~,
  177. <esc>[F, or <esc>OF (this is the letter O followed by F).
  178. *)
  179. BEGIN
  180. IO.Read(c);
  181. IF c = ASCII.esc THEN
  182. IO.Read(c);
  183. (* mode := command; *)
  184. IF c = "[" THEN
  185. IO.Read(c);
  186. IF (c > "0") AND (c <"9") THEN
  187. IO.Read(d);
  188. IF d = "~" THEN
  189. CASE c OF
  190. "4", "8" : num := END_KEY; |
  191. "1", "7" : num := HOME_KEY; |
  192. "5" : num := PAGE_UP; |
  193. "6" : num := PAGE_DOWN;|
  194. "3" : num := DEL_KEY
  195. END;
  196. END;
  197. ELSIF (c = "A") OR (c = "B") OR (c = "C") OR (c = "D") OR (c = "F") OR (c = "H") THEN
  198. CASE c OF
  199. "A" : num := ARROW_UP; |
  200. "B" : num := ARROW_DOWN ; |
  201. "C" : num := ARROW_RIGHT; |
  202. "D" : num := ARROW_LEFT; |
  203. "F" : num := END_KEY; |
  204. "H" : num := HOME_KEY;
  205. END;
  206. ELSIF c = "O" THEN
  207. IO.Read(c);
  208. CASE c OF
  209. "F" : num := END_KEY; |
  210. "H" : num := HOME_KEY;
  211. END;
  212. ELSE
  213. message := ("key not recognized");
  214. END;
  215. (* mode := move; *)
  216. (* <esc>OF <esc>OH à voir !*)
  217. END;
  218. RETURN num;
  219. ELSE
  220. (* mode := edit; *)
  221. RETURN ORD(c)
  222. END;
  223. END editorReadKey;
  224. (*** row operations ***)
  225. PROCEDURE editorAppendRow(VAR line : ARRAY OF CHAR);
  226. VAR
  227. size : CARDINAL;
  228. BEGIN
  229. NEW(theRowPtr);
  230. size := Strings.Length(line);
  231. theRowPtr^.size := size;
  232. Storage.ALLOCATE(theRowPtr^.chars, size);
  233. MemUtils.MemCopy(SYSTEM.ADR(line),size,theRowPtr^.chars);
  234. theRowPtr^.next := NIL;
  235. (* if no lines were allocated *)
  236. IF editorConfig.rows = NIL THEN
  237. editorConfig.rows := theRowPtr;
  238. theRowPtr^.previous := editorConfig.rows;
  239. ELSE (* there are already some lines in the structure *)
  240. theRowPtr^.previous := editorConfig.lastRow;
  241. editorConfig.lastRow^.next := theRowPtr;
  242. END;
  243. editorConfig.lastRow := theRowPtr;
  244. INC(editorConfig.numrows);
  245. END editorAppendRow;
  246. (******************** file I/O ***************)
  247. PROCEDURE editorOpen( fileName : ARRAY OF CHAR);
  248. VAR
  249. theChanId : ChanId;
  250. theResult : OpenResults;
  251. line : ARRAY[0..255] OF CHAR;
  252. BEGIN
  253. (* PROCEDURE OpenRead (VAR cid: ChanId; name: ARRAY OF CHAR; flags: FlagSet; VAR res: OpenResults); *)
  254. OpenRead(theChanId, fileName, read, theResult);
  255. (* test du résultat*)
  256. IF theResult = noSuchFile THEN
  257. die("No such file")
  258. ELSIF theResult=opened THEN (* reading the lines ... *)
  259. (* first line *)
  260. line := "";
  261. ReadString(theChanId, line);
  262. (* testing the result *)
  263. WHILE ReadResult(theChanId) <> endOfInput DO
  264. (* testing end of line *)
  265. IF ReadResult(theChanId) = endOfLine THEN
  266. (* we have to 'skip' the endOfLine ... so strange *)
  267. SkipLine(theChanId);
  268. END;
  269. editorAppendRow(line);
  270. (* reading next line *)
  271. ReadString(theChanId, line);
  272. END;
  273. ELSE
  274. die("Error opening the file");
  275. END;
  276. Close(theChanId);
  277. END editorOpen;
  278. PROCEDURE editorMoveCursor(c : CARDINAL);
  279. BEGIN
  280. WITH editorConfig DO
  281. CASE c OF
  282. ARROW_UP, ORD("e") : IF posY > 1 THEN DEC(posY) END; |
  283. ARROW_DOWN, ORD("x") : IF posY < (screenrows - 1) THEN INC(posY) END; |
  284. ARROW_LEFT, ORD("s") : IF posX > 1 THEN DEC(posX) END; |
  285. ARROW_RIGHT, ORD("d") : IF posX < (screencols - 1) THEN INC(posX) END; |
  286. PAGE_UP : posY := 1; |
  287. PAGE_DOWN : posY := screenrows; |
  288. HOME_KEY : posX := 1; |
  289. END_KEY : posX := screencols;
  290. END;
  291. END
  292. END editorMoveCursor;
  293. PROCEDURE editorProcessKeypress;
  294. VAR
  295. c : CARDINAL;
  296. BEGIN
  297. c := editorReadKey();
  298. CASE c OF
  299. 17 : libc.write(FIO.StdOut,SYSTEM.ADR(cursorHomeStr), cursorHomeStrLen);
  300. libc.write(FIO.StdOut,SYSTEM.ADR(clearScreenStr), clearScreenStrLen);
  301. HALT; |
  302. ORD("e"),
  303. ORD("x"),
  304. ORD("s"),
  305. ORD("d"),
  306. HOME_KEY,
  307. END_KEY,
  308. PAGE_UP,
  309. PAGE_DOWN,
  310. ARROW_UP,
  311. ARROW_DOWN,
  312. ARROW_LEFT,
  313. ARROW_RIGHT : editorMoveCursor(c);
  314. END
  315. END editorProcessKeypress;
  316. (*** Output ***)
  317. PROCEDURE editorDrawRows(VAR ptr : abufTypePtr);
  318. CONST
  319. tilde = "~";
  320. VAR
  321. y : CARDINAL;
  322. welcome : ARRAY [0..79] OF CHAR;
  323. welcomeLen : CARDINAL;
  324. blanks : CARDINAL;
  325. blanksStr : ARRAY[0..79] OF CHAR;
  326. blankStrLength : CARDINAL;
  327. len : CARDINAL;
  328. fileRow : CARDINAL;
  329. BEGIN
  330. (* Creation of the about text *)
  331. welcome := "Kilo editor -- version ";
  332. Strings.Concat(welcome,KILO_VERSION,welcome);
  333. welcomeLen := Strings.Length(welcome);
  334. Strings.Concat(welcome,nextLineDownPos1,welcome);
  335. (* centering the welcome text *)
  336. blanks := (editorConfig.screencols - welcomeLen) /2;
  337. cc[0] := " ";
  338. blanksStr := "";
  339. FOR i := 0 TO blanks DO
  340. Strings.Concat(blanksStr,cc,blanksStr);
  341. END;
  342. blankStrLength := Strings.Length(blanksStr);
  343. (* display of the page *)
  344. theRowPtr := editorConfig.rows;
  345. (* editorConfig.rowoff := 5; *)
  346. FOR y := 1 TO editorConfig.screenrows -1 DO
  347. (* for all lines except the last one, beginning at fileRow *)
  348. fileRow := y + editorConfig.rowoff;
  349. IF fileRow >= editorConfig.numrows THEN
  350. IF ((y = (editorConfig.screenrows / 3)) AND (editorConfig.screencols > welcomeLen)) AND (editorConfig.numrows = 0) THEN
  351. abAppend(ptr,SYSTEM.ADR(blanksStr), blankStrLength);
  352. abAppend(ptr,SYSTEM.ADR(welcome),welcomeLen );
  353. abAppend(ptr,SYSTEM.ADR(eraseLineStr),eraseLineStrLen );
  354. abAppend(ptr,SYSTEM.ADR(nextLineDownPos1),nextLineDownPos1Len );
  355. ELSE
  356. abAppend(ptr,SYSTEM.ADR(tilde), 1);
  357. abAppend(ptr,SYSTEM.ADR(eraseLineStr),eraseLineStrLen );
  358. abAppend(ptr,SYSTEM.ADR(nextLineDownPos1),nextLineDownPos1Len );
  359. END;
  360. ELSE
  361. IF y < editorConfig.rowoff THEN
  362. theRowPtr := theRowPtr^.next;
  363. ELSE
  364. len := theRowPtr^.size;
  365. IF len > editorConfig.screencols THEN
  366. len := editorConfig.screencols
  367. END;
  368. (* displaying the text lines begining at fileRow*)
  369. abAppend(ptr,theRowPtr^.chars,len);
  370. theRowPtr := theRowPtr^.next;
  371. abAppend(ptr,SYSTEM.ADR(eraseLineStr),eraseLineStrLen );
  372. abAppend(ptr,SYSTEM.ADR(nextLineDownPos1),nextLineDownPos1Len );
  373. END;
  374. END;
  375. END;
  376. (* last line *)
  377. abAppend(ptr,SYSTEM.ADR(tilde), 1);
  378. abAppend(ptr,SYSTEM.ADR(eraseLineStr),eraseLineStrLen );
  379. abAppend(ptr,SYSTEM.ADR(nextLineDownPos1),nextLineDownPos1Len );
  380. END editorDrawRows;
  381. PROCEDURE editorRefreshScreen;
  382. VAR
  383. ptr : abufTypePtr;
  384. BEGIN
  385. abufInit(ptr);
  386. abAppend(ptr,SYSTEM.ADR(cursorOffStr), cursorOffStrLen);
  387. abAppend(ptr,SYSTEM.ADR(cursorHomeStr), cursorHomeStrLen);
  388. editorDrawRows(ptr);
  389. (* cursorpos(1,1,FALSE); *)
  390. cursorpos(editorConfig.posX,editorConfig.posY,FALSE);
  391. abAppend(ptr,SYSTEM.ADR(cursorposStr), Strings.Length(cursorposStr));
  392. abAppend(ptr,SYSTEM.ADR(cursorOnStr), cursorOnStrLen);
  393. libc.write(FIO.StdOut,ptr^.b,ptr^.len);
  394. abFree(ptr);
  395. END editorRefreshScreen;
  396. PROCEDURE requestCursorPosition(VAR x,y : CARDINAL);
  397. VAR
  398. c : CHAR;
  399. str : ARRAY [0..15] OF CHAR;
  400. BEGIN
  401. str := "";
  402. SplitV1.InitStructure(theStructure);
  403. libc.write(FIO.StdOut,SYSTEM.ADR(requestCursorPosStr),requestCursorPosStrLen);
  404. (* getting answer *)
  405. str := "";
  406. REPEAT
  407. IO.Read(c);
  408. cc[0] := c;
  409. Strings.Concat(str,cc,str);
  410. UNTIL c = "R";
  411. Strings.Delete(str,0,2);
  412. Strings.Delete(str,Strings.Length(str) -1 ,1);
  413. SplitV1.SplitStr(str, ";", theStructure);
  414. NumberIO.StrToCard(theStructure[0].element,y);
  415. NumberIO.StrToCard(theStructure[1].element,x);
  416. END requestCursorPosition;
  417. PROCEDURE cursorpos(x,y : CARDINAL; emit : BOOLEAN);
  418. BEGIN
  419. cursorposStr := "";
  420. Strings.Concat(cursorposStr, ASCII.esc,cursorposStr);
  421. Strings.Concat(cursorposStr, "[",cursorposStr);
  422. tmpString := "";
  423. Strings.Concat(tmpString,cursorposStr, tmpString);
  424. tmpString1 := "";
  425. Card2Str(y,tmpString1);
  426. Strings.Concat(tmpString,tmpString1, tmpString);
  427. tmpString2[0] := ";";
  428. Strings.Concat(tmpString, tmpString2,tmpString);
  429. tmpString1 := "";
  430. Card2Str(x,tmpString1);
  431. Strings.Concat(tmpString,tmpString1, tmpString);
  432. tmpString2[0] := "H";
  433. Strings.Concat(tmpString, tmpString2,tmpString);
  434. cursorposStr := tmpString;
  435. editorConfig.posX := x;
  436. editorConfig.posY := y;
  437. IF emit THEN
  438. libc.write(FIO.StdOut,SYSTEM.ADR(tmpString),Strings.Length(tmpString));
  439. END;
  440. END cursorpos;
  441. PROCEDURE getWindowSize(VAR y : CARDINAL; VAR x: CARDINAL);
  442. BEGIN
  443. cursorpos(999,999, TRUE);
  444. requestCursorPosition(x,y);
  445. END getWindowSize;
  446. (*** Input ***)
  447. (*** Init ***)
  448. PROCEDURE InitScreenEscapes;
  449. VAR temp : ARRAY[0..10] OF CHAR;
  450. BEGIN
  451. cursorHomeStr := "";
  452. Strings.Concat(cursorHomeStr,ASCII.esc,cursorHomeStr);
  453. Strings.Concat(cursorHomeStr,"[H",cursorHomeStr);
  454. clearScreenStr := "";
  455. Strings.Concat(clearScreenStr,ASCII.esc,clearScreenStr);
  456. Strings.Concat(clearScreenStr,"[2J",clearScreenStr);
  457. tildeStr[0] := "~";
  458. tildeStr[1] := CHR(10);
  459. tildeStr[2] := CHR(13);
  460. cursorposStr := "";
  461. Strings.Concat(cursorposStr,ASCII.esc,cursorposStr);
  462. Strings.Concat(cursorposStr,"[",cursorposStr);
  463. requestCursorPosStr := "";
  464. Strings.Concat(requestCursorPosStr,ASCII.esc,requestCursorPosStr);
  465. Strings.Concat(requestCursorPosStr,"[6n",requestCursorPosStr);
  466. cursorOnStr := "";
  467. Strings.Concat(cursorOnStr,ASCII.esc,cursorOnStr);
  468. Strings.Concat(cursorOnStr,"[?25h",cursorOnStr);
  469. cursorOffStr := "";
  470. Strings.Concat(cursorOffStr,ASCII.esc,cursorOffStr);
  471. Strings.Concat(cursorOffStr,"[?25l",cursorOffStr);
  472. eraseLineStr := "";
  473. Strings.Concat(eraseLineStr,ASCII.esc,eraseLineStr);
  474. Strings.Concat(eraseLineStr,"[K",eraseLineStr);
  475. (* ESC[#E moves cursor to beginning of next line, # lines down *)
  476. nextLineDownPos1 := "";
  477. Strings.Concat(nextLineDownPos1,ASCII.esc,nextLineDownPos1);
  478. Strings.Concat(nextLineDownPos1,"[1E",nextLineDownPos1);
  479. END InitScreenEscapes;
  480. PROCEDURE InitEditor;
  481. BEGIN
  482. TCSAFLUSH := termios.tcsflush ();
  483. InitScreenEscapes;
  484. editorConfig.posX := 1;
  485. editorConfig.posY := 1;
  486. getWindowSize(editorConfig.screenrows, editorConfig.screencols);
  487. editorConfig.posX := 1;
  488. editorConfig.posY := 1;
  489. editorConfig.numrows := 0;
  490. editorConfig.rows := NIL;
  491. editorConfig.rowoff := 1;
  492. libc.write(FIO.StdOut,SYSTEM.ADR(clearScreenStr),4);
  493. END InitEditor;
  494. BEGIN
  495. enablerawMode;
  496. InitEditor;
  497. editorRefreshScreen;
  498. (* fetching the 2nd argument (fileName) *)
  499. theFileName := "";
  500. theArgChanId := ProgramArgs.ArgChan ();
  501. argumentNumber := 0;
  502. WHILE ProgramArgs.IsArgPresent() DO
  503. INC(argumentNumber);
  504. ReadToken(ProgramArgs.ArgChan(), theArgument);
  505. IF argumentNumber = 2 THEN
  506. theFileName := theArgument;
  507. END;
  508. ProgramArgs.NextArg ();
  509. END;
  510. IF argumentNumber >= 2 THEN
  511. editorOpen(theFileName);
  512. END;
  513. LOOP
  514. editorRefreshScreen;
  515. editorProcessKeypress;
  516. END;
  517. END editor.