text.inc 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907
  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. { prevent unecessary system call }
  28. if t.BufPos=0 then
  29. exit;
  30. i:=Do_Write(t.Handle,t.Bufptr,t.BufPos);
  31. if i<>t.BufPos then
  32. InOutRes:=101;
  33. t.BufPos:=0;
  34. End;
  35. Procedure FileOpenFunc(var t:TextRec);
  36. var
  37. Flags : Longint;
  38. Begin
  39. Case t.mode Of
  40. fmInput : Flags:=$10000;
  41. fmOutput : Flags:=$11001;
  42. fmAppend : Flags:=$10101;
  43. else
  44. begin
  45. InOutRes:=102;
  46. exit;
  47. end;
  48. End;
  49. Do_Open(t,PChar(@t.Name),Flags);
  50. t.CloseFunc:=@FileCloseFunc;
  51. t.FlushFunc:=nil;
  52. if t.Mode=fmInput then
  53. t.InOutFunc:=@FileReadFunc
  54. else
  55. begin
  56. t.InOutFunc:=@FileWriteFunc;
  57. { Only install flushing if its a NOT a file, and only check if there
  58. was no error opening the file, because else we always get a bad
  59. file handle error 6 (PFV) }
  60. if (InOutRes=0) and
  61. Do_Isdevice(t.Handle) then
  62. t.FlushFunc:=@FileWriteFunc;
  63. end;
  64. End;
  65. Procedure Assign(out t:Text;const s:String);
  66. Begin
  67. FillChar(t,SizeOf(TextRec),0);
  68. { only set things that are not zero }
  69. TextRec(t).Handle:=UnusedHandle;
  70. TextRec(t).mode:=fmClosed;
  71. TextRec(t).BufSize:=TextRecBufSize;
  72. TextRec(t).Bufptr:=@TextRec(t).Buffer;
  73. TextRec(t).OpenFunc:=@FileOpenFunc;
  74. Case DefaultTextLineBreakStyle Of
  75. tlbsLF: TextRec(t).LineEnd := #10;
  76. tlbsCRLF: TextRec(t).LineEnd := #13#10;
  77. tlbsCR: TextRec(t).LineEnd := #13;
  78. End;
  79. Move(s[1],TextRec(t).Name,Length(s));
  80. End;
  81. Procedure Assign(out t:Text;p:pchar);
  82. begin
  83. Assign(t,StrPas(p));
  84. end;
  85. Procedure Assign(out t:Text;c:char);
  86. begin
  87. Assign(t,string(c));
  88. end;
  89. Procedure Close(var t : Text);[IOCheck];
  90. Begin
  91. if InOutRes<>0 then
  92. Exit;
  93. case TextRec(t).mode of
  94. fmInput,fmOutput,fmAppend:
  95. Begin
  96. { Write pending buffer }
  97. If Textrec(t).Mode=fmoutput then
  98. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  99. {$ifdef FPC_HAS_FEATURE_CONSOLEIO}
  100. { Only close functions not connected to stdout.}
  101. If ((TextRec(t).Handle<>StdInputHandle) and
  102. (TextRec(t).Handle<>StdOutputHandle) and
  103. (TextRec(t).Handle<>StdErrorHandle)) Then
  104. {$endif FPC_HAS_FEATURE_CONSOLEIO}
  105. FileFunc(TextRec(t).CloseFunc)(TextRec(t));
  106. TextRec(t).mode := fmClosed;
  107. { Reset buffer for safety }
  108. TextRec(t).BufPos:=0;
  109. TextRec(t).BufEnd:=0;
  110. End
  111. else inOutRes := 103;
  112. End;
  113. End;
  114. Procedure OpenText(var t : Text;mode,defHdl:Longint);
  115. Begin
  116. Case TextRec(t).mode Of {This gives the fastest code}
  117. fmInput,fmOutput,fmInOut : Close(t);
  118. fmClosed : ;
  119. else
  120. Begin
  121. InOutRes:=102;
  122. exit;
  123. End;
  124. End;
  125. TextRec(t).mode:=mode;
  126. TextRec(t).bufpos:=0;
  127. TextRec(t).bufend:=0;
  128. FileFunc(TextRec(t).OpenFunc)(TextRec(t));
  129. { reset the mode to closed when an error has occured }
  130. if InOutRes<>0 then
  131. TextRec(t).mode:=fmClosed;
  132. End;
  133. Procedure Rewrite(var t : Text);[IOCheck];
  134. Begin
  135. If InOutRes<>0 then
  136. exit;
  137. OpenText(t,fmOutput,1);
  138. End;
  139. Procedure Reset(var t : Text);[IOCheck];
  140. Begin
  141. If InOutRes<>0 then
  142. exit;
  143. OpenText(t,fmInput,0);
  144. End;
  145. Procedure Append(var t : Text);[IOCheck];
  146. Begin
  147. If InOutRes<>0 then
  148. exit;
  149. OpenText(t,fmAppend,1);
  150. End;
  151. Procedure Flush(var t : Text);[IOCheck];
  152. Begin
  153. If InOutRes<>0 then
  154. exit;
  155. if TextRec(t).mode<>fmOutput then
  156. begin
  157. if TextRec(t).mode=fmInput then
  158. InOutRes:=105
  159. else
  160. InOutRes:=103;
  161. exit;
  162. end;
  163. { Not the flushfunc but the inoutfunc should be used, because that
  164. writes the data, flushfunc doesn't need to be assigned }
  165. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  166. End;
  167. Procedure Erase(var t:Text);[IOCheck];
  168. Begin
  169. If InOutRes <> 0 then
  170. exit;
  171. If TextRec(t).mode=fmClosed Then
  172. Do_Erase(PChar(@TextRec(t).Name));
  173. End;
  174. Procedure Rename(var t : text;p:pchar);[IOCheck];
  175. Begin
  176. If InOutRes <> 0 then
  177. exit;
  178. If TextRec(t).mode=fmClosed Then
  179. Begin
  180. Do_Rename(PChar(@TextRec(t).Name),p);
  181. { check error code of do_rename }
  182. If InOutRes = 0 then
  183. Move(p^,TextRec(t).Name,StrLen(p)+1);
  184. End;
  185. End;
  186. Procedure Rename(var t : Text;const s : string);[IOCheck];
  187. var
  188. p : array[0..255] Of Char;
  189. Begin
  190. If InOutRes <> 0 then
  191. exit;
  192. Move(s[1],p,Length(s));
  193. p[Length(s)]:=#0;
  194. Rename(t,Pchar(@p));
  195. End;
  196. Procedure Rename(var t : Text;c : char);[IOCheck];
  197. var
  198. p : array[0..1] Of Char;
  199. Begin
  200. If InOutRes <> 0 then
  201. exit;
  202. p[0]:=c;
  203. p[1]:=#0;
  204. Rename(t,Pchar(@p));
  205. End;
  206. Function Eof(Var t: Text): Boolean;[IOCheck];
  207. Begin
  208. If (InOutRes<>0) then
  209. exit(true);
  210. if (TextRec(t).mode<>fmInput) Then
  211. begin
  212. if TextRec(t).mode=fmOutput then
  213. InOutRes:=104
  214. else
  215. InOutRes:=103;
  216. exit(true);
  217. end;
  218. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  219. begin
  220. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  221. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  222. exit(true);
  223. end;
  224. Eof:=CtrlZMarksEOF and (TextRec(t).Bufptr^[TextRec(t).BufPos]=#26);
  225. end;
  226. Function Eof:Boolean;
  227. Begin
  228. Eof:=Eof(Input);
  229. End;
  230. Function SeekEof (Var t : Text) : Boolean;
  231. var
  232. oldfilepos : Int64;
  233. oldbufpos, oldbufend : SizeInt;
  234. reads: longint;
  235. isdevice: boolean;
  236. Begin
  237. If (InOutRes<>0) then
  238. exit(true);
  239. if (TextRec(t).mode<>fmInput) Then
  240. begin
  241. if TextRec(t).mode=fmOutPut then
  242. InOutRes:=104
  243. else
  244. InOutRes:=103;
  245. exit(true);
  246. end;
  247. { try to save the current position in the file, seekeof() should not move }
  248. { the current file position (JM) }
  249. oldbufpos := TextRec(t).BufPos;
  250. oldbufend := TextRec(t).BufEnd;
  251. reads := 0;
  252. oldfilepos := -1;
  253. isdevice := Do_IsDevice(TextRec(t).handle);
  254. repeat
  255. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  256. begin
  257. { signal that the we will have to do a seek }
  258. inc(reads);
  259. if not isdevice and
  260. (reads = 1) then
  261. begin
  262. oldfilepos := Do_FilePos(TextRec(t).handle) - TextRec(t).BufEnd;
  263. InOutRes:=0;
  264. end;
  265. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  266. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  267. begin
  268. { if we only did a read in which we didn't read anything, the }
  269. { old buffer is still valid and we can simply restore the }
  270. { pointers (JM) }
  271. dec(reads);
  272. SeekEof := true;
  273. break;
  274. end;
  275. end;
  276. case TextRec(t).Bufptr^[TextRec(t).BufPos] of
  277. #26 :
  278. if CtrlZMarksEOF then
  279. begin
  280. SeekEof := true;
  281. break;
  282. end;
  283. #10,#13,#9,' ' :
  284. ;
  285. else
  286. begin
  287. SeekEof := false;
  288. break;
  289. end;
  290. end;
  291. inc(TextRec(t).BufPos);
  292. until false;
  293. { restore file position if not working with a device }
  294. if not isdevice then
  295. { if we didn't modify the buffer, simply restore the BufPos and BufEnd }
  296. { (the latter because it's now probably set to zero because nothing was }
  297. { was read anymore) }
  298. if (reads = 0) then
  299. begin
  300. TextRec(t).BufPos:=oldbufpos;
  301. TextRec(t).BufEnd:=oldbufend;
  302. end
  303. { otherwise return to the old filepos and reset the buffer }
  304. else
  305. begin
  306. do_seek(TextRec(t).handle,oldfilepos);
  307. InOutRes:=0;
  308. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  309. TextRec(t).BufPos:=oldbufpos;
  310. end;
  311. End;
  312. Function SeekEof : Boolean;
  313. Begin
  314. SeekEof:=SeekEof(Input);
  315. End;
  316. Function Eoln(var t:Text) : Boolean;
  317. Begin
  318. If (InOutRes<>0) then
  319. exit(true);
  320. if (TextRec(t).mode<>fmInput) Then
  321. begin
  322. if TextRec(t).mode=fmOutPut then
  323. InOutRes:=104
  324. else
  325. InOutRes:=103;
  326. exit(true);
  327. end;
  328. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  329. begin
  330. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  331. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  332. exit(true);
  333. end;
  334. if CtrlZMarksEOF and (TextRec (T).BufPtr^[TextRec (T).BufPos] = #26) then
  335. exit (true);
  336. Eoln:=(TextRec(t).Bufptr^[TextRec(t).BufPos] in [#10,#13]);
  337. End;
  338. Function Eoln : Boolean;
  339. Begin
  340. Eoln:=Eoln(Input);
  341. End;
  342. Function SeekEoln (Var t : Text) : Boolean;
  343. Begin
  344. If (InOutRes<>0) then
  345. exit(true);
  346. if (TextRec(t).mode<>fmInput) Then
  347. begin
  348. if TextRec(t).mode=fmOutput then
  349. InOutRes:=104
  350. else
  351. InOutRes:=103;
  352. exit(true);
  353. end;
  354. repeat
  355. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  356. begin
  357. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  358. If TextRec(t).BufPos>=TextRec(t).BufEnd Then
  359. exit(true);
  360. end;
  361. case TextRec(t).Bufptr^[TextRec(t).BufPos] of
  362. #26: if CtrlZMarksEOF then
  363. exit (true);
  364. #10,#13 : exit(true);
  365. #9,' ' : ;
  366. else
  367. exit(false);
  368. end;
  369. inc(TextRec(t).BufPos);
  370. until false;
  371. End;
  372. Function SeekEoln : Boolean;
  373. Begin
  374. SeekEoln:=SeekEoln(Input);
  375. End;
  376. Procedure SetTextBuf(Var F : Text; Var Buf; Size : SizeInt);
  377. Begin
  378. TextRec(f).BufPtr:=@Buf;
  379. TextRec(f).BufSize:=Size;
  380. TextRec(f).BufPos:=0;
  381. TextRec(f).BufEnd:=0;
  382. End;
  383. Procedure SetTextLineEnding(Var f:Text; Ending:string);
  384. Begin
  385. TextRec(F).LineEnd:=Ending;
  386. End;
  387. Function fpc_get_input:PText;compilerproc;
  388. begin
  389. fpc_get_input:=@Input;
  390. end;
  391. Function fpc_get_output:PText;compilerproc;
  392. begin
  393. fpc_get_output:=@Output;
  394. end;
  395. {*****************************************************************************
  396. Write(Ln)
  397. *****************************************************************************}
  398. Procedure fpc_WriteBuffer(var f:Text;const b;len:SizeInt);
  399. var
  400. p : pchar;
  401. left,
  402. idx : SizeInt;
  403. begin
  404. p:=pchar(@b);
  405. idx:=0;
  406. left:=TextRec(f).BufSize-TextRec(f).BufPos;
  407. while len>left do
  408. begin
  409. move(p[idx],TextRec(f).Bufptr^[TextRec(f).BufPos],left);
  410. dec(len,left);
  411. inc(idx,left);
  412. inc(TextRec(f).BufPos,left);
  413. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  414. left:=TextRec(f).BufSize-TextRec(f).BufPos;
  415. end;
  416. move(p[idx],TextRec(f).Bufptr^[TextRec(f).BufPos],len);
  417. inc(TextRec(f).BufPos,len);
  418. end;
  419. Procedure fpc_WriteBlanks(var f:Text;len:longint);
  420. var
  421. left : longint;
  422. begin
  423. left:=TextRec(f).BufSize-TextRec(f).BufPos;
  424. while len>left do
  425. begin
  426. FillChar(TextRec(f).Bufptr^[TextRec(f).BufPos],left,' ');
  427. dec(len,left);
  428. inc(TextRec(f).BufPos,left);
  429. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  430. left:=TextRec(f).BufSize-TextRec(f).BufPos;
  431. end;
  432. FillChar(TextRec(f).Bufptr^[TextRec(f).BufPos],len,' ');
  433. inc(TextRec(f).BufPos,len);
  434. end;
  435. Procedure fpc_Write_End(var f:Text); iocheck; compilerproc;
  436. begin
  437. if TextRec(f).FlushFunc<>nil then
  438. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  439. end;
  440. Procedure fpc_Writeln_End(var f:Text); iocheck; compilerproc;
  441. begin
  442. If InOutRes <> 0 then exit;
  443. case TextRec(f).mode of
  444. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  445. begin
  446. { Write EOL }
  447. fpc_WriteBuffer(f,TextRec(f).LineEnd[1],length(TextRec(f).LineEnd));
  448. { Flush }
  449. if TextRec(f).FlushFunc<>nil then
  450. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  451. end;
  452. fmInput: InOutRes:=105
  453. else InOutRes:=103;
  454. end;
  455. end;
  456. Procedure fpc_Write_Text_ShortStr(Len : Longint;var f : Text;const s : String); iocheck; [Public,Alias:'FPC_WRITE_TEXT_SHORTSTR']; compilerproc;
  457. Begin
  458. If (InOutRes<>0) then
  459. exit;
  460. case TextRec(f).mode of
  461. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  462. begin
  463. If Len>Length(s) Then
  464. fpc_WriteBlanks(f,Len-Length(s));
  465. fpc_WriteBuffer(f,s[1],Length(s));
  466. end;
  467. fmInput: InOutRes:=105
  468. else InOutRes:=103;
  469. end;
  470. End;
  471. Procedure fpc_Write_Text_ShortStr_Iso(Len : Longint;var f : Text;const s : String); iocheck; [Public,Alias:'FPC_WRITE_TEXT_SHORTSTR_ISO']; compilerproc;
  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. { default value? }
  479. If Len=-1 then
  480. Len:=length(s);
  481. If Len>Length(s) Then
  482. begin
  483. fpc_WriteBlanks(f,Len-Length(s));
  484. fpc_WriteBuffer(f,s[1],Length(s));
  485. end
  486. else
  487. fpc_WriteBuffer(f,s[1],Len);
  488. end;
  489. fmInput: InOutRes:=105
  490. else InOutRes:=103;
  491. end;
  492. End;
  493. { provide local access to write_str }
  494. procedure Write_Str(Len : Longint;var f : Text;const s : String); iocheck; [external name 'FPC_WRITE_TEXT_SHORTSTR'];
  495. { provide local access to write_str_iso }
  496. procedure Write_Str_Iso(Len : Longint;var f : Text;const s : String); iocheck; [external name 'FPC_WRITE_TEXT_SHORTSTR_ISO'];
  497. Procedure fpc_Write_Text_Pchar_as_Array(Len : Longint;var f : Text;const s : array of char; zerobased: boolean = true); iocheck; compilerproc;
  498. var
  499. ArrayLen : longint;
  500. p : pchar;
  501. Begin
  502. If (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. p:=pchar(@s);
  508. if zerobased then
  509. begin
  510. { can't use StrLen, since that one could try to read past the end }
  511. { of the heap (JM) }
  512. ArrayLen:=IndexByte(p^,high(s)+1,0);
  513. { IndexByte returns -1 if not found (JM) }
  514. if ArrayLen = -1 then
  515. ArrayLen := high(s)+1;
  516. end
  517. else
  518. ArrayLen := high(s)+1;
  519. If Len>ArrayLen Then
  520. fpc_WriteBlanks(f,Len-ArrayLen);
  521. fpc_WriteBuffer(f,p^,ArrayLen);
  522. end;
  523. fmInput: InOutRes:=105
  524. else InOutRes:=103;
  525. end;
  526. End;
  527. Procedure fpc_Write_Text_Pchar_as_Array_Iso(Len : Longint;var f : Text;const s : array of char; zerobased: boolean = true); iocheck; compilerproc;
  528. var
  529. ArrayLen : longint;
  530. p : pchar;
  531. Begin
  532. If (InOutRes<>0) then
  533. exit;
  534. case TextRec(f).mode of
  535. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  536. begin
  537. p:=pchar(@s);
  538. if zerobased then
  539. begin
  540. { can't use StrLen, since that one could try to read past the end }
  541. { of the heap (JM) }
  542. ArrayLen:=IndexByte(p^,high(s)+1,0);
  543. { IndexByte returns -1 if not found (JM) }
  544. if ArrayLen = -1 then
  545. ArrayLen := high(s)+1;
  546. end
  547. else
  548. ArrayLen := high(s)+1;
  549. { default value? }
  550. If Len=-1 then
  551. Len:=ArrayLen;
  552. If Len>ArrayLen Then
  553. begin
  554. fpc_WriteBlanks(f,Len-ArrayLen);
  555. fpc_WriteBuffer(f,p^,ArrayLen);
  556. end
  557. else
  558. fpc_WriteBuffer(f,p^,Len);
  559. end;
  560. fmInput: InOutRes:=105
  561. else InOutRes:=103;
  562. end;
  563. End;
  564. Procedure fpc_Write_Text_PChar_As_Pointer(Len : Longint;var f : Text;p : PChar); iocheck; compilerproc;
  565. var
  566. PCharLen : longint;
  567. Begin
  568. If (p=nil) or (InOutRes<>0) then
  569. exit;
  570. case TextRec(f).mode of
  571. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  572. begin
  573. PCharLen:=StrLen(p);
  574. If Len>PCharLen Then
  575. fpc_WriteBlanks(f,Len-PCharLen);
  576. fpc_WriteBuffer(f,p^,PCharLen);
  577. end;
  578. fmInput: InOutRes:=105
  579. else InOutRes:=103;
  580. end;
  581. End;
  582. Procedure fpc_Write_Text_AnsiStr (Len : Longint; Var f : Text; const S : AnsiString); iocheck; [Public,alias:'FPC_WRITE_TEXT_ANSISTR']; compilerproc;
  583. {
  584. Writes a AnsiString to the Text file T
  585. }
  586. var
  587. SLen : longint;
  588. begin
  589. If (InOutRes<>0) then
  590. exit;
  591. case TextRec(f).mode of
  592. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  593. begin
  594. SLen:=Length(s);
  595. If Len>SLen Then
  596. fpc_WriteBlanks(f,Len-SLen);
  597. if slen > 0 then
  598. fpc_WriteBuffer(f,PChar(S)^,SLen);
  599. end;
  600. fmInput: InOutRes:=105
  601. else InOutRes:=103;
  602. end;
  603. end;
  604. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  605. Procedure fpc_Write_Text_UnicodeStr (Len : Longint; Var f : Text; const S : UnicodeString); iocheck; compilerproc;
  606. {
  607. Writes a UnicodeString to the Text file T
  608. }
  609. var
  610. SLen : longint;
  611. a: ansistring;
  612. begin
  613. If (pointer(S)=nil) or (InOutRes<>0) then
  614. exit;
  615. case TextRec(f).mode of
  616. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  617. begin
  618. SLen:=Length(s);
  619. If Len>SLen Then
  620. fpc_WriteBlanks(f,Len-SLen);
  621. a:=s;
  622. { length(a) can be > slen, e.g. after utf-16 -> utf-8 }
  623. fpc_WriteBuffer(f,pchar(a)^,length(a));
  624. end;
  625. fmInput: InOutRes:=105
  626. else InOutRes:=103;
  627. end;
  628. end;
  629. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  630. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  631. Procedure fpc_Write_Text_WideStr (Len : Longint; Var f : Text; const S : WideString); iocheck; compilerproc;
  632. {
  633. Writes a WideString to the Text file T
  634. }
  635. var
  636. SLen : longint;
  637. a: ansistring;
  638. begin
  639. If (pointer(S)=nil) or (InOutRes<>0) then
  640. exit;
  641. case TextRec(f).mode of
  642. fmOutput { fmAppend gets changed to fmOutPut in do_open (JM) }:
  643. begin
  644. SLen:=Length(s);
  645. If Len>SLen Then
  646. fpc_WriteBlanks(f,Len-SLen);
  647. a:=s;
  648. { length(a) can be > slen, e.g. after utf-16 -> utf-8 }
  649. fpc_WriteBuffer(f,pchar(a)^,length(a));
  650. end;
  651. fmInput: InOutRes:=105
  652. else InOutRes:=103;
  653. end;
  654. end;
  655. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  656. Procedure fpc_Write_Text_SInt(Len : Longint;var t : Text;l : ValSInt); iocheck; compilerproc;
  657. var
  658. s : String;
  659. Begin
  660. If (InOutRes<>0) then
  661. exit;
  662. Str(l,s);
  663. Write_Str(Len,t,s);
  664. End;
  665. Procedure fpc_Write_Text_UInt(Len : Longint;var t : Text;l : ValUInt); iocheck; compilerproc;
  666. var
  667. s : String;
  668. Begin
  669. If (InOutRes<>0) then
  670. exit;
  671. Str(L,s);
  672. Write_Str(Len,t,s);
  673. End;
  674. Procedure fpc_Write_Text_SInt_Iso(Len : Longint;var t : Text;l : ValSInt); iocheck; compilerproc;
  675. var
  676. s : String;
  677. Begin
  678. If (InOutRes<>0) then
  679. exit;
  680. Str(l,s);
  681. { default value? }
  682. if len=-1 then
  683. len:=11
  684. else if len<length(s) then
  685. len:=length(s);
  686. Write_Str_Iso(Len,t,s);
  687. End;
  688. Procedure fpc_Write_Text_UInt_Iso(Len : Longint;var t : Text;l : ValUInt); iocheck; compilerproc;
  689. var
  690. s : String;
  691. Begin
  692. If (InOutRes<>0) then
  693. exit;
  694. Str(L,s);
  695. { default value? }
  696. if len=-1 then
  697. len:=11
  698. else if len<length(s) then
  699. len:=length(s);
  700. Write_Str_Iso(Len,t,s);
  701. End;
  702. {$ifndef CPU64}
  703. procedure fpc_write_text_qword(len : longint;var t : text;q : qword); iocheck; compilerproc;
  704. var
  705. s : string;
  706. begin
  707. if (InOutRes<>0) then
  708. exit;
  709. str(q,s);
  710. write_str(len,t,s);
  711. end;
  712. procedure fpc_write_text_int64(len : longint;var t : text;i : int64); iocheck; compilerproc;
  713. var
  714. s : string;
  715. begin
  716. if (InOutRes<>0) then
  717. exit;
  718. str(i,s);
  719. write_str(len,t,s);
  720. end;
  721. procedure fpc_write_text_qword_iso(len : longint;var t : text;q : qword); iocheck; compilerproc;
  722. var
  723. s : string;
  724. begin
  725. if (InOutRes<>0) then
  726. exit;
  727. str(q,s);
  728. { default value? }
  729. if len=-1 then
  730. len:=20
  731. else if len<length(s) then
  732. len:=length(s);
  733. write_str_iso(len,t,s);
  734. end;
  735. procedure fpc_write_text_int64_iso(len : longint;var t : text;i : int64); iocheck; compilerproc;
  736. var
  737. s : string;
  738. begin
  739. if (InOutRes<>0) then
  740. exit;
  741. str(i,s);
  742. { default value? }
  743. if len=-1 then
  744. len:=20
  745. else if len<length(s) then
  746. len:=length(s);
  747. write_str_iso(len,t,s);
  748. end;
  749. {$endif CPU64}
  750. {$ifndef FPUNONE}
  751. Procedure fpc_Write_Text_Float(rt,fixkomma,Len : Longint;var t : Text;r : ValReal); iocheck; compilerproc;
  752. var
  753. s : String;
  754. Begin
  755. If (InOutRes<>0) then
  756. exit;
  757. Str_real(Len,fixkomma,r,treal_type(rt),s);
  758. Write_Str(Len,t,s);
  759. End;
  760. Procedure fpc_Write_Text_Float_iso(rt,fixkomma,Len : Longint;var t : Text;r : ValReal); iocheck; compilerproc;
  761. var
  762. s : String;
  763. Begin
  764. If (InOutRes<>0) then
  765. exit;
  766. Str_real_iso(Len,fixkomma,r,treal_type(rt),s);
  767. Write_Str(Len,t,s);
  768. End;
  769. {$endif}
  770. procedure fpc_write_text_enum(typinfo,ord2strindex:pointer;len:sizeint;var t:text;ordinal:longint); iocheck; compilerproc;
  771. var
  772. s:string;
  773. begin
  774. if textrec(t).mode<>fmoutput then
  775. begin
  776. if textrec(t).mode=fminput then
  777. inoutres:=105
  778. else
  779. inoutres:=103;
  780. exit;
  781. end;
  782. inoutres := fpc_shortstr_enum_intern(ordinal, len, typinfo, ord2strindex, s);
  783. if (inoutres <> 0) then
  784. exit;
  785. fpc_writeBuffer(t,s[1],length(s));
  786. end;
  787. {$ifdef FPC_HAS_STR_CURRENCY}
  788. Procedure fpc_Write_Text_Currency(fixkomma,Len : Longint;var t : Text;c : Currency); iocheck; compilerproc;
  789. var
  790. s : String;
  791. Begin
  792. If (InOutRes<>0) then
  793. exit;
  794. str(c:Len:fixkomma,s);
  795. Write_Str(Len,t,s);
  796. End;
  797. {$endif FPC_HAS_STR_CURRENCY}
  798. Procedure fpc_Write_Text_Boolean(Len : Longint;var t : Text;b : Boolean); iocheck; compilerproc;
  799. Begin
  800. If (InOutRes<>0) then
  801. exit;
  802. { Can't use array[boolean] because b can be >0 ! }
  803. if b then
  804. Write_Str(Len,t,'TRUE')
  805. else
  806. Write_Str(Len,t,'FALSE');
  807. End;
  808. Procedure fpc_Write_Text_Boolean_Iso(Len : Longint;var t : Text;b : Boolean); iocheck; compilerproc;
  809. Begin
  810. If (InOutRes<>0) then
  811. exit;
  812. { Can't use array[boolean] because b can be >0 ! }
  813. { default value? }
  814. If Len=-1 then
  815. Len:=5;
  816. if b then
  817. Write_Str_Iso(Len,t,'true')
  818. else
  819. Write_Str_Iso(Len,t,'false');
  820. End;
  821. Procedure fpc_Write_Text_Char(Len : Longint;var t : Text;c : Char); iocheck; compilerproc;
  822. Begin
  823. If (InOutRes<>0) then
  824. exit;
  825. if (TextRec(t).mode<>fmOutput) Then
  826. begin
  827. if TextRec(t).mode=fmClosed then
  828. InOutRes:=103
  829. else
  830. InOutRes:=105;
  831. exit;
  832. end;
  833. If Len>1 Then
  834. fpc_WriteBlanks(t,Len-1);
  835. If TextRec(t).BufPos>=TextRec(t).BufSize Then
  836. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  837. TextRec(t).Bufptr^[TextRec(t).BufPos]:=c;
  838. Inc(TextRec(t).BufPos);
  839. End;
  840. Procedure fpc_Write_Text_Char_Iso(Len : Longint;var t : Text;c : Char); iocheck; compilerproc;
  841. Begin
  842. If (InOutRes<>0) then
  843. exit;
  844. if (TextRec(t).mode<>fmOutput) Then
  845. begin
  846. if TextRec(t).mode=fmClosed then
  847. InOutRes:=103
  848. else
  849. InOutRes:=105;
  850. exit;
  851. end;
  852. { default value? }
  853. If Len=-1 then
  854. Len:=1;
  855. If Len>1 Then
  856. fpc_WriteBlanks(t,Len-1)
  857. else If Len<1 Then
  858. exit;
  859. If TextRec(t).BufPos>=TextRec(t).BufSize Then
  860. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  861. TextRec(t).Bufptr^[TextRec(t).BufPos]:=c;
  862. Inc(TextRec(t).BufPos);
  863. End;
  864. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  865. Procedure fpc_Write_Text_WideChar(Len : Longint;var t : Text;c : WideChar); iocheck; compilerproc;
  866. var
  867. a : ansistring;
  868. Begin
  869. If (InOutRes<>0) then
  870. exit;
  871. if (TextRec(t).mode<>fmOutput) Then
  872. begin
  873. if TextRec(t).mode=fmClosed then
  874. InOutRes:=103
  875. else
  876. InOutRes:=105;
  877. exit;
  878. end;
  879. If Len>1 Then
  880. fpc_WriteBlanks(t,Len-1);
  881. If TextRec(t).BufPos>=TextRec(t).BufSize Then
  882. FileFunc(TextRec(t).InOutFunc)(TextRec(t));
  883. { a widechar can be translated into more than a single ansichar }
  884. a:=c;
  885. fpc_WriteBuffer(t,pchar(a)^,length(a));
  886. End;
  887. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  888. {*****************************************************************************
  889. Read(Ln)
  890. *****************************************************************************}
  891. Function NextChar(var f:Text;var s:string):Boolean;
  892. begin
  893. NextChar:=false;
  894. if (TextRec(f).BufPos<TextRec(f).BufEnd) then
  895. if not (CtrlZMarksEOF) or (TextRec(f).Bufptr^[TextRec(f).BufPos]<>#26) then
  896. begin
  897. if length(s)<high(s) then
  898. begin
  899. inc(s[0]);
  900. s[length(s)]:=TextRec(f).BufPtr^[TextRec(f).BufPos];
  901. end;
  902. Inc(TextRec(f).BufPos);
  903. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  904. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  905. NextChar:=true;
  906. end;
  907. end;
  908. Function IgnoreSpaces(var f:Text):Boolean;
  909. {
  910. Removes all leading spaces,tab,eols from the input buffer, returns true if
  911. the buffer is empty
  912. }
  913. var
  914. s : string;
  915. begin
  916. s:='';
  917. IgnoreSpaces:=false;
  918. { Return false when already at EOF }
  919. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  920. exit;
  921. (* Check performed separately to avoid accessing memory outside buffer *)
  922. if CtrlZMarksEOF and (TextRec(f).Bufptr^[TextRec(f).BufPos]=#26) then
  923. exit;
  924. while (TextRec(f).Bufptr^[TextRec(f).BufPos] <= ' ') do
  925. begin
  926. if not NextChar(f,s) then
  927. exit;
  928. { EOF? }
  929. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  930. break;
  931. if CtrlZMarksEOF and (TextRec(f).Bufptr^[TextRec(f).BufPos]=#26) then
  932. break;
  933. end;
  934. IgnoreSpaces:=true;
  935. end;
  936. procedure ReadNumeric(var f:Text;var s:string);
  937. {
  938. Read numeric input, if buffer is empty then return True
  939. }
  940. begin
  941. repeat
  942. if not NextChar(f,s) then
  943. exit;
  944. until (length(s)=high(s)) or (TextRec(f).BufPtr^[TextRec(f).BufPos] <= ' ');
  945. end;
  946. function CheckRead(var f:Text):Boolean;
  947. begin
  948. CheckRead:=False;
  949. { Check error and if file is open and load buf if empty }
  950. If (InOutRes<>0) then
  951. exit;
  952. if (TextRec(f).mode<>fmInput) Then
  953. begin
  954. case TextRec(f).mode of
  955. fmOutPut,fmAppend:
  956. InOutRes:=104;
  957. else
  958. InOutRes:=103;
  959. end;
  960. exit;
  961. end;
  962. if TextRec(f).BufPos>=TextRec(f).BufEnd Then
  963. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  964. CheckRead:=True;
  965. end;
  966. Procedure fpc_Read_End(var f:Text);[Public,Alias:'FPC_READ_END']; iocheck; compilerproc;
  967. begin
  968. if TextRec(f).FlushFunc<>nil then
  969. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  970. end;
  971. Procedure fpc_ReadLn_End(var f : Text);[Public,Alias:'FPC_READLN_END']; iocheck; compilerproc;
  972. var prev: char;
  973. Begin
  974. If not CheckRead(f) then
  975. exit;
  976. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  977. { Flush if set }
  978. begin
  979. if (TextRec(f).FlushFunc<>nil) then
  980. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  981. exit;
  982. end;
  983. if CtrlZMarksEOF and (TextRec (F).BufPtr^ [TextRec (F).BufPos] = #26) then
  984. Exit;
  985. repeat
  986. prev := TextRec(f).BufPtr^[TextRec(f).BufPos];
  987. inc(TextRec(f).BufPos);
  988. { no system uses #10#13 as line seperator (#10 = *nix, #13 = Mac, }
  989. { #13#10 = Dos), so if we've got #10, we can safely exit }
  990. if prev = #10 then
  991. exit;
  992. {$ifdef MACOS}
  993. if prev = #13 then
  994. {StdInput on macos never have dos line ending, so this is safe.}
  995. if TextRec(f).Handle = StdInputHandle then
  996. exit;
  997. {$endif MACOS}
  998. if TextRec(f).BufPos>=TextRec(f).BufEnd Then
  999. begin
  1000. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  1001. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1002. { Flush if set }
  1003. begin
  1004. if (TextRec(f).FlushFunc<>nil) then
  1005. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  1006. exit;
  1007. end;
  1008. end;
  1009. if CtrlZMarksEOF and (TextRec (F).BufPtr^ [TextRec (F).BufPos] = #26) then
  1010. Exit;
  1011. if (prev=#13) then
  1012. { is there also a #10 after it? }
  1013. begin
  1014. if (TextRec(f).BufPtr^[TextRec(f).BufPos]=#10) then
  1015. { yes, skip that one as well }
  1016. inc(TextRec(f).BufPos);
  1017. exit;
  1018. end;
  1019. until false;
  1020. End;
  1021. Procedure fpc_ReadLn_End_Iso(var f : Text);[Public,Alias:'FPC_READLN_END_ISO']; iocheck; compilerproc;
  1022. var prev: char;
  1023. Begin
  1024. If not CheckRead(f) then
  1025. exit;
  1026. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1027. { Flush if set }
  1028. begin
  1029. if (TextRec(f).FlushFunc<>nil) then
  1030. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  1031. exit;
  1032. end;
  1033. if TextRec (F).BufPtr^ [TextRec (F).BufPos] = #26 then
  1034. begin
  1035. inc(TextRec(f).BufPos);
  1036. Exit;
  1037. end;
  1038. repeat
  1039. prev := TextRec(f).BufPtr^[TextRec(f).BufPos];
  1040. inc(TextRec(f).BufPos);
  1041. { no system uses #10#13 as line seperator (#10 = *nix, #13 = Mac, }
  1042. { #13#10 = Dos), so if we've got #10, we can safely exit }
  1043. if prev = #10 then
  1044. exit;
  1045. {$ifdef MACOS}
  1046. if prev = #13 then
  1047. {StdInput on macos never have dos line ending, so this is safe.}
  1048. if TextRec(f).Handle = StdInputHandle then
  1049. exit;
  1050. {$endif MACOS}
  1051. if TextRec(f).BufPos>=TextRec(f).BufEnd Then
  1052. begin
  1053. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  1054. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1055. { Flush if set }
  1056. begin
  1057. if (TextRec(f).FlushFunc<>nil) then
  1058. FileFunc(TextRec(f).FlushFunc)(TextRec(f));
  1059. exit;
  1060. end;
  1061. end;
  1062. if TextRec (F).BufPtr^ [TextRec (F).BufPos] = #26 then
  1063. begin
  1064. inc(TextRec(f).BufPos);
  1065. Exit;
  1066. end;
  1067. if (prev=#13) then
  1068. { is there also a #10 after it? }
  1069. begin
  1070. if (TextRec(f).BufPtr^[TextRec(f).BufPos]=#10) then
  1071. { yes, skip that one as well }
  1072. inc(TextRec(f).BufPos);
  1073. exit;
  1074. end;
  1075. until false;
  1076. End;
  1077. Function ReadPCharLen(var f:Text;s:pchar;maxlen:longint):longint;
  1078. var
  1079. sPos,len : Longint;
  1080. p,startp,maxp : pchar;
  1081. end_of_string:boolean;
  1082. Begin
  1083. ReadPCharLen:=0;
  1084. If not CheckRead(f) then
  1085. exit;
  1086. { Read maximal until Maxlen is reached }
  1087. sPos:=0;
  1088. end_of_string:=false;
  1089. repeat
  1090. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  1091. begin
  1092. FileFunc(TextRec(f).InOutFunc)(TextRec(f));
  1093. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  1094. break;
  1095. end;
  1096. p:=@TextRec(f).Bufptr^[TextRec(f).BufPos];
  1097. if SPos+TextRec(f).BufEnd-TextRec(f).BufPos>MaxLen then
  1098. maxp:=@TextRec(f).BufPtr^[TextRec(f).BufPos+MaxLen-SPos]
  1099. else
  1100. maxp:=@TextRec(f).Bufptr^[TextRec(f).BufEnd];
  1101. startp:=p;
  1102. { find stop character }
  1103. while p<maxp do
  1104. begin
  1105. { Optimization: Do a quick check for a control character first }
  1106. if (p^<' ') then
  1107. begin
  1108. if (p^ in [#10,#13]) or
  1109. (ctrlZmarkseof and (p^=#26)) then
  1110. begin
  1111. end_of_string:=true;
  1112. break;
  1113. end;
  1114. end;
  1115. inc(p);
  1116. end;
  1117. { calculate read bytes }
  1118. len:=p-startp;
  1119. inc(TextRec(f).BufPos,Len);
  1120. Move(startp^,s[sPos],Len);
  1121. inc(sPos,Len);
  1122. until (spos=MaxLen) or end_of_string;
  1123. ReadPCharLen:=spos;
  1124. End;
  1125. Procedure fpc_Read_Text_ShortStr(var f : Text;out s : String); iocheck; compilerproc;
  1126. Begin
  1127. s[0]:=chr(ReadPCharLen(f,pchar(@s[1]),high(s)));
  1128. End;
  1129. Procedure fpc_Read_Text_PChar_As_Pointer(var f : Text; const s : PChar); iocheck; compilerproc;
  1130. Begin
  1131. pchar(s+ReadPCharLen(f,s,$7fffffff))^:=#0;
  1132. End;
  1133. Procedure fpc_Read_Text_PChar_As_Array(var f : Text;out s : array of char; zerobased: boolean = false); iocheck; compilerproc;
  1134. var
  1135. len: longint;
  1136. Begin
  1137. len := ReadPCharLen(f,pchar(@s),high(s)+1);
  1138. if zerobased and
  1139. (len > high(s)) then
  1140. len := high(s);
  1141. if (len <= high(s)) then
  1142. s[len] := #0;
  1143. End;
  1144. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  1145. Procedure fpc_Read_Text_AnsiStr(var f : Text;out s : AnsiString); [public, alias: 'FPC_READ_TEXT_ANSISTR']; iocheck; compilerproc;
  1146. var
  1147. slen,len : SizeInt;
  1148. Begin
  1149. slen:=0;
  1150. Repeat
  1151. // SetLength will reallocate the length.
  1152. SetLength(S,slen+255);
  1153. len:=ReadPCharLen(f,pchar(Pointer(S)+slen),255);
  1154. inc(slen,len);
  1155. Until len<255;
  1156. // Set actual length
  1157. SetLength(S,Slen);
  1158. End;
  1159. Procedure fpc_Read_Text_AnsiStr_Intern(var f : Text;out s : AnsiString); [external name 'FPC_READ_TEXT_ANSISTR'];
  1160. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  1161. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  1162. Procedure fpc_Read_Text_UnicodeStr(var f : Text;out us : UnicodeString); iocheck; compilerproc;
  1163. var
  1164. s: AnsiString;
  1165. Begin
  1166. // all standard input is assumed to be ansi-encoded
  1167. fpc_Read_Text_AnsiStr_Intern(f,s);
  1168. // Convert to unicodestring
  1169. us:=s;
  1170. End;
  1171. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  1172. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  1173. Procedure fpc_Read_Text_WideStr(var f : Text;out ws : WideString); iocheck; compilerproc;
  1174. var
  1175. s: AnsiString;
  1176. Begin
  1177. // all standard input is assumed to be ansi-encoded
  1178. fpc_Read_Text_AnsiStr_Intern(f,s);
  1179. // Convert to widestring
  1180. ws:=s;
  1181. End;
  1182. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  1183. procedure fpc_Read_Text_Char(var f : Text; out c: char); [public, alias: 'FPC_READ_TEXT_CHAR']; iocheck;compilerproc;
  1184. Begin
  1185. c:=#0;
  1186. If not CheckRead(f) then
  1187. exit;
  1188. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  1189. begin
  1190. c := #26;
  1191. exit;
  1192. end;
  1193. c:=TextRec(f).Bufptr^[TextRec(f).BufPos];
  1194. inc(TextRec(f).BufPos);
  1195. end;
  1196. procedure fpc_Read_Text_Char_intern(var f : Text; out c: char); iocheck; [external name 'FPC_READ_TEXT_CHAR'];
  1197. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  1198. procedure fpc_Read_Text_WideChar(var f : Text; out wc: widechar); iocheck;compilerproc;
  1199. var
  1200. ws: widestring;
  1201. i: longint;
  1202. { maximum code point length is 6 characters (with UTF-8) }
  1203. str: array[0..5] of char;
  1204. Begin
  1205. fillchar(str[0],sizeof(str),0);
  1206. for i:=low(str) to high(str) do
  1207. begin
  1208. fpc_Read_Text_Char_intern(f,str[i]);
  1209. case widestringmanager.CodePointLengthProc(@str[0],i+1) of
  1210. -1: { possibly incomplete code point, try with an extra character }
  1211. ;
  1212. 0: { null character }
  1213. begin
  1214. wc:=#0;
  1215. exit;
  1216. end;
  1217. else
  1218. begin
  1219. { valid code point -> convert to widestring}
  1220. widestringmanager.Ansi2WideMoveProc(@str[0],ws,i+1);
  1221. { has to be exactly one widechar }
  1222. if length(ws)=1 then
  1223. begin
  1224. wc:=ws[1];
  1225. exit
  1226. end
  1227. else
  1228. break;
  1229. end;
  1230. end;
  1231. end;
  1232. { invalid widechar input }
  1233. inoutres:=106;
  1234. end;
  1235. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  1236. procedure fpc_Read_Text_Char_Iso(var f : Text; out c: char); iocheck;compilerproc;
  1237. Begin
  1238. c:=' ';
  1239. If not CheckRead(f) then
  1240. exit;
  1241. If TextRec(f).BufPos>=TextRec(f).BufEnd Then
  1242. begin
  1243. c:=' ';
  1244. exit;
  1245. end;
  1246. c:=TextRec(f).Bufptr^[TextRec(f).BufPos];
  1247. inc(TextRec(f).BufPos);
  1248. if c=#13 then
  1249. begin
  1250. c:=' ';
  1251. If not CheckRead(f) or
  1252. (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1253. exit;
  1254. If TextRec(f).Bufptr^[TextRec(f).BufPos]=#10 then
  1255. inc(TextRec(f).BufPos);
  1256. { ignore #26 following a new line }
  1257. If not CheckRead(f) or
  1258. (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1259. exit;
  1260. If TextRec(f).Bufptr^[TextRec(f).BufPos]=#26 then
  1261. inc(TextRec(f).BufPos);
  1262. end
  1263. else if c=#10 then
  1264. begin
  1265. c:=' ';
  1266. { ignore #26 following a new line }
  1267. If not CheckRead(f) or
  1268. (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1269. exit;
  1270. If TextRec(f).Bufptr^[TextRec(f).BufPos]=#26 then
  1271. inc(TextRec(f).BufPos);
  1272. end
  1273. else if c=#26 then
  1274. c:=' ';
  1275. end;
  1276. Procedure fpc_Read_Text_SInt(var f : Text; out l : ValSInt); iocheck; compilerproc;
  1277. var
  1278. hs : String;
  1279. code : longint;
  1280. Begin
  1281. l:=0;
  1282. If not CheckRead(f) then
  1283. exit;
  1284. hs:='';
  1285. if IgnoreSpaces(f) then
  1286. begin
  1287. { When spaces were found and we are now at EOF,
  1288. then we return 0 }
  1289. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1290. exit;
  1291. if CtrlZMarksEOF and (TextRec(f).Bufptr^[TextRec(f).BufPos]=#26) then
  1292. exit;
  1293. ReadNumeric(f,hs);
  1294. end;
  1295. if (hs = '') then
  1296. L := 0
  1297. else
  1298. begin
  1299. Val(hs,l,code);
  1300. if Code <> 0 then
  1301. InOutRes:=106;
  1302. end;
  1303. End;
  1304. Procedure fpc_Read_Text_UInt(var f : Text; out u : ValUInt); iocheck; compilerproc;
  1305. var
  1306. hs : String;
  1307. code : longint;
  1308. Begin
  1309. u:=0;
  1310. If not CheckRead(f) then
  1311. exit;
  1312. hs:='';
  1313. if IgnoreSpaces(f) then
  1314. begin
  1315. { When spaces were found and we are now at EOF,
  1316. then we return 0 }
  1317. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1318. exit;
  1319. ReadNumeric(f,hs);
  1320. end;
  1321. if (hs = '') then
  1322. u := 0
  1323. else
  1324. begin
  1325. val(hs,u,code);
  1326. If code<>0 Then
  1327. InOutRes:=106;
  1328. end;
  1329. End;
  1330. {$ifndef FPUNONE}
  1331. procedure fpc_Read_Text_Float(var f : Text; out v : ValReal); iocheck; compilerproc;
  1332. var
  1333. hs : string;
  1334. code : Word;
  1335. begin
  1336. v:=0.0;
  1337. If not CheckRead(f) then
  1338. exit;
  1339. hs:='';
  1340. if IgnoreSpaces(f) then
  1341. begin
  1342. { When spaces were found and we are now at EOF,
  1343. then we return 0 }
  1344. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1345. exit;
  1346. ReadNumeric(f,hs);
  1347. end;
  1348. val(hs,v,code);
  1349. If code<>0 Then
  1350. InOutRes:=106;
  1351. end;
  1352. {$endif}
  1353. procedure fpc_read_text_enum(str2ordindex:pointer;var t:text;out ordinal:longint); iocheck;compilerproc;
  1354. var s:string;
  1355. code:valsint;
  1356. begin
  1357. if not checkread(t) then
  1358. exit;
  1359. s:='';
  1360. if ignorespaces(t) then
  1361. begin
  1362. { When spaces were found and we are now at EOF, then we return 0 }
  1363. if (TextRec(t).BufPos>=TextRec(t).BufEnd) then
  1364. exit;
  1365. ReadNumeric(t,s);
  1366. end;
  1367. ordinal:=fpc_val_enum_shortstr(str2ordindex,s,code);
  1368. if code<>0 then
  1369. InOutRes:=106;
  1370. end;
  1371. procedure fpc_Read_Text_Currency(var f : Text; out v : Currency); iocheck; compilerproc;
  1372. var
  1373. hs : string;
  1374. code : Word;
  1375. begin
  1376. {$ifdef FPUNONE}
  1377. v:=0;
  1378. {$else}
  1379. v:=0.0;
  1380. {$endif}
  1381. If not CheckRead(f) then
  1382. exit;
  1383. hs:='';
  1384. if IgnoreSpaces(f) then
  1385. begin
  1386. { When spaces were found and we are now at EOF,
  1387. then we return 0 }
  1388. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1389. exit;
  1390. ReadNumeric(f,hs);
  1391. end;
  1392. val(hs,v,code);
  1393. If code<>0 Then
  1394. InOutRes:=106;
  1395. end;
  1396. {$ifndef cpu64}
  1397. procedure fpc_Read_Text_QWord(var f : text; out q : qword); iocheck; compilerproc;
  1398. var
  1399. hs : String;
  1400. code : longint;
  1401. Begin
  1402. q:=0;
  1403. If not CheckRead(f) then
  1404. exit;
  1405. hs:='';
  1406. if IgnoreSpaces(f) then
  1407. begin
  1408. { When spaces were found and we are now at EOF,
  1409. then we return 0 }
  1410. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1411. exit;
  1412. ReadNumeric(f,hs);
  1413. end;
  1414. val(hs,q,code);
  1415. If code<>0 Then
  1416. InOutRes:=106;
  1417. End;
  1418. procedure fpc_Read_Text_Int64(var f : text; out i : int64); iocheck; compilerproc;
  1419. var
  1420. hs : String;
  1421. code : Longint;
  1422. Begin
  1423. i:=0;
  1424. If not CheckRead(f) then
  1425. exit;
  1426. hs:='';
  1427. if IgnoreSpaces(f) then
  1428. begin
  1429. { When spaces were found and we are now at EOF,
  1430. then we return 0 }
  1431. if (TextRec(f).BufPos>=TextRec(f).BufEnd) then
  1432. exit;
  1433. ReadNumeric(f,hs);
  1434. end;
  1435. Val(hs,i,code);
  1436. If code<>0 Then
  1437. InOutRes:=106;
  1438. End;
  1439. {$endif CPU64}
  1440. {*****************************************************************************
  1441. WriteStr/ReadStr
  1442. *****************************************************************************}
  1443. const
  1444. StrPtrIndex = 1;
  1445. { leave space for 128 bit string pointers :) (used for writestr) }
  1446. ShortStrLenIndex = 17;
  1447. { how many bytes of the string have been processed already (used for readstr) }
  1448. BytesReadIndex = 17;
  1449. threadvar
  1450. ReadWriteStrText: textrec;
  1451. procedure WriteStrShort(var t: textrec);
  1452. var
  1453. str: pshortstring;
  1454. newbytes,
  1455. oldlen: longint;
  1456. begin
  1457. if (t.bufpos=0) then
  1458. exit;
  1459. str:=pshortstring(ppointer(@t.userdata[StrPtrIndex])^);
  1460. newbytes:=t.BufPos;
  1461. oldlen:=length(str^);
  1462. if (oldlen+t.bufpos > t.userdata[ShortStrLenIndex]) then
  1463. begin
  1464. newbytes:=t.userdata[ShortStrLenIndex]-oldlen;
  1465. {$ifdef writestr_iolencheck}
  1466. // GPC only gives an io error if {$no-truncate-strings} is active
  1467. // FPC does not have this setting (it never gives errors when a
  1468. // a string expression is truncated)
  1469. { "disk full" }
  1470. inoutres:=101;
  1471. {$endif}
  1472. end;
  1473. setlength(str^,length(str^)+newbytes);
  1474. move(t.bufptr^,str^[oldlen+1],newbytes);
  1475. t.bufpos:=0;
  1476. end;
  1477. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  1478. procedure WriteStrAnsi(var t: textrec);
  1479. var
  1480. str: pansistring;
  1481. oldlen: longint;
  1482. begin
  1483. if (t.bufpos=0) then
  1484. exit;
  1485. str:=pansistring(ppointer(@t.userdata[StrPtrIndex])^);
  1486. oldlen:=length(str^);
  1487. setlength(str^,oldlen+t.bufpos);
  1488. move(t.bufptr^,str^[oldlen+1],t.bufpos);
  1489. t.bufpos:=0;
  1490. end;
  1491. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  1492. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  1493. procedure WriteStrUnicode(var t: textrec);
  1494. var
  1495. temp: ansistring;
  1496. str: punicodestring;
  1497. begin
  1498. if (t.bufpos=0) then
  1499. exit;
  1500. str:=punicodestring(ppointer(@t.userdata[StrPtrIndex])^);
  1501. setlength(temp,t.bufpos);
  1502. move(t.bufptr^,temp[1],t.bufpos);
  1503. str^:=str^+temp;
  1504. t.bufpos:=0;
  1505. end;
  1506. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  1507. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  1508. procedure WriteStrWide(var t: textrec);
  1509. var
  1510. temp: ansistring;
  1511. str: pwidestring;
  1512. begin
  1513. if (t.bufpos=0) then
  1514. exit;
  1515. str:=pwidestring(ppointer(@t.userdata[StrPtrIndex])^);
  1516. setlength(temp,t.bufpos);
  1517. move(t.bufptr^,temp[1],t.bufpos);
  1518. str^:=str^+temp;
  1519. t.bufpos:=0;
  1520. end;
  1521. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  1522. procedure SetupWriteStrCommon(out t: textrec);
  1523. begin
  1524. // initialise
  1525. Assign(text(t),'');
  1526. t.mode:=fmOutput;
  1527. t.OpenFunc:=nil;
  1528. t.CloseFunc:=nil;
  1529. end;
  1530. function fpc_SetupWriteStr_Shortstr(out s: shortstring): PText; compilerproc;
  1531. begin
  1532. setupwritestrcommon(ReadWriteStrText);
  1533. PPointer(@ReadWriteStrText.userdata[StrPtrIndex])^:=@s;
  1534. ReadWriteStrText.userdata[ShortStrLenIndex]:=high(s);
  1535. setlength(s,0);
  1536. ReadWriteStrText.InOutFunc:=@WriteStrShort;
  1537. ReadWriteStrText.FlushFunc:=@WriteStrShort;
  1538. result:=@ReadWriteStrText;
  1539. end;
  1540. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  1541. function fpc_SetupWriteStr_Ansistr(out s: ansistring): PText; compilerproc;
  1542. begin
  1543. setupwritestrcommon(ReadWriteStrText);
  1544. PPointer(@ReadWriteStrText.userdata[StrPtrIndex])^:=@s;
  1545. // automatically done by out-semantics
  1546. // setlength(s,0);
  1547. ReadWriteStrText.InOutFunc:=@WriteStrAnsi;
  1548. ReadWriteStrText.FlushFunc:=@WriteStrAnsi;
  1549. result:=@ReadWriteStrText;
  1550. end;
  1551. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  1552. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  1553. function fpc_SetupWriteStr_Unicodestr(out s: unicodestring): PText; compilerproc;
  1554. begin
  1555. setupwritestrcommon(ReadWriteStrText);
  1556. PPointer(@ReadWriteStrText.userdata[StrPtrIndex])^:=@s;
  1557. // automatically done by out-semantics
  1558. // setlength(s,0);
  1559. ReadWriteStrText.InOutFunc:=@WriteStrUnicode;
  1560. ReadWriteStrText.FlushFunc:=@WriteStrUnicode;
  1561. result:=@ReadWriteStrText;
  1562. end;
  1563. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  1564. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  1565. function fpc_SetupWriteStr_Widestr(out s: widestring): PText; compilerproc;
  1566. begin
  1567. setupwritestrcommon(ReadWriteStrText);
  1568. PPointer(@ReadWriteStrText.userdata[StrPtrIndex])^:=@s;
  1569. // automatically done by out-semantics
  1570. // setlength(s,0);
  1571. ReadWriteStrText.InOutFunc:=@WriteStrWide;
  1572. ReadWriteStrText.FlushFunc:=@WriteStrWide;
  1573. result:=@ReadWriteStrText;
  1574. end;
  1575. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  1576. procedure ReadAnsiStrFinal(var t: textrec);
  1577. begin
  1578. { finalise the temp ansistring }
  1579. PAnsiString(@t.userdata[StrPtrIndex])^ := '';
  1580. end;
  1581. procedure ReadStrCommon(var t: textrec; strdata: pchar; len: sizeint);
  1582. var
  1583. newbytes: sizeint;
  1584. begin
  1585. newbytes := len - PSizeInt(@t.userdata[BytesReadIndex])^;
  1586. if (t.BufSize <= newbytes) then
  1587. newbytes := t.BufSize;
  1588. if (newbytes > 0) then
  1589. begin
  1590. move(strdata[PSizeInt(@t.userdata[BytesReadIndex])^],t.BufPtr^,newbytes);
  1591. inc(PSizeInt(@t.userdata[BytesReadIndex])^,newbytes);
  1592. end;
  1593. t.BufEnd:=newbytes;
  1594. t.BufPos:=0;
  1595. end;
  1596. procedure ReadStrAnsi(var t: textrec);
  1597. var
  1598. str: pansistring;
  1599. begin
  1600. str:=pansistring(@t.userdata[StrPtrIndex]);
  1601. ReadStrCommon(t,@str^[1],length(str^));
  1602. end;
  1603. procedure SetupReadStrCommon(out t: textrec);
  1604. begin
  1605. // initialise
  1606. Assign(text(t),'');
  1607. t.mode:=fmInput;
  1608. t.OpenFunc:=nil;
  1609. t.CloseFunc:=nil;
  1610. PSizeInt(@t.userdata[BytesReadIndex])^:=0;
  1611. end;
  1612. function fpc_SetupReadStr_Ansistr(const s: ansistring): PText; [public, alias: 'FPC_SETUPREADSTR_ANSISTR']; compilerproc;
  1613. begin
  1614. setupreadstrcommon(ReadWriteStrText);
  1615. { we need a reference, because 's' may be a temporary expression }
  1616. PAnsiString(@ReadWriteStrText.userdata[StrPtrIndex])^:=s;
  1617. ReadWriteStrText.InOutFunc:=@ReadStrAnsi;
  1618. { this is called at the end, by fpc_read_end }
  1619. ReadWriteStrText.FlushFunc:=@ReadAnsiStrFinal;
  1620. result:=@ReadWriteStrText;
  1621. end;
  1622. function fpc_SetupReadStr_Ansistr_Intern(const s: ansistring): PText; [external name 'FPC_SETUPREADSTR_ANSISTR'];
  1623. function fpc_SetupReadStr_Shortstr(const s: shortstring): PText; compilerproc;
  1624. begin
  1625. { the reason we convert the short string to ansistring, is because the semantics of
  1626. readstr are defined as:
  1627. *********************
  1628. Apart from the restrictions imposed by requirements given in this clause,
  1629. the execution of readstr(e,v 1 ,...,v n ) where e denotes a
  1630. string-expression and v 1 ,...,v n denote variable-accesses possessing the
  1631. char-type (or a subrange of char-type), the integer-type (or a subrange of
  1632. integer-type), the real-type, a fixed-string-type, or a
  1633. variable-string-type, shall be equivalent to
  1634. begin
  1635. rewrite(f);
  1636. writeln(f, e);
  1637. reset(f);
  1638. read(f, v 1 ,...,v n )
  1639. end
  1640. *********************
  1641. This means that any side effects caused by the evaluation of v 1 .. v n
  1642. must not affect the value of e (= our argument s) -> we need a copy of it.
  1643. An ansistring is the easiest way to get a threadsafe copy, and allows us
  1644. to use the other ansistring readstr helpers too.
  1645. }
  1646. {$ifdef FPC_HAS_FEATURE_ANSISTRINGS}
  1647. result:=fpc_SetupReadStr_Ansistr_Intern(s);
  1648. {$else FPC_HAS_FEATURE_ANSISTRINGS}
  1649. runerror(217);
  1650. {$endif FPC_HAS_FEATURE_ANSISTRINGS}
  1651. end;
  1652. {$ifdef FPC_HAS_FEATURE_WIDESTRINGS}
  1653. function fpc_SetupReadStr_Unicodestr(const s: unicodestring): PText; compilerproc;
  1654. begin
  1655. { we use an ansistring to avoid code duplication, and let the }
  1656. { assignment convert the widestring to an equivalent ansistring }
  1657. result:=fpc_SetupReadStr_Ansistr_Intern(s);
  1658. end;
  1659. {$endif FPC_HAS_FEATURE_WIDESTRINGS}
  1660. {$ifndef FPC_WIDESTRING_EQUAL_UNICODESTRING}
  1661. function fpc_SetupReadStr_Widestr(const s: widestring): PText; compilerproc;
  1662. begin
  1663. { we use an ansistring to avoid code duplication, and let the }
  1664. { assignment convert the widestring to an equivalent ansistring }
  1665. result:=fpc_SetupReadStr_Ansistr_Intern(s);
  1666. end;
  1667. {$endif FPC_WIDESTRING_EQUAL_UNICODESTRING}
  1668. {*****************************************************************************
  1669. Initializing
  1670. *****************************************************************************}
  1671. procedure OpenStdIO(var f:text;mode:longint;hdl:thandle);
  1672. begin
  1673. Assign(f,'');
  1674. TextRec(f).Handle:=hdl;
  1675. TextRec(f).Mode:=mode;
  1676. TextRec(f).Closefunc:=@FileCloseFunc;
  1677. case mode of
  1678. fmInput :
  1679. TextRec(f).InOutFunc:=@FileReadFunc;
  1680. fmOutput :
  1681. begin
  1682. TextRec(f).InOutFunc:=@FileWriteFunc;
  1683. if Do_Isdevice(hdl) then
  1684. TextRec(f).FlushFunc:=@FileWriteFunc;
  1685. end;
  1686. else
  1687. HandleError(102);
  1688. end;
  1689. end;