text.inc 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220
  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); 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. { can't use StrLen, since that one could try to read past the end }
  480. { of the heap (JM) }
  481. ArrayLen:=IndexByte(p^,high(s)+1,0);
  482. { IndexByte returns -1 if not found (JM) }
  483. if ArrayLen = -1 then
  484. ArrayLen := high(s)+1;
  485. If Len>ArrayLen Then
  486. fpc_WriteBlanks(f,Len-ArrayLen);
  487. fpc_WriteBuffer(f,p^,ArrayLen);
  488. end;
  489. fmInput: InOutRes:=105
  490. else InOutRes:=103;
  491. end;
  492. End;
  493. Procedure fpc_Write_Text_PChar_As_Pointer(Len : Longint;var f : Text;p : PChar); iocheck; [Public,Alias:'FPC_WRITE_TEXT_PCHAR_AS_POINTER']; compilerproc;
  494. var
  495. PCharLen : longint;
  496. Begin
  497. If (p=nil) or (InOutRes<>0) then
  498. exit;
  499. case TextRec(f).mode of
  500. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  501. begin
  502. PCharLen:=StrLen(p);
  503. If Len>PCharLen Then
  504. fpc_WriteBlanks(f,Len-PCharLen);
  505. fpc_WriteBuffer(f,p^,PCharLen);
  506. end;
  507. fmInput: InOutRes:=105
  508. else InOutRes:=103;
  509. end;
  510. End;
  511. Procedure fpc_Write_Text_AnsiStr (Len : Longint; Var f : Text; const S : AnsiString); iocheck; [Public,alias:'FPC_WRITE_TEXT_ANSISTR']; compilerproc;
  512. {
  513. Writes a AnsiString to the Text file T
  514. }
  515. var
  516. SLen : longint;
  517. begin
  518. If (InOutRes<>0) then
  519. exit;
  520. case TextRec(f).mode of
  521. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  522. begin
  523. SLen:=Length(s);
  524. If Len>SLen Then
  525. fpc_WriteBlanks(f,Len-SLen);
  526. if slen > 0 then
  527. fpc_WriteBuffer(f,PChar(S)^,SLen);
  528. end;
  529. fmInput: InOutRes:=105
  530. else InOutRes:=103;
  531. end;
  532. end;
  533. Procedure fpc_Write_Text_WideStr (Len : Longint; Var f : Text; const S : WideString); iocheck; [Public,alias:'FPC_WRITE_TEXT_WIDESTR']; compilerproc;
  534. {
  535. Writes a WideString to the Text file T
  536. }
  537. var
  538. SLen : longint;
  539. begin
  540. If (pointer(S)=nil) or (InOutRes<>0) then
  541. exit;
  542. case TextRec(f).mode of
  543. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  544. begin
  545. SLen:=Length(s);
  546. If Len>SLen Then
  547. fpc_WriteBlanks(f,Len-SLen);
  548. fpc_WriteBuffer(f,PChar(AnsiString(S))^,SLen);
  549. end;
  550. fmInput: InOutRes:=105
  551. else InOutRes:=103;
  552. end;
  553. end;
  554. Procedure fpc_Write_Text_SInt(Len : Longint;var t : Text;l : ValSInt); iocheck; [Public,Alias:'FPC_WRITE_TEXT_SINT']; compilerproc;
  555. var
  556. s : String;
  557. Begin
  558. If (InOutRes<>0) then
  559. exit;
  560. Str(l,s);
  561. Write_Str(Len,t,s);
  562. End;
  563. Procedure fpc_Write_Text_UInt(Len : Longint;var t : Text;l : ValUInt); iocheck; [Public,Alias:'FPC_WRITE_TEXT_UINT']; compilerproc;
  564. var
  565. s : String;
  566. Begin
  567. If (InOutRes<>0) then
  568. exit;
  569. Str(L,s);
  570. Write_Str(Len,t,s);
  571. End;
  572. {$ifndef CPU64}
  573. procedure fpc_write_text_qword(len : longint;var t : text;q : qword); iocheck; [public,alias:'FPC_WRITE_TEXT_QWORD']; compilerproc;
  574. var
  575. s : string;
  576. begin
  577. if (InOutRes<>0) then
  578. exit;
  579. str(q,s);
  580. write_str(len,t,s);
  581. end;
  582. procedure fpc_write_text_int64(len : longint;var t : text;i : int64); iocheck; [public,alias:'FPC_WRITE_TEXT_INT64']; compilerproc;
  583. var
  584. s : string;
  585. begin
  586. if (InOutRes<>0) then
  587. exit;
  588. str(i,s);
  589. write_str(len,t,s);
  590. end;
  591. {$endif CPU64}
  592. Procedure fpc_Write_Text_Float(rt,fixkomma,Len : Longint;var t : Text;r : ValReal); iocheck; [Public,Alias:'FPC_WRITE_TEXT_FLOAT']; compilerproc;
  593. var
  594. s : String;
  595. Begin
  596. If (InOutRes<>0) then
  597. exit;
  598. Str_real(Len,fixkomma,r,treal_type(rt),s);
  599. Write_Str(Len,t,s);
  600. End;
  601. Procedure fpc_Write_Text_Boolean(Len : Longint;var t : Text;b : Boolean); iocheck; [Public,Alias:'FPC_WRITE_TEXT_BOOLEAN']; compilerproc;
  602. Begin
  603. If (InOutRes<>0) then
  604. exit;
  605. { Can't use array[boolean] because b can be >0 ! }
  606. if b then
  607. Write_Str(Len,t,'TRUE')
  608. else
  609. Write_Str(Len,t,'FALSE');
  610. End;
  611. Procedure fpc_Write_Text_Char(Len : Longint;var t : Text;c : Char); iocheck; [Public,Alias:'FPC_WRITE_TEXT_CHAR']; compilerproc;
  612. Begin
  613. If (InOutRes<>0) then
  614. exit;
  615. if (TextRec(t).mode<>fmOutput) Then
  616. begin
  617. if TextRec(t).mode=fmClosed then
  618. InOutRes:=103
  619. else
  620. InOutRes:=105;
  621. exit;
  622. end;
  623. If Len>1 Then
  624. fpc_WriteBlanks(t,Len-1);
  625. If TextRec(t).BufPos+1>=TextRec(t).BufSize Then
  626. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  627. TextRec(t).Bufptr^[TextRec(t).BufPos]:=c;
  628. Inc(TextRec(t).BufPos);
  629. End;
  630. Procedure fpc_Write_Text_WideChar(Len : Longint;var t : Text;c : WideChar); iocheck; [Public,Alias:'FPC_WRITE_TEXT_WIDECHAR']; compilerproc;
  631. var
  632. ch : char;
  633. Begin
  634. If (InOutRes<>0) then
  635. exit;
  636. if (TextRec(t).mode<>fmOutput) Then
  637. begin
  638. if TextRec(t).mode=fmClosed then
  639. InOutRes:=103
  640. else
  641. InOutRes:=105;
  642. exit;
  643. end;
  644. If Len>1 Then
  645. fpc_WriteBlanks(t,Len-1);
  646. If TextRec(t).BufPos+1>=TextRec(t).BufSize Then
  647. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  648. ch:=c;
  649. TextRec(t).Bufptr^[TextRec(t).BufPos]:=ch;
  650. Inc(TextRec(t).BufPos);
  651. End;
  652. {*****************************************************************************
  653. Read(Ln)
  654. *****************************************************************************}
  655. Function NextChar(var f:Text;var s:string):Boolean;
  656. begin
  657. NextChar:=false;
  658. if (TextRec(f).BufPos<TextRec(f).BufEnd) then
  659. if not (CtrlZMarksEOF) or (TextRec(f).Bufptr^[TextRec(f).BufPos]<>#26) then
  660. begin
  661. if length(s)<high(s) then
  662. begin
  663. inc(s[0]);
  664. s[length(s)]:=TextRec(f).BufPtr^[TextRec(f).BufPos];
  665. end;
  666. Inc(TextRec(f).BufPos);
  667. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  668. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  669. NextChar:=true;
  670. end;
  671. end;
  672. Function IgnoreSpaces(var f:Text):Boolean;
  673. {
  674. Removes all leading spaces,tab,eols from the input buffer, returns true if
  675. the buffer is empty
  676. }
  677. var
  678. s : string;
  679. begin
  680. s:='';
  681. IgnoreSpaces:=false;
  682. { Return false when already at EOF }
  683. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  684. exit;
  685. (* Check performed separately to avoid accessing memory outside buffer *)
  686. if CtrlZMarksEOF and (TextRec(f).Bufptr^[TextRec(f).BufPos]=#26) then
  687. exit;
  688. while (TextRec(f).Bufptr^[TextRec(f).BufPos] <= ' ') do
  689. begin
  690. if not NextChar(f,s) then
  691. exit;
  692. { EOF? }
  693. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  694. break;
  695. if CtrlZMarksEOF and (TextRec(f).Bufptr^[TextRec(f).BufPos]=#26) then
  696. break;
  697. end;
  698. IgnoreSpaces:=true;
  699. end;
  700. procedure ReadNumeric(var f:Text;var s:string);
  701. {
  702. Read numeric input, if buffer is empty then return True
  703. }
  704. begin
  705. repeat
  706. if not NextChar(f,s) then
  707. exit;
  708. until (length(s)=high(s)) or (TextRec(f).BufPtr^[TextRec(f).BufPos] <= ' ');
  709. end;
  710. Procedure fpc_Read_End(var f:Text);[Public,Alias:'FPC_READ_END']; iocheck; compilerproc;
  711. begin
  712. if TextRec(f).FlushFunc<>nil then
  713. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  714. end;
  715. Procedure fpc_ReadLn_End(var f : Text);[Public,Alias:'FPC_READLN_END']; iocheck; compilerproc;
  716. var prev: char;
  717. Begin
  718. { Check error and if file is open and load buf if empty }
  719. If (InOutRes<>0) then
  720. exit;
  721. if (TextRec(f).mode<>fmInput) Then
  722. begin
  723. case TextRec(f).mode of
  724. fmOutPut,fmAppend:
  725. InOutRes:=104
  726. else
  727. InOutRes:=103;
  728. end;
  729. exit;
  730. end;
  731. if TextRec(f).BufPos>=TextRec(f).BufEnd Then
  732. begin
  733. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  734. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  735. { Flush if set }
  736. begin
  737. if (TextRec(f).FlushFunc<>nil) then
  738. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  739. exit;
  740. end;
  741. end;
  742. if CtrlZMarksEOF and (TextRec (F).BufPtr^ [TextRec (F).BufPos] = #26) then
  743. Exit;
  744. repeat
  745. prev := TextRec(f).BufPtr^[TextRec(f).BufPos];
  746. inc(TextRec(f).BufPos);
  747. { no system uses #10#13 as line seperator (#10 = *nix, #13 = Mac, }
  748. { #13#10 = Dos), so if we've got #10, we can safely exit }
  749. if prev = #10 then
  750. exit;
  751. {$ifdef MACOS}
  752. if prev = #13 then
  753. {StdInput on macos never have dos line ending, so this is safe.}
  754. if TextRec(f).Handle = StdInputHandle then
  755. exit;
  756. {$endif MACOS}
  757. if TextRec(f).BufPos>=TextRec(f).BufEnd Then
  758. begin
  759. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  760. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  761. { Flush if set }
  762. begin
  763. if (TextRec(f).FlushFunc<>nil) then
  764. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  765. exit;
  766. end;
  767. end;
  768. if CtrlZMarksEOF and (TextRec (F).BufPtr^ [TextRec (F).BufPos] = #26) then
  769. Exit;
  770. if (prev=#13) then
  771. { is there also a #10 after it? }
  772. begin
  773. if (TextRec(f).BufPtr^[TextRec(f).BufPos]=#10) then
  774. { yes, skip that one as well }
  775. inc(TextRec(f).BufPos);
  776. exit;
  777. end;
  778. until false;
  779. End;
  780. Function ReadPCharLen(var f:Text;s:pchar;maxlen:longint):longint;
  781. var
  782. sPos,len : Longint;
  783. p,startp,maxp : pchar;
  784. Begin
  785. ReadPCharLen:=0;
  786. { Check error and if file is open }
  787. If (InOutRes<>0) then
  788. exit;
  789. if (TextRec(f).mode<>fmInput) Then
  790. begin
  791. case TextRec(f).mode of
  792. fmOutPut,fmAppend:
  793. InOutRes:=104
  794. else
  795. InOutRes:=103;
  796. end;
  797. exit;
  798. end;
  799. { Read maximal until Maxlen is reached }
  800. sPos:=0;
  801. repeat
  802. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  803. begin
  804. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  805. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  806. break;
  807. end;
  808. p:=@TextRec(f).Bufptr^[TextRec(f).BufPos];
  809. if SPos+TextRec(f).BufEnd-TextRec(f).BufPos>MaxLen then
  810. maxp:=@TextRec(f).BufPtr^[TextRec(f).BufPos+MaxLen-SPos]
  811. else
  812. maxp:=@TextRec(f).Bufptr^[TextRec(f).BufEnd];
  813. startp:=p;
  814. { search linefeed }
  815. while (p<maxp) and not(P^ in [#10,#13]) do
  816. inc(p);
  817. { calculate read bytes }
  818. len:=p-startp;
  819. inc(TextRec(f).BufPos,Len);
  820. Move(startp^,s[sPos],Len);
  821. inc(sPos,Len);
  822. { was it a LF or CR? then leave }
  823. if (spos=MaxLen) or
  824. ((p<maxp) and (p^ in [#10,#13])) then
  825. break;
  826. until false;
  827. ReadPCharLen:=spos;
  828. End;
  829. Procedure fpc_Read_Text_ShortStr(var f : Text;out s : String); iocheck; [Public,Alias:'FPC_READ_TEXT_SHORTSTR']; compilerproc;
  830. Begin
  831. s[0]:=chr(ReadPCharLen(f,pchar(@s[1]),high(s)));
  832. End;
  833. Procedure fpc_Read_Text_PChar_As_Pointer(var f : Text;out s : PChar); iocheck; [Public,Alias:'FPC_READ_TEXT_PCHAR_AS_POINTER']; compilerproc;
  834. Begin
  835. pchar(s+ReadPCharLen(f,s,$7fffffff))^:=#0;
  836. End;
  837. 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;
  838. var
  839. len: longint;
  840. Begin
  841. len := ReadPCharLen(f,pchar(@s),high(s)+1);
  842. if len <= high(s) then
  843. s[len] := #0;
  844. End;
  845. Procedure fpc_Read_Text_AnsiStr(var f : Text;out s : AnsiString); iocheck; [Public,Alias:'FPC_READ_TEXT_ANSISTR']; compilerproc;
  846. var
  847. slen,len : SizeInt;
  848. Begin
  849. slen:=0;
  850. Repeat
  851. // SetLength will reallocate the length.
  852. SetLength(S,slen+255);
  853. len:=ReadPCharLen(f,pchar(Pointer(S)+slen),255);
  854. inc(slen,len);
  855. Until len<255;
  856. // Set actual length
  857. SetLength(S,Slen);
  858. End;
  859. procedure fpc_Read_Text_Char(var f : Text; out c: char); iocheck; [Public,Alias:'FPC_READ_TEXT_CHAR'];compilerproc;
  860. Begin
  861. c:=#0;
  862. { Check error and if file is open }
  863. If (InOutRes<>0) then
  864. exit;
  865. if (TextRec(f).mode<>fmInput) Then
  866. begin
  867. case TextRec(f).mode of
  868. fmOutPut,fmAppend:
  869. InOutRes:=104
  870. else
  871. InOutRes:=103;
  872. end;
  873. exit;
  874. end;
  875. { Read next char or EOF }
  876. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  877. begin
  878. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  879. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  880. begin
  881. c := #26;
  882. exit;
  883. end;
  884. end;
  885. c:=TextRec(f).Bufptr^[TextRec(f).BufPos];
  886. inc(TextRec(f).BufPos);
  887. end;
  888. Procedure fpc_Read_Text_SInt(var f : Text; out l : ValSInt); iocheck; [Public,Alias:'FPC_READ_TEXT_SINT']; compilerproc;
  889. var
  890. hs : String;
  891. code : longint;
  892. Begin
  893. l:=0;
  894. { Leave if error or not open file, else check for empty buf }
  895. If (InOutRes<>0) then
  896. exit;
  897. if (TextRec(f).mode<>fmInput) Then
  898. begin
  899. case TextRec(f).mode of
  900. fmOutPut,fmAppend:
  901. InOutRes:=104
  902. else
  903. InOutRes:=103;
  904. end;
  905. exit;
  906. end;
  907. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  908. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  909. hs:='';
  910. if IgnoreSpaces(f) then
  911. begin
  912. { When spaces were found and we are now at EOF,
  913. then we return 0 }
  914. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  915. exit;
  916. if CtrlZMarksEOF and (TextRec(f).Bufptr^[TextRec(f).BufPos]=#26) then
  917. exit;
  918. ReadNumeric(f,hs);
  919. end;
  920. if (hs = '') then
  921. L := 0
  922. else
  923. begin
  924. Val(hs,l,code);
  925. if Code <> 0 then
  926. InOutRes:=106;
  927. end;
  928. End;
  929. Procedure fpc_Read_Text_UInt(var f : Text; out u : ValUInt); iocheck; [Public,Alias:'FPC_READ_TEXT_UINT']; compilerproc;
  930. var
  931. hs : String;
  932. code : longint;
  933. Begin
  934. u:=0;
  935. { Leave if error or not open file, else check for empty buf }
  936. If (InOutRes<>0) then
  937. exit;
  938. if (TextRec(f).mode<>fmInput) Then
  939. begin
  940. case TextRec(f).mode of
  941. fmOutPut,fmAppend:
  942. InOutRes:=104
  943. else
  944. InOutRes:=103;
  945. end;
  946. exit;
  947. end;
  948. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  949. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  950. hs:='';
  951. if IgnoreSpaces(f) then
  952. begin
  953. { When spaces were found and we are now at EOF,
  954. then we return 0 }
  955. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  956. exit;
  957. ReadNumeric(f,hs);
  958. end;
  959. val(hs,u,code);
  960. If code<>0 Then
  961. InOutRes:=106;
  962. End;
  963. procedure fpc_Read_Text_Float(var f : Text; out v : ValReal); iocheck; [Public,Alias:'FPC_READ_TEXT_FLOAT']; compilerproc;
  964. var
  965. hs : string;
  966. code : Word;
  967. begin
  968. v:=0.0;
  969. { Leave if error or not open file, else check for empty buf }
  970. If (InOutRes<>0) then
  971. exit;
  972. if (TextRec(f).mode<>fmInput) Then
  973. begin
  974. case TextRec(f).mode of
  975. fmOutPut,fmAppend:
  976. InOutRes:=104
  977. else
  978. InOutRes:=103;
  979. end;
  980. exit;
  981. end;
  982. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  983. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  984. hs:='';
  985. if IgnoreSpaces(f) then
  986. begin
  987. { When spaces were found and we are now at EOF,
  988. then we return 0 }
  989. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  990. exit;
  991. ReadNumeric(f,hs);
  992. end;
  993. val(hs,v,code);
  994. If code<>0 Then
  995. InOutRes:=106;
  996. end;
  997. {$ifndef cpu64}
  998. procedure fpc_Read_Text_QWord(var f : text; out q : qword); iocheck; [public,alias:'FPC_READ_TEXT_QWORD']; compilerproc;
  999. var
  1000. hs : String;
  1001. code : longint;
  1002. Begin
  1003. q:=0;
  1004. { Leave if error or not open file, else check for empty buf }
  1005. If (InOutRes<>0) then
  1006. exit;
  1007. if (TextRec(f).mode<>fmInput) Then
  1008. begin
  1009. case TextRec(f).mode of
  1010. fmOutPut,fmAppend:
  1011. InOutRes:=104
  1012. else
  1013. InOutRes:=103;
  1014. end;
  1015. exit;
  1016. end;
  1017. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  1018. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  1019. hs:='';
  1020. if IgnoreSpaces(f) then
  1021. begin
  1022. { When spaces were found and we are now at EOF,
  1023. then we return 0 }
  1024. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1025. exit;
  1026. ReadNumeric(f,hs);
  1027. end;
  1028. val(hs,q,code);
  1029. If code<>0 Then
  1030. InOutRes:=106;
  1031. End;
  1032. procedure fpc_Read_Text_Int64(var f : text; out i : int64); iocheck; [public,alias:'FPC_READ_TEXT_INT64']; compilerproc;
  1033. var
  1034. hs : String;
  1035. code : Longint;
  1036. Begin
  1037. i:=0;
  1038. { Leave if error or not open file, else check for empty buf }
  1039. If (InOutRes<>0) then
  1040. exit;
  1041. if (TextRec(f).mode<>fmInput) Then
  1042. begin
  1043. case TextRec(f).mode of
  1044. fmOutPut,fmAppend:
  1045. InOutRes:=104
  1046. else
  1047. InOutRes:=103;
  1048. end;
  1049. exit;
  1050. end;
  1051. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  1052. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  1053. hs:='';
  1054. if IgnoreSpaces(f) then
  1055. begin
  1056. { When spaces were found and we are now at EOF,
  1057. then we return 0 }
  1058. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1059. exit;
  1060. ReadNumeric(f,hs);
  1061. end;
  1062. Val(hs,i,code);
  1063. If code<>0 Then
  1064. InOutRes:=106;
  1065. End;
  1066. {$endif CPU64}
  1067. {*****************************************************************************
  1068. Initializing
  1069. *****************************************************************************}
  1070. procedure OpenStdIO(var f:text;mode,hdl:longint);
  1071. begin
  1072. Assign(f,'');
  1073. TextRec(f).Handle:=hdl;
  1074. TextRec(f).Mode:=mode;
  1075. TextRec(f).Closefunc:=@FileCloseFunc;
  1076. case mode of
  1077. fmInput :
  1078. TextRec(f).InOutFunc:=@FileReadFunc;
  1079. fmOutput :
  1080. begin
  1081. TextRec(f).InOutFunc:=@FileWriteFunc;
  1082. TextRec(f).FlushFunc:=@FileWriteFunc;
  1083. end;
  1084. else
  1085. HandleError(102);
  1086. end;
  1087. end;