sysutils.pp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. member of the Free Pascal development team
  5. Sysutils unit for linux
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit sysutils;
  13. interface
  14. {$MODE objfpc}
  15. { force ansistrings }
  16. {$H+}
  17. {$if (defined(BSD) or defined(SUNOS)) and defined(FPC_USE_LIBC)}
  18. {$define USE_VFORK}
  19. {$endif}
  20. {$DEFINE OS_FILESETDATEBYNAME}
  21. {$DEFINE HAS_SLEEP}
  22. {$DEFINE HAS_OSERROR}
  23. {$DEFINE HAS_OSCONFIG}
  24. {$DEFINE HAS_TEMPDIR}
  25. {$DEFINE HASUNIX}
  26. {$DEFINE HASCREATEGUID}
  27. {$DEFINE HAS_OSUSERDIR}
  28. uses
  29. Unix,errors,sysconst,Unixtype;
  30. { Include platform independent interface part }
  31. {$i sysutilh.inc}
  32. Function AddDisk(const path:string) : Byte;
  33. { the following is Kylix compatibility stuff, it should be moved to a
  34. special compatibilty unit (FK) }
  35. const
  36. RTL_SIGINT = 0;
  37. RTL_SIGFPE = 1;
  38. RTL_SIGSEGV = 2;
  39. RTL_SIGILL = 3;
  40. RTL_SIGBUS = 4;
  41. RTL_SIGQUIT = 5;
  42. RTL_SIGLAST = RTL_SIGQUIT;
  43. RTL_SIGDEFAULT = -1;
  44. type
  45. TSignalState = (ssNotHooked, ssHooked, ssOverridden);
  46. function InquireSignal(RtlSigNum: Integer): TSignalState;
  47. procedure AbandonSignalHandler(RtlSigNum: Integer);
  48. procedure HookSignal(RtlSigNum: Integer);
  49. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  50. implementation
  51. Uses
  52. {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF}, Baseunix, unixutil;
  53. type
  54. tsiginfo = record
  55. oldsiginfo: sigactionrec;
  56. hooked: boolean;
  57. end;
  58. const
  59. rtlsig2ossig: array[RTL_SIGINT..RTL_SIGLAST] of byte =
  60. (SIGINT,SIGFPE,SIGSEGV,SIGILL,SIGBUS,SIGQUIT);
  61. { to avoid linking in all this stuff in every program,
  62. as it's unlikely to be used by anything but libraries
  63. }
  64. signalinfoinited: boolean = false;
  65. var
  66. siginfo: array[RTL_SIGINT..RTL_SIGLAST] of tsiginfo;
  67. oldsigfpe: SigActionRec; external name '_FPC_OLDSIGFPE';
  68. oldsigsegv: SigActionRec; external name '_FPC_OLDSIGSEGV';
  69. oldsigbus: SigActionRec; external name '_FPC_OLDSIGBUS';
  70. oldsigill: SigActionRec; external name '_FPC_OLDSIGILL';
  71. procedure defaultsighandler; external name '_FPC_DEFAULTSIGHANDLER';
  72. procedure installdefaultsignalhandler(signum: Integer; out oldact: SigActionRec); external name '_FPC_INSTALLDEFAULTSIGHANDLER';
  73. function InternalInquireSignal(RtlSigNum: Integer; out act: SigActionRec; frominit: boolean): TSignalState;
  74. begin
  75. result:=ssNotHooked;
  76. if (RtlSigNum<>RTL_SIGDEFAULT) and
  77. (RtlSigNum<RTL_SIGLAST) then
  78. begin
  79. if (frominit or
  80. siginfo[RtlSigNum].hooked) and
  81. (fpsigaction(rtlsig2ossig[RtlSigNum],nil,@act)=0) then
  82. begin
  83. if not frominit then
  84. begin
  85. { check whether the installed signal handler is still ours }
  86. if (pointer(act.sa_handler)=pointer(@defaultsighandler)) then
  87. result:=ssHooked
  88. else
  89. result:=ssOverridden;
  90. end
  91. else if IsLibrary then
  92. begin
  93. { library -> signals have not been hooked by system init code }
  94. exit
  95. end
  96. else
  97. begin
  98. { program -> signals have been hooked by system init code }
  99. if (byte(RtlSigNum) in [RTL_SIGFPE,RTL_SIGSEGV,RTL_SIGILL,RTL_SIGBUS]) then
  100. begin
  101. if (pointer(act.sa_handler)=pointer(@defaultsighandler)) then
  102. result:=ssHooked
  103. else
  104. result:=ssOverridden;
  105. { return the original handlers as saved by the system unit
  106. (the current call to sigaction simply returned our
  107. system unit's installed handlers)
  108. }
  109. case RtlSigNum of
  110. RTL_SIGFPE:
  111. act:=oldsigfpe;
  112. RTL_SIGSEGV:
  113. act:=oldsigsegv;
  114. RTL_SIGILL:
  115. act:=oldsigill;
  116. RTL_SIGBUS:
  117. act:=oldsigbus;
  118. end;
  119. end
  120. else
  121. begin
  122. { these are not hooked in the startup code }
  123. result:=ssNotHooked;
  124. end
  125. end
  126. end
  127. end;
  128. end;
  129. procedure initsignalinfo;
  130. var
  131. i: Integer;
  132. begin
  133. for i:=RTL_SIGINT to RTL_SIGLAST do
  134. siginfo[i].hooked:=(InternalInquireSignal(i,siginfo[i].oldsiginfo,true)=ssHooked);
  135. signalinfoinited:=true;
  136. end;
  137. function InquireSignal(RtlSigNum: Integer): TSignalState;
  138. var
  139. act: SigActionRec;
  140. begin
  141. if not signalinfoinited then
  142. initsignalinfo;
  143. result:=InternalInquireSignal(RtlSigNum,act,false);
  144. end;
  145. procedure AbandonSignalHandler(RtlSigNum: Integer);
  146. begin
  147. if not signalinfoinited then
  148. initsignalinfo;
  149. if (RtlSigNum<>RTL_SIGDEFAULT) and
  150. (RtlSigNum<RTL_SIGLAST) then
  151. siginfo[RtlSigNum].hooked:=false;
  152. end;
  153. procedure HookSignal(RtlSigNum: Integer);
  154. var
  155. lowsig, highsig, i: Integer;
  156. begin
  157. if not signalinfoinited then
  158. initsignalinfo;
  159. if (RtlSigNum<>RTL_SIGDEFAULT) then
  160. begin
  161. lowsig:=RtlSigNum;
  162. highsig:=RtlSigNum;
  163. end
  164. else
  165. begin
  166. { we don't hook SIGINT and SIGQUIT by default }
  167. lowsig:=RTL_SIGFPE;
  168. highsig:=RTL_SIGBUS;
  169. end;
  170. { install the default rtl signal handler for the selected signal(s) }
  171. for i:=lowsig to highsig do
  172. begin
  173. installdefaultsignalhandler(rtlsig2ossig[i],siginfo[i].oldsiginfo);
  174. siginfo[i].hooked:=true;
  175. end;
  176. end;
  177. procedure UnhookSignal(RtlSigNum: Integer; OnlyIfHooked: Boolean = True);
  178. var
  179. act: SigActionRec;
  180. lowsig, highsig, i: Integer;
  181. state: TSignalState;
  182. begin
  183. if not signalinfoinited then
  184. initsignalinfo;
  185. if (RtlSigNum<>RTL_SIGDEFAULT) then
  186. begin
  187. lowsig:=RtlSigNum;
  188. highsig:=RtlSigNum;
  189. end
  190. else
  191. begin
  192. { we don't hook SIGINT and SIGQUIT by default }
  193. lowsig:=RTL_SIGFPE;
  194. highsig:=RTL_SIGBUS;
  195. end;
  196. for i:=lowsig to highsig do
  197. begin
  198. if not OnlyIfHooked or
  199. (InquireSignal(i)=ssHooked) then
  200. begin
  201. { restore the handler that was present when we hooked the signal,
  202. if we hooked it at one time or another. If the user doesn't
  203. want this, they have to call AbandonSignalHandler() first
  204. }
  205. if siginfo[i].hooked then
  206. act:=siginfo[i].oldsiginfo
  207. else
  208. begin
  209. fillchar(act,sizeof(act),0);
  210. pointer(act.sa_handler):=pointer(SIG_DFL);
  211. end;
  212. if (fpsigaction(rtlsig2ossig[RtlSigNum],@act,nil)=0) then
  213. siginfo[i].hooked:=false;
  214. end;
  215. end;
  216. end;
  217. {$Define OS_FILEISREADONLY} // Specific implementation for Unix.
  218. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  219. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
  220. { Include platform independent implementation part }
  221. {$i sysutils.inc}
  222. { Include SysCreateGUID function }
  223. {$i suuid.inc}
  224. Const
  225. {Date Translation}
  226. C1970=2440588;
  227. D0 = 1461;
  228. D1 = 146097;
  229. D2 =1721119;
  230. Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
  231. Var
  232. YYear,XYear,Temp,TempMonth : LongInt;
  233. Begin
  234. Temp:=((JulianDN-D2) shl 2)-1;
  235. JulianDN:=Temp Div D1;
  236. XYear:=(Temp Mod D1) or 3;
  237. YYear:=(XYear Div D0);
  238. Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
  239. Day:=((Temp Mod 153)+5) Div 5;
  240. TempMonth:=Temp Div 153;
  241. If TempMonth>=10 Then
  242. Begin
  243. inc(YYear);
  244. dec(TempMonth,12);
  245. End;
  246. inc(TempMonth,3);
  247. Month := TempMonth;
  248. Year:=YYear+(JulianDN*100);
  249. end;
  250. Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
  251. {
  252. Transforms Epoch time into local time (hour, minute,seconds)
  253. }
  254. Var
  255. DateNum: LongInt;
  256. Begin
  257. inc(Epoch,TZSeconds);
  258. Datenum:=(Epoch Div 86400) + c1970;
  259. JulianToGregorian(DateNum,Year,Month,day);
  260. Epoch:=Abs(Epoch Mod 86400);
  261. Hour:=Epoch Div 3600;
  262. Epoch:=Epoch Mod 3600;
  263. Minute:=Epoch Div 60;
  264. Second:=Epoch Mod 60;
  265. End;
  266. {****************************************************************************
  267. File Functions
  268. ****************************************************************************}
  269. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  270. Var
  271. DotPos,SlashPos,i : longint;
  272. Begin
  273. SlashPos:=0;
  274. DotPos:=256;
  275. i:=Length(Path);
  276. While (i>0) and (SlashPos=0) Do
  277. Begin
  278. If (DotPos=256) and (Path[i]='.') Then
  279. begin
  280. DotPos:=i;
  281. end;
  282. If (Path[i]='/') Then
  283. SlashPos:=i;
  284. Dec(i);
  285. End;
  286. Ext:=Copy(Path,DotPos,255);
  287. Dir:=Copy(Path,1,SlashPos);
  288. Name:=Copy(Path,SlashPos + 1,DotPos - SlashPos - 1);
  289. End;
  290. Function DoFileLocking(Handle: Longint; Mode: Integer) : Longint;
  291. var
  292. lockop: cint;
  293. lockres: cint;
  294. closeres: cint;
  295. lockerr: cint;
  296. begin
  297. DoFileLocking:=Handle;
  298. {$ifdef beos}
  299. {$else}
  300. if (Handle>=0) then
  301. begin
  302. {$ifdef solaris}
  303. { Solaris' flock is based on top of fcntl, which does not allow
  304. exclusive locks for files only opened for reading nor shared
  305. locks for files opened only for writing.
  306. If no locking is specified, we normally need an exclusive lock.
  307. So create an exclusive lock for fmOpenWrite and fmOpenReadWrite,
  308. but only a shared lock for fmOpenRead (since an exclusive lock
  309. is not possible in that case)
  310. }
  311. if ((mode and (fmShareCompat or fmShareExclusive or fmShareDenyWrite or fmShareDenyRead or fmShareDenyNone)) = 0) then
  312. begin
  313. if ((mode and (fmOpenRead or fmOpenWrite or fmOpenReadWrite)) = fmOpenRead) then
  314. mode := mode or fmShareDenyWrite
  315. else
  316. mode := mode or fmShareExclusive;
  317. end;
  318. {$endif solaris}
  319. case (mode and (fmShareCompat or fmShareExclusive or fmShareDenyWrite or fmShareDenyRead or fmShareDenyNone)) of
  320. fmShareCompat,
  321. fmShareExclusive:
  322. lockop:=LOCK_EX or LOCK_NB;
  323. fmShareDenyWrite:
  324. lockop:=LOCK_SH or LOCK_NB;
  325. fmShareDenyNone:
  326. exit;
  327. else
  328. begin
  329. { fmShareDenyRead does not exit under *nix, only shared access
  330. (similar to fmShareDenyWrite) and exclusive access (same as
  331. fmShareExclusive)
  332. }
  333. repeat
  334. closeres:=FpClose(Handle);
  335. until (closeres<>-1) or (fpgeterrno<>ESysEINTR);
  336. DoFileLocking:=-1;
  337. exit;
  338. end;
  339. end;
  340. repeat
  341. lockres:=fpflock(Handle,lockop);
  342. until (lockres=0) or
  343. (fpgeterrno<>ESysEIntr);
  344. lockerr:=fpgeterrno;
  345. { Only return an error if locks are working and the file was already
  346. locked. Not if locks are simply unsupported (e.g., on Angstrom Linux
  347. you always get ESysNOLCK in the default configuration) }
  348. if (lockres<>0) and
  349. ((lockerr=ESysEAGAIN) or
  350. (lockerr=EsysEDEADLK)) then
  351. begin
  352. repeat
  353. closeres:=FpClose(Handle);
  354. until (closeres<>-1) or (fpgeterrno<>ESysEINTR);
  355. DoFileLocking:=-1;
  356. exit;
  357. end;
  358. end;
  359. {$endif not beos}
  360. end;
  361. Function FileOpen (Const FileName : string; Mode : Integer) : Longint;
  362. Var
  363. LinuxFlags : longint;
  364. begin
  365. LinuxFlags:=0;
  366. case (Mode and (fmOpenRead or fmOpenWrite or fmOpenReadWrite)) of
  367. fmOpenRead : LinuxFlags:=LinuxFlags or O_RdOnly;
  368. fmOpenWrite : LinuxFlags:=LinuxFlags or O_WrOnly;
  369. fmOpenReadWrite : LinuxFlags:=LinuxFlags or O_RdWr;
  370. end;
  371. repeat
  372. FileOpen:=fpOpen (pointer(FileName),LinuxFlags);
  373. until (FileOpen<>-1) or (fpgeterrno<>ESysEINTR);
  374. FileOpen:=DoFileLocking(FileOpen, Mode);
  375. end;
  376. Function FileCreate (Const FileName : String) : Longint;
  377. begin
  378. repeat
  379. FileCreate:=fpOpen(pointer(FileName),O_RdWr or O_Creat or O_Trunc);
  380. until (FileCreate<>-1) or (fpgeterrno<>ESysEINTR);
  381. end;
  382. Function FileCreate (Const FileName : String;Mode : Longint) : Longint;
  383. begin
  384. repeat
  385. FileCreate:=fpOpen(pointer(FileName),O_RdWr or O_Creat or O_Trunc,Mode);
  386. until (FileCreate<>-1) or (fpgeterrno<>ESysEINTR);
  387. end;
  388. Function FileRead (Handle : Longint; Var Buffer; Count : longint) : Longint;
  389. begin
  390. repeat
  391. FileRead:=fpRead (Handle,Buffer,Count);
  392. until (FileRead<>-1) or (fpgeterrno<>ESysEINTR);
  393. end;
  394. Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
  395. begin
  396. repeat
  397. FileWrite:=fpWrite (Handle,Buffer,Count);
  398. until (FileWrite<>-1) or (fpgeterrno<>ESysEINTR);
  399. end;
  400. Function FileSeek (Handle,FOffset,Origin : Longint) : Longint;
  401. begin
  402. result:=longint(FileSeek(Handle,int64(FOffset),Origin));
  403. end;
  404. Function FileSeek (Handle : Longint; FOffset : Int64; Origin : Longint) : Int64;
  405. begin
  406. FileSeek:=fplSeek (Handle,FOffset,Origin);
  407. end;
  408. Procedure FileClose (Handle : Longint);
  409. var
  410. res: cint;
  411. begin
  412. repeat
  413. res:=fpclose(Handle);
  414. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  415. end;
  416. Function FileTruncate (Handle: THandle; Size: Int64) : boolean;
  417. var
  418. res: cint;
  419. begin
  420. if (SizeOf (TOff) < 8) (* fpFTruncate only supporting signed 32-bit size *)
  421. and (Size > high (longint)) then
  422. FileTruncate := false
  423. else
  424. begin
  425. repeat
  426. res:=fpftruncate(Handle,Size);
  427. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  428. FileTruncate:=res>=0;
  429. end;
  430. end;
  431. {$ifndef FPUNONE}
  432. Function UnixToWinAge(UnixAge : time_t): Longint;
  433. Var
  434. Y,M,D,hh,mm,ss : word;
  435. begin
  436. EpochToLocal(UnixAge,y,m,d,hh,mm,ss);
  437. Result:=DateTimeToFileDate(EncodeDate(y,m,d)+EncodeTime(hh,mm,ss,0));
  438. end;
  439. Function FileAge (Const FileName : String): Longint;
  440. Var Info : Stat;
  441. begin
  442. If fpstat (pointer(FileName),Info)<0 then
  443. exit(-1)
  444. else
  445. Result:=UnixToWinAge(info.st_mtime);
  446. end;
  447. {$endif}
  448. Function FileExists (Const FileName : String) : Boolean;
  449. begin
  450. // Don't use stat. It fails on files >2 GB.
  451. // Access obeys the same access rules, so the result should be the same.
  452. FileExists:=fpAccess(pointer(filename),F_OK)=0;
  453. end;
  454. Function DirectoryExists (Const Directory : String) : Boolean;
  455. Var Info : Stat;
  456. begin
  457. DirectoryExists:=(fpstat(pointer(Directory),Info)>=0) and fpS_ISDIR(Info.st_mode);
  458. end;
  459. Function LinuxToWinAttr (const FN : Ansistring; Const Info : Stat) : Longint;
  460. Var
  461. LinkInfo : Stat;
  462. begin
  463. Result:=faArchive;
  464. If fpS_ISDIR(Info.st_mode) then
  465. Result:=Result or faDirectory;
  466. If (Length(FN)>=2) and
  467. (FN[1]='.') and
  468. (FN[2]<>'.') then
  469. Result:=Result or faHidden;
  470. If (Info.st_Mode and S_IWUSR)=0 Then
  471. Result:=Result or faReadOnly;
  472. If fpS_ISSOCK(Info.st_mode) or fpS_ISBLK(Info.st_mode) or fpS_ISCHR(Info.st_mode) or fpS_ISFIFO(Info.st_mode) Then
  473. Result:=Result or faSysFile;
  474. If fpS_ISLNK(Info.st_mode) Then
  475. begin
  476. Result:=Result or faSymLink;
  477. // Windows reports if the link points to a directory.
  478. if (fpstat(FN,LinkInfo)>=0) and fpS_ISDIR(LinkInfo.st_mode) then
  479. Result := Result or faDirectory;
  480. end;
  481. end;
  482. Function FNMatch(const Pattern,Name:string):Boolean;
  483. Var
  484. LenPat,LenName : longint;
  485. Function DoFNMatch(i,j:longint):Boolean;
  486. Var
  487. Found : boolean;
  488. Begin
  489. Found:=true;
  490. While Found and (i<=LenPat) Do
  491. Begin
  492. Case Pattern[i] of
  493. '?' : Found:=(j<=LenName);
  494. '*' : Begin
  495. {find the next character in pattern, different of ? and *}
  496. while Found do
  497. begin
  498. inc(i);
  499. if i>LenPat then Break;
  500. case Pattern[i] of
  501. '*' : ;
  502. '?' : begin
  503. if j>LenName then begin DoFNMatch:=false; Exit; end;
  504. inc(j);
  505. end;
  506. else
  507. Found:=false;
  508. end;
  509. end;
  510. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  511. {Now, find in name the character which i points to, if the * or ?
  512. wasn't the last character in the pattern, else, use up all the
  513. chars in name}
  514. Found:=false;
  515. if (i<=LenPat) then
  516. begin
  517. repeat
  518. {find a letter (not only first !) which maches pattern[i]}
  519. while (j<=LenName) and (name[j]<>pattern[i]) do
  520. inc (j);
  521. if (j<LenName) then
  522. begin
  523. if DoFnMatch(i+1,j+1) then
  524. begin
  525. i:=LenPat;
  526. j:=LenName;{we can stop}
  527. Found:=true;
  528. Break;
  529. end else
  530. inc(j);{We didn't find one, need to look further}
  531. end else
  532. if j=LenName then
  533. begin
  534. Found:=true;
  535. Break;
  536. end;
  537. { This 'until' condition must be j>LenName, not j>=LenName.
  538. That's because when we 'need to look further' and
  539. j = LenName then loop must not terminate. }
  540. until (j>LenName);
  541. end else
  542. begin
  543. j:=LenName;{we can stop}
  544. Found:=true;
  545. end;
  546. end;
  547. else {not a wildcard character in pattern}
  548. Found:=(j<=LenName) and (pattern[i]=name[j]);
  549. end;
  550. inc(i);
  551. inc(j);
  552. end;
  553. DoFnMatch:=Found and (j>LenName);
  554. end;
  555. Begin {start FNMatch}
  556. LenPat:=Length(Pattern);
  557. LenName:=Length(Name);
  558. FNMatch:=DoFNMatch(1,1);
  559. End;
  560. Type
  561. TUnixFindData = Record
  562. NamePos : LongInt; {to track which search this is}
  563. DirPtr : Pointer; {directory pointer for reading directory}
  564. SearchSpec : String;
  565. SearchType : Byte; {0=normal, 1=open will close, 2=only 1 file}
  566. SearchAttr : Byte; {attribute we are searching for}
  567. End;
  568. PUnixFindData = ^TUnixFindData;
  569. Procedure FindClose(Var f: TSearchRec);
  570. var
  571. UnixFindData : PUnixFindData;
  572. Begin
  573. UnixFindData:=PUnixFindData(f.FindHandle);
  574. If (UnixFindData=Nil) then
  575. Exit;
  576. if UnixFindData^.SearchType=0 then
  577. begin
  578. if UnixFindData^.dirptr<>nil then
  579. fpclosedir(pdir(UnixFindData^.dirptr)^);
  580. end;
  581. Dispose(UnixFindData);
  582. f.FindHandle:=nil;
  583. End;
  584. Function FindGetFileInfo(const s:string;var f:TSearchRec):boolean;
  585. var
  586. st : baseunix.stat;
  587. WinAttr : longint;
  588. begin
  589. FindGetFileInfo:=false;
  590. If Assigned(F.FindHandle) and ((((PUnixFindData(f.FindHandle)^.searchattr)) and faSymlink) > 0) then
  591. FindGetFileInfo:=(fplstat(pointer(s),st)=0)
  592. else
  593. FindGetFileInfo:=(fpstat(pointer(s),st)=0);
  594. If not FindGetFileInfo then
  595. exit;
  596. WinAttr:=LinuxToWinAttr(ExtractFileName(s),st);
  597. If ((WinAttr and Not(PUnixFindData(f.FindHandle)^.searchattr))=0) Then
  598. Begin
  599. f.Name:=ExtractFileName(s);
  600. f.Attr:=WinAttr;
  601. f.Size:=st.st_Size;
  602. f.Mode:=st.st_mode;
  603. {$ifndef FPUNONE}
  604. f.Time:=UnixToWinAge(st.st_mtime);
  605. {$endif}
  606. FindGetFileInfo:=true;
  607. End
  608. else
  609. FindGetFileInfo:=false;
  610. end;
  611. Function FindNext (Var Rslt : TSearchRec) : Longint;
  612. {
  613. re-opens dir if not already in array and calls FindGetFileInfo
  614. }
  615. Var
  616. DirName : String;
  617. FName,
  618. SName : string;
  619. Found,
  620. Finished : boolean;
  621. p : pdirent;
  622. UnixFindData : PUnixFindData;
  623. Begin
  624. Result:=-1;
  625. UnixFindData:=PUnixFindData(Rslt.FindHandle);
  626. { SearchSpec='' means that there were no wild cards, so only one file to
  627. find.
  628. }
  629. If (UnixFindData=Nil) then
  630. exit;
  631. if UnixFindData^.SearchSpec='' then
  632. exit;
  633. if (UnixFindData^.SearchType=0) and
  634. (UnixFindData^.Dirptr=nil) then
  635. begin
  636. If UnixFindData^.NamePos = 0 Then
  637. DirName:='./'
  638. Else
  639. DirName:=Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos);
  640. UnixFindData^.DirPtr := fpopendir(Pchar(pointer(DirName)));
  641. end;
  642. SName:=Copy(UnixFindData^.SearchSpec,UnixFindData^.NamePos+1,Length(UnixFindData^.SearchSpec));
  643. Found:=False;
  644. Finished:=(UnixFindData^.dirptr=nil);
  645. While Not Finished Do
  646. Begin
  647. p:=fpreaddir(pdir(UnixFindData^.dirptr)^);
  648. if p=nil then
  649. FName:=''
  650. else
  651. FName:=p^.d_name;
  652. If FName='' Then
  653. Finished:=True
  654. Else
  655. Begin
  656. If FNMatch(SName,FName) Then
  657. Begin
  658. Found:=FindGetFileInfo(Copy(UnixFindData^.SearchSpec,1,UnixFindData^.NamePos)+FName,Rslt);
  659. if Found then
  660. begin
  661. Result:=0;
  662. exit;
  663. end;
  664. End;
  665. End;
  666. End;
  667. End;
  668. Function FindFirst (Const Path : String; Attr : Longint; out Rslt : TSearchRec) : Longint;
  669. {
  670. opens dir and calls FindNext if needed.
  671. }
  672. var
  673. UnixFindData : PUnixFindData;
  674. Begin
  675. Result:=-1;
  676. fillchar(Rslt,sizeof(Rslt),0);
  677. if Path='' then
  678. exit;
  679. { Allocate UnixFindData (we always need it, for the search attributes) }
  680. New(UnixFindData);
  681. FillChar(UnixFindData^,sizeof(UnixFindData^),0);
  682. Rslt.FindHandle:=UnixFindData;
  683. {We always also search for readonly and archive, regardless of Attr:}
  684. UnixFindData^.SearchAttr := Attr or faarchive or fareadonly;
  685. {Wildcards?}
  686. if (Pos('?',Path)=0) and (Pos('*',Path)=0) then
  687. begin
  688. if FindGetFileInfo(Path,Rslt) then
  689. Result:=0;
  690. end
  691. else
  692. begin
  693. {Create Info}
  694. UnixFindData^.SearchSpec := Path;
  695. UnixFindData^.NamePos := Length(UnixFindData^.SearchSpec);
  696. while (UnixFindData^.NamePos>0) and (UnixFindData^.SearchSpec[UnixFindData^.NamePos]<>'/') do
  697. dec(UnixFindData^.NamePos);
  698. Result:=FindNext(Rslt);
  699. end;
  700. If (Result<>0) then
  701. FindClose(Rslt);
  702. End;
  703. Function FileGetDate (Handle : Longint) : Longint;
  704. Var Info : Stat;
  705. begin
  706. If (fpFStat(Handle,Info))<0 then
  707. Result:=-1
  708. else
  709. Result:=Info.st_Mtime;
  710. end;
  711. Function FileSetDate (Handle,Age : Longint) : Longint;
  712. begin
  713. // Impossible under Linux from FileHandle !!
  714. FileSetDate:=-1;
  715. end;
  716. Function FileGetAttr (Const FileName : String) : Longint;
  717. Var Info : Stat;
  718. begin
  719. If FpStat (pointer(FileName),Info)<0 then
  720. Result:=-1
  721. Else
  722. Result:=LinuxToWinAttr(Pchar(ExtractFileName(FileName)),Info);
  723. end;
  724. Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
  725. begin
  726. Result:=-1;
  727. end;
  728. Function DeleteFile (Const FileName : String) : Boolean;
  729. begin
  730. Result:=fpUnLink (pointer(FileName))>=0;
  731. end;
  732. Function RenameFile (Const OldName, NewName : String) : Boolean;
  733. begin
  734. RenameFile:=BaseUnix.FpRename(pointer(OldNAme),pointer(NewName))>=0;
  735. end;
  736. Function FileIsReadOnly(const FileName: String): Boolean;
  737. begin
  738. Result := fpAccess(PChar(pointer(FileName)),W_OK)<>0;
  739. end;
  740. Function FileSetDate (Const FileName : String;Age : Longint) : Longint;
  741. var
  742. t: TUTimBuf;
  743. begin
  744. Result := 0;
  745. t.actime := Age;
  746. t.modtime := Age;
  747. if fputime(PChar(pointer(FileName)), @t) = -1 then
  748. Result := fpgeterrno;
  749. end;
  750. {****************************************************************************
  751. Disk Functions
  752. ****************************************************************************}
  753. {
  754. The Diskfree and Disksize functions need a file on the specified drive, since this
  755. is required for the statfs system call.
  756. These filenames are set in drivestr[0..26], and have been preset to :
  757. 0 - '.' (default drive - hence current dir is ok.)
  758. 1 - '/fd0/.' (floppy drive 1 - should be adapted to local system )
  759. 2 - '/fd1/.' (floppy drive 2 - should be adapted to local system )
  760. 3 - '/' (C: equivalent of dos is the root partition)
  761. 4..26 (can be set by you're own applications)
  762. ! Use AddDisk() to Add new drives !
  763. They both return -1 when a failure occurs.
  764. }
  765. Const
  766. FixDriveStr : array[0..3] of pchar=(
  767. '.',
  768. '/fd0/.',
  769. '/fd1/.',
  770. '/.'
  771. );
  772. var
  773. Drives : byte = 4;
  774. DriveStr : array[4..26] of pchar;
  775. Function AddDisk(const path:string) : Byte;
  776. begin
  777. if not (DriveStr[Drives]=nil) then
  778. FreeMem(DriveStr[Drives]);
  779. GetMem(DriveStr[Drives],length(Path)+1);
  780. StrPCopy(DriveStr[Drives],path);
  781. Result:=Drives;
  782. inc(Drives);
  783. if Drives>26 then
  784. Drives:=4;
  785. end;
  786. Function DiskFree(Drive: Byte): int64;
  787. var
  788. fs : tstatfs;
  789. Begin
  790. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
  791. ((Drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
  792. Diskfree:=int64(fs.bavail)*int64(fs.bsize)
  793. else
  794. Diskfree:=-1;
  795. End;
  796. Function DiskSize(Drive: Byte): int64;
  797. var
  798. fs : tstatfs;
  799. Begin
  800. if ((Drive in [Low(FixDriveStr)..High(FixDriveStr)]) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
  801. ((drive <= High(drivestr)) and (not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
  802. DiskSize:=int64(fs.blocks)*int64(fs.bsize)
  803. else
  804. DiskSize:=-1;
  805. End;
  806. Procedure FreeDriveStr;
  807. var
  808. i: longint;
  809. begin
  810. for i:=low(drivestr) to high(drivestr) do
  811. if assigned(drivestr[i]) then
  812. begin
  813. freemem(drivestr[i]);
  814. drivestr[i]:=nil;
  815. end;
  816. end;
  817. Function GetCurrentDir : String;
  818. begin
  819. GetDir (0,Result);
  820. end;
  821. Function SetCurrentDir (Const NewDir : String) : Boolean;
  822. begin
  823. {$I-}
  824. ChDir(NewDir);
  825. {$I+}
  826. result := (IOResult = 0);
  827. end;
  828. Function CreateDir (Const NewDir : String) : Boolean;
  829. begin
  830. {$I-}
  831. MkDir(NewDir);
  832. {$I+}
  833. result := (IOResult = 0);
  834. end;
  835. Function RemoveDir (Const Dir : String) : Boolean;
  836. begin
  837. {$I-}
  838. RmDir(Dir);
  839. {$I+}
  840. result := (IOResult = 0);
  841. end;
  842. {****************************************************************************
  843. Misc Functions
  844. ****************************************************************************}
  845. {****************************************************************************
  846. Locale Functions
  847. ****************************************************************************}
  848. Function GetEpochTime: cint;
  849. {
  850. Get the number of seconds since 00:00, January 1 1970, GMT
  851. the time NOT corrected any way
  852. }
  853. begin
  854. GetEpochTime:=fptime;
  855. end;
  856. procedure GetTime(var hour,min,sec,msec,usec:word);
  857. {
  858. Gets the current time, adjusted to local time
  859. }
  860. var
  861. year,day,month:Word;
  862. tz:timeval;
  863. begin
  864. fpgettimeofday(@tz,nil);
  865. EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
  866. msec:=tz.tv_usec div 1000;
  867. usec:=tz.tv_usec mod 1000;
  868. end;
  869. procedure GetTime(var hour,min,sec,sec100:word);
  870. {
  871. Gets the current time, adjusted to local time
  872. }
  873. var
  874. usec : word;
  875. begin
  876. gettime(hour,min,sec,sec100,usec);
  877. sec100:=sec100 div 10;
  878. end;
  879. Procedure GetTime(Var Hour,Min,Sec:Word);
  880. {
  881. Gets the current time, adjusted to local time
  882. }
  883. var
  884. msec,usec : Word;
  885. Begin
  886. gettime(hour,min,sec,msec,usec);
  887. End;
  888. Procedure GetDate(Var Year,Month,Day:Word);
  889. {
  890. Gets the current date, adjusted to local time
  891. }
  892. var
  893. hour,minute,second : word;
  894. Begin
  895. EpochToLocal(fptime,year,month,day,hour,minute,second);
  896. End;
  897. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  898. {
  899. Gets the current date, adjusted to local time
  900. }
  901. Begin
  902. EpochToLocal(fptime,year,month,day,hour,minute,second);
  903. End;
  904. {$ifndef FPUNONE}
  905. Procedure GetLocalTime(var SystemTime: TSystemTime);
  906. var
  907. usecs : Word;
  908. begin
  909. GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second, SystemTime.MilliSecond, usecs);
  910. GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day);
  911. // SystemTime.MilliSecond := 0;
  912. end ;
  913. {$endif}
  914. Procedure InitAnsi;
  915. Var
  916. i : longint;
  917. begin
  918. { Fill table entries 0 to 127 }
  919. for i := 0 to 96 do
  920. UpperCaseTable[i] := chr(i);
  921. for i := 97 to 122 do
  922. UpperCaseTable[i] := chr(i - 32);
  923. for i := 123 to 191 do
  924. UpperCaseTable[i] := chr(i);
  925. Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
  926. for i := 0 to 64 do
  927. LowerCaseTable[i] := chr(i);
  928. for i := 65 to 90 do
  929. LowerCaseTable[i] := chr(i + 32);
  930. for i := 91 to 191 do
  931. LowerCaseTable[i] := chr(i);
  932. Move (CPISO88591LCT,LowerCaseTable[192],SizeOf(CPISO88591UCT));
  933. end;
  934. Procedure InitInternational;
  935. begin
  936. InitInternationalGeneric;
  937. InitAnsi;
  938. end;
  939. function SysErrorMessage(ErrorCode: Integer): String;
  940. begin
  941. Result:=StrError(ErrorCode);
  942. end;
  943. {****************************************************************************
  944. OS utility functions
  945. ****************************************************************************}
  946. Function GetEnvironmentVariable(Const EnvVar : String) : String;
  947. begin
  948. Result:=StrPas(BaseUnix.FPGetenv(PChar(pointer(EnvVar))));
  949. end;
  950. Function GetEnvironmentVariableCount : Integer;
  951. begin
  952. Result:=FPCCountEnvVar(EnvP);
  953. end;
  954. Function GetEnvironmentString(Index : Integer) : String;
  955. begin
  956. Result:=FPCGetEnvStrFromP(Envp,Index);
  957. end;
  958. function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString):integer;
  959. var
  960. pid : longint;
  961. e : EOSError;
  962. CommandLine: AnsiString;
  963. cmdline2 : ppchar;
  964. Begin
  965. { always surround the name of the application by quotes
  966. so that long filenames will always be accepted. But don't
  967. do it if there are already double quotes!
  968. }
  969. // Only place we still parse
  970. cmdline2:=nil;
  971. if Comline<>'' Then
  972. begin
  973. CommandLine:=ComLine;
  974. { Make an unique copy because stringtoppchar modifies the
  975. string }
  976. UniqueString(CommandLine);
  977. cmdline2:=StringtoPPChar(CommandLine,1);
  978. cmdline2^:=pchar(pointer(Path));
  979. end
  980. else
  981. begin
  982. getmem(cmdline2,2*sizeof(pchar));
  983. cmdline2^:=pchar(Path);
  984. cmdline2[1]:=nil;
  985. end;
  986. {$ifdef USE_VFORK}
  987. pid:=fpvFork;
  988. {$else USE_VFORK}
  989. pid:=fpFork;
  990. {$endif USE_VFORK}
  991. if pid=0 then
  992. begin
  993. {The child does the actual exec, and then exits}
  994. fpexecv(pchar(pointer(Path)),Cmdline2);
  995. { If the execve fails, we return an exitvalue of 127, to let it be known}
  996. fpExit(127);
  997. end
  998. else
  999. if pid=-1 then {Fork failed}
  1000. begin
  1001. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  1002. e.ErrorCode:=-1;
  1003. raise e;
  1004. end;
  1005. { We're in the parent, let's wait. }
  1006. result:=WaitProcess(pid); // WaitPid and result-convert
  1007. if Comline<>'' Then
  1008. freemem(cmdline2);
  1009. if (result<0) or (result=127) then
  1010. begin
  1011. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  1012. E.ErrorCode:=result;
  1013. Raise E;
  1014. end;
  1015. End;
  1016. function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array Of AnsiString):integer;
  1017. var
  1018. pid : longint;
  1019. e : EOSError;
  1020. Begin
  1021. pid:=fpFork;
  1022. if pid=0 then
  1023. begin
  1024. {The child does the actual exec, and then exits}
  1025. fpexecl(Path,Comline);
  1026. { If the execve fails, we return an exitvalue of 127, to let it be known}
  1027. fpExit(127);
  1028. end
  1029. else
  1030. if pid=-1 then {Fork failed}
  1031. begin
  1032. e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
  1033. e.ErrorCode:=-1;
  1034. raise e;
  1035. end;
  1036. { We're in the parent, let's wait. }
  1037. result:=WaitProcess(pid); // WaitPid and result-convert
  1038. if (result<0) or (result=127) then
  1039. begin
  1040. E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
  1041. E.ErrorCode:=result;
  1042. raise E;
  1043. end;
  1044. End;
  1045. procedure Sleep(milliseconds: Cardinal);
  1046. Var
  1047. timeout,timeoutresult : TTimespec;
  1048. res: cint;
  1049. begin
  1050. timeout.tv_sec:=milliseconds div 1000;
  1051. timeout.tv_nsec:=1000*1000*(milliseconds mod 1000);
  1052. repeat
  1053. res:=fpnanosleep(@timeout,@timeoutresult);
  1054. timeout:=timeoutresult;
  1055. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  1056. end;
  1057. Function GetLastOSError : Integer;
  1058. begin
  1059. Result:=fpgetErrNo;
  1060. end;
  1061. { ---------------------------------------------------------------------
  1062. Application config files
  1063. ---------------------------------------------------------------------}
  1064. Function GetHomeDir : String;
  1065. begin
  1066. Result:=GetEnvironmentVariable('HOME');
  1067. If (Result<>'') then
  1068. Result:=IncludeTrailingPathDelimiter(Result);
  1069. end;
  1070. { Follows base-dir spec,
  1071. see [http://freedesktop.org/Standards/basedir-spec].
  1072. Always ends with PathDelim. }
  1073. Function XdgConfigHome : String;
  1074. begin
  1075. Result:=GetEnvironmentVariable('XDG_CONFIG_HOME');
  1076. if (Result='') then
  1077. Result:=GetHomeDir + '.config/'
  1078. else
  1079. Result:=IncludeTrailingPathDelimiter(Result);
  1080. end;
  1081. Function GetAppConfigDir(Global : Boolean) : String;
  1082. begin
  1083. If Global then
  1084. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  1085. else
  1086. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  1087. if VendorName<>'' then
  1088. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1089. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1090. end;
  1091. Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
  1092. begin
  1093. If Global then
  1094. Result:=IncludeTrailingPathDelimiter(SysConfigDir)
  1095. else
  1096. Result:=IncludeTrailingPathDelimiter(XdgConfigHome);
  1097. if SubDir then
  1098. begin
  1099. if VendorName<>'' then
  1100. Result:=IncludeTrailingPathDelimiter(Result+VendorName);
  1101. Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
  1102. end;
  1103. Result:=Result+ApplicationName+ConfigExtension;
  1104. end;
  1105. {****************************************************************************
  1106. GetTempDir
  1107. ****************************************************************************}
  1108. Function GetTempDir(Global : Boolean) : String;
  1109. begin
  1110. If Assigned(OnGetTempDir) then
  1111. Result:=OnGetTempDir(Global)
  1112. else
  1113. begin
  1114. Result:=GetEnvironmentVariable('TEMP');
  1115. If (Result='') Then
  1116. Result:=GetEnvironmentVariable('TMP');
  1117. if (Result='') then
  1118. Result:='/tmp/' // fallback.
  1119. end;
  1120. if (Result<>'') then
  1121. Result:=IncludeTrailingPathDelimiter(Result);
  1122. end;
  1123. {****************************************************************************
  1124. GetUserDir
  1125. ****************************************************************************}
  1126. Var
  1127. TheUserDir : String;
  1128. Function GetUserDir : String;
  1129. begin
  1130. If (TheUserDir='') then
  1131. begin
  1132. TheUserDir:=GetEnvironmentVariable('HOME');
  1133. if (TheUserDir<>'') then
  1134. TheUserDir:=IncludeTrailingPathDelimiter(TheUserDir)
  1135. else
  1136. TheUserDir:=GetTempDir(False);
  1137. end;
  1138. Result:=TheUserDir;
  1139. end;
  1140. Procedure SysBeep;
  1141. begin
  1142. Write(#7);
  1143. Flush(Output);
  1144. end;
  1145. {****************************************************************************
  1146. Initialization code
  1147. ****************************************************************************}
  1148. Initialization
  1149. InitExceptions; { Initialize exceptions. OS independent }
  1150. InitInternational; { Initialize internationalization settings }
  1151. SysConfigDir:='/etc'; { Initialize system config dir }
  1152. OnBeep:=@SysBeep;
  1153. Finalization
  1154. FreeDriveStr;
  1155. DoneExceptions;
  1156. end.