unix.pp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt,
  4. BSD parts (c) 2000 by Marco van de Voort
  5. members of the Free Pascal development team.
  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 Unix;
  13. Interface
  14. Uses BaseUnix,UnixType;
  15. {$if (defined(BSD) or defined(SUNOS)) and defined(FPC_USE_LIBC)}
  16. {$define USE_VFORK}
  17. {$endif}
  18. {$i aliasptp.inc}
  19. { Get Types and Constants only exported in this unit }
  20. {$i unxconst.inc}
  21. // We init to zero to be able to put timezone stuff under IFDEF, and still
  22. // keep the code working.
  23. // We can't do this hear, since unixutil functions access this.
  24. // var
  25. // Tzseconds : Longint = 0;
  26. {********************
  27. File
  28. ********************}
  29. Const
  30. P_IN = 1; // pipes (?)
  31. P_OUT = 2;
  32. Const
  33. LOCK_SH = 1; // flock constants ?
  34. LOCK_EX = 2;
  35. LOCK_UN = 8;
  36. LOCK_NB = 4;
  37. Type
  38. Tpipe = baseunix.tfildes; // compability.
  39. {******************************************************************************
  40. Procedure/Functions
  41. ******************************************************************************}
  42. {**************************
  43. Time/Date Handling
  44. ***************************}
  45. var
  46. tzdaylight : boolean;
  47. tzname : array[boolean] of pchar;
  48. {$IFNDEF DONT_READ_TIMEZONE} // allows to disable linking in and trying for platforms
  49. // it doesn't (yet) work for.
  50. { timezone support }
  51. procedure GetLocalTimezone(timer:cint;var leap_correct,leap_hit:cint);
  52. procedure GetLocalTimezone(timer:cint);
  53. procedure ReadTimezoneFile(fn:string);
  54. function GetTimezoneFile:string;
  55. {$ENDIF}
  56. {**************************
  57. Process Handling
  58. ***************************}
  59. //
  60. // These are much better, in nearly all ways.
  61. //
  62. function FpExecLE (Const PathName:AnsiString;const S:Array Of AnsiString;MyEnv:ppchar):cint;
  63. function FpExecL(Const PathName:AnsiString;const S:Array Of AnsiString):cint;
  64. function FpExecLP(Const PathName:AnsiString;const S:Array Of AnsiString):cint;
  65. function FpExecV(Const PathName:AnsiString;args:ppchar):cint;
  66. function FpExecVP(Const PathName:AnsiString;args:ppchar):cint;
  67. function FpExecVPE(Const PathName:AnsiString;args,env:ppchar):cint;
  68. Function Shell (const Command:String):cint; deprecated;
  69. Function Shell (const Command:AnsiString):cint; deprecated;
  70. Function fpSystem(const Command:string):cint;
  71. Function fpSystem(const Command:AnsiString):cint;
  72. Function WaitProcess (Pid:cint):cint;
  73. { like WaitPid(PID,@result,0) Handling of Signal interrupts (errno=EINTR), returning the Exitcode of Process (>=0) or -Status if terminated}
  74. Function WIFSTOPPED (Status: Integer): Boolean;
  75. Function W_EXITCODE (ReturnCode, Signal: Integer): Integer;
  76. Function W_STOPCODE (Signal: Integer): Integer;
  77. {**************************
  78. File Handling
  79. ***************************}
  80. {$ifndef FPC_USE_LIBC} // defined using cdecl for libc.
  81. Function fsync (fd : cint) : cint;
  82. Function fpFlock (fd,mode : cint) : cint ;
  83. Function fStatFS (Fd: cint;Var Info:tstatfs):cint;
  84. Function StatFS (Path:pchar;Var Info:tstatfs):cint;
  85. {$endif}
  86. Function fpFlock (var T : text;mode : cint) : cint;
  87. Function fpFlock (var F : File;mode : cint) : cint;
  88. Function SelectText (var T:Text;TimeOut :PTimeVal):cint; deprecated;
  89. Function SelectText (var T:Text;TimeOut :cint):cint; deprecated;
  90. {**************************
  91. Directory Handling
  92. ***************************}
  93. procedure SeekDir(p:pdir;loc:clong);
  94. function TellDir(p:pdir):TOff;
  95. {**************************
  96. Pipe/Fifo/Stream
  97. ***************************}
  98. Function AssignPipe (var pipe_in,pipe_out:cint):cint;
  99. Function AssignPipe (var pipe_in,pipe_out:text):cint;
  100. Function AssignPipe (var pipe_in,pipe_out:file):cint;
  101. //Function PClose (Var F:text) : cint;
  102. //Function PClose (Var F:file) : cint;
  103. Function POpen (var F:text;const Prog:Ansistring;rw:char):cint;
  104. Function POpen (var F:file;const Prog:Ansistring;rw:char):cint;
  105. Function AssignStream(Var StreamIn,Streamout:text;Const Prog:ansiString;const args : array of ansistring) : cint;
  106. Function AssignStream(Var StreamIn,Streamout,streamerr:text;Const Prog:ansiString;const args : array of ansistring) : cint;
  107. Function GetDomainName:String;
  108. Function GetHostName:String;
  109. {**************************
  110. Memory functions
  111. ***************************}
  112. Const
  113. // The portable MAP_* and PROT_ constants are exported from unit Unix for compability.
  114. PROT_READ = baseunix.PROT_READ; { page can be read }
  115. PROT_WRITE = baseunix.PROT_WRITE; { page can be written }
  116. PROT_EXEC = baseunix.PROT_EXEC; { page can be executed }
  117. PROT_NONE = baseunix.PROT_NONE; { page can not be accessed }
  118. MAP_FAILED = baseunix.MAP_FAILED; { mmap() failed }
  119. MAP_SHARED = baseunix.MAP_SHARED; { Share changes }
  120. MAP_PRIVATE = baseunix.MAP_PRIVATE; { Changes are private }
  121. MAP_TYPE = baseunix.MAP_TYPE; { Mask for type of mapping }
  122. MAP_FIXED = baseunix.MAP_FIXED; { Interpret addr exactly }
  123. { Flags to `msync'. }
  124. MS_ASYNC = 1; { Sync memory asynchronously. }
  125. MS_SYNC = 4; { Synchronous memory sync. }
  126. MS_INVALIDATE = 2; { Invalidate the caches. }
  127. {**************************
  128. Utility functions
  129. ***************************}
  130. Type
  131. TFSearchOption = (NoCurrentDirectory,
  132. CurrentDirectoryFirst,
  133. CurrentDirectoryLast);
  134. Function FSearch (const path:AnsiString;dirlist:Ansistring;CurrentDirStrategy:TFSearchOption):AnsiString;
  135. Function FSearch (const path:AnsiString;dirlist:AnsiString):AnsiString;
  136. procedure SigRaise (sig:integer);
  137. {$ifdef FPC_USE_LIBC}
  138. const clib = 'c';
  139. {$i unxdeclh.inc}
  140. {$else}
  141. {$i unxsysch.inc} // calls used in system and not reexported from baseunix
  142. {$endif}
  143. {******************************************************************************
  144. Implementation
  145. ******************************************************************************}
  146. {$i unxovlh.inc}
  147. Implementation
  148. Uses UnixUtil, // tzseconds
  149. Strings {$ifndef FPC_USE_LIBC},Syscall{$endif};
  150. {$i unxovl.inc}
  151. {$ifndef FPC_USE_LIBC}
  152. {$i syscallh.inc}
  153. {$i unxsysc.inc}
  154. {$endif}
  155. { Get the definitions of textrec and filerec }
  156. {$i textrec.inc}
  157. {$i filerec.inc}
  158. {$i unxfunc.inc} { Platform specific implementations }
  159. Function getenv(name:string):Pchar; external name 'FPC_SYSC_FPGETENV';
  160. {******************************************************************************
  161. Process related calls
  162. ******************************************************************************}
  163. { Most calls of WaitPID do not handle the result correctly, this funktion treats errors more correctly }
  164. Function WaitProcess(Pid:cint):cint; { like WaitPid(PID,@result,0) Handling of Signal interrupts (errno=EINTR), returning the Exitcode of Process (>=0) or -Status if terminated}
  165. var
  166. r,s : cint;
  167. begin
  168. s:=$7F00;
  169. repeat
  170. r:=fpWaitPid(Pid,@s,0);
  171. if (r=-1) and (fpgeterrno=ESysEIntr) Then
  172. r:=0;
  173. until (r<>0);
  174. if (r=-1) or (r=0) then // 0 is not a valid return and should never occur (it means status invalid when using WNOHANG)
  175. WaitProcess:=-1 // return -1 to indicate an error. fpwaitpid updated it.
  176. else
  177. begin
  178. if wifexited(s) then
  179. WaitProcess:=wexitstatus(s)
  180. else if (s>0) then // Until now there is not use of the highest bit , but check this for the future
  181. WaitProcess:=-s // normal case
  182. else
  183. WaitProcess:=s; // s<0 should not occur, but wie return also a negativ value
  184. end;
  185. end;
  186. function intFpExecVEMaybeP (Const PathName:AnsiString;Args,MyEnv:ppchar;SearchPath:Boolean):cint;
  187. // does an ExecVE, but still has to handle P
  188. // execv variants call this directly, execl variants indirectly via
  189. // intfpexecl
  190. Var
  191. NewCmd : ansistring;
  192. ThePath : AnsiString;
  193. Begin
  194. If SearchPath and (pos('/',pathname)=0) Then
  195. Begin
  196. // The above could be better. (check if not escaped/quoted '/'s) ?
  197. // (Jilles says this is ok)
  198. // Stevens says only search if newcmd contains no '/'
  199. // fsearch is not ansistring clean yet.
  200. ThePath:=fpgetenv('PATH');
  201. if thepath='' then
  202. thepath:='.'; // FreeBSD uses _PATH_DEFPATH = /usr/bin:/bin
  203. // but a quick check showed that _PATH_DEFPATH
  204. // varied from OS to OS
  205. newcmd:=FSearch(pathname,thepath,NoCurrentDirectory);
  206. // FreeBSD libc keeps on trying till a file is successfully run.
  207. // Stevens says "try each path prefix"
  208. // execp puts newcmd here.
  209. args^:=pchar(newcmd);
  210. End else
  211. newcmd:=pathname;
  212. // repeat
  213. // if searchpath then args^:=pchar(commandtorun)
  214. IntFpExecVEMaybeP:=fpExecVE(newcmd,Args,MyEnv);
  215. {
  216. // Code that if exec fails due to permissions, tries to run it with sh
  217. // Should we deallocate p on fail? -> no fpexit is run no matter what
  218. //
  219. }
  220. // if intfpexecvemaybep=-1 then zoekvolgende file.
  221. // until (Goexit) or SearchExit;
  222. {
  223. If IntFpExec=-1 Then
  224. Begin
  225. Error:=fpGetErrno
  226. Case Error of
  227. ESysE2Big : Exit(-1);
  228. ESysELoop,
  229. : Exit(-1);
  230. }
  231. end;
  232. function intFpExecl (Const PathName:AnsiString;const s:array of ansistring;MyEnv:ppchar;SearchPath:Boolean):cint;
  233. { Handles the array of ansistring -> ppchar conversion.
  234. Base for the the "l" variants.
  235. }
  236. var p:ppchar;
  237. begin
  238. If PathName='' Then
  239. Begin
  240. fpsetErrno(ESysEnoEnt);
  241. Exit(-1); // Errno?
  242. End;
  243. p:=ArrayStringToPPchar(s,1);
  244. if p=NIL Then
  245. Begin
  246. GetMem(p,2*sizeof(pchar));
  247. if p=nil then
  248. begin
  249. {$ifdef xunix}
  250. fpseterrno(ESysEnoMem);
  251. {$endif}
  252. fpseterrno(ESysEnoEnt);
  253. exit(-1);
  254. end;
  255. p[1]:=nil;
  256. End;
  257. p^:=pchar(PathName);
  258. IntFPExecL:=intFpExecVEMaybeP(PathName,p,MyEnv,SearchPath);
  259. // If we come here, no attempts were executed successfully.
  260. Freemem(p);
  261. end;
  262. function FpExecLE (Const PathName:AnsiString;const S:Array Of AnsiString;MyEnv:ppchar):cint;
  263. Begin
  264. FpExecLE:=intFPExecl(PathName,s,MyEnv,false);
  265. End;
  266. function FpExecL(Const PathName:AnsiString;const S:Array Of AnsiString):cint;
  267. Begin
  268. FpExecL:=intFPExecl(PathName,S,EnvP,false);
  269. End;
  270. function FpExecLP(Const PathName:AnsiString;const S:Array Of AnsiString):cint;
  271. Begin
  272. FpExecLP:=intFPExecl(PathName,S,EnvP,True);
  273. End;
  274. function FpExecV(Const PathName:AnsiString;args:ppchar):cint;
  275. Begin
  276. fpexecV:=intFpExecVEMaybeP (PathName,args,envp,false);
  277. End;
  278. function FpExecVP(Const PathName:AnsiString;args:ppchar):cint;
  279. Begin
  280. fpexecVP:=intFpExecVEMaybeP (PathName,args,envp,true);
  281. End;
  282. function FpExecVPE(Const PathName:AnsiString;args,env:ppchar):cint;
  283. Begin
  284. fpexecVPE:=intFpExecVEMaybeP (PathName,args,env,true);
  285. End;
  286. // exect and execvP (ExecCapitalP) are not implement
  287. // Non POSIX anyway.
  288. // Exect turns on tracing for the process
  289. // execvP has the searchpath as array of ansistring ( const char *search_path)
  290. {$define FPC_USE_FPEXEC}
  291. {$if defined(FPC_USE_FPEXEC) and not defined(USE_VFORK)}
  292. {$define SHELL_USE_FPEXEC}
  293. {$endif}
  294. Function Shell(const Command:String):cint; deprecated;
  295. {
  296. Executes the shell, and passes it the string Command. (Through /bin/sh -c)
  297. The current environment is passed to the shell.
  298. It waits for the shell to exit, and returns its exit status.
  299. If the Exec call failed exit status 127 is reported.
  300. }
  301. { Changed the structure:
  302. - the previous version returns an undefinied value if fork fails
  303. - it returns the status of Waitpid instead of the Process returnvalue (see the doc to Shell)
  304. - it uses exit(127) not ExitProc (The Result in pp386: going on Compiling in 2 processes!)
  305. - ShellArgs are now released
  306. - The Old CreateShellArg gives back pointers to a local var
  307. }
  308. var
  309. {$ifndef SHELL_USE_FPEXEC}
  310. p : ppchar;
  311. {$endif}
  312. pid : cint;
  313. begin
  314. {$ifndef SHELL_USE_FPEXEC}
  315. p:=CreateShellArgv(command);
  316. {$endif}
  317. {$ifdef USE_VFORK}
  318. pid:=fpvfork;
  319. {$else USE_VFORK}
  320. pid:=fpfork;
  321. {$endif USE_VFORK}
  322. if pid=0 then // We are in the Child
  323. begin
  324. {This is the child.}
  325. {$ifndef SHELL_USE_FPEXEC}
  326. fpExecve(p^,p,envp);
  327. {$else}
  328. fpexecl('/bin/sh',['-c',Command]);
  329. {$endif}
  330. fpExit(127); // was Exit(127)
  331. end
  332. else if (pid<>-1) then // Successfull started
  333. Shell:=WaitProcess(pid)
  334. else // no success
  335. Shell:=-1; // indicate an error
  336. {$ifndef SHELL_USE_FPEXEC}
  337. FreeShellArgV(p);
  338. {$endif}
  339. end;
  340. Function Shell(const Command:AnsiString):cint;
  341. {
  342. AnsiString version of Shell
  343. }
  344. var
  345. {$ifndef SHELL_USE_FPEXEC}
  346. p : ppchar;
  347. {$endif}
  348. pid : cint;
  349. begin { Changes as above }
  350. {$ifndef SHELL_USE_FPEXEC}
  351. p:=CreateShellArgv(command);
  352. {$endif}
  353. {$ifdef USE_VFORK}
  354. pid:=fpvfork;
  355. {$else USE_VFORK}
  356. pid:=fpfork;
  357. {$endif USE_VFORK}
  358. if pid=0 then // We are in the Child
  359. begin
  360. {$ifdef SHELL_USE_FPEXEC}
  361. fpexecl('/bin/sh',['-c',Command]);
  362. {$else}
  363. fpExecve(p^,p,envp);
  364. {$endif}
  365. fpExit(127); // was exit(127)!! We must exit the Process, not the function
  366. end
  367. else if (pid<>-1) then // Successfull started
  368. Shell:=WaitProcess(pid)
  369. else // no success
  370. Shell:=-1;
  371. {$ifndef SHELL_USE_FPEXEC}
  372. FreeShellArgV(p);
  373. {$ENDIF}
  374. end;
  375. {$ifdef FPC_USE_LIBC}
  376. function xfpsystem(p:pchar):cint; cdecl; external clib name 'system';
  377. function fpsystem(const Command:string):cint;
  378. var c:array[0..255] of char;
  379. begin
  380. strpcopy(@c,command);
  381. fpsystem:=xfpsystem(@c);
  382. end;
  383. Function fpSystem(const Command:AnsiString):cint;
  384. begin
  385. fpsystem:=xfpsystem(pchar(command));
  386. end;
  387. {$else}
  388. Function fpSystem(const Command:string):cint;
  389. var
  390. pid,savedpid : cint;
  391. pstat : cint;
  392. ign,intact,
  393. quitact : SigactionRec;
  394. newsigblock,
  395. oldsigblock : tsigset;
  396. begin { Changes as above }
  397. if command='' then exit(1);
  398. ign.sa_handler:=SigActionHandler(SIG_IGN);
  399. fpsigemptyset(ign.sa_mask);
  400. ign.sa_flags:=0;
  401. fpsigaction(SIGINT, @ign, @intact);
  402. fpsigaction(SIGQUIT, @ign, @quitact);
  403. fpsigemptyset(newsigblock);
  404. fpsigaddset(newsigblock,SIGCHLD);
  405. fpsigprocmask(SIG_BLOCK,newsigblock,oldsigblock);
  406. pid:=fpfork;
  407. if pid=0 then // We are in the Child
  408. begin
  409. fpsigaction(SIGINT,@intact,NIL);
  410. fpsigaction(SIGQUIT,@quitact,NIL);
  411. fpsigprocmask(SIG_SETMASK,@oldsigblock,NIL);
  412. fpexecl('/bin/sh',['-c',Command]);
  413. fpExit(127); // was exit(127)!! We must exit the Process, not the function
  414. end
  415. else if (pid<>-1) then // Successfull started
  416. begin
  417. savedpid:=pid;
  418. repeat
  419. pid:=fpwaitpid(savedpid,@pstat,0);
  420. until (pid<>-1) and (fpgeterrno()<>ESysEintr);
  421. if pid=-1 Then
  422. fpsystem:=-1
  423. else
  424. fpsystem:=pstat;
  425. end
  426. else // no success
  427. fpsystem:=-1;
  428. fpsigaction(SIGINT,@intact,NIL);
  429. fpsigaction(SIGQUIT,@quitact,NIL);
  430. fpsigprocmask(SIG_SETMASK,@oldsigblock,NIL);
  431. end;
  432. Function fpSystem(const Command:AnsiString):cint;
  433. {
  434. AnsiString version of Shell
  435. }
  436. var
  437. pid,savedpid : cint;
  438. pstat : cint;
  439. ign,intact,
  440. quitact : SigactionRec;
  441. newsigblock,
  442. oldsigblock : tsigset;
  443. begin { Changes as above }
  444. if command='' then exit(1);
  445. ign.sa_handler:=SigActionHandler(SIG_IGN);
  446. fpsigemptyset(ign.sa_mask);
  447. ign.sa_flags:=0;
  448. fpsigaction(SIGINT, @ign, @intact);
  449. fpsigaction(SIGQUIT, @ign, @quitact);
  450. fpsigemptyset(newsigblock);
  451. fpsigaddset(newsigblock,SIGCHLD);
  452. fpsigprocmask(SIG_BLOCK,newsigblock,oldsigblock);
  453. pid:=fpfork;
  454. if pid=0 then // We are in the Child
  455. begin
  456. fpsigaction(SIGINT,@intact,NIL);
  457. fpsigaction(SIGQUIT,@quitact,NIL);
  458. fpsigprocmask(SIG_SETMASK,@oldsigblock,NIL);
  459. fpexecl('/bin/sh',['-c',Command]);
  460. fpExit(127); // was exit(127)!! We must exit the Process, not the function
  461. end
  462. else if (pid<>-1) then // Successfull started
  463. begin
  464. savedpid:=pid;
  465. repeat
  466. pid:=fpwaitpid(savedpid,@pstat,0);
  467. until (pid<>-1) and (fpgeterrno()<>ESysEintr);
  468. if pid=-1 Then
  469. fpsystem:=-1
  470. else
  471. fpsystem:=pstat;
  472. end
  473. else // no success
  474. fpsystem:=-1;
  475. fpsigaction(SIGINT,@intact,NIL);
  476. fpsigaction(SIGQUIT,@quitact,NIL);
  477. fpsigprocmask(SIG_SETMASK,@oldsigblock,NIL);
  478. end;
  479. {$endif}
  480. Function WIFSTOPPED(Status: Integer): Boolean;
  481. begin
  482. WIFSTOPPED:=((Status and $FF)=$7F);
  483. end;
  484. Function W_EXITCODE(ReturnCode, Signal: Integer): Integer;
  485. begin
  486. W_EXITCODE:=(ReturnCode shl 8) or Signal;
  487. end;
  488. Function W_STOPCODE(Signal: Integer): Integer;
  489. begin
  490. W_STOPCODE:=(Signal shl 8) or $7F;
  491. end;
  492. {$IFNDEF DONT_READ_TIMEZONE}
  493. { Include timezone handling routines which use /usr/share/timezone info }
  494. {$i timezone.inc}
  495. {$endif}
  496. {******************************************************************************
  497. FileSystem calls
  498. ******************************************************************************}
  499. Function fpFlock (var T : text;mode : cint) : cint;
  500. begin
  501. fpFlock:=fpFlock(TextRec(T).Handle,mode);
  502. end;
  503. Function fpFlock (var F : File;mode : cint) :cint;
  504. begin
  505. fpFlock:=fpFlock(FileRec(F).Handle,mode);
  506. end;
  507. Function SelectText(var T:Text;TimeOut :PTimeval):cint;
  508. Var
  509. F:TfdSet;
  510. begin
  511. if textrec(t).mode=fmclosed then
  512. begin
  513. fpseterrno(ESysEBADF);
  514. exit(-1);
  515. end;
  516. FpFD_ZERO(f);
  517. fpFD_SET(textrec(T).handle,f);
  518. if textrec(T).mode=fminput then
  519. SelectText:=fpselect(textrec(T).handle+1,@f,nil,nil,TimeOut)
  520. else
  521. SelectText:=fpselect(textrec(T).handle+1,nil,@f,nil,TimeOut);
  522. end;
  523. Function SelectText(var T:Text;TimeOut :cint):cint;
  524. var
  525. p : PTimeVal;
  526. tv : TimeVal;
  527. begin
  528. if TimeOut=-1 then
  529. p:=nil
  530. else
  531. begin
  532. tv.tv_Sec:=Timeout div 1000;
  533. tv.tv_Usec:=(Timeout mod 1000)*1000;
  534. p:=@tv;
  535. end;
  536. SelectText:=SelectText(T,p);
  537. end;
  538. {******************************************************************************
  539. Directory
  540. ******************************************************************************}
  541. procedure SeekDir(p:pdir;loc:clong);
  542. begin
  543. if p=nil then
  544. begin
  545. fpseterrno(ESysEBADF);
  546. exit;
  547. end;
  548. {$if not(defined(bsd)) and not(defined(solaris)) }
  549. p^.dd_nextoff:=fplseek(p^.dd_fd,loc,seek_set);
  550. {$endif}
  551. p^.dd_size:=0;
  552. p^.dd_loc:=0;
  553. end;
  554. function TellDir(p:pdir):TOff;
  555. begin
  556. if p=nil then
  557. begin
  558. fpseterrno(ESysEBADF);
  559. telldir:=-1;
  560. exit;
  561. end;
  562. telldir:=fplseek(p^.dd_fd,0,seek_cur)
  563. { We could try to use the nextoff field here, but on my 1.2.13
  564. kernel, this gives nothing... This may have to do with
  565. the readdir implementation of libc... I also didn't find any trace of
  566. the field in the kernel code itself, So I suspect it is an artifact of libc.
  567. Michael. }
  568. end;
  569. {******************************************************************************
  570. Pipes/Fifo
  571. ******************************************************************************}
  572. Procedure OpenPipe(var F:Text);
  573. begin
  574. case textrec(f).mode of
  575. fmoutput :
  576. if textrec(f).userdata[1]<>P_OUT then
  577. textrec(f).mode:=fmclosed;
  578. fminput :
  579. if textrec(f).userdata[1]<>P_IN then
  580. textrec(f).mode:=fmclosed;
  581. else
  582. textrec(f).mode:=fmclosed;
  583. end;
  584. end;
  585. Function IOPipe(var F:text):cint;
  586. begin
  587. IOPipe:=0;
  588. case textrec(f).mode of
  589. fmoutput :
  590. begin
  591. { first check if we need something to write, else we may
  592. get a SigPipe when Close() is called (PFV) }
  593. if textrec(f).bufpos>0 then
  594. IOPipe:=fpwrite(textrec(f).handle,pchar(textrec(f).bufptr),textrec(f).bufpos);
  595. end;
  596. fminput : Begin
  597. textrec(f).bufend:=fpread(textrec(f).handle,pchar(textrec(f).bufptr),textrec(f).bufsize);
  598. IOPipe:=textrec(f).bufend;
  599. End;
  600. end;
  601. textrec(f).bufpos:=0;
  602. end;
  603. Function FlushPipe(var F:Text):cint;
  604. begin
  605. FlushPipe:=0;
  606. if (textrec(f).mode=fmoutput) and (textrec(f).bufpos<>0) then
  607. FlushPipe:=IOPipe(f);
  608. textrec(f).bufpos:=0;
  609. end;
  610. Function ClosePipe(var F:text):cint;
  611. begin
  612. textrec(f).mode:=fmclosed;
  613. ClosePipe:=fpclose(textrec(f).handle);
  614. end;
  615. Function AssignPipe(var pipe_in,pipe_out:text):cint;
  616. {
  617. Sets up a pair of file variables, which act as a pipe. The first one can
  618. be read from, the second one can be written to.
  619. }
  620. var
  621. f_in,f_out : cint;
  622. begin
  623. if AssignPipe(f_in,f_out)=-1 then
  624. exit(-1);
  625. { Set up input }
  626. Assign(Pipe_in,'');
  627. Textrec(Pipe_in).Handle:=f_in;
  628. Textrec(Pipe_in).Mode:=fmInput;
  629. Textrec(Pipe_in).userdata[1]:=P_IN;
  630. TextRec(Pipe_in).OpenFunc:=@OpenPipe;
  631. TextRec(Pipe_in).InOutFunc:=@IOPipe;
  632. TextRec(Pipe_in).FlushFunc:=@FlushPipe;
  633. TextRec(Pipe_in).CloseFunc:=@ClosePipe;
  634. { Set up output }
  635. Assign(Pipe_out,'');
  636. Textrec(Pipe_out).Handle:=f_out;
  637. Textrec(Pipe_out).Mode:=fmOutput;
  638. Textrec(Pipe_out).userdata[1]:=P_OUT;
  639. TextRec(Pipe_out).OpenFunc:=@OpenPipe;
  640. TextRec(Pipe_out).InOutFunc:=@IOPipe;
  641. TextRec(Pipe_out).FlushFunc:=@FlushPipe;
  642. TextRec(Pipe_out).CloseFunc:=@ClosePipe;
  643. AssignPipe:=0;
  644. end;
  645. Function AssignPipe(var pipe_in,pipe_out:file):cint;
  646. {
  647. Sets up a pair of file variables, which act as a pipe. The first one can
  648. be read from, the second one can be written to.
  649. If the operation was unsuccesful,
  650. }
  651. var
  652. f_in,f_out : cint;
  653. begin
  654. if AssignPipe(f_in,f_out)=-1 then
  655. exit(-1);
  656. { Set up input }
  657. Assign(Pipe_in,'');
  658. Filerec(Pipe_in).Handle:=f_in;
  659. Filerec(Pipe_in).Mode:=fmInput;
  660. Filerec(Pipe_in).recsize:=1;
  661. Filerec(Pipe_in).userdata[1]:=P_IN;
  662. { Set up output }
  663. Assign(Pipe_out,'');
  664. Filerec(Pipe_out).Handle:=f_out;
  665. Filerec(Pipe_out).Mode:=fmoutput;
  666. Filerec(Pipe_out).recsize:=1;
  667. Filerec(Pipe_out).userdata[1]:=P_OUT;
  668. AssignPipe:=0;
  669. end;
  670. Function PCloseText(Var F:text):cint;
  671. {
  672. May not use @PClose due overloading
  673. }
  674. begin
  675. PCloseText:=PClose(f);
  676. end;
  677. Function POpen(var F:text;const Prog:Ansistring;rw:char):cint;
  678. {
  679. Starts the program in 'Prog' and makes it's input or out put the
  680. other end of a pipe. If rw is 'w' or 'W', then whatever is written to
  681. F, will be read from stdin by the program in 'Prog'. The inverse is true
  682. for 'r' or 'R' : whatever the program in 'Prog' writes to stdout, can be
  683. read from 'f'.
  684. }
  685. var
  686. pipi,
  687. pipo : text;
  688. pid : cint;
  689. pl : ^cint;
  690. {$if not defined(FPC_USE_FPEXEC) or defined(USE_VFORK)}
  691. pp : array[0..3] of pchar;
  692. temp : string[255];
  693. {$endif not FPC_USE_FPEXEC or USE_VFORK}
  694. ret : cint;
  695. begin
  696. rw:=upcase(rw);
  697. if not (rw in ['R','W']) then
  698. begin
  699. FpSetErrno(ESysEnoent);
  700. exit(-1);
  701. end;
  702. ret:=AssignPipe(pipi,pipo);
  703. if ret=-1 then
  704. exit(-1);
  705. {$ifdef USE_VFORK}
  706. pid:=fpvfork;
  707. {$else USE_VFORK}
  708. pid:=fpfork;
  709. {$endif USE_VFORK}
  710. if pid=-1 then
  711. begin
  712. close(pipi);
  713. close(pipo);
  714. exit(-1);
  715. end;
  716. if pid=0 then
  717. begin
  718. { We're in the child }
  719. if rw='W' then
  720. begin
  721. if (textrec(pipi).handle <> stdinputhandle) then
  722. begin
  723. ret:=fpdup2(pipi,input);
  724. {$ifdef USE_VFORK}
  725. fpclose(textrec(pipi).handle);
  726. {$else USE_VFORK}
  727. close(pipi);
  728. {$endif USE_VFORK}
  729. end;
  730. {$ifdef USE_VFORK}
  731. fpclose(textrec(pipo).handle);
  732. {$else USE_VFORK}
  733. close(pipo);
  734. {$endif USE_VFORK}
  735. if ret=-1 then
  736. fpexit(127);
  737. end
  738. else
  739. begin
  740. {$ifdef USE_VFORK}
  741. fpclose(textrec(pipi).handle);
  742. {$else USE_VFORK}
  743. close(pipi);
  744. {$endif USE_VFORK}
  745. if (textrec(pipo).handle <> stdoutputhandle) then
  746. begin
  747. ret:=fpdup2(pipo,output);
  748. {$ifdef USE_VFORK}
  749. fpclose(textrec(pipo).handle);
  750. {$else USE_VFORK}
  751. close(pipo);
  752. {$endif USE_VFORK}
  753. end;
  754. if ret=-1 then
  755. fpexit(127);
  756. end;
  757. {$if defined(FPC_USE_FPEXEC) and not defined(USE_VFORK)}
  758. fpexecl(pchar('/bin/sh'),['-c',Prog]);
  759. {$else}
  760. temp:='/bin/sh'#0'-c'#0;
  761. pp[0]:=@temp[1];
  762. pp[1]:=@temp[9];
  763. pp[2]:=@prog[1];
  764. pp[3]:=Nil;
  765. fpExecve('/bin/sh',@pp,envp);
  766. {$endif}
  767. fpexit(127);
  768. end
  769. else
  770. begin
  771. { We're in the parent }
  772. if rw='W' then
  773. begin
  774. close(pipi);
  775. f:=pipo;
  776. end
  777. else
  778. begin
  779. close(pipo);
  780. f:=pipi;
  781. end;
  782. textrec(f).bufptr:=@textrec(f).buffer;
  783. {Save the process ID - needed when closing }
  784. pl:=pcint(@textrec(f).userdata[2]);
  785. { avoid alignment error on sparc }
  786. move(pid,pl^,sizeof(pid));
  787. textrec(f).closefunc:=@PCloseText;
  788. end;
  789. POpen:=0;
  790. end;
  791. Function POpen(var F:file;const Prog:Ansistring;rw:char):cint;
  792. {
  793. Starts the program in 'Prog' and makes it's input or out put the
  794. other end of a pipe. If rw is 'w' or 'W', then whatever is written to
  795. F, will be read from stdin by the program in 'Prog'. The inverse is true
  796. for 'r' or 'R' : whatever the program in 'Prog' writes to stdout, can be
  797. read from 'f'.
  798. }
  799. var
  800. pipi,
  801. pipo : file;
  802. pid : cint;
  803. pl : ^cint;
  804. {$if not defined(FPC_USE_FPEXEC) or defined(USE_VFORK)}
  805. pp : array[0..3] of pchar;
  806. temp : string[255];
  807. {$endif not FPC_USE_FPEXEC or USE_VFORK}
  808. ret : cint;
  809. begin
  810. rw:=upcase(rw);
  811. if not (rw in ['R','W']) then
  812. begin
  813. FpSetErrno(ESysEnoent);
  814. exit(-1);
  815. end;
  816. ret:=AssignPipe(pipi,pipo);
  817. if ret=-1 then
  818. exit(-1);
  819. {$ifdef USE_VFORK}
  820. pid:=fpvfork;
  821. {$else USE_VFORK}
  822. pid:=fpfork;
  823. {$endif USE_VFORK}
  824. if pid=-1 then
  825. begin
  826. close(pipi);
  827. close(pipo);
  828. exit(-1);
  829. end;
  830. if pid=0 then
  831. begin
  832. { We're in the child }
  833. if rw='W' then
  834. begin
  835. if (filerec(pipi).handle <> stdinputhandle) then
  836. begin
  837. ret:=fpdup2(filerec(pipi).handle,stdinputhandle);
  838. {$ifdef USE_VFORK}
  839. fpclose(filerec(pipi).handle);
  840. {$else USE_VFORK}
  841. close(pipi);
  842. {$endif USE_VFORK}
  843. end;
  844. {$ifdef USE_VFORK}
  845. fpclose(filerec(pipo).handle);
  846. {$else USE_VFORK}
  847. close(pipo);
  848. {$endif USE_VFORK}
  849. if ret=-1 then
  850. fpexit(127);
  851. end
  852. else
  853. begin
  854. {$ifdef USE_VFORK}
  855. fpclose(filerec(pipi).handle);
  856. {$else USE_VFORK}
  857. close(pipi);
  858. {$endif USE_VFORK}
  859. if (filerec(pipo).handle <> stdoutputhandle) then
  860. begin
  861. ret:=fpdup2(filerec(pipo).handle,stdoutputhandle);
  862. {$ifdef USE_VFORK}
  863. fpclose(filerec(pipo).handle);
  864. {$else USE_VFORK}
  865. close(pipo);
  866. {$endif USE_VFORK}
  867. end;
  868. if ret=-1 then
  869. fpexit(127);
  870. end;
  871. {$if defined(FPC_USE_FPEXEC) and not defined(USE_VFORK)}
  872. fpexecl(pchar('/bin/sh'),['-c',Prog]);
  873. {$else}
  874. temp:='/bin/sh'#0'-c'#0;
  875. pp[0]:=@temp[1];
  876. pp[1]:=@temp[9];
  877. pp[2]:=@prog[1];
  878. pp[3]:=Nil;
  879. fpExecve('/bin/sh',@pp,envp);
  880. {$endif}
  881. fpexit(127);
  882. end
  883. else
  884. begin
  885. { We're in the parent }
  886. if rw='W' then
  887. begin
  888. close(pipi);
  889. f:=pipo;
  890. end
  891. else
  892. begin
  893. close(pipo);
  894. f:=pipi;
  895. end;
  896. {Save the process ID - needed when closing }
  897. pl:=pcint(@filerec(f).userdata[2]);
  898. { avoid alignment error on sparc }
  899. move(pid,pl^,sizeof(pid));
  900. end;
  901. POpen:=0;
  902. end;
  903. Function AssignStream(Var StreamIn,Streamout:text;Const Prog:ansiString;const args : array of ansistring) : cint;
  904. {
  905. Starts the program in 'Prog' and makes its input and output the
  906. other end of two pipes, which are the stdin and stdout of a program
  907. specified in 'Prog'.
  908. streamout can be used to write to the program, streamin can be used to read
  909. the output of the program. See the following diagram :
  910. Parent Child
  911. STreamout --> Input
  912. Streamin <-- Output
  913. Return value is the process ID of the process being spawned, or -1 in case of failure.
  914. }
  915. var
  916. pipi,
  917. pipo : text;
  918. pid : cint;
  919. pl : ^cint;
  920. begin
  921. AssignStream:=-1;
  922. if AssignPipe(streamin,pipo)=-1 Then
  923. exit(-1);
  924. if AssignPipe(pipi,streamout)=-1 Then
  925. begin
  926. close(streamin);
  927. close(pipo);
  928. exit(-1);
  929. end;
  930. pid:=fpfork;
  931. if pid=-1 then
  932. begin
  933. close(pipi);
  934. close(pipo);
  935. close (streamin);
  936. close (streamout);
  937. exit;
  938. end;
  939. if pid=0 then
  940. begin
  941. { We're in the child }
  942. { Close what we don't need }
  943. close(streamout);
  944. close(streamin);
  945. if fpdup2(pipi,input)=-1 Then
  946. halt(127);
  947. close(pipi);
  948. If fpdup2(pipo,output)=-1 Then
  949. halt (127);
  950. close(pipo);
  951. fpExecl(Prog,args);
  952. halt(127);
  953. end
  954. else
  955. begin
  956. { we're in the parent}
  957. close(pipo);
  958. close(pipi);
  959. {Save the process ID - needed when closing }
  960. pl:=pcint(@textrec(StreamIn).userdata[2]);
  961. { avoid alignment error on sparc }
  962. move(pid,pl^,sizeof(pid));
  963. textrec(StreamIn).closefunc:=@PCloseText;
  964. {Save the process ID - needed when closing }
  965. pl:=pcint(@textrec(StreamOut).userdata[2]);
  966. { avoid alignment error on sparc }
  967. move(pid,pl^,sizeof(pid));
  968. textrec(StreamOut).closefunc:=@PCloseText;
  969. AssignStream:=Pid;
  970. end;
  971. end;
  972. Function AssignStream(Var StreamIn,Streamout,streamerr:text;Const Prog:ansiString;const args : array of ansistring) : cint;
  973. {
  974. Starts the program in 'prog' and makes its input, output and error output the
  975. other end of three pipes, which are the stdin, stdout and stderr of a program
  976. specified in 'prog'.
  977. StreamOut can be used to write to the program, StreamIn can be used to read
  978. the output of the program, StreamErr reads the error output of the program.
  979. See the following diagram :
  980. Parent Child
  981. StreamOut --> StdIn (input)
  982. StreamIn <-- StdOut (output)
  983. StreamErr <-- StdErr (error output)
  984. }
  985. var
  986. PipeIn, PipeOut, PipeErr: text;
  987. pid: cint;
  988. pl: ^cint;
  989. begin
  990. AssignStream := -1;
  991. // Assign pipes
  992. if AssignPipe(StreamIn, PipeOut)=-1 Then
  993. Exit(-1);
  994. If AssignPipe(StreamErr, PipeErr)=-1 Then
  995. begin
  996. Close(StreamIn);
  997. Close(PipeOut);
  998. exit(-1);
  999. end;
  1000. if AssignPipe(PipeIn, StreamOut)=-1 Then
  1001. begin
  1002. Close(StreamIn);
  1003. Close(PipeOut);
  1004. Close(StreamErr);
  1005. Close(PipeErr);
  1006. exit(-1);
  1007. end;
  1008. // Fork
  1009. pid := fpFork;
  1010. if pid=-1 then begin
  1011. Close(StreamIn);
  1012. Close(PipeOut);
  1013. Close(StreamErr);
  1014. Close(PipeErr);
  1015. Close(PipeIn);
  1016. Close(StreamOut);
  1017. exit(-1);
  1018. end;
  1019. if pid = 0 then begin
  1020. // *** We are in the child ***
  1021. // Close what we don not need
  1022. Close(StreamOut);
  1023. Close(StreamIn);
  1024. Close(StreamErr);
  1025. // Connect pipes
  1026. if fpdup2(PipeIn, Input)=-1 Then
  1027. Halt(127);
  1028. Close(PipeIn);
  1029. if fpdup2(PipeOut, Output)=-1 Then
  1030. Halt(127);
  1031. Close(PipeOut);
  1032. if fpdup2(PipeErr, StdErr)=-1 Then
  1033. Halt(127);
  1034. Close(PipeErr);
  1035. // Execute program
  1036. fpExecl(Prog,args);
  1037. Halt(127);
  1038. end else begin
  1039. // *** We are in the parent ***
  1040. Close(PipeErr);
  1041. Close(PipeOut);
  1042. Close(PipeIn);
  1043. // Save the process ID - needed when closing
  1044. pl := pcint(@TextRec(StreamIn).userdata[2]);
  1045. { avoid alignment error on sparc }
  1046. move(pid,pl^,sizeof(pid));
  1047. TextRec(StreamIn).closefunc := @PCloseText;
  1048. // Save the process ID - needed when closing
  1049. pl := pcint(@TextRec(StreamOut).userdata[2]);
  1050. { avoid alignment error on sparc }
  1051. move(pid,pl^,sizeof(pid));
  1052. TextRec(StreamOut).closefunc := @PCloseText;
  1053. // Save the process ID - needed when closing
  1054. pl := pcint(@TextRec(StreamErr).userdata[2]);
  1055. { avoid alignment error on sparc }
  1056. move(pid,pl^,sizeof(pid));
  1057. TextRec(StreamErr).closefunc := @PCloseText;
  1058. AssignStream := pid;
  1059. end;
  1060. end;
  1061. {******************************************************************************
  1062. General information calls
  1063. ******************************************************************************}
  1064. {$ifdef Linux}
  1065. Function GetDomainName:String; { linux only!}
  1066. // domainname is a glibc extension.
  1067. {
  1068. Get machines domain name. Returns empty string if not set.
  1069. }
  1070. Var
  1071. Sysn : utsname;
  1072. begin
  1073. If fpUname(sysn)<>0 then
  1074. getdomainname:=''
  1075. else
  1076. getdomainname:=strpas(@Sysn.domain[0]);
  1077. end;
  1078. {$endif}
  1079. {$ifdef sunos}
  1080. { sunos doesn't support GetDomainName, see also
  1081. http://www.sun.com/software/solaris/programs/abi/appcert_faq.xml#q18
  1082. }
  1083. Function GetDomainName:String;
  1084. begin
  1085. GetDomainName:='';
  1086. end;
  1087. {$endif sunos}
  1088. {$ifdef BSD}
  1089. function intGetDomainName(Name:PChar; NameLen:Cint):cint;
  1090. {$ifndef FPC_USE_LIBC}
  1091. external name 'FPC_SYSC_GETDOMAINNAME';
  1092. {$else FPC_USE_LIBC}
  1093. cdecl; external clib name 'getdomainname';
  1094. {$endif FPC_USE_LIBC}
  1095. Function GetDomainName:String; { linux only!}
  1096. // domainname is a glibc extension.
  1097. {
  1098. Get machines domain name. Returns empty string if not set.
  1099. }
  1100. begin
  1101. if intGetDomainName(@getdomainname[1],255)=-1 then
  1102. getdomainname:=''
  1103. else
  1104. getdomainname[0]:=chr(strlen(@getdomainname[1]));
  1105. end;
  1106. {$endif}
  1107. Function GetHostName:String;
  1108. {
  1109. Get machines name. Returns empty string if not set.
  1110. }
  1111. Var
  1112. Sysn : utsname;
  1113. begin
  1114. If fpuname(sysn)=-1 then
  1115. gethostname:=''
  1116. else
  1117. gethostname:=strpas(@Sysn.nodename[0]);
  1118. end;
  1119. {******************************************************************************
  1120. Signal handling calls
  1121. ******************************************************************************}
  1122. procedure SigRaise(sig:integer);
  1123. begin
  1124. fpKill(fpGetPid,Sig);
  1125. end;
  1126. {******************************************************************************
  1127. Utility calls
  1128. ******************************************************************************}
  1129. Function FSearch(const path:AnsiString;dirlist:Ansistring;CurrentDirStrategy:TFSearchOption):AnsiString;
  1130. {
  1131. Searches for a file 'path' in the list of direcories in 'dirlist'.
  1132. returns an empty string if not found. Wildcards are NOT allowed.
  1133. If dirlist is empty, it is set to '.'
  1134. This function tries to make FSearch use ansistrings, and decrease
  1135. stringhandling overhead at the same time.
  1136. }
  1137. Var
  1138. mydir,NewDir : ansistring;
  1139. p1 : cint;
  1140. Info : Stat;
  1141. i,j : cint;
  1142. p : pchar;
  1143. Begin
  1144. if CurrentDirStrategy=CurrentDirectoryFirst Then
  1145. Dirlist:='.:'+dirlist; {Make sure current dir is first to be searched.}
  1146. if CurrentDirStrategy=CurrentDirectoryLast Then
  1147. Dirlist:=dirlist+':.'; {Make sure current dir is last to be searched.}
  1148. {Replace ':' and ';' with #0}
  1149. for p1:=1 to length(dirlist) do
  1150. if (dirlist[p1]=':') or (dirlist[p1]=';') then
  1151. dirlist[p1]:=#0;
  1152. {Check for WildCards}
  1153. If (Pos('?',Path) <> 0) or (Pos('*',Path) <> 0) Then
  1154. FSearch:='' {No wildcards allowed in these things.}
  1155. Else
  1156. Begin
  1157. p:=pchar(dirlist);
  1158. i:=length(dirlist);
  1159. j:=1;
  1160. Repeat
  1161. mydir:=ansistring(p);
  1162. if (length(mydir)>0) and (mydir[length(mydir)]<>'/') then
  1163. mydir:=mydir+'/';
  1164. NewDir:=mydir+Path;
  1165. if (FpStat(NewDir,Info)>=0) and
  1166. (not fpS_ISDIR(Info.st_Mode)) then
  1167. Begin
  1168. If Pos('./',NewDir)=1 Then
  1169. Delete(NewDir,1,2);
  1170. {DOS strips off an initial .\}
  1171. End
  1172. Else
  1173. NewDir:='';
  1174. while (j<=i) and (p^<>#0) do begin inc(j); inc(p); end;
  1175. if p^=#0 then inc(p);
  1176. Until (j>=i) or (Length(NewDir) > 0);
  1177. FSearch:=NewDir;
  1178. End;
  1179. End;
  1180. Function FSearch(const path:AnsiString;dirlist:Ansistring):AnsiString;
  1181. Begin
  1182. FSearch:=FSearch(path,dirlist,CurrentDirectoryFirst);
  1183. End;
  1184. {--------------------------------
  1185. Stat.Mode Macro's
  1186. --------------------------------}
  1187. Initialization
  1188. {$IFNDEF DONT_READ_TIMEZONE}
  1189. InitLocalTime;
  1190. {$endif}
  1191. finalization
  1192. {$IFNDEF DONT_READ_TIMEZONE}
  1193. DoneLocalTime;
  1194. {$endif}
  1195. End.