unix.pp 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Michael Van Canneyt,
  5. BSD parts (c) 2000 by Marco van de Voort
  6. members of the Free Pascal development team.
  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 Unix;
  14. Interface
  15. Uses BaseUnix;
  16. {// i ostypes.inc}
  17. { Get Types and Constants }
  18. {$i sysconst.inc}
  19. {$i systypes.inc}
  20. { Get System call numbers and error-numbers}
  21. {$i sysnr.inc}
  22. {$i errno.inc}
  23. {$I signal.inc}
  24. {$i ostypes.inc}
  25. var
  26. // ErrNo,
  27. LinuxError : Longint;
  28. {********************
  29. Process
  30. ********************}
  31. const
  32. { For getting/setting priority }
  33. Prio_Process = 0;
  34. Prio_PGrp = 1;
  35. Prio_User = 2;
  36. {$ifdef Solaris}
  37. WNOHANG = $100;
  38. WUNTRACED = $4;
  39. {$ELSE}
  40. WNOHANG = $1;
  41. WUNTRACED = $2;
  42. __WCLONE = $80000000;
  43. {$ENDIF}
  44. {********************
  45. File
  46. ********************}
  47. Const
  48. P_IN = 1;
  49. P_OUT = 2;
  50. Const
  51. LOCK_SH = 1;
  52. LOCK_EX = 2;
  53. LOCK_UN = 8;
  54. LOCK_NB = 4;
  55. Type
  56. Tpipe = array[1..2] of longint;
  57. pglob = ^tglob;
  58. tglob = record
  59. name : pchar;
  60. next : pglob;
  61. end;
  62. ComStr = String[255];
  63. PathStr = String[255];
  64. DirStr = String[255];
  65. NameStr = String[255];
  66. ExtStr = String[255];
  67. const
  68. { For File control mechanism }
  69. F_GetFd = 1;
  70. F_SetFd = 2;
  71. F_GetFl = 3;
  72. F_SetFl = 4;
  73. {$ifdef Solaris}
  74. F_DupFd = 0;
  75. F_Dup2Fd = 9;
  76. F_GetOwn = 23;
  77. F_SetOwn = 24;
  78. F_GetLk = 14;
  79. F_SetLk = 6;
  80. F_SetLkW = 7;
  81. F_FreeSp = 11;
  82. {$else}
  83. F_GetLk = 5;
  84. F_SetLk = 6;
  85. F_SetLkW = 7;
  86. F_SetOwn = 8;
  87. F_GetOwn = 9;
  88. {$endif}
  89. {********************
  90. IOCtl(TermIOS)
  91. ********************}
  92. {Is too freebsd/Linux specific}
  93. {$I termios.inc}
  94. {********************
  95. Info
  96. ********************}
  97. Type
  98. TSysinfo = packed record
  99. uptime : longint;
  100. loads : array[1..3] of longint;
  101. totalram,
  102. freeram,
  103. sharedram,
  104. bufferram,
  105. totalswap,
  106. freeswap : longint;
  107. procs : integer;
  108. s : string[18];
  109. end;
  110. PSysInfo = ^TSysInfo;
  111. {******************************************************************************
  112. Procedure/Functions
  113. ******************************************************************************}
  114. {**************************
  115. Time/Date Handling
  116. ***************************}
  117. var
  118. tzdaylight : boolean;
  119. tzseconds : longint;
  120. tzname : array[boolean] of pchar;
  121. { timezone support }
  122. procedure GetLocalTimezone(timer:longint;var leap_correct,leap_hit:longint);
  123. procedure GetLocalTimezone(timer:longint);
  124. procedure ReadTimezoneFile(fn:string);
  125. function GetTimezoneFile:string;
  126. //Procedure GetTimeOfDay(var tv:timeval);
  127. //Function GetTimeOfDay:longint;
  128. Function GetEpochTime: longint;
  129. Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
  130. Function LocalToEpoch(year,month,day,hour,minute,second:Word):Longint;
  131. procedure GetTime(var hour,min,sec,msec,usec:word);
  132. procedure GetTime(var hour,min,sec,sec100:word);
  133. procedure GetTime(var hour,min,sec:word);
  134. Procedure GetDate(Var Year,Month,Day:Word);
  135. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  136. function SetTime(Hour,Min,Sec:word) : Boolean;
  137. function SetDate(Year,Month,Day:Word) : Boolean;
  138. function SetDateTime(Year,Month,Day,hour,minute,second:Word) : Boolean;
  139. {**************************
  140. Process Handling
  141. ***************************}
  142. function CreateShellArgV(const prog:string):ppchar;
  143. function CreateShellArgV(const prog:Ansistring):ppchar;
  144. //Procedure Execve(Path: pathstr;args:ppchar;ep:ppchar);
  145. //Procedure Execve(Path: AnsiString;args:ppchar;ep:ppchar);
  146. //Procedure Execve(path: pchar;args:ppchar;ep:ppchar);
  147. Procedure Execv(const path:pathstr;args:ppchar);
  148. Procedure Execv(const path: AnsiString;args:ppchar);
  149. Procedure Execvp(Path: Pathstr;Args:ppchar;Ep:ppchar);
  150. Procedure Execvp(Path: AnsiString; Args:ppchar;Ep:ppchar);
  151. Procedure Execl(const Todo: String);
  152. Procedure Execl(const Todo: Ansistring);
  153. Procedure Execle(Todo: String;Ep:ppchar);
  154. Procedure Execle(Todo: AnsiString;Ep:ppchar);
  155. Procedure Execlp(Todo: string;Ep:ppchar);
  156. Procedure Execlp(Todo: Ansistring;Ep:ppchar);
  157. Function Shell(const Command:String):Longint;
  158. Function Shell(const Command:AnsiString):Longint;
  159. {Clone for FreeBSD is copied from the LinuxThread port, and rfork based}
  160. function Clone(func:TCloneFunc;sp:pointer;flags:longint;args:pointer):longint;
  161. Function WaitProcess(Pid:longint):Longint; { like WaitPid(PID,@result,0) Handling of Signal interrupts (errno=EINTR), returning the Exitcode of Process (>=0) or -Status if terminated}
  162. Function WIFSTOPPED(Status: Integer): Boolean;
  163. Function W_EXITCODE(ReturnCode, Signal: Integer): Integer;
  164. Function W_STOPCODE(Signal: Integer): Integer;
  165. {**************************
  166. File Handling
  167. ***************************}
  168. Function fdFlush (fd : Longint) : Boolean;
  169. Function Flock (fd,mode : longint) : boolean;
  170. Function Flock (var T : text;mode : longint) : boolean;
  171. Function Flock (var F : File;mode : longint) : boolean;
  172. Function StatFS(Path:Pathstr;Var Info:tstatfs):Boolean;
  173. Function StatFS(Fd: Longint;Var Info:tstatfs):Boolean;
  174. Function Select(N:cint;readfds,writefds,exceptfds:pfdset;TimeOut:cint):cint;
  175. Function SelectText(var T:Text;TimeOut :PTimeVal):Longint;
  176. Function SelectText(var T:Text;TimeOut :Longint):Longint;
  177. {**************************
  178. Directory Handling
  179. ***************************}
  180. procedure SeekDir(p:pdir;off:longint);
  181. function TellDir(p:pdir):longint;
  182. {**************************
  183. Pipe/Fifo/Stream
  184. ***************************}
  185. Function AssignPipe(var pipe_in,pipe_out:longint):boolean;
  186. Function AssignPipe(var pipe_in,pipe_out:text):boolean;
  187. Function AssignPipe(var pipe_in,pipe_out:file):boolean;
  188. Function PClose(Var F:text) : longint;
  189. Function PClose(Var F:file) : longint;
  190. Procedure POpen(var F:text;const Prog:String;rw:char);
  191. Procedure POpen(var F:file;const Prog:String;rw:char);
  192. function AssignStream(Var StreamIn,Streamout:text;Const Prog:String) : longint;
  193. function AssignStream(var StreamIn, StreamOut, StreamErr: Text; const prog: String): LongInt;
  194. {$ifndef BSD}
  195. Function GetDomainName:String;
  196. Function GetHostName:String;
  197. Function Sysinfo(var Info:TSysinfo):Boolean;
  198. {$endif}
  199. {**************************
  200. IOCtl/Termios Functions
  201. ***************************}
  202. Function TCGetAttr(fd:longint;var tios:TermIOS):boolean;
  203. Function TCSetAttr(fd:longint;OptAct:longint;const tios:TermIOS):boolean;
  204. Procedure CFSetISpeed(var tios:TermIOS;speed:Cardinal);
  205. Procedure CFSetOSpeed(var tios:TermIOS;speed:Cardinal);
  206. Procedure CFMakeRaw(var tios:TermIOS);
  207. Function TCSendBreak(fd,duration:longint):boolean;
  208. Function TCSetPGrp(fd,id:longint):boolean;
  209. Function TCGetPGrp(fd:longint;var id:longint):boolean;
  210. Function TCFlush(fd,qsel:longint):boolean;
  211. Function TCDrain(fd:longint):boolean;
  212. Function TCFlow(fd,act:longint):boolean;
  213. Function IsATTY(Handle:Longint):Boolean;
  214. Function IsATTY(f:text):Boolean;
  215. function TTYname(Handle:Longint):string;
  216. function TTYname(var F:Text):string;
  217. {**************************
  218. Memory functions
  219. ***************************}
  220. const
  221. PROT_READ = $1; { page can be read }
  222. PROT_WRITE = $2; { page can be written }
  223. PROT_EXEC = $4; { page can be executed }
  224. PROT_NONE = $0; { page can not be accessed }
  225. MAP_SHARED = $1; { Share changes }
  226. // MAP_PRIVATE = $2; { Changes are private }
  227. MAP_TYPE = $f; { Mask for type of mapping }
  228. MAP_FIXED = $10; { Interpret addr exactly }
  229. // MAP_ANONYMOUS = $20; { don't use a file }
  230. MAP_GROWSDOWN = $100; { stack-like segment }
  231. MAP_DENYWRITE = $800; { ETXTBSY }
  232. MAP_EXECUTABLE = $1000; { mark it as an executable }
  233. MAP_LOCKED = $2000; { pages are locked }
  234. MAP_NORESERVE = $4000; { don't check for reservations }
  235. type
  236. tmmapargs=record
  237. address : longint;
  238. size : longint;
  239. prot : longint;
  240. flags : longint;
  241. fd : longint;
  242. offset : longint;
  243. end;
  244. //function MMap(const m:tmmapargs):longint;
  245. function MUnMap (P : Pointer; Size : Longint) : Boolean;
  246. {**************************
  247. Utility functions
  248. ***************************}
  249. Function Octal(l:longint):longint;
  250. Function FExpand(Const Path: PathStr):PathStr;
  251. Function FSearch(const path:pathstr;dirlist:string):pathstr;
  252. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  253. Function Dirname(Const path:pathstr):pathstr;
  254. Function Basename(Const path:pathstr;Const suf:pathstr):pathstr;
  255. Function FNMatch(const Pattern,Name:string):Boolean;
  256. Function Glob(Const path:pathstr):pglob;
  257. Procedure Globfree(var p:pglob);
  258. Function StringToPPChar(Var S:String):ppchar;
  259. Function StringToPPChar(Var S:AnsiString):ppchar;
  260. Function StringToPPChar(S : Pchar):ppchar;
  261. Function GetFS(var T:Text):longint;
  262. Function GetFS(Var F:File):longint;
  263. {Filedescriptorsets}
  264. {Stat.Mode Types}
  265. Function S_ISLNK(m:word):boolean;
  266. Function S_ISSOCK(m:word):boolean;
  267. {******************************************************************************
  268. Implementation
  269. ******************************************************************************}
  270. {$i unxsysch.inc}
  271. Implementation
  272. Uses Strings;
  273. {$i syscallh.inc}
  274. {$i unxsysc.inc}
  275. {$i ossysch.inc}
  276. { Get the definitions of textrec and filerec }
  277. {$i textrec.inc}
  278. {$i filerec.inc}
  279. { Raw System calls are in Syscalls.inc}
  280. {$i syscalls.inc}
  281. {$i unixsysc.inc} {Syscalls only used in unit Unix/Linux}
  282. Function getenv(name:string):Pchar; external name 'FPC_SYSC_FPGETENV';
  283. {******************************************************************************
  284. Process related calls
  285. ******************************************************************************}
  286. { Most calls of WaitPID do not handle the result correctly, this funktion treats errors more correctly }
  287. Function WaitProcess(Pid:longint):Longint; { like WaitPid(PID,@result,0) Handling of Signal interrupts (errno=EINTR), returning the Exitcode of Process (>=0) or -Status if terminated}
  288. var r,s : LongInt;
  289. begin
  290. repeat
  291. s:=$7F00;
  292. r:=fpWaitPid(Pid,s,0);
  293. until (r<>-1) or (LinuxError<>ESysEINTR);
  294. if (r=-1) or (r=0) then // 0 is not a valid return and should never occur (it means status invalid when using WNOHANG)
  295. WaitProcess:=-1 // return -1 to indicate an error
  296. else
  297. begin
  298. {$ifndef Solaris}
  299. { at least correct for Linux and Darwin (JM) }
  300. if (s and $7F)=0 then // Only this is a valid returncode
  301. {$else}
  302. if (s and $FF)=0 then // Only this is a valid returncode
  303. {$endif}
  304. WaitProcess:=s shr 8
  305. else if (s>0) then // Until now there is not use of the highest bit , but check this for the future
  306. WaitProcess:=-s // normal case
  307. else
  308. WaitProcess:=s; // s<0 should not occur, but wie return also a negativ value
  309. end;
  310. end;
  311. function InternalCreateShellArgV(cmd:pChar; len:longint):ppchar;
  312. {
  313. Create an argv which executes a command in a shell using /bin/sh -c
  314. }
  315. const Shell = '/bin/sh'#0'-c'#0;
  316. var
  317. pp,p : ppchar;
  318. // temp : string; !! Never pass a local var back!!
  319. begin
  320. getmem(pp,4*4);
  321. p:=pp;
  322. p^:=@Shell[1];
  323. inc(p);
  324. p^:=@Shell[9];
  325. inc(p);
  326. getmem(p^,len+1);
  327. move(cmd^,p^^,len);
  328. pchar(p^)[len]:=#0;
  329. inc(p);
  330. p^:=Nil;
  331. InternalCreateShellArgV:=pp;
  332. end;
  333. function CreateShellArgV(const prog:string):ppchar;
  334. begin
  335. CreateShellArgV:=InternalCreateShellArgV(@prog[1],length(prog));
  336. end;
  337. function CreateShellArgV(const prog:Ansistring):ppchar;
  338. {
  339. Create an argv which executes a command in a shell using /bin/sh -c
  340. using a AnsiString;
  341. }
  342. begin
  343. CreateShellArgV:=InternalCreateShellArgV(@prog[1],length(prog)); // if ppc works like delphi this also work when @prog[1] is invalid (len=0)
  344. end;
  345. procedure FreeShellArgV(p:ppchar);
  346. begin
  347. if (p<>nil) then begin
  348. freemem(p[2]);
  349. freemem(p);
  350. end;
  351. end;
  352. Procedure Execv(const path: AnsiString;args:ppchar);
  353. {
  354. Overloaded ansistring version.
  355. }
  356. begin
  357. fpExecVe(Path,Args,envp)
  358. end;
  359. Procedure Execvp(Path: AnsiString; Args:ppchar;Ep:ppchar);
  360. {
  361. Overloaded ansistring version
  362. }
  363. var
  364. thepath : Ansistring;
  365. begin
  366. if path[1]<>'/' then
  367. begin
  368. Thepath:=strpas(fpgetenv('PATH'));
  369. if thepath='' then
  370. thepath:='.';
  371. Path:=FSearch(path,thepath)
  372. end
  373. else
  374. Path:='';
  375. if Path='' then
  376. linuxerror:=ESysEnoent
  377. else
  378. fpExecve(Path,args,ep);{On error linuxerror will get set there}
  379. end;
  380. Procedure Execv(const path:pathstr;args:ppchar);
  381. {
  382. Replaces the current program by the program specified in path,
  383. arguments in args are passed to Execve.
  384. the current environment is passed on.
  385. }
  386. begin
  387. fpExecve(path,args,envp); {On error linuxerror will get set there}
  388. end;
  389. Procedure Execvp(Path:Pathstr;Args:ppchar;Ep:ppchar);
  390. {
  391. This does the same as Execve, only it searches the PATH environment
  392. for the place of the Executable, except when Path starts with a slash.
  393. if the PATH environment variable is unavailable, the path is set to '.'
  394. }
  395. var
  396. thepath : string;
  397. begin
  398. if path[1]<>'/' then
  399. begin
  400. Thepath:=strpas(fpgetenv('PATH'));
  401. if thepath='' then
  402. thepath:='.';
  403. Path:=FSearch(path,thepath)
  404. end
  405. else
  406. Path:='';
  407. if Path='' then
  408. linuxerror:=ESysEnoent
  409. else
  410. fpExecve(Path,args,ep);{On error linuxerror will get set there}
  411. end;
  412. Procedure Execle(Todo:string;Ep:ppchar);
  413. {
  414. This procedure takes the string 'Todo', parses it for command and
  415. command options, and Executes the command with the given options.
  416. The string 'Todo' shoud be of the form 'command options', options
  417. separated by commas.
  418. the PATH environment is not searched for 'command'.
  419. The specified environment(in 'ep') is passed on to command
  420. }
  421. var
  422. p : ppchar;
  423. begin
  424. p:=StringToPPChar(ToDo);
  425. if (p=nil) or (p^=nil) then
  426. exit;
  427. fpExecVE(p^,p,EP);
  428. end;
  429. Procedure Execle(Todo:AnsiString;Ep:ppchar);
  430. {
  431. This procedure takes the string 'Todo', parses it for command and
  432. command options, and Executes the command with the given options.
  433. The string 'Todo' shoud be of the form 'command options', options
  434. separated by commas.
  435. the PATH environment is not searched for 'command'.
  436. The specified environment(in 'ep') is passed on to command
  437. }
  438. var
  439. p : ppchar;
  440. begin
  441. p:=StringToPPChar(ToDo);
  442. if (p=nil) or (p^=nil) then
  443. exit;
  444. fpExecVE(p^,p,EP);
  445. end;
  446. Procedure Execl(const Todo:string);
  447. {
  448. This procedure takes the string 'Todo', parses it for command and
  449. command options, and Executes the command with the given options.
  450. The string 'Todo' shoud be of the form 'command options', options
  451. separated by commas.
  452. the PATH environment is not searched for 'command'.
  453. The current environment is passed on to command
  454. }
  455. begin
  456. ExecLE(ToDo,EnvP);
  457. end;
  458. Procedure Execlp(Todo:string;Ep:ppchar);
  459. {
  460. This procedure takes the string 'Todo', parses it for command and
  461. command options, and Executes the command with the given options.
  462. The string 'Todo' shoud be of the form 'command options', options
  463. separated by commas.
  464. the PATH environment is searched for 'command'.
  465. The specified environment (in 'ep') is passed on to command
  466. }
  467. var
  468. p : ppchar;
  469. begin
  470. p:=StringToPPchar(todo);
  471. if (p=nil) or (p^=nil) then
  472. exit;
  473. ExecVP(StrPas(p^),p,EP);
  474. end;
  475. Procedure Execlp(Todo: Ansistring;Ep:ppchar);
  476. {
  477. Overloaded ansistring version.
  478. }
  479. var
  480. p : ppchar;
  481. begin
  482. p:=StringToPPchar(todo);
  483. if (p=nil) or (p^=nil) then
  484. exit;
  485. ExecVP(StrPas(p^),p,EP);
  486. end;
  487. Function Shell(const Command:String):Longint;
  488. {
  489. Executes the shell, and passes it the string Command. (Through /bin/sh -c)
  490. The current environment is passed to the shell.
  491. It waits for the shell to exit, and returns its exit status.
  492. If the Exec call failed exit status 127 is reported.
  493. }
  494. { Changed the structure:
  495. - the previous version returns an undefinied value if fork fails
  496. - it returns the status of Waitpid instead of the Process returnvalue (see the doc to Shell)
  497. - it uses exit(127) not ExitProc (The Result in pp386: going on Compiling in 2 processes!)
  498. - ShellArgs are now released
  499. - The Old CreateShellArg gives back pointers to a local var
  500. }
  501. var
  502. p : ppchar;
  503. pid : longint;
  504. begin
  505. p:=CreateShellArgv(command);
  506. pid:=fpfork;
  507. if pid=0 then // We are in the Child
  508. begin
  509. {This is the child.}
  510. fpExecve(p^,p,envp);
  511. fpExit(127); // was Exit(127)
  512. end
  513. else if (pid<>-1) then // Successfull started
  514. Shell:=WaitProcess(pid) {Linuxerror is set there}
  515. else // no success
  516. Shell:=-1; // indicate an error
  517. FreeShellArgV(p);
  518. end;
  519. Function Shell(const Command:AnsiString):Longint;
  520. {
  521. AnsiString version of Shell
  522. }
  523. var
  524. p : ppchar;
  525. pid : longint;
  526. begin { Changes as above }
  527. p:=CreateShellArgv(command);
  528. pid:=fpfork;
  529. if pid=0 then // We are in the Child
  530. begin
  531. fpExecve(p^,p,envp);
  532. fpExit(127); // was exit(127)!! We must exit the Process, not the function
  533. end
  534. else if (pid<>-1) then // Successfull started
  535. Shell:=WaitProcess(pid) {Linuxerror is set there}
  536. else // no success
  537. Shell:=-1;
  538. FreeShellArgV(p);
  539. end;
  540. Function WIFSTOPPED(Status: Integer): Boolean;
  541. begin
  542. WIFSTOPPED:=((Status and $FF)=$7F);
  543. end;
  544. Function W_EXITCODE(ReturnCode, Signal: Integer): Integer;
  545. begin
  546. W_EXITCODE:=(ReturnCode shl 8) or Signal;
  547. end;
  548. Function W_STOPCODE(Signal: Integer): Integer;
  549. begin
  550. W_STOPCODE:=(Signal shl 8) or $7F;
  551. end;
  552. {******************************************************************************
  553. Date and Time related calls
  554. ******************************************************************************}
  555. Const
  556. {Date Translation}
  557. C1970=2440588;
  558. D0 = 1461;
  559. D1 = 146097;
  560. D2 =1721119;
  561. Function GregorianToJulian(Year,Month,Day:Longint):LongInt;
  562. Var
  563. Century,XYear: LongInt;
  564. Begin
  565. If Month<=2 Then
  566. Begin
  567. Dec(Year);
  568. Inc(Month,12);
  569. End;
  570. Dec(Month,3);
  571. Century:=(longint(Year Div 100)*D1) shr 2;
  572. XYear:=(longint(Year Mod 100)*D0) shr 2;
  573. GregorianToJulian:=((((Month*153)+2) div 5)+Day)+D2+XYear+Century;
  574. End;
  575. Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
  576. Var
  577. YYear,XYear,Temp,TempMonth : LongInt;
  578. Begin
  579. Temp:=((JulianDN-D2) shl 2)-1;
  580. JulianDN:=Temp Div D1;
  581. XYear:=(Temp Mod D1) or 3;
  582. YYear:=(XYear Div D0);
  583. Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
  584. Day:=((Temp Mod 153)+5) Div 5;
  585. TempMonth:=Temp Div 153;
  586. If TempMonth>=10 Then
  587. Begin
  588. inc(YYear);
  589. dec(TempMonth,12);
  590. End;
  591. inc(TempMonth,3);
  592. Month := TempMonth;
  593. Year:=YYear+(JulianDN*100);
  594. end;
  595. Function GetEpochTime: longint;
  596. {
  597. Get the number of seconds since 00:00, January 1 1970, GMT
  598. the time NOT corrected any way
  599. }
  600. begin
  601. GetEpochTime:=fptime;
  602. end;
  603. Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
  604. {
  605. Transforms Epoch time into local time (hour, minute,seconds)
  606. }
  607. Var
  608. DateNum: LongInt;
  609. Begin
  610. inc(Epoch,TZSeconds);
  611. Datenum:=(Epoch Div 86400) + c1970;
  612. JulianToGregorian(DateNum,Year,Month,day);
  613. Epoch:=Abs(Epoch Mod 86400);
  614. Hour:=Epoch Div 3600;
  615. Epoch:=Epoch Mod 3600;
  616. Minute:=Epoch Div 60;
  617. Second:=Epoch Mod 60;
  618. End;
  619. Function LocalToEpoch(year,month,day,hour,minute,second:Word):Longint;
  620. {
  621. Transforms local time (year,month,day,hour,minutes,second) to Epoch time
  622. (seconds since 00:00, january 1 1970, corrected for local time zone)
  623. }
  624. Begin
  625. LocalToEpoch:=((GregorianToJulian(Year,Month,Day)-c1970)*86400)+
  626. (LongInt(Hour)*3600)+(Minute*60)+Second-TZSeconds;
  627. End;
  628. procedure GetTime(var hour,min,sec,msec,usec:word);
  629. {
  630. Gets the current time, adjusted to local time
  631. }
  632. var
  633. year,day,month:Word;
  634. tz:timeval;
  635. begin
  636. fpgettimeofday(@tz,nil);
  637. EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
  638. msec:=tz.tv_usec div 1000;
  639. usec:=tz.tv_usec mod 1000;
  640. end;
  641. procedure GetTime(var hour,min,sec,sec100:word);
  642. {
  643. Gets the current time, adjusted to local time
  644. }
  645. var
  646. usec : word;
  647. begin
  648. gettime(hour,min,sec,sec100,usec);
  649. sec100:=sec100 div 10;
  650. end;
  651. Procedure GetTime(Var Hour,Min,Sec:Word);
  652. {
  653. Gets the current time, adjusted to local time
  654. }
  655. var
  656. msec,usec : Word;
  657. Begin
  658. gettime(hour,min,sec,msec,usec);
  659. End;
  660. Procedure GetDate(Var Year,Month,Day:Word);
  661. {
  662. Gets the current date, adjusted to local time
  663. }
  664. var
  665. hour,minute,second : word;
  666. Begin
  667. EpochToLocal(fptime,year,month,day,hour,minute,second);
  668. End;
  669. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  670. {
  671. Gets the current date, adjusted to local time
  672. }
  673. Begin
  674. EpochToLocal(fptime,year,month,day,hour,minute,second);
  675. End;
  676. {$ifndef BSD}
  677. {$ifdef linux}
  678. Function stime (t : longint) : Boolean;
  679. var
  680. sr : Syscallregs;
  681. begin
  682. sr.reg2:=longint(@t);
  683. SysCall(Syscall_nr_stime,sr);
  684. linuxerror:=fpgeterrno;;
  685. stime:=linuxerror=0;
  686. end;
  687. {$endif}
  688. {$endif}
  689. {$ifdef BSD}
  690. Function stime (t : longint) : Boolean;
  691. begin
  692. end;
  693. {$endif}
  694. Function SetTime(Hour,Min,Sec:word) : boolean;
  695. var
  696. Year, Month, Day : Word;
  697. begin
  698. GetDate (Year, Month, Day);
  699. SetTime:=stime ( LocalToEpoch ( Year, Month, Day, Hour, Min, Sec ) );
  700. end;
  701. Function SetDate(Year,Month,Day:Word) : boolean;
  702. var
  703. Hour, Minute, Second, Sec100 : Word;
  704. begin
  705. GetTime ( Hour, Minute, Second, Sec100 );
  706. SetDate:=stime ( LocalToEpoch ( Year, Month, Day, Hour, Minute, Second ) );
  707. end;
  708. Function SetDateTime(Year,Month,Day,hour,minute,second:Word) : Boolean;
  709. begin
  710. SetDateTime:=stime ( LocalToEpoch ( Year, Month, Day, Hour, Minute, Second ) );
  711. end;
  712. { Include timezone handling routines which use /usr/share/timezone info }
  713. {$i timezone.inc}
  714. {******************************************************************************
  715. FileSystem calls
  716. ******************************************************************************}
  717. Function fdOpen(pathname:string;flags:longint):longint;
  718. begin
  719. pathname:=pathname+#0;
  720. fdOpen:=fpOpen(@pathname[1],flags,438);
  721. linuxerror:=fpgeterrno;;
  722. end;
  723. Function fdOpen(pathname:string;flags,mode:longint):longint;
  724. begin
  725. pathname:=pathname+#0;
  726. fdOpen:=fpOpen(@pathname[1],flags,mode);
  727. linuxerror:=fpgeterrno;;
  728. end;
  729. Procedure Execl(const Todo:Ansistring);
  730. {
  731. Overloaded AnsiString Version of ExecL.
  732. }
  733. begin
  734. ExecLE(ToDo,EnvP);
  735. end;
  736. {$ifdef BSD}
  737. Function Fcntl(Fd:longint;Cmd:longint):longint;
  738. {
  739. Read or manipulate a file.(See also fcntl (2) )
  740. Possible values for Cmd are :
  741. F_GetFd,F_GetFl,F_GetOwn
  742. Errors are reported in Linuxerror;
  743. If Cmd is different from the allowed values, linuxerror=ESysEninval.
  744. }
  745. begin
  746. if (cmd in [F_GetFd,F_GetFl,F_GetOwn]) then
  747. begin
  748. Linuxerror:=fpfcntl(fd,cmd,0);
  749. if linuxerror=-1 then
  750. begin
  751. linuxerror:=fpgeterrno;;
  752. fcntl:=0;
  753. end
  754. else
  755. begin
  756. fcntl:=linuxerror;
  757. linuxerror:=0;
  758. end;
  759. end
  760. else
  761. begin
  762. linuxerror:=ESysEinval;
  763. Fcntl:=0;
  764. end;
  765. end;
  766. Procedure Fcntl(Fd:longint;Cmd:longint;Arg:Longint);
  767. {
  768. Read or manipulate a file. (See also fcntl (2) )
  769. Possible values for Cmd are :
  770. F_setFd,F_SetFl,F_GetLk,F_SetLk,F_SetLkW,F_SetOwn;
  771. Errors are reported in Linuxerror;
  772. If Cmd is different from the allowed values, linuxerror=ESysEninval.
  773. F_DupFD is not allowed, due to the structure of Files in Pascal.
  774. }
  775. begin
  776. if (cmd in [F_SetFd,F_SetFl,F_GetLk,F_SetLk,F_SetLkw,F_SetOwn]) then
  777. begin
  778. fpfcntl(fd,cmd,arg);
  779. linuxerror:=fpgeterrno;;
  780. end
  781. else
  782. linuxerror:=ESysEinval;
  783. end;
  784. {$endif}
  785. Function Fcntl(var Fd:Text;Cmd:longint):longint;
  786. begin
  787. Fcntl := Fcntl(textrec(Fd).handle, Cmd);
  788. end;
  789. Procedure Fcntl(var Fd:Text;Cmd,Arg:Longint);
  790. begin
  791. Fcntl(textrec(Fd).handle, Cmd, Arg);
  792. end;
  793. Function Flock (var T : text;mode : longint) : boolean;
  794. begin
  795. Flock:=Flock(TextRec(T).Handle,mode);
  796. end;
  797. Function Flock (var F : File;mode : longint) : boolean;
  798. begin
  799. Flock:=Flock(FileRec(F).Handle,mode);
  800. end;
  801. Function Select(N:cint;readfds,writefds,exceptfds:pfdset;TimeOut:cint):cint;
  802. {
  803. Select checks whether the file descriptor sets in readfs/writefs/exceptfs
  804. have changed.
  805. This function allows specification of a timeout as a longint.
  806. }
  807. var
  808. p : PTimeVal;
  809. tv : TimeVal;
  810. begin
  811. if TimeOut=-1 then
  812. p:=nil
  813. else
  814. begin
  815. tv.tv_Sec:=Timeout div 1000;
  816. tv.tv_Usec:=(Timeout mod 1000)*1000;
  817. p:=@tv;
  818. end;
  819. Select:=fpSelect(N,Readfds,WriteFds,ExceptFds,p);
  820. end;
  821. Function SelectText(var T:Text;TimeOut :PTimeval):Longint;
  822. Var
  823. F:TfdSet;
  824. begin
  825. if textrec(t).mode=fmclosed then
  826. begin
  827. LinuxError:=ESysEBADF;
  828. exit(-1);
  829. end;
  830. Fpfdemptyset(f);
  831. fpfdaddset(f,textrec(T).handle);
  832. if textrec(T).mode=fminput then
  833. SelectText:=fpselect(textrec(T).handle+1,@f,nil,nil,TimeOut)
  834. else
  835. SelectText:=fpselect(textrec(T).handle+1,nil,@f,nil,TimeOut);
  836. end;
  837. Function SelectText(var T:Text;TimeOut :Longint):Longint;
  838. var
  839. p : PTimeVal;
  840. tv : TimeVal;
  841. begin
  842. if TimeOut=-1 then
  843. p:=nil
  844. else
  845. begin
  846. tv.tv_Sec:=Timeout div 1000;
  847. tv.tv_Usec:=(Timeout mod 1000)*1000;
  848. p:=@tv;
  849. end;
  850. SelectText:=SelectText(T,p);
  851. end;
  852. {******************************************************************************
  853. Directory
  854. ******************************************************************************}
  855. procedure SeekDir(p:pdir;off:longint);
  856. begin
  857. if p=nil then
  858. begin
  859. fpseterrno(ESysEBADF);
  860. exit;
  861. end;
  862. {$ifndef bsd}
  863. p^.dd_nextoff:=fplseek(p^.dd_fd,off,seek_set);
  864. {$endif}
  865. p^.dd_size:=0;
  866. p^.dd_loc:=0;
  867. end;
  868. function TellDir(p:pdir):longint;
  869. begin
  870. if p=nil then
  871. begin
  872. fpseterrno(ESysEBADF);
  873. telldir:=-1;
  874. exit;
  875. end;
  876. telldir:=fplseek(p^.dd_fd,0,seek_cur)
  877. { We could try to use the nextoff field here, but on my 1.2.13
  878. kernel, this gives nothing... This may have to do with
  879. the readdir implementation of libc... I also didn't find any trace of
  880. the field in the kernel code itself, So I suspect it is an artifact of libc.
  881. Michael. }
  882. end;
  883. {******************************************************************************
  884. Pipes/Fifo
  885. ******************************************************************************}
  886. Procedure OpenPipe(var F:Text);
  887. begin
  888. case textrec(f).mode of
  889. fmoutput :
  890. if textrec(f).userdata[1]<>P_OUT then
  891. textrec(f).mode:=fmclosed;
  892. fminput :
  893. if textrec(f).userdata[1]<>P_IN then
  894. textrec(f).mode:=fmclosed;
  895. else
  896. textrec(f).mode:=fmclosed;
  897. end;
  898. end;
  899. Procedure IOPipe(var F:text);
  900. begin
  901. case textrec(f).mode of
  902. fmoutput :
  903. begin
  904. { first check if we need something to write, else we may
  905. get a SigPipe when Close() is called (PFV) }
  906. if textrec(f).bufpos>0 then
  907. fpwrite(textrec(f).handle,pchar(textrec(f).bufptr),textrec(f).bufpos);
  908. end;
  909. fminput :
  910. textrec(f).bufend:=fpread(textrec(f).handle,pchar(textrec(f).bufptr),textrec(f).bufsize);
  911. end;
  912. textrec(f).bufpos:=0;
  913. end;
  914. Procedure FlushPipe(var F:Text);
  915. begin
  916. if (textrec(f).mode=fmoutput) and (textrec(f).bufpos<>0) then
  917. IOPipe(f);
  918. textrec(f).bufpos:=0;
  919. end;
  920. Procedure ClosePipe(var F:text);
  921. begin
  922. textrec(f).mode:=fmclosed;
  923. fpclose(textrec(f).handle);
  924. end;
  925. Function AssignPipe(var pipe_in,pipe_out:text):boolean;
  926. {
  927. Sets up a pair of file variables, which act as a pipe. The first one can
  928. be read from, the second one can be written to.
  929. If the operation was unsuccesful, linuxerror is set.
  930. }
  931. var
  932. f_in,f_out : longint;
  933. begin
  934. if not AssignPipe(f_in,f_out) then
  935. begin
  936. AssignPipe:=false;
  937. exit;
  938. end;
  939. { Set up input }
  940. Assign(Pipe_in,'');
  941. Textrec(Pipe_in).Handle:=f_in;
  942. Textrec(Pipe_in).Mode:=fmInput;
  943. Textrec(Pipe_in).userdata[1]:=P_IN;
  944. TextRec(Pipe_in).OpenFunc:=@OpenPipe;
  945. TextRec(Pipe_in).InOutFunc:=@IOPipe;
  946. TextRec(Pipe_in).FlushFunc:=@FlushPipe;
  947. TextRec(Pipe_in).CloseFunc:=@ClosePipe;
  948. { Set up output }
  949. Assign(Pipe_out,'');
  950. Textrec(Pipe_out).Handle:=f_out;
  951. Textrec(Pipe_out).Mode:=fmOutput;
  952. Textrec(Pipe_out).userdata[1]:=P_OUT;
  953. TextRec(Pipe_out).OpenFunc:=@OpenPipe;
  954. TextRec(Pipe_out).InOutFunc:=@IOPipe;
  955. TextRec(Pipe_out).FlushFunc:=@FlushPipe;
  956. TextRec(Pipe_out).CloseFunc:=@ClosePipe;
  957. AssignPipe:=true;
  958. end;
  959. Function AssignPipe(var pipe_in,pipe_out:file):boolean;
  960. {
  961. Sets up a pair of file variables, which act as a pipe. The first one can
  962. be read from, the second one can be written to.
  963. If the operation was unsuccesful, linuxerror is set.
  964. }
  965. var
  966. f_in,f_out : longint;
  967. begin
  968. if not AssignPipe(f_in,f_out) then
  969. begin
  970. AssignPipe:=false;
  971. exit;
  972. end;
  973. { Set up input }
  974. Assign(Pipe_in,'');
  975. Filerec(Pipe_in).Handle:=f_in;
  976. Filerec(Pipe_in).Mode:=fmInput;
  977. Filerec(Pipe_in).recsize:=1;
  978. Filerec(Pipe_in).userdata[1]:=P_IN;
  979. { Set up output }
  980. Assign(Pipe_out,'');
  981. Filerec(Pipe_out).Handle:=f_out;
  982. Filerec(Pipe_out).Mode:=fmoutput;
  983. Filerec(Pipe_out).recsize:=1;
  984. Filerec(Pipe_out).userdata[1]:=P_OUT;
  985. AssignPipe:=true;
  986. end;
  987. Procedure PCloseText(Var F:text);
  988. {
  989. May not use @PClose due overloading
  990. }
  991. begin
  992. PClose(f);
  993. end;
  994. Procedure POpen(var F:text;const Prog:String;rw:char);
  995. {
  996. Starts the program in 'Prog' and makes it's input or out put the
  997. other end of a pipe. If rw is 'w' or 'W', then whatever is written to
  998. F, will be read from stdin by the program in 'Prog'. The inverse is true
  999. for 'r' or 'R' : whatever the program in 'Prog' writes to stdout, can be
  1000. read from 'f'.
  1001. }
  1002. var
  1003. pipi,
  1004. pipo : text;
  1005. pid : longint;
  1006. pl : ^longint;
  1007. pp : ppchar;
  1008. begin
  1009. LinuxError:=0;
  1010. rw:=upcase(rw);
  1011. if not (rw in ['R','W']) then
  1012. begin
  1013. LinuxError:=ESysEnoent;
  1014. exit;
  1015. end;
  1016. AssignPipe(pipi,pipo);
  1017. if Linuxerror<>0 then
  1018. exit;
  1019. pid:=fpfork;
  1020. if linuxerror<>0 then
  1021. begin
  1022. close(pipi);
  1023. close(pipo);
  1024. exit;
  1025. end;
  1026. if pid=0 then
  1027. begin
  1028. { We're in the child }
  1029. if rw='W' then
  1030. begin
  1031. close(pipo);
  1032. fpdup2(pipi,input);
  1033. close(pipi);
  1034. if linuxerror<>0 then
  1035. halt(127);
  1036. end
  1037. else
  1038. begin
  1039. close(pipi);
  1040. fpdup2(pipo,output);
  1041. close(pipo);
  1042. if linuxerror<>0 then
  1043. halt(127);
  1044. end;
  1045. pp:=createshellargv(prog);
  1046. fpExecve(pp^,pp,envp);
  1047. halt(127);
  1048. end
  1049. else
  1050. begin
  1051. { We're in the parent }
  1052. if rw='W' then
  1053. begin
  1054. close(pipi);
  1055. f:=pipo;
  1056. textrec(f).bufptr:=@textrec(f).buffer;
  1057. end
  1058. else
  1059. begin
  1060. close(pipo);
  1061. f:=pipi;
  1062. textrec(f).bufptr:=@textrec(f).buffer;
  1063. end;
  1064. {Save the process ID - needed when closing }
  1065. pl:=@(textrec(f).userdata[2]);
  1066. pl^:=pid;
  1067. textrec(f).closefunc:=@PCloseText;
  1068. end;
  1069. end;
  1070. Procedure POpen(var F:file;const Prog:String;rw:char);
  1071. {
  1072. Starts the program in 'Prog' and makes it's input or out put the
  1073. other end of a pipe. If rw is 'w' or 'W', then whatever is written to
  1074. F, will be read from stdin by the program in 'Prog'. The inverse is true
  1075. for 'r' or 'R' : whatever the program in 'Prog' writes to stdout, can be
  1076. read from 'f'.
  1077. }
  1078. var
  1079. pipi,
  1080. pipo : file;
  1081. pid : longint;
  1082. pl : ^longint;
  1083. p,pp : ppchar;
  1084. temp : string[255];
  1085. begin
  1086. LinuxError:=0;
  1087. rw:=upcase(rw);
  1088. if not (rw in ['R','W']) then
  1089. begin
  1090. LinuxError:=ESysEnoent;
  1091. exit;
  1092. end;
  1093. AssignPipe(pipi,pipo);
  1094. if Linuxerror<>0 then
  1095. exit;
  1096. pid:=fpfork;
  1097. if linuxerror<>0 then
  1098. begin
  1099. close(pipi);
  1100. close(pipo);
  1101. exit;
  1102. end;
  1103. if pid=0 then
  1104. begin
  1105. { We're in the child }
  1106. if rw='W' then
  1107. begin
  1108. close(pipo);
  1109. fpdup2(filerec(pipi).handle,stdinputhandle);
  1110. close(pipi);
  1111. if linuxerror<>0 then
  1112. halt(127);
  1113. end
  1114. else
  1115. begin
  1116. close(pipi);
  1117. fpdup2(filerec(pipo).handle,stdoutputhandle);
  1118. close(pipo);
  1119. if linuxerror<>0 then
  1120. halt(127);
  1121. end;
  1122. getmem(pp,sizeof(pchar)*4);
  1123. temp:='/bin/sh'#0'-c'#0+prog+#0;
  1124. p:=pp;
  1125. p^:=@temp[1];
  1126. inc(p);
  1127. p^:=@temp[9];
  1128. inc(p);
  1129. p^:=@temp[12];
  1130. inc(p);
  1131. p^:=Nil;
  1132. fpExecve(ansistring('/bin/sh'),pp,envp);
  1133. halt(127);
  1134. end
  1135. else
  1136. begin
  1137. { We're in the parent }
  1138. if rw='W' then
  1139. begin
  1140. close(pipi);
  1141. f:=pipo;
  1142. end
  1143. else
  1144. begin
  1145. close(pipo);
  1146. f:=pipi;
  1147. end;
  1148. {Save the process ID - needed when closing }
  1149. pl:=@(filerec(f).userdata[2]);
  1150. pl^:=pid;
  1151. end;
  1152. end;
  1153. Function AssignStream(Var StreamIn,Streamout:text;Const Prog:String) : longint;
  1154. {
  1155. Starts the program in 'Prog' and makes its input and output the
  1156. other end of two pipes, which are the stdin and stdout of a program
  1157. specified in 'Prog'.
  1158. streamout can be used to write to the program, streamin can be used to read
  1159. the output of the program. See the following diagram :
  1160. Parent Child
  1161. STreamout --> Input
  1162. Streamin <-- Output
  1163. Return value is the process ID of the process being spawned, or -1 in case of failure.
  1164. }
  1165. var
  1166. pipi,
  1167. pipo : text;
  1168. pid : longint;
  1169. pl : ^Longint;
  1170. begin
  1171. LinuxError:=0;
  1172. AssignStream:=-1;
  1173. AssignPipe(streamin,pipo);
  1174. if Linuxerror<>0 then
  1175. exit;
  1176. AssignPipe(pipi,streamout);
  1177. if Linuxerror<>0 then
  1178. exit;
  1179. pid:=fpfork;
  1180. if linuxerror<>0 then
  1181. begin
  1182. close(pipi);
  1183. close(pipo);
  1184. close (streamin);
  1185. close (streamout);
  1186. exit;
  1187. end;
  1188. if pid=0 then
  1189. begin
  1190. { We're in the child }
  1191. { Close what we don't need }
  1192. close(streamout);
  1193. close(streamin);
  1194. fpdup2(pipi,input);
  1195. if linuxerror<>0 then
  1196. halt(127);
  1197. close(pipi);
  1198. fpdup2(pipo,output);
  1199. if linuxerror<>0 then
  1200. halt (127);
  1201. close(pipo);
  1202. Execl(Prog);
  1203. halt(127);
  1204. end
  1205. else
  1206. begin
  1207. { we're in the parent}
  1208. close(pipo);
  1209. close(pipi);
  1210. {Save the process ID - needed when closing }
  1211. pl:=@(textrec(StreamIn).userdata[2]);
  1212. pl^:=pid;
  1213. textrec(StreamIn).closefunc:=@PCloseText;
  1214. {Save the process ID - needed when closing }
  1215. pl:=@(textrec(StreamOut).userdata[2]);
  1216. pl^:=pid;
  1217. textrec(StreamOut).closefunc:=@PCloseText;
  1218. AssignStream:=Pid;
  1219. end;
  1220. end;
  1221. function AssignStream(var StreamIn, StreamOut, StreamErr: Text; const prog: String): LongInt;
  1222. {
  1223. Starts the program in 'prog' and makes its input, output and error output the
  1224. other end of three pipes, which are the stdin, stdout and stderr of a program
  1225. specified in 'prog'.
  1226. StreamOut can be used to write to the program, StreamIn can be used to read
  1227. the output of the program, StreamErr reads the error output of the program.
  1228. See the following diagram :
  1229. Parent Child
  1230. StreamOut --> StdIn (input)
  1231. StreamIn <-- StdOut (output)
  1232. StreamErr <-- StdErr (error output)
  1233. }
  1234. var
  1235. PipeIn, PipeOut, PipeErr: text;
  1236. pid: LongInt;
  1237. pl: ^LongInt;
  1238. begin
  1239. LinuxError := 0;
  1240. AssignStream := -1;
  1241. // Assign pipes
  1242. AssignPipe(StreamIn, PipeOut);
  1243. if LinuxError <> 0 then exit;
  1244. AssignPipe(StreamErr, PipeErr);
  1245. if LinuxError <> 0 then begin
  1246. Close(StreamIn);
  1247. Close(PipeOut);
  1248. exit;
  1249. end;
  1250. AssignPipe(PipeIn, StreamOut);
  1251. if LinuxError <> 0 then begin
  1252. Close(StreamIn);
  1253. Close(PipeOut);
  1254. Close(StreamErr);
  1255. Close(PipeErr);
  1256. exit;
  1257. end;
  1258. // Fork
  1259. pid := fpFork;
  1260. if LinuxError <> 0 then begin
  1261. Close(StreamIn);
  1262. Close(PipeOut);
  1263. Close(StreamErr);
  1264. Close(PipeErr);
  1265. Close(PipeIn);
  1266. Close(StreamOut);
  1267. exit;
  1268. end;
  1269. if pid = 0 then begin
  1270. // *** We are in the child ***
  1271. // Close what we don not need
  1272. Close(StreamOut);
  1273. Close(StreamIn);
  1274. Close(StreamErr);
  1275. // Connect pipes
  1276. fpdup2(PipeIn, Input);
  1277. if LinuxError <> 0 then Halt(127);
  1278. Close(PipeIn);
  1279. fpdup2(PipeOut, Output);
  1280. if LinuxError <> 0 then Halt(127);
  1281. Close(PipeOut);
  1282. fpdup2(PipeErr, StdErr);
  1283. if LinuxError <> 0 then Halt(127);
  1284. Close(PipeErr);
  1285. // Execute program
  1286. Execl(Prog);
  1287. Halt(127);
  1288. end else begin
  1289. // *** We are in the parent ***
  1290. Close(PipeErr);
  1291. Close(PipeOut);
  1292. Close(PipeIn);
  1293. // Save the process ID - needed when closing
  1294. pl := @(TextRec(StreamIn).userdata[2]);
  1295. pl^ := pid;
  1296. TextRec(StreamIn).closefunc := @PCloseText;
  1297. // Save the process ID - needed when closing
  1298. pl := @(TextRec(StreamOut).userdata[2]);
  1299. pl^ := pid;
  1300. TextRec(StreamOut).closefunc := @PCloseText;
  1301. // Save the process ID - needed when closing
  1302. pl := @(TextRec(StreamErr).userdata[2]);
  1303. pl^ := pid;
  1304. TextRec(StreamErr).closefunc := @PCloseText;
  1305. AssignStream := pid;
  1306. end;
  1307. end;
  1308. {******************************************************************************
  1309. General information calls
  1310. ******************************************************************************}
  1311. {$ifndef BSD}
  1312. Function GetDomainName:String; { linux only!}
  1313. // domainname is a glibc extension.
  1314. {
  1315. Get machines domain name. Returns empty string if not set.
  1316. }
  1317. Var
  1318. Sysn : utsname;
  1319. begin
  1320. fpUname(Sysn);
  1321. linuxerror:=fpgeterrno;;
  1322. If linuxerror<>0 then
  1323. getdomainname:=''
  1324. else
  1325. getdomainname:=strpas(@Sysn.domain[0]);
  1326. end;
  1327. {$endif}
  1328. Function GetHostName:String;
  1329. {
  1330. Get machines name. Returns empty string if not set.
  1331. }
  1332. Var
  1333. Sysn : utsname;
  1334. begin
  1335. fpuname(Sysn);
  1336. linuxerror:=fpgeterrno;;
  1337. If linuxerror<>0 then
  1338. gethostname:=''
  1339. else
  1340. gethostname:=strpas(@Sysn.nodename[0]);
  1341. end;
  1342. {******************************************************************************
  1343. Signal handling calls
  1344. ******************************************************************************}
  1345. procedure SigRaise(sig:integer);
  1346. begin
  1347. fpKill(fpGetPid,Sig);
  1348. end;
  1349. {******************************************************************************
  1350. IOCtl and Termios calls
  1351. ******************************************************************************}
  1352. Function TCGetAttr(fd:longint;var tios:TermIOS):boolean;
  1353. begin
  1354. {$ifndef BSD}
  1355. TCGetAttr:=fpIOCtl(fd,TCGETS,@tios)>0;
  1356. {$else}
  1357. TCGETAttr:=fpIoCtl(Fd,TIOCGETA,@tios)>0;
  1358. {$endif}
  1359. end;
  1360. Function TCSetAttr(fd:longint;OptAct:longint;const tios:TermIOS):boolean;
  1361. var
  1362. nr:longint;
  1363. begin
  1364. {$ifndef BSD}
  1365. case OptAct of
  1366. TCSANOW : nr:=TCSETS;
  1367. TCSADRAIN : nr:=TCSETSW;
  1368. TCSAFLUSH : nr:=TCSETSF;
  1369. {$else}
  1370. case OptAct of
  1371. TCSANOW : nr:=TIOCSETA;
  1372. TCSADRAIN : nr:=TIOCSETAW;
  1373. TCSAFLUSH : nr:=TIOCSETAF;
  1374. {$endif}
  1375. else
  1376. begin
  1377. fpsetErrNo(ESysEINVAL);
  1378. TCSetAttr:=false;
  1379. exit;
  1380. end;
  1381. end;
  1382. TCSetAttr:=fpIOCtl(fd,nr,@Tios)>0;
  1383. end;
  1384. Procedure CFSetISpeed(var tios:TermIOS;speed:Cardinal);
  1385. begin
  1386. {$ifndef BSD}
  1387. tios.c_cflag:=(tios.c_cflag and (not CBAUD)) or speed;
  1388. {$else}
  1389. tios.c_ispeed:=speed; {Probably the Bxxxx speed constants}
  1390. {$endif}
  1391. end;
  1392. Procedure CFSetOSpeed(var tios:TermIOS;speed:Cardinal);
  1393. begin
  1394. {$ifndef BSD}
  1395. CFSetISpeed(tios,speed);
  1396. {$else}
  1397. tios.c_ospeed:=speed;
  1398. {$endif}
  1399. end;
  1400. Procedure CFMakeRaw(var tios:TermIOS);
  1401. begin
  1402. {$ifndef BSD}
  1403. with tios do
  1404. begin
  1405. c_iflag:=c_iflag and (not (IGNBRK or BRKINT or PARMRK or ISTRIP or
  1406. INLCR or IGNCR or ICRNL or IXON));
  1407. c_oflag:=c_oflag and (not OPOST);
  1408. c_lflag:=c_lflag and (not (ECHO or ECHONL or ICANON or ISIG or IEXTEN));
  1409. c_cflag:=(c_cflag and (not (CSIZE or PARENB))) or CS8;
  1410. end;
  1411. {$else}
  1412. with tios do
  1413. begin
  1414. c_iflag:=c_iflag and (not (IMAXBEL or IXOFF or INPCK or BRKINT or
  1415. PARMRK or ISTRIP or INLCR or IGNCR or ICRNL or IXON or
  1416. IGNPAR));
  1417. c_iflag:=c_iflag OR IGNBRK;
  1418. c_oflag:=c_oflag and (not OPOST);
  1419. c_lflag:=c_lflag and (not (ECHO or ECHOE or ECHOK or ECHONL or ICANON or
  1420. ISIG or IEXTEN or NOFLSH or TOSTOP or PENDIN));
  1421. c_cflag:=(c_cflag and (not (CSIZE or PARENB))) or (CS8 OR cread);
  1422. c_cc[VMIN]:=1;
  1423. c_cc[VTIME]:=0;
  1424. end;
  1425. {$endif}
  1426. end;
  1427. Function TCSendBreak(fd,duration:longint):boolean;
  1428. begin
  1429. {$ifndef BSD}
  1430. TCSendBreak:=fpIOCtl(fd,TCSBRK,pointer(duration))>0;
  1431. {$else}
  1432. TCSendBreak:=fpIOCtl(fd,TIOCSBRK,0)>0;
  1433. {$endif}
  1434. end;
  1435. Function TCSetPGrp(fd,id:longint):boolean;
  1436. begin
  1437. TCSetPGrp:=fpIOCtl(fd,TIOCSPGRP,pointer(id))>0;
  1438. end;
  1439. Function TCGetPGrp(fd:longint;var id:longint):boolean;
  1440. begin
  1441. TCGetPGrp:=fpIOCtl(fd,TIOCGPGRP,@id)>0;
  1442. end;
  1443. Function TCDrain(fd:longint):boolean;
  1444. begin
  1445. {$ifndef BSD}
  1446. TCDrain:=fpIOCtl(fd,TCSBRK,pointer(1))>0;
  1447. {$else}
  1448. TCDrain:=fpIOCtl(fd,TIOCDRAIN,0)>0; {Should set timeout to 1 first?}
  1449. {$endif}
  1450. end;
  1451. Function TCFlow(fd,act:longint):boolean;
  1452. begin
  1453. {$ifndef BSD}
  1454. TCFlow:=fpIOCtl(fd,TCXONC,pointer(act))>0;
  1455. {$else}
  1456. case act OF
  1457. TCOOFF : TCFlow:=fpIoctl(fd,TIOCSTOP,0)>0;
  1458. TCOOn : TCFlow:=fpIOctl(Fd,TIOCStart,0)>0;
  1459. TCIOFF : {N/I}
  1460. end;
  1461. {$endif}
  1462. end;
  1463. Function TCFlush(fd,qsel:longint):boolean;
  1464. begin
  1465. {$ifndef BSD}
  1466. TCFlush:=fpIOCtl(fd,TCFLSH,pointer(qsel))>0;
  1467. {$else}
  1468. TCFlush:=fpIOCtl(fd,TIOCFLUSH,pointer(qsel))>0;
  1469. {$endif}
  1470. end;
  1471. Function IsATTY(Handle:Longint):Boolean;
  1472. {
  1473. Check if the filehandle described by 'handle' is a TTY (Terminal)
  1474. }
  1475. var
  1476. t : Termios;
  1477. begin
  1478. IsAtty:=TCGetAttr(Handle,t);
  1479. end;
  1480. Function IsATTY(f: text):Boolean;
  1481. {
  1482. Idem as previous, only now for text variables.
  1483. }
  1484. begin
  1485. IsATTY:=IsaTTY(textrec(f).handle);
  1486. end;
  1487. function TTYName(Handle:Longint):string;
  1488. {
  1489. Return the name of the current tty described by handle f.
  1490. returns empty string in case of an error.
  1491. }
  1492. var
  1493. mydev,
  1494. myino : longint;
  1495. st : stat;
  1496. function mysearch(n:string): boolean;
  1497. {searches recursively for the device in the directory given by n,
  1498. returns true if found and sets the name of the device in ttyname}
  1499. var dirstream : pdir;
  1500. d : pdirent;
  1501. name : string;
  1502. st : stat;
  1503. begin
  1504. dirstream:=fpopendir(n);
  1505. if (linuxerror<>0) then
  1506. exit;
  1507. d:=fpReaddir(dirstream^);
  1508. while (d<>nil) do
  1509. begin
  1510. name:=n+'/'+strpas(@(d^.d_name));
  1511. fpstat(name,st);
  1512. if linuxerror=0 then
  1513. begin
  1514. if (fpISDIR(st.st_mode)) and { if it is a directory }
  1515. (strpas(@(d^.d_name))<>'.') and { but not ., .. and fd subdirs }
  1516. (strpas(@(d^.d_name))<>'..') and
  1517. (strpas(@(d^.d_name))<>'') and
  1518. (strpas(@(d^.d_name))<>'fd') then
  1519. begin {we found a directory, search inside it}
  1520. if mysearch(name) then
  1521. begin {the device is here}
  1522. fpclosedir(dirstream^); {then don't continue searching}
  1523. mysearch:=true;
  1524. exit;
  1525. end;
  1526. end
  1527. else if (d^.d_fileno=myino) and (st.st_dev=mydev) then
  1528. begin
  1529. fpclosedir(dirstream^);
  1530. ttyname:=name;
  1531. mysearch:=true;
  1532. exit;
  1533. end;
  1534. end;
  1535. d:=fpReaddir(dirstream^);
  1536. end;
  1537. fpclosedir(dirstream^);
  1538. mysearch:=false;
  1539. end;
  1540. begin
  1541. TTYName:='';
  1542. fpfstat(handle,st);
  1543. if (fpgeterrno<>0) and isatty (handle) then
  1544. exit;
  1545. mydev:=st.st_dev;
  1546. myino:=st.st_ino;
  1547. mysearch('/dev');
  1548. end;
  1549. function TTYName(var F:Text):string;
  1550. {
  1551. Idem as previous, only now for text variables;
  1552. }
  1553. begin
  1554. TTYName:=TTYName(textrec(f).handle);
  1555. end;
  1556. {******************************************************************************
  1557. Utility calls
  1558. ******************************************************************************}
  1559. Function Octal(l:longint):longint;
  1560. {
  1561. Convert an octal specified number to decimal;
  1562. }
  1563. var
  1564. octnr,
  1565. oct : longint;
  1566. begin
  1567. octnr:=0;
  1568. oct:=0;
  1569. while (l>0) do
  1570. begin
  1571. oct:=oct or ((l mod 10) shl octnr);
  1572. l:=l div 10;
  1573. inc(octnr,3);
  1574. end;
  1575. Octal:=oct;
  1576. end;
  1577. Function StringToPPChar(S: PChar):ppchar;
  1578. var
  1579. nr : longint;
  1580. Buf : ^char;
  1581. p : ppchar;
  1582. begin
  1583. buf:=s;
  1584. nr:=0;
  1585. while(buf^<>#0) do
  1586. begin
  1587. while (buf^ in [' ',#9,#10]) do
  1588. inc(buf);
  1589. inc(nr);
  1590. while not (buf^ in [' ',#0,#9,#10]) do
  1591. inc(buf);
  1592. end;
  1593. getmem(p,nr*4);
  1594. StringToPPChar:=p;
  1595. if p=nil then
  1596. begin
  1597. LinuxError:=ESysEnomem;
  1598. exit;
  1599. end;
  1600. buf:=s;
  1601. while (buf^<>#0) do
  1602. begin
  1603. while (buf^ in [' ',#9,#10]) do
  1604. begin
  1605. buf^:=#0;
  1606. inc(buf);
  1607. end;
  1608. p^:=buf;
  1609. inc(p);
  1610. p^:=nil;
  1611. while not (buf^ in [' ',#0,#9,#10]) do
  1612. inc(buf);
  1613. end;
  1614. end;
  1615. {
  1616. function FExpand (const Path: PathStr): PathStr;
  1617. - declared in fexpand.inc
  1618. }
  1619. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  1620. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
  1621. {$I fexpand.inc}
  1622. {$UNDEF FPC_FEXPAND_GETENVPCHAR}
  1623. {$UNDEF FPC_FEXPAND_TILDE}
  1624. Function FSearch(const path:pathstr;dirlist:string):pathstr;
  1625. {
  1626. Searches for a file 'path' in the list of direcories in 'dirlist'.
  1627. returns an empty string if not found. Wildcards are NOT allowed.
  1628. If dirlist is empty, it is set to '.'
  1629. }
  1630. Var
  1631. NewDir : PathStr;
  1632. p1 : Longint;
  1633. Info : Stat;
  1634. Begin
  1635. {Replace ':' with ';'}
  1636. for p1:=1to length(dirlist) do
  1637. if dirlist[p1]=':' then
  1638. dirlist[p1]:=';';
  1639. {Check for WildCards}
  1640. If (Pos('?',Path) <> 0) or (Pos('*',Path) <> 0) Then
  1641. FSearch:='' {No wildcards allowed in these things.}
  1642. Else
  1643. Begin
  1644. Dirlist:='.;'+dirlist;{Make sure current dir is first to be searched.}
  1645. Repeat
  1646. p1:=Pos(';',DirList);
  1647. If p1=0 Then
  1648. p1:=255;
  1649. NewDir:=Copy(DirList,1,P1 - 1);
  1650. if NewDir[Length(NewDir)]<>'/' then
  1651. NewDir:=NewDir+'/';
  1652. NewDir:=NewDir+Path;
  1653. Delete(DirList,1,p1);
  1654. if FpStat(NewDir,Info)>=0 then
  1655. Begin
  1656. If Pos('./',NewDir)=1 Then
  1657. Delete(NewDir,1,2);
  1658. {DOS strips off an initial .\}
  1659. End
  1660. Else
  1661. NewDir:='';
  1662. Until (DirList='') or (Length(NewDir) > 0);
  1663. FSearch:=NewDir;
  1664. End;
  1665. End;
  1666. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  1667. Var
  1668. DotPos,SlashPos,i : longint;
  1669. Begin
  1670. SlashPos:=0;
  1671. DotPos:=256;
  1672. i:=Length(Path);
  1673. While (i>0) and (SlashPos=0) Do
  1674. Begin
  1675. If (DotPos=256) and (Path[i]='.') Then
  1676. begin
  1677. DotPos:=i;
  1678. end;
  1679. If (Path[i]='/') Then
  1680. SlashPos:=i;
  1681. Dec(i);
  1682. End;
  1683. Ext:=Copy(Path,DotPos,255);
  1684. Dir:=Copy(Path,1,SlashPos);
  1685. Name:=Copy(Path,SlashPos + 1,DotPos - SlashPos - 1);
  1686. End;
  1687. Function Dirname(Const path:pathstr):pathstr;
  1688. {
  1689. This function returns the directory part of a complete path.
  1690. Unless the directory is root '/', The last character is not
  1691. a slash.
  1692. }
  1693. var
  1694. Dir : PathStr;
  1695. Name : NameStr;
  1696. Ext : ExtStr;
  1697. begin
  1698. FSplit(Path,Dir,Name,Ext);
  1699. if length(Dir)>1 then
  1700. Delete(Dir,length(Dir),1);
  1701. DirName:=Dir;
  1702. end;
  1703. Function StringToPPChar(Var S:String):ppchar;
  1704. {
  1705. Create a PPChar to structure of pchars which are the arguments specified
  1706. in the string S. Especially usefull for creating an ArgV for Exec-calls
  1707. Note that the string S is destroyed by this call.
  1708. }
  1709. begin
  1710. S:=S+#0;
  1711. StringToPPChar:=StringToPPChar(@S[1]);
  1712. end;
  1713. Function StringToPPChar(Var S:AnsiString):ppchar;
  1714. {
  1715. Create a PPChar to structure of pchars which are the arguments specified
  1716. in the string S. Especially usefull for creating an ArgV for Exec-calls
  1717. }
  1718. begin
  1719. StringToPPChar:=StringToPPChar(PChar(S));
  1720. end;
  1721. Function Basename(Const path:pathstr;Const suf:pathstr):pathstr;
  1722. {
  1723. This function returns the filename part of a complete path. If suf is
  1724. supplied, it is cut off the filename.
  1725. }
  1726. var
  1727. Dir : PathStr;
  1728. Name : NameStr;
  1729. Ext : ExtStr;
  1730. begin
  1731. FSplit(Path,Dir,Name,Ext);
  1732. if Suf<>Ext then
  1733. Name:=Name+Ext;
  1734. BaseName:=Name;
  1735. end;
  1736. Function FNMatch(const Pattern,Name:string):Boolean;
  1737. Var
  1738. LenPat,LenName : longint;
  1739. Function DoFNMatch(i,j:longint):Boolean;
  1740. Var
  1741. Found : boolean;
  1742. Begin
  1743. Found:=true;
  1744. While Found and (i<=LenPat) Do
  1745. Begin
  1746. Case Pattern[i] of
  1747. '?' : Found:=(j<=LenName);
  1748. '*' : Begin
  1749. {find the next character in pattern, different of ? and *}
  1750. while Found and (i<LenPat) do
  1751. begin
  1752. inc(i);
  1753. case Pattern[i] of
  1754. '*' : ;
  1755. '?' : begin
  1756. inc(j);
  1757. Found:=(j<=LenName);
  1758. end;
  1759. else
  1760. Found:=false;
  1761. end;
  1762. end;
  1763. {Now, find in name the character which i points to, if the * or ?
  1764. wasn't the last character in the pattern, else, use up all the
  1765. chars in name}
  1766. Found:=true;
  1767. if (i<=LenPat) then
  1768. begin
  1769. repeat
  1770. {find a letter (not only first !) which maches pattern[i]}
  1771. while (j<=LenName) and (name[j]<>pattern[i]) do
  1772. inc (j);
  1773. if (j<LenName) then
  1774. begin
  1775. if DoFnMatch(i+1,j+1) then
  1776. begin
  1777. i:=LenPat;
  1778. j:=LenName;{we can stop}
  1779. Found:=true;
  1780. end
  1781. else
  1782. inc(j);{We didn't find one, need to look further}
  1783. end;
  1784. until (j>=LenName);
  1785. end
  1786. else
  1787. j:=LenName;{we can stop}
  1788. end;
  1789. else {not a wildcard character in pattern}
  1790. Found:=(j<=LenName) and (pattern[i]=name[j]);
  1791. end;
  1792. inc(i);
  1793. inc(j);
  1794. end;
  1795. DoFnMatch:=Found and (j>LenName);
  1796. end;
  1797. Begin {start FNMatch}
  1798. LenPat:=Length(Pattern);
  1799. LenName:=Length(Name);
  1800. FNMatch:=DoFNMatch(1,1);
  1801. End;
  1802. Procedure Globfree(var p : pglob);
  1803. {
  1804. Release memory occupied by pglob structure, and names in it.
  1805. sets p to nil.
  1806. }
  1807. var
  1808. temp : pglob;
  1809. begin
  1810. while assigned(p) do
  1811. begin
  1812. temp:=p^.next;
  1813. if assigned(p^.name) then
  1814. freemem(p^.name);
  1815. dispose(p);
  1816. p:=temp;
  1817. end;
  1818. end;
  1819. Function Glob(Const path:pathstr):pglob;
  1820. {
  1821. Fills a tglob structure with entries matching path,
  1822. and returns a pointer to it. Returns nil on error,
  1823. linuxerror is set accordingly.
  1824. }
  1825. var
  1826. temp,
  1827. temp2 : string[255];
  1828. thedir : pdir;
  1829. buffer : pdirent;
  1830. root,
  1831. current : pglob;
  1832. begin
  1833. { Get directory }
  1834. temp:=dirname(path);
  1835. if temp='' then
  1836. temp:='.';
  1837. temp:=temp+#0;
  1838. thedir:=fpopendir(@temp[1]);
  1839. if thedir=nil then
  1840. begin
  1841. glob:=nil;
  1842. linuxerror:=fpgeterrno;;
  1843. exit;
  1844. end;
  1845. temp:=basename(path,''); { get the pattern }
  1846. if thedir^.dd_fd<0 then
  1847. begin
  1848. linuxerror:=fpgeterrno;;
  1849. glob:=nil;
  1850. exit;
  1851. end;
  1852. {get the entries}
  1853. root:=nil;
  1854. current:=nil;
  1855. repeat
  1856. buffer:=fpreaddir(thedir^);
  1857. if buffer=nil then
  1858. break;
  1859. temp2:=strpas(@(buffer^.d_name[0]));
  1860. if fnmatch(temp,temp2) then
  1861. begin
  1862. if root=nil then
  1863. begin
  1864. new(root);
  1865. current:=root;
  1866. end
  1867. else
  1868. begin
  1869. new(current^.next);
  1870. current:=current^.next;
  1871. end;
  1872. if current=nil then
  1873. begin
  1874. linuxerror:=ESysENOMEM;
  1875. globfree(root);
  1876. break;
  1877. end;
  1878. current^.next:=nil;
  1879. getmem(current^.name,length(temp2)+1);
  1880. if current^.name=nil then
  1881. begin
  1882. linuxerror:=ESysENOMEM;
  1883. globfree(root);
  1884. break;
  1885. end;
  1886. move(buffer^.d_name[0],current^.name^,length(temp2)+1);
  1887. end;
  1888. until false;
  1889. fpclosedir(thedir^);
  1890. glob:=root;
  1891. end;
  1892. Function GetFS (var T:Text):longint;
  1893. {
  1894. Get File Descriptor of a text file.
  1895. }
  1896. begin
  1897. if textrec(t).mode=fmclosed then
  1898. exit(-1)
  1899. else
  1900. GETFS:=textrec(t).Handle
  1901. end;
  1902. Function GetFS(Var F:File):longint;
  1903. {
  1904. Get File Descriptor of an unTyped file.
  1905. }
  1906. begin
  1907. { Handle and mode are on the same place in textrec and filerec. }
  1908. if filerec(f).mode=fmclosed then
  1909. exit(-1)
  1910. else
  1911. GETFS:=filerec(f).Handle
  1912. end;
  1913. {--------------------------------
  1914. Stat.Mode Macro's
  1915. --------------------------------}
  1916. Function S_ISLNK(m:word):boolean;
  1917. {
  1918. Check mode field of inode for link.
  1919. }
  1920. begin
  1921. S_ISLNK:=(m and STAT_IFMT)=STAT_IFLNK;
  1922. end;
  1923. Function S_ISSOCK(m:word):boolean;
  1924. {
  1925. Check mode field of inode for socket.
  1926. }
  1927. begin
  1928. S_ISSOCK:=(m and STAT_IFMT)=STAT_IFSOCK;
  1929. end;
  1930. Initialization
  1931. InitLocalTime;
  1932. finalization
  1933. DoneLocalTime;
  1934. End.
  1935. {
  1936. $Log$
  1937. Revision 1.32 2003-09-15 20:08:49 marco
  1938. * small fixes. FreeBSD now cycles
  1939. Revision 1.31 2003/09/14 20:15:01 marco
  1940. * Unix reform stage two. Remove all calls from Unix that exist in Baseunix.
  1941. Revision 1.30 2003/07/08 21:23:24 peter
  1942. * sparc fixes
  1943. Revision 1.29 2003/05/30 19:58:40 marco
  1944. * Getting NetBSD/i386 to compile.
  1945. Revision 1.28 2003/05/29 19:16:16 marco
  1946. * fixed a small *BSD gotcha
  1947. Revision 1.27 2003/05/24 20:39:54 jonas
  1948. * fixed ExitCode translation in WaitProcess for Linux and Darwin (and
  1949. probably other BSD's as well)
  1950. Revision 1.26 2003/03/11 08:27:59 michael
  1951. * stringtoppchar should use tabs instead of backspace as delimiter
  1952. Revision 1.25 2002/12/18 16:50:39 marco
  1953. * Unix RTL generic parts. Linux working, *BSD will follow shortly
  1954. Revision 1.24 2002/09/07 16:01:28 peter
  1955. * old logs removed and tabs fixed
  1956. Revision 1.23 2002/08/06 13:30:46 sg
  1957. * replaced some Longints with Cardinals, to mach the C headers
  1958. * updated the termios record
  1959. Revision 1.22 2002/03/05 20:04:25 michael
  1960. + Patch from Sebastian for FCNTL call
  1961. Revision 1.21 2002/01/02 12:22:54 marco
  1962. * Removed ifdef arround getepoch.
  1963. }