unix.pp 50 KB

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