sysutils.pp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Florian Klaempfl
  5. member of the Free Pascal development team
  6. Sysutils unit for Go32v2
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit sysutils;
  14. interface
  15. {$MODE objfpc}
  16. { force ansistrings }
  17. {$H+}
  18. uses
  19. go32,dos;
  20. { Include platform independent interface part }
  21. {$i sysutilh.inc}
  22. implementation
  23. { Include platform independent implementation part }
  24. {$i sysutils.inc}
  25. {****************************************************************************
  26. File Functions
  27. ****************************************************************************}
  28. { some internal constants }
  29. const
  30. ofRead = $0000; { Open for reading }
  31. ofWrite = $0001; { Open for writing }
  32. ofReadWrite = $0002; { Open for reading/writing }
  33. faFail = $0000; { Fail if file does not exist }
  34. faCreate = $0010; { Create if file does not exist }
  35. faOpen = $0001; { Open if file exists }
  36. faOpenReplace = $0002; { Clear if file exists }
  37. Type
  38. PSearchrec = ^Searchrec;
  39. { converts S to a pchar and copies it to the transfer-buffer. }
  40. procedure StringToTB(const S: string);
  41. var
  42. P: pchar;
  43. Len: integer;
  44. begin
  45. Len := Length(S) + 1;
  46. P := StrPCopy(StrAlloc(Len), S);
  47. SysCopyToDos(longint(P), Len);
  48. StrDispose(P);
  49. end ;
  50. { Native OpenFile function.
  51. if return value <> 0 call failed. }
  52. function OpenFile(const FileName: string; var Handle: longint; Mode, Action: word): longint;
  53. var
  54. Regs: registers;
  55. begin
  56. result := 0;
  57. Handle := 0;
  58. StringToTB(FileName);
  59. if LFNSupport then Regs.Eax:=$716c
  60. else Regs.Eax:=$6c00;
  61. Regs.Edx := Action; { Action if file exists/not exists }
  62. Regs.Ds := tb_segment;
  63. Regs.Esi := tb_offset;
  64. Regs.Ebx := $2000 + (Mode and $ff); { file open mode }
  65. Regs.Ecx := $20; { Attributes }
  66. RealIntr($21, Regs);
  67. if Regs.Flags and CarryFlag <> 0 then result := Regs.Ax
  68. else Handle := Regs.Ax;
  69. end ;
  70. Function FileOpen (Const FileName : string; Mode : Integer) : Longint;
  71. var
  72. e: integer;
  73. Begin
  74. e := OpenFile(FileName, result, Mode, faOpen);
  75. if e <> 0 then
  76. result := -1;
  77. end;
  78. Function FileCreate (Const FileName : String) : Longint;
  79. var
  80. e: integer;
  81. begin
  82. e := OpenFile(FileName, result, ofReadWrite, faCreate or faOpenReplace);
  83. if e <> 0 then
  84. result := -1;
  85. end;
  86. Function FileRead (Handle : Longint; Var Buffer; Count : longint) : Longint;
  87. var
  88. regs : registers;
  89. size,
  90. readsize : longint;
  91. begin
  92. readsize:=0;
  93. while Count > 0 do
  94. begin
  95. if Count>tb_size then
  96. size:=tb_size
  97. else
  98. size:=Count;
  99. regs.realecx:=size;
  100. regs.realedx:=tb_offset;
  101. regs.realds:=tb_segment;
  102. regs.realebx:=Handle;
  103. regs.realeax:=$3f00;
  104. RealIntr($21,regs);
  105. if (regs.realflags and carryflag) <> 0 then
  106. begin
  107. Result:=-1;
  108. exit;
  109. end;
  110. syscopyfromdos(Longint(@Buffer)+readsize,lo(regs.realeax));
  111. inc(readsize,lo(regs.realeax));
  112. dec(Count,lo(regs.realeax));
  113. { stop when not the specified size is read }
  114. if lo(regs.realeax)<size then
  115. break;
  116. end;
  117. Result:=readsize;
  118. end;
  119. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  120. var
  121. regs : registers;
  122. size,
  123. writesize : longint;
  124. begin
  125. writesize:=0;
  126. while Count > 0 do
  127. begin
  128. if Count>tb_size then
  129. size:=tb_size
  130. else
  131. size:=Count;
  132. syscopytodos(Longint(@Buffer)+writesize,size);
  133. regs.realecx:=size;
  134. regs.realedx:=tb_offset;
  135. regs.realds:=tb_segment;
  136. regs.realebx:=Handle;
  137. regs.realeax:=$4000;
  138. RealIntr($21,regs);
  139. if (regs.realflags and carryflag) <> 0 then
  140. begin
  141. Result:=-1;
  142. exit;
  143. end;
  144. inc(writesize,lo(regs.realeax));
  145. dec(Count,lo(regs.realeax));
  146. { stop when not the specified size is written }
  147. if lo(regs.realeax)<size then
  148. break;
  149. end;
  150. Result:=WriteSize;
  151. end;
  152. Function FileSeek (Handle, FOffset, Origin : Longint) : Longint;
  153. var
  154. Regs: registers;
  155. begin
  156. Regs.Eax := $4200;
  157. Regs.Al := Origin;
  158. Regs.Edx := Lo(FOffset);
  159. Regs.Ecx := Hi(FOffset);
  160. Regs.Ebx := Handle;
  161. RealIntr($21, Regs);
  162. if Regs.Flags and CarryFlag <> 0 then
  163. result := -1
  164. else begin
  165. LongRec(result).Lo := Regs.Ax;
  166. LongRec(result).Hi := Regs.Dx;
  167. end ;
  168. end;
  169. Function FileSeek (Handle : Longint; FOffset,Origin : Int64) : Int64;
  170. begin
  171. {$warning need to add 64bit call }
  172. FileSeek:=FileSeek(Handle,Longint(FOffset),Longint(Origin));
  173. end;
  174. Procedure FileClose (Handle : Longint);
  175. var
  176. Regs: registers;
  177. begin
  178. if Handle<=4 then
  179. exit;
  180. Regs.Eax := $3e00;
  181. Regs.Ebx := Handle;
  182. RealIntr($21, Regs);
  183. end;
  184. Function FileTruncate (Handle,Size: Longint) : boolean;
  185. var
  186. regs : trealregs;
  187. begin
  188. FileSeek(Handle,Size,0);
  189. Regs.realecx := 0;
  190. Regs.realedx := tb_offset;
  191. Regs.ds := tb_segment;
  192. Regs.ebx := Handle;
  193. Regs.eax:=$4000;
  194. RealIntr($21, Regs);
  195. FileTruncate:=(regs.realflags and carryflag)=0;
  196. end;
  197. Function FileAge (Const FileName : String): Longint;
  198. var Handle: longint;
  199. begin
  200. Handle := FileOpen(FileName, 0);
  201. if Handle <> -1 then
  202. begin
  203. result := FileGetDate(Handle);
  204. FileClose(Handle);
  205. end
  206. else
  207. result := -1;
  208. end;
  209. Function FileExists (Const FileName : String) : Boolean;
  210. var Handle: longint;
  211. begin
  212. //!! This can be done quicker, need to find out how
  213. Result := (OpenFile(FileName, Handle, ofRead, faOpen) = 0);
  214. if Handle <> 0 then
  215. FileClose(Handle);
  216. end;
  217. Function FindFirst (Const Path : String; Attr : Longint; Var Rslt : TSearchRec) : Longint;
  218. Var Sr : PSearchrec;
  219. begin
  220. //!! Sr := New(PSearchRec);
  221. getmem(sr,sizeof(searchrec));
  222. Rslt.FindHandle := longint(Sr);
  223. DOS.FindFirst(Path, Attr, Sr^);
  224. result := -DosError;
  225. if result = 0 then
  226. begin
  227. Rslt.Time := Sr^.Time;
  228. Rslt.Size := Sr^.Size;
  229. Rslt.Attr := Sr^.Attr;
  230. Rslt.ExcludeAttr := 0;
  231. Rslt.Name := Sr^.Name;
  232. end ;
  233. end;
  234. Function FindNext (Var Rslt : TSearchRec) : Longint;
  235. var
  236. Sr: PSearchRec;
  237. begin
  238. Sr := PSearchRec(Rslt.FindHandle);
  239. if Sr <> nil then
  240. begin
  241. DOS.FindNext(Sr^);
  242. result := -DosError;
  243. if result = 0 then
  244. begin
  245. Rslt.Time := Sr^.Time;
  246. Rslt.Size := Sr^.Size;
  247. Rslt.Attr := Sr^.Attr;
  248. Rslt.ExcludeAttr := 0;
  249. Rslt.Name := Sr^.Name;
  250. end;
  251. end;
  252. end;
  253. Procedure FindClose (Var F : TSearchrec);
  254. var
  255. Sr: PSearchRec;
  256. begin
  257. Sr := PSearchRec(F.FindHandle);
  258. if Sr <> nil then
  259. begin
  260. //!! Dispose(Sr);
  261. // This call is non dummy if LFNSupport is true PM
  262. DOS.FindClose(SR^);
  263. freemem(sr,sizeof(searchrec));
  264. end;
  265. F.FindHandle := 0;
  266. end;
  267. Function FileGetDate (Handle : Longint) : Longint;
  268. var
  269. Regs: registers;
  270. begin
  271. //!! for win95 an alternative function is available.
  272. Regs.Ebx := Handle;
  273. Regs.Eax := $5700;
  274. RealIntr($21, Regs);
  275. if Regs.Flags and CarryFlag <> 0 then
  276. result := -1
  277. else
  278. begin
  279. LongRec(result).Lo := Regs.cx;
  280. LongRec(result).Hi := Regs.dx;
  281. end ;
  282. end;
  283. Function FileSetDate (Handle, Age : Longint) : Longint;
  284. var
  285. Regs: registers;
  286. begin
  287. Regs.Ebx := Handle;
  288. Regs.Eax := $5701;
  289. Regs.Ecx := Lo(Age);
  290. Regs.Edx := Hi(Age);
  291. RealIntr($21, Regs);
  292. if Regs.Flags and CarryFlag <> 0 then
  293. result := -Regs.Ax
  294. else
  295. result := 0;
  296. end;
  297. Function FileGetAttr (Const FileName : String) : Longint;
  298. var
  299. Regs: registers;
  300. begin
  301. StringToTB(FileName);
  302. Regs.Edx := tb_offset;
  303. Regs.Ds := tb_segment;
  304. if LFNSupport then
  305. begin
  306. Regs.Ax := $7143;
  307. Regs.Bx := 0;
  308. end
  309. else
  310. Regs.Ax := $4300;
  311. RealIntr($21, Regs);
  312. if Regs.Flags and CarryFlag <> 0 then
  313. result := -1
  314. else
  315. result := Regs.Cx;
  316. end;
  317. Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
  318. var
  319. Regs: registers;
  320. begin
  321. StringToTB(FileName);
  322. Regs.Edx := tb_offset;
  323. Regs.Ds := tb_segment;
  324. if LFNSupport then
  325. begin
  326. Regs.Ax := $7143;
  327. Regs.Bx := 1;
  328. end
  329. else
  330. Regs.Ax := $4301;
  331. Regs.Cx := Attr;
  332. RealIntr($21, Regs);
  333. if Regs.Flags and CarryFlag <> 0 then
  334. result := -Regs.Ax
  335. else
  336. result := 0;
  337. end;
  338. Function DeleteFile (Const FileName : String) : Boolean;
  339. var
  340. Regs: registers;
  341. begin
  342. StringToTB(FileName);
  343. Regs.Edx := tb_offset;
  344. Regs.Ds := tb_segment;
  345. if LFNSupport then
  346. Regs.Eax := $7141
  347. else
  348. Regs.Eax := $4100;
  349. Regs.Esi := 0;
  350. Regs.Ecx := 0;
  351. RealIntr($21, Regs);
  352. result := (Regs.Flags and CarryFlag = 0);
  353. end;
  354. Function RenameFile (Const OldName, NewName : String) : Boolean;
  355. var
  356. Regs: registers;
  357. begin
  358. StringToTB(OldName + #0 + NewName);
  359. Regs.Edx := tb_offset;
  360. Regs.Ds := tb_segment;
  361. Regs.Edi := tb_offset + Length(OldName) + 1;
  362. Regs.Es := tb_segment;
  363. if LFNSupport then
  364. Regs.Eax := $7156
  365. else
  366. Regs.Eax := $5600;
  367. Regs.Ecx := $ff;
  368. RealIntr($21, Regs);
  369. result := (Regs.Flags and CarryFlag = 0);
  370. end;
  371. {****************************************************************************
  372. Disk Functions
  373. ****************************************************************************}
  374. TYPE ExtendedFat32FreeSpaceRec=packed Record
  375. RetSize : WORD; { (ret) size of returned structure}
  376. Strucversion : WORD; {(call) structure version (0000h)
  377. (ret) actual structure version (0000h)}
  378. SecPerClus, {number of sectors per cluster}
  379. BytePerSec, {number of bytes per sector}
  380. AvailClusters, {number of available clusters}
  381. TotalClusters, {total number of clusters on the drive}
  382. AvailPhysSect, {physical sectors available on the drive}
  383. TotalPhysSect, {total physical sectors on the drive}
  384. AvailAllocUnits, {Available allocation units}
  385. TotalAllocUnits : DWORD; {Total allocation units}
  386. Dummy,Dummy2 : DWORD; {8 bytes reserved}
  387. END;
  388. function do_diskdata(drive : byte; Free : BOOLEAN) : Int64;
  389. VAR S : String;
  390. Rec : ExtendedFat32FreeSpaceRec;
  391. regs : registers;
  392. BEGIN
  393. if (swap(dosversion)>=$070A) AND LFNSupport then
  394. begin
  395. DosError:=0;
  396. S:='C:\'#0;
  397. if Drive=0 then
  398. begin
  399. GetDir(Drive,S);
  400. Setlength(S,4);
  401. S[4]:=#0;
  402. end
  403. else
  404. S[1]:=chr(Drive+64);
  405. Rec.Strucversion:=0;
  406. dosmemput(tb_segment,tb_offset,Rec,SIZEOF(ExtendedFat32FreeSpaceRec));
  407. dosmemput(tb_segment,tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1,S[1],4);
  408. regs.dx:=tb_offset+Sizeof(ExtendedFat32FreeSpaceRec)+1;
  409. regs.ds:=tb_segment;
  410. regs.di:=tb_offset;
  411. regs.es:=tb_segment;
  412. regs.cx:=Sizeof(ExtendedFat32FreeSpaceRec);
  413. regs.ax:=$7303;
  414. msdos(regs);
  415. if regs.ax<>$ffff then
  416. begin
  417. copyfromdos(rec,Sizeof(ExtendedFat32FreeSpaceRec));
  418. if Free then
  419. Do_DiskData:=int64(rec.AvailAllocUnits)*rec.SecPerClus*rec.BytePerSec
  420. else
  421. Do_DiskData:=int64(rec.TotalAllocUnits)*rec.SecPerClus*rec.BytePerSec;
  422. end
  423. else
  424. Do_DiskData:=-1;
  425. end
  426. else
  427. begin
  428. DosError:=0;
  429. regs.dl:=drive;
  430. regs.ah:=$36;
  431. msdos(regs);
  432. if regs.ax<>$FFFF then
  433. begin
  434. if Free then
  435. Do_DiskData:=int64(regs.ax)*regs.bx*regs.cx
  436. else
  437. Do_DiskData:=int64(regs.ax)*regs.cx*regs.dx;
  438. end
  439. else
  440. do_diskdata:=-1;
  441. end;
  442. end;
  443. function diskfree(drive : byte) : int64;
  444. begin
  445. diskfree:=Do_DiskData(drive,TRUE);
  446. end;
  447. function disksize(drive : byte) : int64;
  448. begin
  449. disksize:=Do_DiskData(drive,false);
  450. end;
  451. Function GetCurrentDir : String;
  452. begin
  453. GetDir(0, result);
  454. end;
  455. Function SetCurrentDir (Const NewDir : String) : Boolean;
  456. begin
  457. {$I-}
  458. ChDir(NewDir);
  459. {$I+}
  460. result := (IOResult = 0);
  461. end;
  462. Function CreateDir (Const NewDir : String) : Boolean;
  463. begin
  464. {$I-}
  465. MkDir(NewDir);
  466. {$I+}
  467. result := (IOResult = 0);
  468. end;
  469. Function RemoveDir (Const Dir : String) : Boolean;
  470. begin
  471. {$I-}
  472. RmDir(Dir);
  473. {$I+}
  474. result := (IOResult = 0);
  475. end;
  476. {****************************************************************************
  477. Time Functions
  478. ****************************************************************************}
  479. Procedure GetLocalTime(var SystemTime: TSystemTime);
  480. var
  481. Regs: Registers;
  482. begin
  483. Regs.ah := $2C;
  484. RealIntr($21, Regs);
  485. SystemTime.Hour := Regs.Ch;
  486. SystemTime.Minute := Regs.Cl;
  487. SystemTime.Second := Regs.Dh;
  488. SystemTime.MilliSecond := Regs.Dl;
  489. Regs.ah := $2A;
  490. RealIntr($21, Regs);
  491. SystemTime.Year := Regs.Cx;
  492. SystemTime.Month := Regs.Dh;
  493. SystemTime.Day := Regs.Dl;
  494. end ;
  495. {****************************************************************************
  496. Misc Functions
  497. ****************************************************************************}
  498. procedure Beep;
  499. begin
  500. end;
  501. {****************************************************************************
  502. Locale Functions
  503. ****************************************************************************}
  504. { Codepage constants }
  505. const
  506. CP_US = 437;
  507. CP_MultiLingual = 850;
  508. CP_SlavicLatin2 = 852;
  509. CP_Turkish = 857;
  510. CP_Portugal = 860;
  511. CP_IceLand = 861;
  512. CP_Canada = 863;
  513. CP_NorwayDenmark = 865;
  514. { CountryInfo }
  515. type
  516. TCountryInfo = packed record
  517. InfoId: byte;
  518. case integer of
  519. 1: ( Size: word;
  520. CountryId: word;
  521. CodePage: word;
  522. CountryInfo: array[0..33] of byte );
  523. 2: ( UpperCaseTable: longint );
  524. 4: ( FilenameUpperCaseTable: longint );
  525. 5: ( FilecharacterTable: longint );
  526. 6: ( CollatingTable: longint );
  527. 7: ( DBCSLeadByteTable: longint );
  528. end ;
  529. procedure GetExtendedCountryInfo(InfoId: integer; CodePage, CountryId: word; var CountryInfo: TCountryInfo);
  530. Var Regs: Registers;
  531. begin
  532. Regs.AH := $65;
  533. Regs.AL := InfoId;
  534. Regs.BX := CodePage;
  535. Regs.DX := CountryId;
  536. Regs.ES := transfer_buffer div 16;
  537. Regs.DI := transfer_buffer and 15;
  538. Regs.CX := SizeOf(TCountryInfo);
  539. RealIntr($21, Regs);
  540. DosMemGet(transfer_buffer div 16,
  541. transfer_buffer and 15,
  542. CountryInfo, Regs.CX );
  543. end;
  544. procedure InitAnsi;
  545. var
  546. CountryInfo: TCountryInfo; i: integer;
  547. begin
  548. { Fill table entries 0 to 127 }
  549. for i := 0 to 96 do
  550. UpperCaseTable[i] := chr(i);
  551. for i := 97 to 122 do
  552. UpperCaseTable[i] := chr(i - 32);
  553. for i := 123 to 127 do
  554. UpperCaseTable[i] := chr(i);
  555. for i := 0 to 64 do
  556. LowerCaseTable[i] := chr(i);
  557. for i := 65 to 90 do
  558. LowerCaseTable[i] := chr(i + 32);
  559. for i := 91 to 255 do
  560. LowerCaseTable[i] := chr(i);
  561. { Get country and codepage info }
  562. GetExtendedCountryInfo(1, $FFFF, $FFFF, CountryInfo);
  563. if CountryInfo.CodePage = 850 then
  564. begin
  565. { Special, known case }
  566. Move(CP850UCT, UpperCaseTable[128], 128);
  567. Move(CP850LCT, LowerCaseTable[128], 128);
  568. end
  569. else
  570. begin
  571. { this needs to be checked !!
  572. this is correct only if UpperCaseTable is
  573. and Offset:Segment word record (PM) }
  574. { get the uppercase table from dosmemory }
  575. GetExtendedCountryInfo(2, $FFFF, $FFFF, CountryInfo);
  576. DosMemGet(CountryInfo.UpperCaseTable shr 16, 2 + CountryInfo.UpperCaseTable and 65535, UpperCaseTable[128], 128);
  577. for i := 128 to 255 do
  578. begin
  579. if UpperCaseTable[i] <> chr(i) then
  580. LowerCaseTable[ord(UpperCaseTable[i])] := chr(i);
  581. end;
  582. end;
  583. end;
  584. Procedure InitInternational;
  585. begin
  586. InitAnsi;
  587. end;
  588. function SysErrorMessage(ErrorCode: Integer): String;
  589. begin
  590. Result:=Format(SUnknownErrorCode,[ErrorCode]);
  591. end;
  592. {****************************************************************************
  593. Os utils
  594. ****************************************************************************}
  595. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  596. begin
  597. Result:=getenv(EnvVar);
  598. end;
  599. {****************************************************************************
  600. Initialization code
  601. ****************************************************************************}
  602. Initialization
  603. InitExceptions; { Initialize exceptions. OS independent }
  604. InitInternational; { Initialize internationalization settings }
  605. Finalization
  606. DoneExceptions;
  607. end.
  608. {
  609. $Log$
  610. Revision 1.8 2002-01-25 16:23:03 peter
  611. * merged filesearch() fix
  612. Revision 1.7 2002/01/19 11:57:55 peter
  613. * merged fixes
  614. Revision 1.6 2001/10/25 21:23:49 peter
  615. * added 64bit fileseek
  616. Revision 1.5 2001/06/03 15:18:01 peter
  617. * eoutofmemory and einvalidpointer fix
  618. Revision 1.4 2001/02/20 22:14:19 peter
  619. * merged getenvironmentvariable
  620. Revision 1.3 2000/08/30 06:29:19 michael
  621. + Merged syserrormsg fix
  622. Revision 1.2 2000/08/20 15:46:46 peter
  623. * sysutils.pp moved to target and merged with disk.inc, filutil.inc
  624. Revision 1.1.2.2 2000/08/22 19:21:48 michael
  625. + Implemented syserrormessage. Made dummies for go32v2 and OS/2
  626. * Changed linux/errors.pp so it uses pchars for storage.
  627. Revision 1.1.2.1 2000/08/20 15:08:32 peter
  628. * forgot the add command :(
  629. }