FileIO-1.mod 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  1. IMPLEMENTATION MODULE FileIO ;
  2. (* This module attempts to provide several potentially non-portable
  3. facilities for Coco/R.
  4. (a) A general file input/output module, with all routines required for
  5. Coco/R itself, as well as several other that would be useful in
  6. Coco-generated applications.
  7. (b) Definition of the "LONGINT" type needed by Coco.
  8. (c) Some conversion functions to handle this long type.
  9. (d) Some "long" and other constant literals that may be problematic
  10. on some implementations.
  11. (e) Some string handling primitives needed to interface to a variety
  12. of known implementations.
  13. The intention is that the rest of the code of Coco and its generated
  14. parsers should be as portable as possible. Provided the definition
  15. module given, and the associated implementation, satisfy the
  16. specification given here, this should be almost 100% possible (with
  17. the exception of a few constants, avoid changing anything in this
  18. specification).
  19. FileIO is based on code by MB 1990/11/25; heavily modified and extended
  20. by PDT and others between 1992/1/6 and the present day. *)
  21. (* This is the generic WinTel version *)
  22. FROM SYSTEM IMPORT TSIZE;
  23. IMPORT FileSystem, Strings, InOut;
  24. FROM OS2DEF IMPORT APIRET;
  25. FROM OS2ARG IMPORT ArgCount, Arg, STRING, PSTRING,
  26. EnvCount, Env ;
  27. FROM DOSDATETIME IMPORT DATETIME, DosGetDateTime;
  28. FROM Storage IMPORT ALLOCATE, DEALLOCATE;
  29. CONST
  30. MaxFiles = BitSetSize;
  31. NameLength = 256;
  32. BufSize = 1024 ;
  33. TYPE Buftype = ARRAY [0..BufSize] OF CHAR;
  34. VAR
  35. Handles: BITSET;
  36. Opened: ARRAY [0 .. MaxFiles-1] OF File;
  37. FromKeyboard, ToScreen: BOOLEAN;
  38. Param: LONGCARD;
  39. Continue: PROC;
  40. TYPE CommandType = POINTER TO ARRAY [0..255] OF CHAR;
  41. File = POINTER TO FileRec;
  42. FileRec = RECORD
  43. ref: FileSystem.File;
  44. self: File;
  45. handle: CARDINAL;
  46. savedCh: CHAR;
  47. textOK, eof, eol, noOutput, noInput, haveCh: BOOLEAN;
  48. name: ARRAY [0 .. NameLength] OF CHAR;
  49. END;
  50. PROCEDURE NextParameter (VAR s: ARRAY OF CHAR);
  51. VAR P : PSTRING;
  52. BEGIN
  53. INC(Param);
  54. IF Param <= ArgCount()
  55. THEN P := Arg ( Param );
  56. IF P # NIL THEN Assign ( P^, s);END;
  57. ELSE s[0] := 0C
  58. END
  59. END NextParameter;
  60. PROCEDURE GetEnv ( envVar : ARRAY OF CHAR; VAR s : ARRAY OF CHAR );
  61. VAR pos, index, idxmax : LONGCARD;
  62. match : BOOLEAN;
  63. ct : CommandType;
  64. i,j : LONGCARD;
  65. c : CHAR;
  66. BEGIN
  67. match := FALSE;
  68. s [ 0 ] := CHR(0);
  69. j := Strings.Length (envVar);
  70. FOR i := 0 TO j DO envVar[i] := CAP(envVar[i]) END;
  71. idxmax := EnvCount();
  72. INC (idxmax);
  73. index := 0;
  74. WHILE (index < idxmax) AND (NOT match) DO
  75. ct := CommandType( Env (index));
  76. IF ct # NIL THEN
  77. pos := Strings.Pos ( envVar, ct^ );
  78. match := ( pos = 0)
  79. END; (* if ct # *)
  80. INC (index);
  81. END; (* While *)
  82. IF match THEN
  83. i:=0;
  84. REPEAT c := ct^[i]; INC (i) UNTIL c = '=';
  85. c := ct^[i];
  86. WHILE ct^[i] = ' ' DO INC(i) END;
  87. j := 0;
  88. REPEAT
  89. c := ct^[i];
  90. s[j] := c ;
  91. INC(i); INC(j);
  92. UNTIL ( c = CHR(0)) OR (j = HIGH(s)) ;
  93. END;
  94. END GetEnv ;
  95. PROCEDURE ASCIIZ (VAR s1, s2: ARRAY OF CHAR);
  96. (* Convert s2 to a nul terminated string in s1 *)
  97. VAR i: CARDINAL;
  98. BEGIN
  99. i := 0;
  100. WHILE (i <= HIGH(s2)) & (s2[i] # 0C) DO
  101. s1[i] := s2[i]; INC(i)
  102. END;
  103. s1[i] := 0C
  104. END ASCIIZ;
  105. PROCEDURE Open (VAR f: File; fileName: ARRAY OF CHAR; newFile: BOOLEAN);
  106. VAR
  107. i: CARDINAL;
  108. NoWrite: BOOLEAN;
  109. name: ARRAY [0 .. NameLength] OF CHAR;
  110. BEGIN
  111. ExtractFileName(fileName, name);
  112. FOR i := 0 TO NameLength - 1 DO name[i] := CAP(name[i]) END;
  113. IF (name[0] = 0C) OR (Strings.Compare(name, "CON") = 0) THEN
  114. (* con already opened, but reset it *)
  115. Okay := TRUE; f := con;
  116. f^.savedCh := 0C; f^.haveCh := FALSE;
  117. f^.eof := FALSE; f^.eol := FALSE; f^.name := "CON";
  118. RETURN
  119. ELSIF Strings.Compare(name, "ERR") = 0 THEN
  120. Okay := TRUE; f := err; RETURN
  121. ELSE
  122. ALLOCATE(f, SIZE(FileRec));
  123. NoWrite := FALSE;
  124. IF newFile
  125. THEN FileSystem.Create( f^.ref, fileName)
  126. ELSE
  127. FileSystem.Lookup(f^.ref, fileName, FALSE );
  128. END;
  129. Okay := f^.ref.res = 0;
  130. IF ~ Okay
  131. THEN
  132. DEALLOCATE(f, SIZE(FileRec)); f := NIL
  133. ELSE
  134. (* textOK below may have to be altered according to implementation *)
  135. f^.savedCh := 0C; f^.haveCh := FALSE; f^.textOK := TRUE;
  136. f^.eof := newFile; f^.eol := newFile; f^.self := f;
  137. f^.noInput := newFile; f^.noOutput := ~ newFile OR NoWrite;
  138. ASCIIZ(f^.name, fileName);
  139. i := 0 (* find next available filehandle *);
  140. WHILE (i IN Handles) & (i < MaxFiles) DO INC(i) END;
  141. IF i < MaxFiles
  142. THEN f^.handle := i; INCL(Handles, i); Opened[i] := f
  143. ELSE (* WriteString(err, "Too many files"); Okay := FALSE *)
  144. END;
  145. (* IF Okay THEN FIO.AssignBuffer(f^.ref, f^.buffer) END; *)
  146. END
  147. END
  148. END Open;
  149. PROCEDURE NotRead (f: File): BOOLEAN;
  150. BEGIN
  151. RETURN (f = NIL) OR (f^.self # f) OR (f^.noInput);
  152. END NotRead;
  153. PROCEDURE NotWrite (f: File): BOOLEAN;
  154. BEGIN
  155. RETURN (f = NIL) OR (f^.self # f) OR (f^.noOutput);
  156. END NotWrite;
  157. PROCEDURE NotFile (f: File): BOOLEAN;
  158. BEGIN
  159. IF (f = NIL) THEN RETURN TRUE END;
  160. IF (f^.self # f) OR (File(f) = con) OR (File(f) = err)
  161. THEN RETURN TRUE END;
  162. IF (File(f) = StdIn) & FromKeyboard
  163. THEN RETURN TRUE END;
  164. IF (File(f) = StdOut) & ToScreen
  165. THEN RETURN TRUE END;
  166. RETURN FALSE
  167. END NotFile;
  168. PROCEDURE Close (VAR f: File);
  169. BEGIN
  170. (* IF f = NIL THEN RETURN END;*)
  171. IF NotFile(f) OR (File(f) = StdIn) OR (File(f) = StdOut)
  172. THEN Okay := FALSE
  173. ELSE
  174. EXCL(Handles, f^.handle);
  175. FileSystem.Close(f^.ref);
  176. Okay := f^.ref.res = 0;
  177. IF Okay THEN DEALLOCATE(f, TSIZE(FileRec)) END;
  178. f := NIL
  179. END
  180. END Close;
  181. PROCEDURE CloseAll;
  182. VAR
  183. handle: CARDINAL;
  184. BEGIN
  185. FOR handle := 0 TO MaxFiles - 1 DO
  186. IF handle IN Handles THEN Close(Opened[handle]) END
  187. END;
  188. IF ~ ToScreen THEN FileSystem.Close(StdOut^.ref) END;
  189. Continue;
  190. END CloseAll;
  191. PROCEDURE Delete (VAR f: File);
  192. BEGIN
  193. IF NotFile(f) OR (File(f) = StdIn) OR (File(f) = StdOut)
  194. THEN Okay := FALSE
  195. ELSE
  196. EXCL(Handles, f^.handle);
  197. FileSystem.Close (f^.ref);
  198. FileSystem.Delete(f^.ref);
  199. Okay := f^.ref.res = 0;
  200. IF Okay THEN DEALLOCATE(f, TSIZE(FileRec)) END;
  201. f := NIL
  202. END
  203. END Delete;
  204. PROCEDURE SLENGTH (stringVal: ARRAY OF CHAR): CARDINAL;
  205. BEGIN
  206. RETURN CARDINAL ( Strings.Length(stringVal) )
  207. END SLENGTH;
  208. PROCEDURE Concat (string1, string2: ARRAY OF CHAR; VAR destination: ARRAY OF CHAR);
  209. BEGIN
  210. Strings.Concat( string1, string2,destination );
  211. END Concat;
  212. PROCEDURE Assign ( source: ARRAY OF CHAR; VAR destination: ARRAY OF CHAR);
  213. BEGIN
  214. Strings.Assign ( source, destination )
  215. END Assign;
  216. PROCEDURE Extract (source: ARRAY OF CHAR; startIndex: CARDINAL;
  217. numberToExtract: CARDINAL; VAR destination: ARRAY OF CHAR);
  218. BEGIN
  219. Strings.Copy (source, startIndex, numberToExtract, destination )
  220. END Extract;
  221. PROCEDURE Compare (stringVal1, stringVal2: ARRAY OF CHAR): INTEGER;
  222. BEGIN
  223. RETURN Strings.Compare(stringVal1, stringVal2)
  224. END Compare;
  225. PROCEDURE SearchFile (VAR f: File; envVar, fileName: ARRAY OF CHAR;
  226. newFile: BOOLEAN);
  227. VAR
  228. i, j: INTEGER;
  229. k : CARDINAL;
  230. c: CHAR;
  231. fname: ARRAY [0 .. NameLength] OF CHAR;
  232. path: ARRAY [0 .. NameLength] OF CHAR;
  233. BEGIN
  234. FOR k := 0 TO CARDINAL ( HIGH(envVar) ) DO envVar[k] := CAP(envVar[k]) END;
  235. GetEnv(envVar, path);
  236. i := 0;
  237. REPEAT
  238. j := 0;
  239. REPEAT
  240. c := path[i]; fname[j] := c; INC(i); INC(j)
  241. UNTIL (c = PathSep) OR (c = 0C);
  242. IF (j > 1) & (fname[j-2] = DirSep) THEN DEC(j) ELSE fname[j-1] := DirSep END;
  243. fname[j] := 0C; Concat(fname, fileName, fname);
  244. Open(f, fname, newFile);
  245. UNTIL (c = 0C) OR Okay
  246. END SearchFile;
  247. PROCEDURE ExtractFileName (fullName : ARRAY OF CHAR; VAR fileName : ARRAY OF CHAR );
  248. VAR i, l, start: CARDINAL;
  249. BEGIN
  250. start := 0; l := 0;
  251. WHILE (l <= HIGH(fullName)) & (fullName[l] # 0C) DO
  252. IF (fullName[l] = ":") OR (fullName[l] = DirSep) THEN start := l + 1 END;
  253. INC(l)
  254. END;
  255. i := 0;
  256. WHILE (start < l) & (i <= HIGH(fileName)) DO
  257. fileName[i] := fullName[start]; INC(start); INC(i)
  258. END;
  259. IF i <= HIGH(fileName) THEN fileName[i] := 0C END
  260. END ExtractFileName;
  261. PROCEDURE ExtractDirectory (fullName : ARRAY OF CHAR; VAR directory : ARRAY OF CHAR );
  262. VAR i, start: CARDINAL;
  263. BEGIN
  264. start := 0; i := 0;
  265. WHILE (i <= HIGH(fullName)) & (fullName[i] # 0C) DO
  266. IF i <= HIGH(directory) THEN directory[i] := fullName[i] END;
  267. IF (fullName[i] = ":") OR (fullName[i] = DirSep) THEN start := i + 1 END;
  268. INC(i)
  269. END;
  270. IF start <= HIGH(directory) THEN directory[start] := 0C END
  271. END ExtractDirectory ;
  272. PROCEDURE AppendExtension (oldName, ext: ARRAY OF CHAR; VAR newName: ARRAY OF CHAR);
  273. VAR i, j: CARDINAL;
  274. fn: ARRAY [0 .. NameLength] OF CHAR;
  275. BEGIN
  276. ExtractDirectory(oldName, newName);
  277. ExtractFileName(oldName, fn);
  278. i := 0; j := 0;
  279. WHILE (i <= NameLength) & (fn[i] # 0C) DO
  280. IF fn[i] = "." THEN j := i + 1 END;
  281. INC(i)
  282. END;
  283. IF (j # i) (* then name did not end with "." *) OR (i = 0)
  284. THEN IF j # 0 THEN i := j - 1 END;
  285. IF (ext[0] # ".") & (ext[0] # 0C) THEN
  286. IF i <= NameLength THEN fn[i] := "."; INC(i) END
  287. END;
  288. j := 0;
  289. WHILE (j <= HIGH(ext)) & (ext[j] # 0C) & (i <= NameLength) DO
  290. fn[i] := ext[j]; INC(i); INC(j)
  291. END
  292. END;
  293. IF i <= NameLength THEN fn[i] := 0C END;
  294. Strings.Concat(newName, fn, newName)
  295. END AppendExtension;
  296. PROCEDURE ChangeExtension (oldName, ext: ARRAY OF CHAR; VAR newName: ARRAY OF CHAR);
  297. VAR i, j: CARDINAL;
  298. fn: ARRAY [0 .. NameLength] OF CHAR;
  299. BEGIN
  300. ExtractDirectory(oldName, newName);
  301. ExtractFileName(oldName, fn);
  302. i := 0; j := 0;
  303. WHILE (i <= NameLength) & (fn[i] # 0C) DO
  304. IF fn[i] = "." THEN j := i + 1 END;
  305. INC(i)
  306. END;
  307. IF j # 0 THEN i := j - 1 END;
  308. IF (ext[0] # ".") & (ext[0] # 0C)
  309. THEN IF i <= NameLength THEN fn[i] := "."; INC(i) END
  310. END;
  311. j := 0;
  312. WHILE (j <= HIGH(ext)) & (ext[j] # 0C) & (i <= NameLength) DO
  313. fn[i] := ext[j]; INC(i); INC(j)
  314. END;
  315. IF i <= NameLength THEN fn[i] := 0C END;
  316. Strings.Concat(newName, fn, newName)
  317. END ChangeExtension;
  318. PROCEDURE Length (f: File): INT32;
  319. VAR result: LONGCARD;
  320. BEGIN
  321. IF NotFile(f)
  322. THEN Okay := FALSE; RETURN 0
  323. ELSE FileSystem.LongLength (f^.ref, result );
  324. Okay := f^.ref.res = 0;
  325. RETURN INT32(result)
  326. END
  327. END Length;
  328. PROCEDURE GetPos (f: File): INT32;
  329. VAR pos: LONGCARD;
  330. BEGIN
  331. IF NotFile(f)
  332. THEN Okay := FALSE; RETURN Long0
  333. ELSE FileSystem.GetLongPos(f^.ref, pos );
  334. Okay := f^.ref.res = 0;
  335. RETURN pos
  336. END
  337. END GetPos;
  338. PROCEDURE SetPos (f: File; pos: INT32);
  339. BEGIN
  340. IF NotFile(f)
  341. THEN Okay := FALSE
  342. ELSE FileSystem.SetLongPos(f^.ref, LONGCARD(pos) );
  343. Okay := f^.ref.res = 0; f^.haveCh := FALSE
  344. END
  345. END SetPos;
  346. PROCEDURE Reset (f: File);
  347. BEGIN
  348. IF NotFile(f)
  349. THEN Okay := FALSE
  350. ELSE SetPos(f, 0);
  351. IF Okay
  352. THEN f^.haveCh := FALSE;
  353. f^.eof := f^.noInput;
  354. f^.eol := f^.noInput
  355. END
  356. END
  357. END Reset;
  358. PROCEDURE Rewrite (f: File);
  359. VAR c: CHAR;
  360. BEGIN
  361. IF NotFile(f)
  362. THEN Okay := FALSE
  363. ELSE SetPos(f, 0);
  364. IF Okay
  365. THEN WriteBytes(f, c, 0);
  366. f^.haveCh := FALSE;
  367. f^.savedCh := 0C;
  368. f^.eof := FALSE;
  369. f^.eol := FALSE
  370. END
  371. END
  372. END Rewrite;
  373. PROCEDURE EndOfLine (f: File): BOOLEAN;
  374. BEGIN
  375. IF NotRead(f)
  376. THEN Okay := FALSE;
  377. RETURN TRUE
  378. ELSE Okay := TRUE;
  379. RETURN f^.eol OR f^.eof
  380. END
  381. END EndOfLine;
  382. PROCEDURE EndOfFile (f: File): BOOLEAN;
  383. BEGIN
  384. IF NotRead(f)
  385. THEN Okay := FALSE;
  386. RETURN TRUE
  387. ELSE Okay := TRUE;
  388. RETURN f^.eof
  389. END
  390. END EndOfFile;
  391. PROCEDURE ErrWrite (ch: CHAR);
  392. CONST StdErr = DOSFILEMGR.STDERR;
  393. VAR c : ARRAY [0..0] OF CHAR;
  394. res,n : LONGCARD;
  395. BEGIN
  396. c[0] := ch;
  397. res := LONGCARD( DOSFILEMGR.DosWrite (StdErr,c,1,n))
  398. END ErrWrite;
  399. (* --------------A VERIFIER ------>>>> redirection *)
  400. PROCEDURE ConRead (VAR ch: CHAR);
  401. BEGIN
  402. InOut.Read ( ch )
  403. END ConRead;
  404. PROCEDURE ConWrite ( ch : CHAR );
  405. BEGIN
  406. InOut.Write (ch );
  407. END ConWrite;
  408. (*------------------------------------------------*)
  409. PROCEDURE Read (f: File; VAR ch: CHAR);
  410. BEGIN
  411. IF NotRead(f) THEN Okay := FALSE; ch := 0C; RETURN END;
  412. IF f^.haveCh OR f^.eof
  413. THEN ch := f^.savedCh;
  414. Okay := ch # 0C;
  415. ELSE
  416. IF (File(f) = con) OR (File(f) = StdIn) & FromKeyboard
  417. THEN ConRead(ch);
  418. Write(con, ch);
  419. IF ch = BS
  420. THEN ConWrite(" ");
  421. ConWrite(BS)
  422. END;
  423. Okay := ch # EOFChar;
  424. ELSE FileSystem.ReadChar(f^.ref, ch);
  425. IF ch = CR THEN FileSystem.ReadChar(f^.ref, ch); ch := EOL END;
  426. Okay := f^.ref.res = 0;
  427. IF ch = EOFChar THEN Okay := FALSE END;
  428. END;
  429. END;
  430. IF ~ Okay THEN ch := 0C END;
  431. f^.savedCh := ch; f^.haveCh := ~ Okay;
  432. f^.eof := ch = 0C; f^.eol := f^.eof OR (ch = EOL);
  433. END Read;
  434. PROCEDURE ReadAgain (f: File);
  435. BEGIN
  436. IF NotRead(f)
  437. THEN Okay := FALSE
  438. ELSE f^.haveCh := TRUE
  439. END
  440. END ReadAgain;
  441. PROCEDURE ReadLn (f: File);
  442. VAR ch: CHAR;
  443. BEGIN
  444. IF NotRead(f) THEN Okay := FALSE; RETURN END;
  445. WHILE ~ f^.eol DO Read(f, ch) END;
  446. f^.haveCh := FALSE; f^.eol := FALSE;
  447. END ReadLn;
  448. PROCEDURE ReadString (f: File; VAR str: ARRAY OF CHAR);
  449. VAR j: CARDINAL;
  450. ch: CHAR;
  451. BEGIN
  452. str[0] := 0C; j := 0;
  453. IF NotRead(f) THEN Okay := FALSE; RETURN END;
  454. REPEAT Read(f, ch) UNTIL (ch # " ") OR ~ Okay;
  455. IF Okay THEN
  456. WHILE ch >= " " DO
  457. IF j <= HIGH(str) THEN str[j] := ch END; INC(j);
  458. Read(f, ch);
  459. WHILE (ch = BS) OR (ch = DEL) DO
  460. IF j > 0 THEN DEC(j) END; Read(f, ch) END
  461. END;
  462. IF j <= HIGH(str) THEN str[j] := 0C END;
  463. Okay := j > 0; f^.haveCh := TRUE; f^.savedCh := ch;
  464. END
  465. END ReadString;
  466. PROCEDURE ReadLine (f: File; VAR str: ARRAY OF CHAR);
  467. VAR j: CARDINAL;
  468. ch: CHAR;
  469. BEGIN
  470. str[0] := 0C; j := 0;
  471. IF NotRead(f) THEN Okay := FALSE; RETURN END;
  472. Read(f, ch);
  473. IF Okay
  474. THEN WHILE ch >= " " DO
  475. IF j <= HIGH(str) THEN str[j] := ch END; INC(j);
  476. Read(f, ch);
  477. WHILE (ch = BS) OR (ch = DEL) DO
  478. IF j > 0 THEN DEC(j) END; Read(f, ch)
  479. END
  480. END;
  481. IF j <= HIGH(str) THEN str[j] := 0C END;
  482. Okay := j > 0; f^.haveCh := TRUE; f^.savedCh := ch;
  483. END
  484. END ReadLine;
  485. PROCEDURE ReadToken (f: File; VAR str: ARRAY OF CHAR);
  486. VAR j: CARDINAL;
  487. ch: CHAR;
  488. BEGIN
  489. str[0] := 0C; j := 0;
  490. IF NotRead(f) THEN Okay := FALSE; RETURN END;
  491. REPEAT Read(f, ch) UNTIL (ch > " ") OR ~ Okay;
  492. IF Okay
  493. THEN WHILE ch > " " DO
  494. IF j <= HIGH(str) THEN str[j] := ch END; INC(j);
  495. Read(f, ch);
  496. WHILE (ch = BS) OR (ch = DEL) DO
  497. IF j > 0 THEN DEC(j) END; Read(f, ch)
  498. END
  499. END;
  500. IF j <= HIGH(str) THEN str[j] := 0C END;
  501. Okay := j > 0; f^.haveCh := TRUE; f^.savedCh := ch;
  502. END
  503. END ReadToken;
  504. PROCEDURE ReadInt (f: File; VAR i: INTEGER);
  505. VAR
  506. Digit: INTEGER;
  507. j: CARDINAL;
  508. Negative: BOOLEAN;
  509. s: ARRAY [0 .. 80] OF CHAR;
  510. BEGIN
  511. i := 0; j := 0;
  512. IF NotRead(f) THEN Okay := FALSE; RETURN END;
  513. ReadToken(f, s);
  514. IF s[0] = "-" (* deal with sign *)
  515. THEN Negative := TRUE; INC(j)
  516. ELSE Negative := FALSE; IF s[0] = "+" THEN INC(j) END
  517. END;
  518. IF (s[j] < "0") OR (s[j] > "9") THEN Okay := FALSE END;
  519. WHILE (j <= 80) & (s[j] >= "0") & (s[j] <= "9") DO
  520. Digit := VAL(INTEGER, ORD(s[j]) - ORD("0"));
  521. IF i <= (MAX(INTEGER) - Digit) DIV 10
  522. THEN i := 10 * i + Digit
  523. ELSE Okay := FALSE
  524. END;
  525. INC(j)
  526. END;
  527. IF Negative THEN i := -i END;
  528. IF (j > 80) OR (s[j] # 0C) THEN Okay := FALSE END;
  529. IF ~ Okay THEN i := 0 END;
  530. END ReadInt;
  531. PROCEDURE ReadCard (f: File; VAR i: CARDINAL);
  532. VAR
  533. Digit: CARDINAL;
  534. j: CARDINAL;
  535. s: ARRAY [0 .. 80] OF CHAR;
  536. BEGIN
  537. i := 0; j := 0;
  538. IF NotRead(f) THEN Okay := FALSE; RETURN END;
  539. ReadToken(f, s);
  540. WHILE (j <= 80) & (s[j] >= "0") & (s[j] <= "9") DO
  541. Digit := ORD(s[j]) - ORD("0");
  542. IF i <= (MAX(CARDINAL) - Digit) DIV 10
  543. THEN i := 10 * i + Digit
  544. ELSE Okay := FALSE
  545. END;
  546. INC(j)
  547. END;
  548. IF (j > 80) OR (s[j] # 0C) THEN Okay := FALSE END;
  549. IF ~ Okay THEN i := 0 END;
  550. END ReadCard;
  551. PROCEDURE ReadBytes (f: File; VAR buf: ARRAY OF SYSTEM.BYTE; VAR len: CARDINAL);
  552. VAR TooMany: BOOLEAN;
  553. Wanted : LONGCARD;
  554. BEGIN
  555. IF NotRead(f) OR (File(f) = con)
  556. THEN Okay := FALSE; len := 0;
  557. ELSE
  558. IF len = 0 THEN Okay := TRUE; RETURN END;
  559. TooMany := len - 1 > HIGH(buf);
  560. IF TooMany THEN Wanted := HIGH(buf) + 1 ELSE Wanted := len END;
  561. f^.ref.res := LONGCARD ( DOSFILEMGR.DosRead( f^.ref.id, buf, HIGH(buf)+1, Wanted ));
  562. Okay := f^.ref.res = 0;
  563. IF len # Wanted THEN Okay := FALSE END;
  564. END;
  565. IF ~ Okay THEN f^.eof := TRUE END;
  566. IF TooMany THEN Okay := FALSE END;
  567. END ReadBytes;
  568. PROCEDURE Write (f: File; ch: CHAR);
  569. BEGIN
  570. IF NotWrite(f) THEN Okay := FALSE; RETURN END;
  571. IF (File(f) = con) OR (File(f) = StdOut) & ToScreen
  572. THEN
  573. IF ch = EOL
  574. THEN ConWrite(CR); ConWrite(LF)
  575. ELSE ConWrite(ch)
  576. END;
  577. Okay := TRUE;
  578. ELSIF File(f) = err
  579. THEN
  580. IF ch = EOL
  581. THEN ErrWrite(CR); ErrWrite(LF)
  582. ELSE ErrWrite(ch)
  583. END;
  584. Okay := TRUE;
  585. ELSE
  586. IF ch = EOL
  587. THEN FileSystem.WriteLn(f^.ref)
  588. ELSE FileSystem.WriteChar(f^.ref, ch)
  589. END;
  590. Okay := f^.ref.res = 0;
  591. END;
  592. END Write;
  593. PROCEDURE WriteLn (f: File);
  594. BEGIN
  595. IF NotWrite(f)
  596. THEN Okay := FALSE;
  597. ELSE Write(f, EOL)
  598. END
  599. END WriteLn;
  600. PROCEDURE WriteString (f: File; str: ARRAY OF CHAR);
  601. VAR
  602. pos: CARDINAL;
  603. BEGIN
  604. IF NotWrite(f) THEN Okay := FALSE; RETURN END;
  605. pos := 0;
  606. WHILE (pos <= HIGH(str)) & (str[pos] # 0C) DO
  607. Write(f, str[pos]); INC(pos)
  608. END
  609. END WriteString;
  610. PROCEDURE WriteText (f: File; text: ARRAY OF CHAR; len: INTEGER);
  611. VAR i,j, slen : LONGCARD;
  612. BEGIN
  613. IF NotWrite(f) THEN Okay := FALSE; RETURN END;
  614. IF len > 0 THEN j := LONGCARD(len - 1) ELSE j := 0 END;
  615. slen := Strings.Length(text);
  616. FOR i := 0 TO j DO
  617. IF i < slen THEN Write(f, text[i]) ELSE Write(f, " ") END;
  618. END
  619. END WriteText;
  620. PROCEDURE WriteInt (f: File; n: INTEGER; wid: CARDINAL);
  621. VAR
  622. l, d: CARDINAL;
  623. x: INTEGER;
  624. t: ARRAY [1 .. 25] OF CHAR;
  625. sign: CHAR;
  626. BEGIN
  627. IF NotWrite(f) THEN Okay := FALSE; RETURN END;
  628. IF n < 0
  629. THEN sign := "-"; x := - n;
  630. ELSE sign := " "; x := n;
  631. END;
  632. l := 0;
  633. REPEAT
  634. d := x MOD 10; x := x DIV 10;
  635. INC(l); t[l] := CHR(ORD("0") + d);
  636. UNTIL x = 0;
  637. IF wid = 0 THEN Write(f, " ") END;
  638. WHILE wid > l + 1 DO Write(f, " "); DEC(wid); END;
  639. IF (sign = "-") OR (wid > l) THEN Write(f, sign); END;
  640. WHILE l > 0 DO Write(f, t[l]); DEC(l); END;
  641. END WriteInt;
  642. PROCEDURE WriteCard (f: File; n, wid: CARDINAL);
  643. VAR
  644. l, d: CARDINAL;
  645. t: ARRAY [1 .. 25] OF CHAR;
  646. BEGIN
  647. IF NotWrite(f) THEN Okay := FALSE; RETURN END;
  648. l := 0;
  649. REPEAT
  650. d := n MOD 10; n := n DIV 10;
  651. INC(l); t[l] := CHR(ORD("0") + d);
  652. UNTIL n = 0;
  653. IF wid = 0 THEN Write(f, " ") END;
  654. WHILE wid > l DO Write(f, " "); DEC(wid); END;
  655. WHILE l > 0 DO Write(f, t[l]); DEC(l); END;
  656. END WriteCard;
  657. PROCEDURE WriteBytes (f: File; VAR buf: ARRAY OF SYSTEM.BYTE; len: CARDINAL);
  658. VAR
  659. TooMany: BOOLEAN;
  660. len2 : LONGCARD;
  661. BEGIN
  662. TooMany := (len > 0) & (len - 1 > HIGH(buf));
  663. IF NotWrite(f) OR (File(f) = con) OR (File(f) = err)
  664. THEN
  665. Okay := FALSE
  666. ELSE
  667. IF TooMany THEN len := CARDINAL ( HIGH(buf) + 1 ) END;
  668. len2 := LONGCARD (len);
  669. f^.ref.res := LONGCARD ( DOSFILEMGR.DosRead( f^.ref.id, buf, HIGH(buf)+1, len2 ));
  670. Okay := f^.ref.res = 0;
  671. END;
  672. IF TooMany THEN Okay := FALSE END;
  673. END WriteBytes;
  674. PROCEDURE Write2 (f: File; i: SHORTCARD);
  675. BEGIN
  676. Write(f, CHR(i DIV 10 + ORD("0")));
  677. Write(f, CHR(i MOD 10 + ORD("0")));
  678. END Write2;
  679. PROCEDURE WriteDate (f: File);
  680. VAR
  681. dt : DATETIME;
  682. r : APIRET;
  683. BEGIN
  684. IF NotWrite(f) THEN Okay := FALSE; RETURN END;
  685. r := DosGetDateTime (dt);
  686. WITH dt DO
  687. Write2(f, day); Write(f, "/"); Write2(f, month); Write(f, "/");
  688. WriteCard(f, year, 4)
  689. END;
  690. END WriteDate;
  691. PROCEDURE WriteTime (f: File);
  692. VAR
  693. dt : DATETIME;
  694. r : APIRET;
  695. BEGIN
  696. IF NotWrite(f) THEN Okay := FALSE; RETURN END;
  697. r := DosGetDateTime ( dt);
  698. WITH dt DO
  699. Write2(f, hours); Write(f, ":"); Write2(f, minutes); Write(f, ":");
  700. Write2(f, seconds)
  701. END;
  702. END WriteTime;
  703. VAR
  704. Hrs0, Mins0, Secs0, Hsecs0: SHORTCARD;
  705. Hrs1, Mins1, Secs1, Hsecs1: SHORTCARD;
  706. PROCEDURE GetInitTime();
  707. VAR dt : DATETIME;
  708. r : APIRET;
  709. BEGIN
  710. r := DosGetDateTime ( dt );
  711. WITH dt DO
  712. Hrs0 := hours; Mins0 := minutes;
  713. Secs0 := seconds; Hsecs0 := hundredths;
  714. END;
  715. END GetInitTime;
  716. PROCEDURE WriteElapsedTime (f: File);
  717. VAR dt : DATETIME;
  718. r : APIRET;
  719. s : CARDINAL;
  720. hs : SHORTCARD;
  721. BEGIN
  722. IF NotWrite(f) THEN Okay := FALSE; RETURN END;
  723. r:= DosGetDateTime( dt );
  724. WriteString(f, "Elapsed time: ");
  725. WITH dt DO
  726. IF hours >= Hrs1
  727. THEN s := (hours - Hrs1) * 3600 + (minutes - Mins1) * 60 + seconds - Secs1
  728. ELSE s := (hours + 24 - Hrs1) * 3600 + (minutes - Mins1) * 60 + seconds - Secs1
  729. END;
  730. IF hundredths >= Hsecs1
  731. THEN hs := hundredths - Hsecs1
  732. ELSE hs := (hundredths + 100) - Hsecs1; DEC(s);
  733. END;
  734. WriteCard(f, s, 1); Write(f, ".");
  735. Write2(f, hs); WriteString(f, " s"); WriteLn(f);
  736. Hrs1 := hours; Mins1 := minutes; Secs1 := seconds; Hsecs1 := hundredths;
  737. END;
  738. END WriteElapsedTime;
  739. PROCEDURE WriteExecutionTime (f: File);
  740. VAR dt : DATETIME;
  741. r : APIRET;
  742. s : CARDINAL;
  743. hs : SHORTCARD;
  744. BEGIN
  745. IF NotWrite(f) THEN Okay := FALSE; RETURN END;
  746. r:= DosGetDateTime( dt );
  747. WriteString(f, "Execution time: ");
  748. WITH dt DO
  749. IF hours >= Hrs0
  750. THEN s := (hours - Hrs0) * 3600 + (minutes - Mins0) * 60 + seconds - Secs0
  751. ELSE s := (hours + 24 - Hrs0) * 3600 + (minutes - Mins0) * 60 + seconds - Secs0
  752. END;
  753. IF hundredths >= Hsecs0
  754. THEN hs := hundredths - Hsecs0
  755. ELSE hs := (hundredths + 100) - Hsecs0; DEC(s);
  756. END;
  757. WriteCard(f, s, 1); Write(f, ".");
  758. Write2(f, hs); WriteString(f, " s"); WriteLn(f);
  759. END;
  760. END WriteExecutionTime;
  761. PROCEDURE INTL (n: INT32): INTEGER;
  762. BEGIN
  763. RETURN VAL(INTEGER, n)
  764. END INTL;
  765. PROCEDURE INT (n: CARDINAL): INT32;
  766. BEGIN
  767. RETURN VAL(INT32, n)
  768. END INT;
  769. PROCEDURE ORDL (n: INT32): CARDINAL;
  770. BEGIN
  771. RETURN VAL(CARDINAL, n)
  772. END ORDL;
  773. PROCEDURE QuitExecution;
  774. BEGIN
  775. HALT
  776. END QuitExecution;
  777. (* OS2 Std Channels *)
  778. PROCEDURE InitStdChannels();
  779. BEGIN
  780. WITH StdOut^.ref DO
  781. id := DOSFILEMGR.STDOUT;
  782. eof := FALSE;
  783. tmp := FALSE;
  784. name := "SCREEN$";
  785. END;
  786. WITH StdIn^.ref DO
  787. id := DOSFILEMGR.STDIN;
  788. eof := FALSE;
  789. tmp := FALSE;
  790. name := "KBD$";
  791. END;
  792. END InitStdChannels;
  793. BEGIN
  794. Handles := BITSET{};
  795. Okay := FALSE; EOFChar := 32C;
  796. Param := 0;
  797. GetInitTime();
  798. Hrs1 := Hrs0; Mins1 := Mins0; Secs1 := Secs0; Hsecs1 := Hsecs0;
  799. ALLOCATE(con, SYSTEM.TSIZE(FileRec));
  800. con^.ref := InOut.out;
  801. con^.savedCh := 0C; con^.haveCh := FALSE; con^.self := con;
  802. con^.noOutput := FALSE; con^.noInput := FALSE; con^.textOK := TRUE;
  803. con^.eof := FALSE; con^.eol := FALSE;
  804. IF FromKeyboard
  805. THEN ALLOCATE(StdIn, SYSTEM.TSIZE(FileRec));
  806. ELSE ALLOCATE(StdIn, SYSTEM.TSIZE(FileRec));
  807. END;
  808. StdIn^.ref := InOut.in;
  809. StdIn^.savedCh := 0C; StdIn^.haveCh := FALSE; StdIn^.self := StdIn;
  810. StdIn^.noOutput := TRUE; StdIn^.noInput := FALSE; StdIn^.textOK := TRUE;
  811. StdIn^.eof := FALSE; StdIn^.eol := FALSE;
  812. IF ToScreen
  813. THEN ALLOCATE(StdOut, SYSTEM.TSIZE(FileRec));
  814. ELSE ALLOCATE(StdOut, SYSTEM.TSIZE(FileRec));
  815. END;
  816. StdOut^.ref := InOut.out;
  817. StdOut^.savedCh := 0C; StdOut^.haveCh := FALSE; StdOut^.self := StdOut;
  818. StdOut^.noOutput := FALSE; StdOut^.noInput := TRUE; StdOut^.textOK := TRUE;
  819. StdOut^.eof := TRUE; StdOut^.eol := TRUE;
  820. InitStdChannels();
  821. END FileIO .