text.inc 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225
  1. {
  2. This file is part of the Free Pascal Run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {****************************************************************************
  11. subroutines For TextFile handling
  12. ****************************************************************************}
  13. Procedure FileCloseFunc(Var t:TextRec);
  14. Begin
  15. Do_Close(t.Handle);
  16. t.Handle:=UnusedHandle;
  17. End;
  18. Procedure FileReadFunc(var t:TextRec);
  19. Begin
  20. t.BufEnd:=Do_Read(t.Handle,t.Bufptr,t.BufSize);
  21. t.BufPos:=0;
  22. End;
  23. Procedure FileWriteFunc(var t:TextRec);
  24. var
  25. i : longint;
  26. Begin
  27. i:=Do_Write(t.Handle,t.Bufptr,t.BufPos);
  28. if i<>t.BufPos then
  29. InOutRes:=101;
  30. t.BufPos:=0;
  31. End;
  32. Procedure FileOpenFunc(var t:TextRec);
  33. var
  34. Flags : Longint;
  35. Begin
  36. Case t.mode Of
  37. fmInput : Flags:=$10000;
  38. fmOutput : Flags:=$11001;
  39. fmAppend : Flags:=$10101;
  40. else
  41. begin
  42. InOutRes:=102;
  43. exit;
  44. end;
  45. End;
  46. Do_Open(t,PChar(@t.Name),Flags);
  47. t.CloseFunc:=@FileCloseFunc;
  48. t.FlushFunc:=nil;
  49. if t.Mode=fmInput then
  50. t.InOutFunc:=@FileReadFunc
  51. else
  52. begin
  53. t.InOutFunc:=@FileWriteFunc;
  54. { Only install flushing if its a NOT a file, and only check if there
  55. was no error opening the file, becuase else we always get a bad
  56. file handle error 6 (PFV) }
  57. if (InOutRes=0) and
  58. Do_Isdevice(t.Handle) then
  59. t.FlushFunc:=@FileWriteFunc;
  60. end;
  61. End;
  62. Procedure assign(var t:Text;const s:String);
  63. Begin
  64. FillChar(t,SizeOf(TextRec),0);
  65. { only set things that are not zero }
  66. TextRec(t).Handle:=UnusedHandle;
  67. TextRec(t).mode:=fmClosed;
  68. TextRec(t).BufSize:=TextRecBufSize;
  69. TextRec(t).Bufptr:=@TextRec(t).Buffer;
  70. TextRec(t).OpenFunc:=@FileOpenFunc;
  71. Case DefaultTextLineBreakStyle Of
  72. tlbsLF: TextRec(t).LineEnd := #10;
  73. tlbsCRLF: TextRec(t).LineEnd := #13#10;
  74. tlbsCR: TextRec(t).LineEnd := #13;
  75. End;
  76. Move(s[1],TextRec(t).Name,Length(s));
  77. End;
  78. Procedure assign(var t:Text;p:pchar);
  79. begin
  80. Assign(t,StrPas(p));
  81. end;
  82. Procedure assign(var t:Text;c:char);
  83. begin
  84. Assign(t,string(c));
  85. end;
  86. Procedure Close(var t : Text);[IOCheck];
  87. Begin
  88. if InOutRes<>0 then
  89. Exit;
  90. case TextRec(t).mode of
  91. fmInput,fmOutPut,fmAppend:
  92. Begin
  93. { Write pending buffer }
  94. If Textrec(t).Mode=fmoutput then
  95. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  96. { Only close functions not connected to stdout.}
  97. If ((TextRec(t).Handle<>StdInputHandle) and
  98. (TextRec(t).Handle<>StdOutputHandle) and
  99. (TextRec(t).Handle<>StdErrorHandle)) Then
  100. FileFunc(TextRec(t).CloseFunc)(TextRec(t));
  101. TextRec(t).mode := fmClosed;
  102. { Reset buffer for safety }
  103. TextRec(t).BufPos:=0;
  104. TextRec(t).BufEnd:=0;
  105. End
  106. else inOutRes := 103;
  107. End;
  108. End;
  109. Procedure OpenText(var t : Text;mode,defHdl:Longint);
  110. Begin
  111. Case TextRec(t).mode Of {This gives the fastest code}
  112. fmInput,fmOutput,fmInOut : Close(t);
  113. fmClosed : ;
  114. else
  115. Begin
  116. InOutRes:=102;
  117. exit;
  118. End;
  119. End;
  120. TextRec(t).mode:=mode;
  121. TextRec(t).bufpos:=0;
  122. TextRec(t).bufend:=0;
  123. FileFunc(TextRec(t).OpenFunc)(TextRec(t));
  124. { reset the mode to closed when an error has occured }
  125. if InOutRes<>0 then
  126. TextRec(t).mode:=fmClosed;
  127. End;
  128. Procedure Rewrite(var t : Text);[IOCheck];
  129. Begin
  130. If InOutRes<>0 then
  131. exit;
  132. OpenText(t,fmOutput,1);
  133. End;
  134. Procedure Reset(var t : Text);[IOCheck];
  135. Begin
  136. If InOutRes<>0 then
  137. exit;
  138. OpenText(t,fmInput,0);
  139. End;
  140. Procedure Append(var t : Text);[IOCheck];
  141. Begin
  142. If InOutRes<>0 then
  143. exit;
  144. OpenText(t,fmAppend,1);
  145. End;
  146. Procedure Flush(var t : Text);[IOCheck];
  147. Begin
  148. If InOutRes<>0 then
  149. exit;
  150. if TextRec(t).mode<>fmOutput then
  151. begin
  152. if TextRec(t).mode=fmInput then
  153. InOutRes:=105
  154. else
  155. InOutRes:=103;
  156. exit;
  157. end;
  158. { Not the flushfunc but the inoutfunc should be used, becuase that
  159. writes the data, flushfunc doesn't need to be assigned }
  160. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  161. End;
  162. Procedure Erase(var t:Text);[IOCheck];
  163. Begin
  164. If InOutRes <> 0 then
  165. exit;
  166. If TextRec(t).mode=fmClosed Then
  167. Do_Erase(PChar(@TextRec(t).Name));
  168. End;
  169. Procedure Rename(var t : text;p:pchar);[IOCheck];
  170. Begin
  171. If InOutRes <> 0 then
  172. exit;
  173. If TextRec(t).mode=fmClosed Then
  174. Begin
  175. Do_Rename(PChar(@TextRec(t).Name),p);
  176. { check error code of do_rename }
  177. If InOutRes = 0 then
  178. Move(p^,TextRec(t).Name,StrLen(p)+1);
  179. End;
  180. End;
  181. Procedure Rename(var t : Text;const s : string);[IOCheck];
  182. var
  183. p : array[0..255] Of Char;
  184. Begin
  185. If InOutRes <> 0 then
  186. exit;
  187. Move(s[1],p,Length(s));
  188. p[Length(s)]:=#0;
  189. Rename(t,Pchar(@p));
  190. End;
  191. Procedure Rename(var t : Text;c : char);[IOCheck];
  192. var
  193. p : array[0..1] Of Char;
  194. Begin
  195. If InOutRes <> 0 then
  196. exit;
  197. p[0]:=c;
  198. p[1]:=#0;
  199. Rename(t,Pchar(@p));
  200. End;
  201. Function Eof(Var t: Text): Boolean;[IOCheck];
  202. Begin
  203. If (InOutRes<>0) then
  204. exit(true);
  205. if (TextRec(t).mode<>fmInput) Then
  206. begin
  207. if TextRec(t).mode=fmOutput then
  208. InOutRes:=104
  209. else
  210. InOutRes:=103;
  211. exit(true);
  212. end;
  213. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  214. begin
  215. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  216. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  217. exit(true);
  218. end;
  219. Eof:=CtrlZMarksEOF and (TextRec(t).Bufptr^[TextRec(t).BufPos]=#26);
  220. end;
  221. Function Eof:Boolean;
  222. Begin
  223. Eof:=Eof(Input);
  224. End;
  225. Function SeekEof (Var t : Text) : Boolean;
  226. var
  227. oldfilepos : Int64;
  228. oldbufpos, oldbufend : SizeInt;
  229. reads: longint;
  230. isdevice: boolean;
  231. Begin
  232. If (InOutRes<>0) then
  233. exit(true);
  234. if (TextRec(t).mode<>fmInput) Then
  235. begin
  236. if TextRec(t).mode=fmOutPut then
  237. InOutRes:=104
  238. else
  239. InOutRes:=103;
  240. exit(true);
  241. end;
  242. { try to save the current position in the file, seekeof() should not move }
  243. { the current file position (JM) }
  244. oldbufpos := TextRec(t).BufPos;
  245. oldbufend := TextRec(t).BufEnd;
  246. reads := 0;
  247. oldfilepos := -1;
  248. isdevice := Do_IsDevice(TextRec(t).handle);
  249. repeat
  250. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  251. begin
  252. { signal that the we will have to do a seek }
  253. inc(reads);
  254. if not isdevice and
  255. (reads = 1) then
  256. begin
  257. oldfilepos := Do_FilePos(TextRec(t).handle) - TextRec(t).BufEnd;
  258. InOutRes:=0;
  259. end;
  260. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  261. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  262. begin
  263. { if we only did a read in which we didn't read anything, the }
  264. { old buffer is still valid and we can simply restore the }
  265. { pointers (JM) }
  266. dec(reads);
  267. SeekEof := true;
  268. break;
  269. end;
  270. end;
  271. case TextRec(t).Bufptr^[TextRec(t).BufPos] of
  272. #26 :
  273. if CtrlZMarksEOF then
  274. begin
  275. SeekEof := true;
  276. break;
  277. end;
  278. #10,#13,#9,' ' :
  279. ;
  280. else
  281. begin
  282. SeekEof := false;
  283. break;
  284. end;
  285. end;
  286. inc(TextRec(t).BufPos);
  287. until false;
  288. { restore file position if not working with a device }
  289. if not isdevice then
  290. { if we didn't modify the buffer, simply restore the BufPos and BufEnd }
  291. { (the latter becuase it's now probably set to zero because nothing was }
  292. { was read anymore) }
  293. if (reads = 0) then
  294. begin
  295. TextRec(t).BufPos:=oldbufpos;
  296. TextRec(t).BufEnd:=oldbufend;
  297. end
  298. { otherwise return to the old filepos and reset the buffer }
  299. else
  300. begin
  301. do_seek(TextRec(t).handle,oldfilepos);
  302. InOutRes:=0;
  303. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  304. TextRec(t).BufPos:=oldbufpos;
  305. end;
  306. End;
  307. Function SeekEof : Boolean;
  308. Begin
  309. SeekEof:=SeekEof(Input);
  310. End;
  311. Function Eoln(var t:Text) : Boolean;
  312. Begin
  313. If (InOutRes<>0) then
  314. exit(true);
  315. if (TextRec(t).mode<>fmInput) Then
  316. begin
  317. if TextRec(t).mode=fmOutPut then
  318. InOutRes:=104
  319. else
  320. InOutRes:=103;
  321. exit(true);
  322. end;
  323. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  324. begin
  325. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  326. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  327. exit(true);
  328. end;
  329. if CtrlZMarksEOF and (TextRec (T).BufPtr^[TextRec (T).BufPos] = #26) then
  330. exit (true);
  331. Eoln:=(TextRec(t).Bufptr^[TextRec(t).BufPos] in [#10,#13]);
  332. End;
  333. Function Eoln : Boolean;
  334. Begin
  335. Eoln:=Eoln(Input);
  336. End;
  337. Function SeekEoln (Var t : Text) : Boolean;
  338. Begin
  339. If (InOutRes<>0) then
  340. exit(true);
  341. if (TextRec(t).mode<>fmInput) Then
  342. begin
  343. if TextRec(t).mode=fmOutput then
  344. InOutRes:=104
  345. else
  346. InOutRes:=103;
  347. exit(true);
  348. end;
  349. repeat
  350. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  351. begin
  352. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  353. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  354. exit(true);
  355. end;
  356. case TextRec(t).Bufptr^[TextRec(t).BufPos] of
  357. #26: if CtrlZMarksEOF then
  358. exit (true);
  359. #10,#13 : exit(true);
  360. #9,' ' : ;
  361. else
  362. exit(false);
  363. end;
  364. inc(TextRec(t).BufPos);
  365. until false;
  366. End;
  367. Function SeekEoln : Boolean;
  368. Begin
  369. SeekEoln:=SeekEoln(Input);
  370. End;
  371. Procedure SetTextBuf(Var F : Text; Var Buf; Size : SizeInt);
  372. Begin
  373. TextRec(f).BufPtr:=@Buf;
  374. TextRec(f).BufSize:=Size;
  375. TextRec(f).BufPos:=0;
  376. TextRec(f).BufEnd:=0;
  377. End;
  378. Procedure SetTextLineEnding(Var f:Text; Ending:string);
  379. Begin
  380. TextRec(F).LineEnd:=Ending;
  381. End;
  382. Function fpc_get_input:PText;compilerproc;
  383. begin
  384. fpc_get_input:=@Input;
  385. end;
  386. Function fpc_get_output:PText;compilerproc;
  387. begin
  388. fpc_get_output:=@Output;
  389. end;
  390. {*****************************************************************************
  391. Write(Ln)
  392. *****************************************************************************}
  393. Procedure fpc_WriteBuffer(var f:Text;const b;len:SizeInt);[Public,Alias:'FPC_WRITEBUFFER'];
  394. var
  395. p : pchar;
  396. left,
  397. idx : SizeInt;
  398. begin
  399. p:=pchar(@b);
  400. idx:=0;
  401. left:=TextRec(f).BufSize-TextRec(f).BufPos;
  402. while len>left do
  403. begin
  404. move(p[idx],TextRec(f).Bufptr^[TextRec(f).BufPos],left);
  405. dec(len,left);
  406. inc(idx,left);
  407. inc(TextRec(f).BufPos,left);
  408. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  409. left:=TextRec(f).BufSize-TextRec(f).BufPos;
  410. end;
  411. move(p[idx],TextRec(f).Bufptr^[TextRec(f).BufPos],len);
  412. inc(TextRec(f).BufPos,len);
  413. end;
  414. Procedure fpc_WriteBlanks(var f:Text;len:longint);[Public,Alias:'FPC_WRITEBLANKS'];
  415. var
  416. left : longint;
  417. begin
  418. left:=TextRec(f).BufSize-TextRec(f).BufPos;
  419. while len>left do
  420. begin
  421. FillChar(TextRec(f).Bufptr^[TextRec(f).BufPos],left,' ');
  422. dec(len,left);
  423. inc(TextRec(f).BufPos,left);
  424. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  425. left:=TextRec(f).BufSize-TextRec(f).BufPos;
  426. end;
  427. FillChar(TextRec(f).Bufptr^[TextRec(f).BufPos],len,' ');
  428. inc(TextRec(f).BufPos,len);
  429. end;
  430. Procedure fpc_Write_End(var f:Text);[Public,Alias:'FPC_WRITE_END']; iocheck; compilerproc;
  431. begin
  432. if TextRec(f).FlushFunc<>nil then
  433. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  434. end;
  435. Procedure fpc_Writeln_End(var f:Text);[Public,Alias:'FPC_WRITELN_END']; iocheck; compilerproc;
  436. begin
  437. If InOutRes <> 0 then exit;
  438. case TextRec(f).mode of
  439. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  440. begin
  441. { Write EOL }
  442. fpc_WriteBuffer(f,TextRec(f).LineEnd[1],length(TextRec(f).LineEnd));
  443. { Flush }
  444. if TextRec(f).FlushFunc<>nil then
  445. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  446. end;
  447. fmInput: InOutRes:=105
  448. else InOutRes:=103;
  449. end;
  450. end;
  451. Procedure fpc_Write_Text_ShortStr(Len : Longint;var f : Text;const s : String); iocheck; [Public,Alias:'FPC_WRITE_TEXT_SHORTSTR']; compilerproc;
  452. Begin
  453. If (InOutRes<>0) then
  454. exit;
  455. case TextRec(f).mode of
  456. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  457. begin
  458. If Len>Length(s) Then
  459. fpc_WriteBlanks(f,Len-Length(s));
  460. fpc_WriteBuffer(f,s[1],Length(s));
  461. end;
  462. fmInput: InOutRes:=105
  463. else InOutRes:=103;
  464. end;
  465. End;
  466. { provide local access to write_str }
  467. procedure Write_Str(Len : Longint;var f : Text;const s : String); iocheck; [external name 'FPC_WRITE_TEXT_SHORTSTR'];
  468. Procedure fpc_Write_Text_Pchar_as_Array(Len : Longint;var f : Text;const s : array of char; zerobased: boolean = true); iocheck; [Public,Alias:'FPC_WRITE_TEXT_PCHAR_AS_ARRAY']; compilerproc;
  469. var
  470. ArrayLen : longint;
  471. p : pchar;
  472. Begin
  473. If (InOutRes<>0) then
  474. exit;
  475. case TextRec(f).mode of
  476. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  477. begin
  478. p:=pchar(@s);
  479. if (zerobased) then
  480. begin
  481. { can't use StrLen, since that one could try to read past the end }
  482. { of the heap (JM) }
  483. ArrayLen:=IndexByte(p^,high(s)+1,0);
  484. { IndexByte returns -1 if not found (JM) }
  485. if ArrayLen = -1 then
  486. ArrayLen := high(s)+1;
  487. end
  488. else
  489. ArrayLen := high(s)+1;
  490. If Len>ArrayLen Then
  491. fpc_WriteBlanks(f,Len-ArrayLen);
  492. fpc_WriteBuffer(f,p^,ArrayLen);
  493. end;
  494. fmInput: InOutRes:=105
  495. else InOutRes:=103;
  496. end;
  497. End;
  498. Procedure fpc_Write_Text_PChar_As_Pointer(Len : Longint;var f : Text;p : PChar); iocheck; [Public,Alias:'FPC_WRITE_TEXT_PCHAR_AS_POINTER']; compilerproc;
  499. var
  500. PCharLen : longint;
  501. Begin
  502. If (p=nil) or (InOutRes<>0) then
  503. exit;
  504. case TextRec(f).mode of
  505. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  506. begin
  507. PCharLen:=StrLen(p);
  508. If Len>PCharLen Then
  509. fpc_WriteBlanks(f,Len-PCharLen);
  510. fpc_WriteBuffer(f,p^,PCharLen);
  511. end;
  512. fmInput: InOutRes:=105
  513. else InOutRes:=103;
  514. end;
  515. End;
  516. Procedure fpc_Write_Text_AnsiStr (Len : Longint; Var f : Text; const S : AnsiString); iocheck; [Public,alias:'FPC_WRITE_TEXT_ANSISTR']; compilerproc;
  517. {
  518. Writes a AnsiString to the Text file T
  519. }
  520. var
  521. SLen : longint;
  522. begin
  523. If (InOutRes<>0) then
  524. exit;
  525. case TextRec(f).mode of
  526. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  527. begin
  528. SLen:=Length(s);
  529. If Len>SLen Then
  530. fpc_WriteBlanks(f,Len-SLen);
  531. if slen > 0 then
  532. fpc_WriteBuffer(f,PChar(S)^,SLen);
  533. end;
  534. fmInput: InOutRes:=105
  535. else InOutRes:=103;
  536. end;
  537. end;
  538. Procedure fpc_Write_Text_WideStr (Len : Longint; Var f : Text; const S : WideString); iocheck; [Public,alias:'FPC_WRITE_TEXT_WIDESTR']; compilerproc;
  539. {
  540. Writes a WideString to the Text file T
  541. }
  542. var
  543. SLen : longint;
  544. begin
  545. If (pointer(S)=nil) or (InOutRes<>0) then
  546. exit;
  547. case TextRec(f).mode of
  548. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  549. begin
  550. SLen:=Length(s);
  551. If Len>SLen Then
  552. fpc_WriteBlanks(f,Len-SLen);
  553. fpc_WriteBuffer(f,PChar(AnsiString(S))^,SLen);
  554. end;
  555. fmInput: InOutRes:=105
  556. else InOutRes:=103;
  557. end;
  558. end;
  559. Procedure fpc_Write_Text_SInt(Len : Longint;var t : Text;l : ValSInt); iocheck; [Public,Alias:'FPC_WRITE_TEXT_SINT']; compilerproc;
  560. var
  561. s : String;
  562. Begin
  563. If (InOutRes<>0) then
  564. exit;
  565. Str(l,s);
  566. Write_Str(Len,t,s);
  567. End;
  568. Procedure fpc_Write_Text_UInt(Len : Longint;var t : Text;l : ValUInt); iocheck; [Public,Alias:'FPC_WRITE_TEXT_UINT']; compilerproc;
  569. var
  570. s : String;
  571. Begin
  572. If (InOutRes<>0) then
  573. exit;
  574. Str(L,s);
  575. Write_Str(Len,t,s);
  576. End;
  577. {$ifndef CPU64}
  578. procedure fpc_write_text_qword(len : longint;var t : text;q : qword); iocheck; [public,alias:'FPC_WRITE_TEXT_QWORD']; compilerproc;
  579. var
  580. s : string;
  581. begin
  582. if (InOutRes<>0) then
  583. exit;
  584. str(q,s);
  585. write_str(len,t,s);
  586. end;
  587. procedure fpc_write_text_int64(len : longint;var t : text;i : int64); iocheck; [public,alias:'FPC_WRITE_TEXT_INT64']; compilerproc;
  588. var
  589. s : string;
  590. begin
  591. if (InOutRes<>0) then
  592. exit;
  593. str(i,s);
  594. write_str(len,t,s);
  595. end;
  596. {$endif CPU64}
  597. Procedure fpc_Write_Text_Float(rt,fixkomma,Len : Longint;var t : Text;r : ValReal); iocheck; [Public,Alias:'FPC_WRITE_TEXT_FLOAT']; compilerproc;
  598. var
  599. s : String;
  600. Begin
  601. If (InOutRes<>0) then
  602. exit;
  603. Str_real(Len,fixkomma,r,treal_type(rt),s);
  604. Write_Str(Len,t,s);
  605. End;
  606. Procedure fpc_Write_Text_Boolean(Len : Longint;var t : Text;b : Boolean); iocheck; [Public,Alias:'FPC_WRITE_TEXT_BOOLEAN']; compilerproc;
  607. Begin
  608. If (InOutRes<>0) then
  609. exit;
  610. { Can't use array[boolean] because b can be >0 ! }
  611. if b then
  612. Write_Str(Len,t,'TRUE')
  613. else
  614. Write_Str(Len,t,'FALSE');
  615. End;
  616. Procedure fpc_Write_Text_Char(Len : Longint;var t : Text;c : Char); iocheck; [Public,Alias:'FPC_WRITE_TEXT_CHAR']; compilerproc;
  617. Begin
  618. If (InOutRes<>0) then
  619. exit;
  620. if (TextRec(t).mode<>fmOutput) Then
  621. begin
  622. if TextRec(t).mode=fmClosed then
  623. InOutRes:=103
  624. else
  625. InOutRes:=105;
  626. exit;
  627. end;
  628. If Len>1 Then
  629. fpc_WriteBlanks(t,Len-1);
  630. If TextRec(t).BufPos+1>=TextRec(t).BufSize Then
  631. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  632. TextRec(t).Bufptr^[TextRec(t).BufPos]:=c;
  633. Inc(TextRec(t).BufPos);
  634. End;
  635. Procedure fpc_Write_Text_WideChar(Len : Longint;var t : Text;c : WideChar); iocheck; [Public,Alias:'FPC_WRITE_TEXT_WIDECHAR']; compilerproc;
  636. var
  637. ch : char;
  638. Begin
  639. If (InOutRes<>0) then
  640. exit;
  641. if (TextRec(t).mode<>fmOutput) Then
  642. begin
  643. if TextRec(t).mode=fmClosed then
  644. InOutRes:=103
  645. else
  646. InOutRes:=105;
  647. exit;
  648. end;
  649. If Len>1 Then
  650. fpc_WriteBlanks(t,Len-1);
  651. If TextRec(t).BufPos+1>=TextRec(t).BufSize Then
  652. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  653. ch:=c;
  654. TextRec(t).Bufptr^[TextRec(t).BufPos]:=ch;
  655. Inc(TextRec(t).BufPos);
  656. End;
  657. {*****************************************************************************
  658. Read(Ln)
  659. *****************************************************************************}
  660. Function NextChar(var f:Text;var s:string):Boolean;
  661. begin
  662. NextChar:=false;
  663. if (TextRec(f).BufPos<TextRec(f).BufEnd) then
  664. if not (CtrlZMarksEOF) or (TextRec(f).Bufptr^[TextRec(f).BufPos]<>#26) then
  665. begin
  666. if length(s)<high(s) then
  667. begin
  668. inc(s[0]);
  669. s[length(s)]:=TextRec(f).BufPtr^[TextRec(f).BufPos];
  670. end;
  671. Inc(TextRec(f).BufPos);
  672. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  673. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  674. NextChar:=true;
  675. end;
  676. end;
  677. Function IgnoreSpaces(var f:Text):Boolean;
  678. {
  679. Removes all leading spaces,tab,eols from the input buffer, returns true if
  680. the buffer is empty
  681. }
  682. var
  683. s : string;
  684. begin
  685. s:='';
  686. IgnoreSpaces:=false;
  687. { Return false when already at EOF }
  688. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  689. exit;
  690. (* Check performed separately to avoid accessing memory outside buffer *)
  691. if CtrlZMarksEOF and (TextRec(f).Bufptr^[TextRec(f).BufPos]=#26) then
  692. exit;
  693. while (TextRec(f).Bufptr^[TextRec(f).BufPos] <= ' ') do
  694. begin
  695. if not NextChar(f,s) then
  696. exit;
  697. { EOF? }
  698. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  699. break;
  700. if CtrlZMarksEOF and (TextRec(f).Bufptr^[TextRec(f).BufPos]=#26) then
  701. break;
  702. end;
  703. IgnoreSpaces:=true;
  704. end;
  705. procedure ReadNumeric(var f:Text;var s:string);
  706. {
  707. Read numeric input, if buffer is empty then return True
  708. }
  709. begin
  710. repeat
  711. if not NextChar(f,s) then
  712. exit;
  713. until (length(s)=high(s)) or (TextRec(f).BufPtr^[TextRec(f).BufPos] <= ' ');
  714. end;
  715. Procedure fpc_Read_End(var f:Text);[Public,Alias:'FPC_READ_END']; iocheck; compilerproc;
  716. begin
  717. if TextRec(f).FlushFunc<>nil then
  718. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  719. end;
  720. Procedure fpc_ReadLn_End(var f : Text);[Public,Alias:'FPC_READLN_END']; iocheck; compilerproc;
  721. var prev: char;
  722. Begin
  723. { Check error and if file is open and load buf if empty }
  724. If (InOutRes<>0) then
  725. exit;
  726. if (TextRec(f).mode<>fmInput) Then
  727. begin
  728. case TextRec(f).mode of
  729. fmOutPut,fmAppend:
  730. InOutRes:=104
  731. else
  732. InOutRes:=103;
  733. end;
  734. exit;
  735. end;
  736. if TextRec(f).BufPos>=TextRec(f).BufEnd Then
  737. begin
  738. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  739. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  740. { Flush if set }
  741. begin
  742. if (TextRec(f).FlushFunc<>nil) then
  743. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  744. exit;
  745. end;
  746. end;
  747. if CtrlZMarksEOF and (TextRec (F).BufPtr^ [TextRec (F).BufPos] = #26) then
  748. Exit;
  749. repeat
  750. prev := TextRec(f).BufPtr^[TextRec(f).BufPos];
  751. inc(TextRec(f).BufPos);
  752. { no system uses #10#13 as line seperator (#10 = *nix, #13 = Mac, }
  753. { #13#10 = Dos), so if we've got #10, we can safely exit }
  754. if prev = #10 then
  755. exit;
  756. {$ifdef MACOS}
  757. if prev = #13 then
  758. {StdInput on macos never have dos line ending, so this is safe.}
  759. if TextRec(f).Handle = StdInputHandle then
  760. exit;
  761. {$endif MACOS}
  762. if TextRec(f).BufPos>=TextRec(f).BufEnd Then
  763. begin
  764. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  765. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  766. { Flush if set }
  767. begin
  768. if (TextRec(f).FlushFunc<>nil) then
  769. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  770. exit;
  771. end;
  772. end;
  773. if CtrlZMarksEOF and (TextRec (F).BufPtr^ [TextRec (F).BufPos] = #26) then
  774. Exit;
  775. if (prev=#13) then
  776. { is there also a #10 after it? }
  777. begin
  778. if (TextRec(f).BufPtr^[TextRec(f).BufPos]=#10) then
  779. { yes, skip that one as well }
  780. inc(TextRec(f).BufPos);
  781. exit;
  782. end;
  783. until false;
  784. End;
  785. Function ReadPCharLen(var f:Text;s:pchar;maxlen:longint):longint;
  786. var
  787. sPos,len : Longint;
  788. p,startp,maxp : pchar;
  789. Begin
  790. ReadPCharLen:=0;
  791. { Check error and if file is open }
  792. If (InOutRes<>0) then
  793. exit;
  794. if (TextRec(f).mode<>fmInput) Then
  795. begin
  796. case TextRec(f).mode of
  797. fmOutPut,fmAppend:
  798. InOutRes:=104
  799. else
  800. InOutRes:=103;
  801. end;
  802. exit;
  803. end;
  804. { Read maximal until Maxlen is reached }
  805. sPos:=0;
  806. repeat
  807. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  808. begin
  809. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  810. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  811. break;
  812. end;
  813. p:=@TextRec(f).Bufptr^[TextRec(f).BufPos];
  814. if SPos+TextRec(f).BufEnd-TextRec(f).BufPos>MaxLen then
  815. maxp:=@TextRec(f).BufPtr^[TextRec(f).BufPos+MaxLen-SPos]
  816. else
  817. maxp:=@TextRec(f).Bufptr^[TextRec(f).BufEnd];
  818. startp:=p;
  819. { search linefeed }
  820. while (p<maxp) and not(P^ in [#10,#13]) do
  821. inc(p);
  822. { calculate read bytes }
  823. len:=p-startp;
  824. inc(TextRec(f).BufPos,Len);
  825. Move(startp^,s[sPos],Len);
  826. inc(sPos,Len);
  827. { was it a LF or CR? then leave }
  828. if (spos=MaxLen) or
  829. ((p<maxp) and (p^ in [#10,#13])) then
  830. break;
  831. until false;
  832. ReadPCharLen:=spos;
  833. End;
  834. Procedure fpc_Read_Text_ShortStr(var f : Text;out s : String); iocheck; [Public,Alias:'FPC_READ_TEXT_SHORTSTR']; compilerproc;
  835. Begin
  836. s[0]:=chr(ReadPCharLen(f,pchar(@s[1]),high(s)));
  837. End;
  838. Procedure fpc_Read_Text_PChar_As_Pointer(var f : Text;out s : PChar); iocheck; [Public,Alias:'FPC_READ_TEXT_PCHAR_AS_POINTER']; compilerproc;
  839. Begin
  840. pchar(s+ReadPCharLen(f,s,$7fffffff))^:=#0;
  841. End;
  842. Procedure fpc_Read_Text_PChar_As_Array(var f : Text;out s : array of char); iocheck; [Public,Alias:'FPC_READ_TEXT_PCHAR_AS_ARRAY']; compilerproc;
  843. var
  844. len: longint;
  845. Begin
  846. len := ReadPCharLen(f,pchar(@s),high(s)+1);
  847. if len <= high(s) then
  848. s[len] := #0;
  849. End;
  850. Procedure fpc_Read_Text_AnsiStr(var f : Text;out s : AnsiString); iocheck; [Public,Alias:'FPC_READ_TEXT_ANSISTR']; compilerproc;
  851. var
  852. slen,len : SizeInt;
  853. Begin
  854. slen:=0;
  855. Repeat
  856. // SetLength will reallocate the length.
  857. SetLength(S,slen+255);
  858. len:=ReadPCharLen(f,pchar(Pointer(S)+slen),255);
  859. inc(slen,len);
  860. Until len<255;
  861. // Set actual length
  862. SetLength(S,Slen);
  863. End;
  864. procedure fpc_Read_Text_Char(var f : Text; out c: char); iocheck; [Public,Alias:'FPC_READ_TEXT_CHAR'];compilerproc;
  865. Begin
  866. c:=#0;
  867. { Check error and if file is open }
  868. If (InOutRes<>0) then
  869. exit;
  870. if (TextRec(f).mode<>fmInput) Then
  871. begin
  872. case TextRec(f).mode of
  873. fmOutPut,fmAppend:
  874. InOutRes:=104
  875. else
  876. InOutRes:=103;
  877. end;
  878. exit;
  879. end;
  880. { Read next char or EOF }
  881. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  882. begin
  883. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  884. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  885. begin
  886. c := #26;
  887. exit;
  888. end;
  889. end;
  890. c:=TextRec(f).Bufptr^[TextRec(f).BufPos];
  891. inc(TextRec(f).BufPos);
  892. end;
  893. Procedure fpc_Read_Text_SInt(var f : Text; out l : ValSInt); iocheck; [Public,Alias:'FPC_READ_TEXT_SINT']; compilerproc;
  894. var
  895. hs : String;
  896. code : longint;
  897. Begin
  898. l:=0;
  899. { Leave if error or not open file, else check for empty buf }
  900. If (InOutRes<>0) then
  901. exit;
  902. if (TextRec(f).mode<>fmInput) Then
  903. begin
  904. case TextRec(f).mode of
  905. fmOutPut,fmAppend:
  906. InOutRes:=104
  907. else
  908. InOutRes:=103;
  909. end;
  910. exit;
  911. end;
  912. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  913. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  914. hs:='';
  915. if IgnoreSpaces(f) then
  916. begin
  917. { When spaces were found and we are now at EOF,
  918. then we return 0 }
  919. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  920. exit;
  921. if CtrlZMarksEOF and (TextRec(f).Bufptr^[TextRec(f).BufPos]=#26) then
  922. exit;
  923. ReadNumeric(f,hs);
  924. end;
  925. if (hs = '') then
  926. L := 0
  927. else
  928. begin
  929. Val(hs,l,code);
  930. if Code <> 0 then
  931. InOutRes:=106;
  932. end;
  933. End;
  934. Procedure fpc_Read_Text_UInt(var f : Text; out u : ValUInt); iocheck; [Public,Alias:'FPC_READ_TEXT_UINT']; compilerproc;
  935. var
  936. hs : String;
  937. code : longint;
  938. Begin
  939. u:=0;
  940. { Leave if error or not open file, else check for empty buf }
  941. If (InOutRes<>0) then
  942. exit;
  943. if (TextRec(f).mode<>fmInput) Then
  944. begin
  945. case TextRec(f).mode of
  946. fmOutPut,fmAppend:
  947. InOutRes:=104
  948. else
  949. InOutRes:=103;
  950. end;
  951. exit;
  952. end;
  953. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  954. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  955. hs:='';
  956. if IgnoreSpaces(f) then
  957. begin
  958. { When spaces were found and we are now at EOF,
  959. then we return 0 }
  960. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  961. exit;
  962. ReadNumeric(f,hs);
  963. end;
  964. val(hs,u,code);
  965. If code<>0 Then
  966. InOutRes:=106;
  967. End;
  968. procedure fpc_Read_Text_Float(var f : Text; out v : ValReal); iocheck; [Public,Alias:'FPC_READ_TEXT_FLOAT']; compilerproc;
  969. var
  970. hs : string;
  971. code : Word;
  972. begin
  973. v:=0.0;
  974. { Leave if error or not open file, else check for empty buf }
  975. If (InOutRes<>0) then
  976. exit;
  977. if (TextRec(f).mode<>fmInput) Then
  978. begin
  979. case TextRec(f).mode of
  980. fmOutPut,fmAppend:
  981. InOutRes:=104
  982. else
  983. InOutRes:=103;
  984. end;
  985. exit;
  986. end;
  987. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  988. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  989. hs:='';
  990. if IgnoreSpaces(f) then
  991. begin
  992. { When spaces were found and we are now at EOF,
  993. then we return 0 }
  994. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  995. exit;
  996. ReadNumeric(f,hs);
  997. end;
  998. val(hs,v,code);
  999. If code<>0 Then
  1000. InOutRes:=106;
  1001. end;
  1002. {$ifndef cpu64}
  1003. procedure fpc_Read_Text_QWord(var f : text; out q : qword); iocheck; [public,alias:'FPC_READ_TEXT_QWORD']; compilerproc;
  1004. var
  1005. hs : String;
  1006. code : longint;
  1007. Begin
  1008. q:=0;
  1009. { Leave if error or not open file, else check for empty buf }
  1010. If (InOutRes<>0) then
  1011. exit;
  1012. if (TextRec(f).mode<>fmInput) Then
  1013. begin
  1014. case TextRec(f).mode of
  1015. fmOutPut,fmAppend:
  1016. InOutRes:=104
  1017. else
  1018. InOutRes:=103;
  1019. end;
  1020. exit;
  1021. end;
  1022. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  1023. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  1024. hs:='';
  1025. if IgnoreSpaces(f) then
  1026. begin
  1027. { When spaces were found and we are now at EOF,
  1028. then we return 0 }
  1029. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1030. exit;
  1031. ReadNumeric(f,hs);
  1032. end;
  1033. val(hs,q,code);
  1034. If code<>0 Then
  1035. InOutRes:=106;
  1036. End;
  1037. procedure fpc_Read_Text_Int64(var f : text; out i : int64); iocheck; [public,alias:'FPC_READ_TEXT_INT64']; compilerproc;
  1038. var
  1039. hs : String;
  1040. code : Longint;
  1041. Begin
  1042. i:=0;
  1043. { Leave if error or not open file, else check for empty buf }
  1044. If (InOutRes<>0) then
  1045. exit;
  1046. if (TextRec(f).mode<>fmInput) Then
  1047. begin
  1048. case TextRec(f).mode of
  1049. fmOutPut,fmAppend:
  1050. InOutRes:=104
  1051. else
  1052. InOutRes:=103;
  1053. end;
  1054. exit;
  1055. end;
  1056. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  1057. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  1058. hs:='';
  1059. if IgnoreSpaces(f) then
  1060. begin
  1061. { When spaces were found and we are now at EOF,
  1062. then we return 0 }
  1063. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1064. exit;
  1065. ReadNumeric(f,hs);
  1066. end;
  1067. Val(hs,i,code);
  1068. If code<>0 Then
  1069. InOutRes:=106;
  1070. End;
  1071. {$endif CPU64}
  1072. {*****************************************************************************
  1073. Initializing
  1074. *****************************************************************************}
  1075. procedure OpenStdIO(var f:text;mode,hdl:longint);
  1076. begin
  1077. Assign(f,'');
  1078. TextRec(f).Handle:=hdl;
  1079. TextRec(f).Mode:=mode;
  1080. TextRec(f).Closefunc:=@FileCloseFunc;
  1081. case mode of
  1082. fmInput :
  1083. TextRec(f).InOutFunc:=@FileReadFunc;
  1084. fmOutput :
  1085. begin
  1086. TextRec(f).InOutFunc:=@FileWriteFunc;
  1087. TextRec(f).FlushFunc:=@FileWriteFunc;
  1088. end;
  1089. else
  1090. HandleError(102);
  1091. end;
  1092. end;