StreamReaders.Mos 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. MODULE StreamReaders;
  2. IMPORT
  3. SYSTEM;
  4. CONST
  5. Ok* = 0; (** zero result code means no error occurred *)
  6. EOF* = 4201; (** error returned when Receive reads past end of file or stream *)
  7. EOT* = 1AX; (** EOT character *)
  8. StringFull = 4202;
  9. FormatError* = 4203; (** error returned when ReadInt fails *)
  10. CR* = 0DX; LF* = 0AX; TAB* = 9X; SP* = 20X;
  11. TYPE
  12. Float = REAL;
  13. Bytes2 = ARRAY 2 OF CHAR;
  14. Bytes4 = ARRAY 4 OF CHAR;
  15. Bytes8 = ARRAY 8 OF CHAR;
  16. (** Any stream input procedure. *)
  17. Receiver* = PROCEDURE( VAR reader: Reader; VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len, res: LONGINT );
  18. Reader* = RECORD
  19. head, tail: LONGINT;
  20. buf: POINTER TO ARRAY OF CHAR;
  21. res*: LONGINT; (** result of last input operation. *)
  22. receive: Receiver;
  23. received*: LONGINT; (** count of received bytes *)
  24. END;
  25. PROCEDURE Init*(VAR reader: Reader; receiver: Receiver; size: LONGINT);
  26. BEGIN
  27. NEW(reader.buf,size);
  28. reader.receive := receiver;
  29. reader.res := 0;
  30. END Init;
  31. (** reset the reader by dropping the bytes in the buffer, resetting the result code and setting received to 0.
  32. This is used by seekable extensions of the reader *)
  33. PROCEDURE Reset*(VAR r: Reader);
  34. BEGIN
  35. r.head := 0; r.tail := 0; r.res := Ok; r.received := 0
  36. END Reset;
  37. (** Return bytes currently available in input buffer. *)
  38. PROCEDURE Available*(VAR r: Reader): LONGINT;
  39. VAR n: LONGINT;
  40. BEGIN
  41. IF (r.res = Ok) THEN
  42. IF (r.head = r.tail) THEN r.head := 0; r.receive( r, r.buf^, 0, LEN( r.buf ), 0, r.tail, r.res ); INC( r.received, r.tail );
  43. ELSIF (r.tail # LEN( r.buf )) THEN
  44. r.receive( r, r.buf^, r.tail, LEN( r.buf ) - r.tail, 0, n, r.res ); (* poll *)
  45. INC( r.tail, n ); INC( r.received, n )
  46. END;
  47. IF r.res = EOF THEN r.res := Ok END (* ignore EOF here *)
  48. END;
  49. RETURN r.tail - r.head
  50. END Available;
  51. (** Current read position. *)
  52. PROCEDURE Pos*(CONST r: Reader): LONGINT;
  53. BEGIN
  54. RETURN r.received - (r.tail - r.head)
  55. END Pos;
  56. (** -- Read raw binary data -- *)
  57. (** Read one byte. x=0X if no success (e.g. file ended) *)
  58. PROCEDURE Char*(VAR r: Reader; VAR x: CHAR );
  59. BEGIN
  60. IF (r.head = r.tail) & (r.res = Ok) THEN r.head := 0; r.receive( r, r.buf^, 0, LEN( r.buf ), 1, r.tail, r.res ); INC( r.received, r.tail ) END;
  61. IF r.res = Ok THEN x := r.buf[r.head]; INC( r.head ) ELSE x := 0X END
  62. END Char;
  63. (** Like Read, but return result. Return 0X if no success (e.g. file ended) *)
  64. PROCEDURE Get*(VAR r: Reader): CHAR;
  65. BEGIN
  66. IF (r.head = r.tail) & (r.res = Ok) THEN r.head := 0; r.receive( r, r.buf^, 0, LEN( r.buf ), 1, r.tail, r.res ); INC( r.received, r.tail ) END;
  67. IF r.res = Ok THEN INC( r.head ); RETURN r.buf[r.head - 1] ELSE RETURN 0X END
  68. END Get;
  69. (** Like Get, but leave the byte in the input buffer. *)
  70. PROCEDURE Peek*(VAR r: Reader): CHAR;
  71. BEGIN
  72. IF (r.head = r.tail) & (r.res = Ok) THEN
  73. r.head := 0; r.receive( r, r.buf^, 0, LEN( r.buf ), 1, r.tail, r.res ); INC( r.received, r.tail );
  74. IF r.res = EOF THEN (* ignore EOF here *)
  75. r.res := Ok; r.tail := 0; RETURN 0X (* Peek returns 0X at eof *)
  76. END
  77. END;
  78. IF r.res = Ok THEN RETURN r.buf[r.head] ELSE RETURN 0X END
  79. END Peek;
  80. (** Read size bytes into x, starting at ofs. The len parameter returns the number of bytes that were actually read. *)
  81. PROCEDURE Bytes*(VAR r: Reader; VAR x: ARRAY OF CHAR; ofs, size: LONGINT; VAR len: LONGINT );
  82. VAR n: LONGINT;
  83. BEGIN
  84. ASSERT ( size >= 0 );
  85. len := 0;
  86. LOOP
  87. n := r.tail - r.head; (* bytes available *)
  88. IF n = 0 THEN (* no data available *)
  89. r.head := 0;
  90. IF r.res = Ok THEN (* fill buffer *)
  91. r.receive( r, r.buf^, 0, LEN( r.buf ), 1, r.tail, r.res ); INC( r.received, r.tail )
  92. END;
  93. IF r.res # Ok THEN (* should not be reading from erroneous rider *)
  94. WHILE size # 0 DO x[ofs] := 0X; INC( ofs ); DEC( size ) END; (* clear rest of buffer *)
  95. IF (r.res = EOF) & (len # 0) THEN r.res := Ok END; (* ignore EOF if some data being returned *)
  96. EXIT
  97. END;
  98. n := r.tail
  99. END;
  100. IF n > size THEN n := size END;
  101. ASSERT ( ofs + n <= LEN( x ) ); (* index check *)
  102. SYSTEM.MOVE( ADDRESSOF( r.buf[r.head] ), ADDRESSOF( x[ofs] ), n ); INC( r.head, n ); INC( len, n );
  103. IF size = n THEN EXIT END; (* done *)
  104. INC( ofs, n ); DEC( size, n )
  105. END
  106. END Bytes;
  107. (** Skip n bytes on the reader. *)
  108. PROCEDURE SkipBytes*(VAR r: Reader; n: LONGINT );
  109. VAR ch: CHAR;
  110. BEGIN
  111. WHILE n > 0 DO ch := Get(r); DEC( n ) END
  112. END SkipBytes;
  113. (** Read a SHORTINT. *)
  114. PROCEDURE RawSInt*(VAR r: Reader; VAR x: SHORTINT );
  115. BEGIN
  116. x := SYSTEM.VAL( SHORTINT, Get(r) )
  117. END RawSInt;
  118. (** Read an INTEGER. *)
  119. PROCEDURE RawInt*(VAR r: Reader; VAR x: INTEGER );
  120. VAR x0, x1: CHAR;
  121. BEGIN
  122. x0 := Get(r); x1 := Get(r); (* defined order *)
  123. x := ORD( x1 ) * 100H + ORD( x0 )
  124. END RawInt;
  125. (** Read a LONGINT. *)
  126. PROCEDURE RawLInt*(VAR r: Reader; VAR x: LONGINT );
  127. VAR ignore: LONGINT;
  128. BEGIN
  129. Bytes(r,SYSTEM.VAL( Bytes4, x ), 0, 4, ignore )
  130. END RawLInt;
  131. (** Read a HUGEINT. *)
  132. PROCEDURE RawHInt*(VAR r: Reader; VAR x: HUGEINT );
  133. VAR ignore: LONGINT;
  134. BEGIN
  135. Bytes(r,SYSTEM.VAL( Bytes8, x ), 0, 8, ignore )
  136. END RawHInt;
  137. (** Read a 32 bit value in network byte order (most significant byte first) *)
  138. PROCEDURE Net32*(VAR r: Reader): LONGINT;
  139. BEGIN
  140. RETURN LONG( ORD( Get(r) ) ) * 1000000H + LONG( ORD( Get(r) ) ) * 10000H + LONG( ORD( Get(r) ) ) * 100H + LONG( ORD( Get(r) ) )
  141. END Net32;
  142. (** Read an unsigned 16bit value in network byte order (most significant byte first) *)
  143. PROCEDURE Net16*(VAR r: Reader): LONGINT;
  144. BEGIN
  145. RETURN LONG( ORD( Get(r) ) ) * 100H + LONG( ORD( Get(r) ) )
  146. END Net16;
  147. (** Read an unsigned byte *)
  148. PROCEDURE Net8*(VAR r: Reader): LONGINT;
  149. BEGIN
  150. RETURN LONG( ORD( Get(r) ) )
  151. END Net8;
  152. (** Read a SET. *)
  153. PROCEDURE RawSet*(VAR r: Reader; VAR x: SET );
  154. VAR ignore: LONGINT;
  155. BEGIN
  156. Bytes(r,SYSTEM.VAL( Bytes4, x ), 0, 4, ignore )
  157. END RawSet;
  158. (** Read a BOOLEAN. *)
  159. PROCEDURE RawBool*(VAR r: Reader; VAR x: BOOLEAN );
  160. BEGIN
  161. x := (Get(r) # 0X)
  162. END RawBool;
  163. (** Read a REAL. *)
  164. PROCEDURE RawReal*(VAR r: Reader; VAR x: REAL );
  165. VAR ignore: LONGINT;
  166. BEGIN
  167. Bytes(r,SYSTEM.VAL( Bytes4, x ), 0, 4, ignore )
  168. END RawReal;
  169. (** Read a LONGREAL. *)
  170. PROCEDURE RawLReal*(VAR r: Reader; VAR x: LONGREAL );
  171. VAR ignore: LONGINT;
  172. BEGIN
  173. Bytes(r,SYSTEM.VAL( Bytes8, x ), 0, 8, ignore )
  174. END RawLReal;
  175. (** Read a 0X-terminated string. If the input string is larger than x, read the full string and assign the truncated 0X-terminated value to x. *)
  176. PROCEDURE RawString*(VAR r: Reader; VAR x: ARRAY OF CHAR );
  177. VAR i, m: LONGINT; ch: CHAR;
  178. BEGIN
  179. i := 0; m := LEN( x ) - 1;
  180. LOOP
  181. ch := Get(r); (* also returns 0X on error *)
  182. IF ch = 0X THEN EXIT END;
  183. IF i < m THEN x[i] := ch; INC( i ) END
  184. END;
  185. x[i] := 0X
  186. END RawString;
  187. (** Read a number in a compressed format. *)
  188. PROCEDURE RawNum*(VAR r: Reader; VAR x: LONGINT );
  189. VAR ch: CHAR; n, y: LONGINT;
  190. BEGIN
  191. n := 0; y := 0; ch := Get(r);
  192. WHILE ch >= 80X DO INC( y, LSH( LONG( ORD( ch ) ) - 128, n ) ); INC( n, 7 ); ch := Get(r) END;
  193. x := ASH( LSH( LONG( ORD( ch ) ), 25 ), n - 25 ) + y
  194. END RawNum;
  195. (** -- Read formatted data (uses Peek for one character lookahead) -- *)
  196. (** Read an integer value in decimal or hexadecimal. If hex = TRUE, recognize the "H" postfix for hexadecimal numbers. *)
  197. PROCEDURE Int*(VAR r: Reader; VAR x: LONGINT; hex: BOOLEAN );
  198. VAR vd, vh, sgn, d: LONGINT; ch: CHAR; ok: BOOLEAN;
  199. BEGIN
  200. vd := 0; vh := 0; sgn := 1; ok := FALSE;
  201. IF Peek(r) = "-" THEN sgn := -1; ch := Get(r) END;
  202. LOOP
  203. ch := Peek(r);
  204. IF (ch >= "0") & (ch <= "9") THEN d := ORD( ch ) - ORD( "0" )
  205. ELSIF hex & (CAP( ch ) >= "A") & (CAP( ch ) <= "F") THEN d := ORD( CAP( ch ) ) - ORD( "A" ) + 10
  206. ELSE EXIT
  207. END;
  208. vd := 10 * vd + d; vh := 16 * vh + d; (* ignore overflow *)
  209. ch := Get(r); ok := TRUE
  210. END;
  211. IF hex & (CAP( ch ) = "H") THEN (* optional "H" present *)
  212. vd := vh; (* use the hex value *)
  213. ch := Get(r)
  214. END;
  215. x := sgn * vd;
  216. IF (r.res = 0) & ~ok THEN r.res := FormatError END
  217. END Int;
  218. (** Return TRUE iff at the end of a line (or file). *)
  219. PROCEDURE EOLN*(VAR r: Reader): BOOLEAN;
  220. VAR ch: CHAR;
  221. BEGIN
  222. ch := Peek(r); RETURN (ch = CR) OR (ch = LF) OR (r.res # Ok)
  223. END EOLN;
  224. (** Read all characters until the end of the line (inclusive). If the input string is larger than x, read the full string and assign
  225. the truncated 0X-terminated value to x. *)
  226. PROCEDURE Ln*(VAR r: Reader; VAR x: ARRAY OF CHAR );
  227. VAR i, m: LONGINT; ch: CHAR;
  228. BEGIN
  229. i := 0; m := LEN( x ) - 1;
  230. LOOP
  231. ch := Peek(r);
  232. IF (ch = CR) OR (ch = LF) OR (r.res # Ok) THEN EXIT END;
  233. IF i < m THEN x[i] := ch; INC( i ) END;
  234. ch := Get(r)
  235. END;
  236. x[i] := 0X;
  237. IF ch = CR THEN ch := Get(r) END;
  238. IF Peek(r) = LF THEN ch := Get(r) END
  239. END Ln;
  240. (** Read all characters until the end of the line (inclusive) or an <EOT> character.
  241. If the input string is larger than x, read the full string and assign the truncated 0X-terminated
  242. value to x. *)
  243. PROCEDURE LnEOT*(VAR r: Reader; VAR x: ARRAY OF CHAR );
  244. VAR i, m: LONGINT; ch: CHAR;
  245. BEGIN
  246. i := 0; m := LEN( x ) - 1;
  247. LOOP
  248. ch := Peek(r);
  249. IF (ch = CR) OR (ch = LF) OR (ch = EOT) OR (r.res # Ok) THEN EXIT END;
  250. IF i < m THEN x[i] := ch; INC( i ) END;
  251. ch := Get(r)
  252. END;
  253. x[i] := 0X;
  254. IF ch = CR THEN ch := Get(r) END;
  255. IF Peek(r) = LF THEN ch := Get(r) END;
  256. IF ch = EOT THEN ch := Get(r) END
  257. END LnEOT;
  258. (** Skip over all characters until the end of the line (inclusive). *)
  259. PROCEDURE SkipLn*(VAR r: Reader);
  260. VAR ch: CHAR;
  261. BEGIN
  262. LOOP
  263. ch := Peek(r);
  264. IF (ch = CR) OR (ch = LF) OR (r.res # Ok) THEN EXIT END;
  265. ch := Get(r)
  266. END;
  267. IF ch = CR THEN ch := Get(r) END;
  268. IF Peek(r) = LF THEN ch := Get(r) END
  269. END SkipLn;
  270. (** Skip over space and TAB characters. *)
  271. PROCEDURE SkipSpaces*(VAR r: Reader);
  272. VAR ch: CHAR;
  273. BEGIN
  274. LOOP
  275. ch := Peek(r);
  276. IF (ch # TAB) & (ch # SP) THEN EXIT END;
  277. ch := Get(r)
  278. END
  279. END SkipSpaces;
  280. (** Skip over space, TAB and EOLN characters. *)
  281. PROCEDURE SkipWhitespace*(VAR r: Reader);
  282. VAR ch: CHAR;
  283. BEGIN
  284. LOOP
  285. ch := Peek(r);
  286. IF (ch # SP) & (ch # CR) & (ch # LF) & (ch # TAB) THEN EXIT END;
  287. ch := Get(r)
  288. END
  289. END SkipWhitespace;
  290. (** Read a token, consisting of any string of characters terminated by space, TAB or EOLN. *)
  291. PROCEDURE Token*(VAR r: Reader; VAR token: ARRAY OF CHAR );
  292. VAR j, max: LONGINT; ch: CHAR;
  293. BEGIN
  294. j := 0; max := LEN( token ) - 1;
  295. LOOP
  296. ch := Peek(r);
  297. IF (ch = SP) OR (ch = CR) OR (ch = LF) OR (ch = TAB) OR (r.res # Ok) THEN EXIT END;
  298. IF j < max THEN token[j] := ch; INC( j ) END;
  299. ch := Get(r)
  300. END;
  301. token[j] := 0X
  302. END Token;
  303. (** Read an optionally "" or '' enquoted string. Will not read past the end of a line. *)
  304. PROCEDURE String*(VAR r: Reader; VAR string: ARRAY OF CHAR );
  305. VAR c, delimiter: CHAR; i, len: LONGINT;
  306. BEGIN
  307. c := Peek(r);
  308. IF (c # "'") & (c # '"') THEN Token(r,string )
  309. ELSE
  310. delimiter := Get(r); c := Peek(r); i := 0; len := LEN( string ) - 1;
  311. WHILE (i < len) & (c # delimiter) & (c # CR) & (c # LF) & (r.res = Ok) DO string[i] := Get(r); INC( i ); c := Peek(r) END;
  312. IF (c = delimiter) THEN c := Get(r) END;
  313. string[i] := 0X
  314. END
  315. END String;
  316. (** First skip whitespace, then read string *)
  317. PROCEDURE GetString*(VAR r: Reader; VAR string : ARRAY OF CHAR): BOOLEAN;
  318. BEGIN
  319. SkipWhitespace(r);
  320. String(r,string);
  321. RETURN string[0] # 0X;
  322. END GetString;
  323. (** First skip whitespace, then read integer *)
  324. PROCEDURE GetInteger*(VAR r: Reader; VAR integer : LONGINT; isHexadecimal : BOOLEAN): BOOLEAN;
  325. BEGIN
  326. SkipWhitespace(r);
  327. Int(r,integer, isHexadecimal);
  328. RETURN r.res = Ok;
  329. END GetInteger;
  330. (** First skip whitespace, then read 1 byte character *)
  331. PROCEDURE GetChar*(VAR r: Reader; VAR ch : CHAR): BOOLEAN;
  332. BEGIN
  333. SkipWhitespace(r);
  334. Char(r,ch);
  335. RETURN ch # 0X;
  336. END GetChar;
  337. PROCEDURE GetFloat*(VAR r: Reader; VAR x: Float): BOOLEAN;
  338. VAR str: ARRAY 32 OF CHAR;
  339. BEGIN
  340. IF GetString(r,str) THEN
  341. StrToFloat(str,x);
  342. RETURN TRUE;
  343. ELSE
  344. RETURN FALSE;
  345. END;
  346. END GetFloat;
  347. (** converts a string to a real value *)
  348. (* adopted from Strings.Mod *)
  349. PROCEDURE StrToFloat*(CONST s: ARRAY OF CHAR; VAR r: Float);
  350. VAR p, e: LONGINT; y, g: Float; neg, negE: BOOLEAN;
  351. BEGIN
  352. p := 0;
  353. WHILE (s[p] = " ") OR (s[p] = "0") DO INC(p) END;
  354. IF s[p] = "-" THEN neg := TRUE; INC(p) ELSE neg := FALSE END;
  355. WHILE (s[p] = " ") OR (s[p] = "0") DO INC(p) END;
  356. y := 0;
  357. WHILE ("0" <= s[p]) & (s[p] <= "9") DO
  358. y := y * 10 + (ORD(s[p]) - 30H);
  359. INC(p);
  360. END;
  361. IF s[p] = "." THEN
  362. INC(p); g := 1;
  363. WHILE ("0" <= s[p]) & (s[p] <= "9") DO
  364. g := g / 10; y := y + g * (ORD(s[p]) - 30H);
  365. INC(p);
  366. END;
  367. END;
  368. IF (s[p] = "d") OR (s[p] = "D") OR (s[p] = "e") OR (s[p] = "E") THEN
  369. INC(p); e := 0;
  370. IF s[p] = "-" THEN negE := TRUE; INC(p)
  371. ELSIF s[p] = "+" THEN negE := FALSE; INC(p)
  372. ELSE negE := FALSE
  373. END;
  374. WHILE (s[p] = "0") DO INC(p) END;
  375. WHILE ("0" <= s[p]) & (s[p] <= "9") DO
  376. e := e * 10 + (ORD(s[p]) - 30H);
  377. INC(p);
  378. END;
  379. IF negE THEN
  380. FOR p := 1 TO e DO y := y * (Float(1)/Float(10)); END;
  381. (*y := y / Reals.Ten(e);*)
  382. ELSE
  383. FOR p := 1 TO e DO y := y * Float(10); END;
  384. (*y := y * Reals.Ten(e);*)
  385. END;
  386. END;
  387. IF neg THEN y := -y END;
  388. r := y
  389. END StrToFloat;
  390. PROCEDURE SetString * (VAR r: Reader; CONST str: ARRAY OF CHAR);
  391. VAR
  392. len: LONGINT;
  393. BEGIN
  394. len := 0;
  395. WHILE str[len] # 0X DO INC(len) END;
  396. IF len > LEN(r.buf) THEN len := LEN(r.buf) END;
  397. r.head := 0;
  398. r.tail := len;
  399. r.received := len;
  400. r.res := Ok;
  401. SYSTEM.MOVE(ADDRESSOF(str[0]), ADDRESSOF(r.buf[0]), len)
  402. END SetString;
  403. PROCEDURE SetRawString * (VAR r: Reader; CONST buf: ARRAY OF CHAR; ofs, len: LONGINT);
  404. BEGIN
  405. IF len > LEN(r.buf) THEN len := LEN(r.buf) END;
  406. r.head := 0;
  407. r.tail := len;
  408. r.received := len;
  409. r.res := Ok;
  410. SYSTEM.MOVE(ADDRESSOF(buf[ofs]), ADDRESSOF(r.buf[0]), len)
  411. END SetRawString;
  412. PROCEDURE StringReaderReceive * (VAR reader: Reader; VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len, res: LONGINT);
  413. BEGIN
  414. IF min = 0 THEN res := Ok ELSE res := EOF END;
  415. len := 0
  416. END StringReaderReceive;
  417. END StreamReaders.