unixutil.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. <What does this file>
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit unixutil;
  13. interface
  14. var
  15. Tzseconds : Longint;
  16. Type
  17. ComStr = String[255];
  18. PathStr = String[255];
  19. DirStr = String[255];
  20. NameStr = String[255];
  21. ExtStr = String[255];
  22. Function Dirname(Const path:pathstr):pathstr;
  23. Function StringToPPChar(S: PChar;ReserveEntries:integer):ppchar;
  24. Function StringToPPChar(Var S:String;ReserveEntries:integer):ppchar;
  25. Function StringToPPChar(Var S:AnsiString;ReserveEntries:integer):ppchar;
  26. function ArrayStringToPPchar(const S:Array of AnsiString;reserveentries:Longint):ppchar; // const ?
  27. Function Basename(Const path:pathstr;Const suf:pathstr):pathstr;
  28. Function FNMatch(const Pattern,Name:string):Boolean;
  29. Function GetFS (var T:Text):longint;
  30. Function GetFS(Var F:File):longint;
  31. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  32. Function LocalToEpoch(year,month,day,hour,minute,second:Word):Longint;
  33. Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
  34. Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
  35. Function GregorianToJulian(Year,Month,Day:Longint):LongInt;
  36. implementation
  37. {$I textrec.inc}
  38. {$i filerec.inc}
  39. function ArrayStringToPPchar(const S:Array of AnsiString;reserveentries:Longint):ppchar; // const ?
  40. // Extra allocate reserveentries pchar's at the beginning (default param=0 after 1.0.x ?)
  41. // Note: for internal use by skilled programmers only
  42. // if "s" goes out of scope in the parent procedure, the pointer is dangling.
  43. var p : ppchar;
  44. Res,
  45. i : LongInt;
  46. begin
  47. if High(s)<Low(s) Then Exit(NIL);
  48. Getmem(p,sizeof(pchar)*(high(s)-low(s)+ReserveEntries+2)); // one more for NIL, one more
  49. // for cmd
  50. if p=nil then
  51. begin
  52. {$ifdef xunix}
  53. fpseterrno(ESysEnomem);
  54. {$endif}
  55. exit(NIL);
  56. end;
  57. for i:=low(s) to high(s) do
  58. p[i+Reserveentries]:=pchar(s[i]);
  59. p[high(s)+1+Reserveentries]:=nil;
  60. ArrayStringToPPchar:=p;
  61. end;
  62. Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
  63. Var
  64. DotPos,SlashPos,i : longint;
  65. Begin
  66. SlashPos:=0;
  67. DotPos:=256;
  68. i:=Length(Path);
  69. While (i>0) and (SlashPos=0) Do
  70. Begin
  71. If (DotPos=256) and (Path[i]='.') Then
  72. begin
  73. DotPos:=i;
  74. end;
  75. If (Path[i]='/') Then
  76. SlashPos:=i;
  77. Dec(i);
  78. End;
  79. Ext:=Copy(Path,DotPos,255);
  80. Dir:=Copy(Path,1,SlashPos);
  81. Name:=Copy(Path,SlashPos + 1,DotPos - SlashPos - 1);
  82. End;
  83. Function Dirname(Const path:pathstr):pathstr;
  84. {
  85. This function returns the directory part of a complete path.
  86. Unless the directory is root '/', The last character is not
  87. a slash.
  88. }
  89. var
  90. Dir : PathStr;
  91. Name : NameStr;
  92. Ext : ExtStr;
  93. begin
  94. FSplit(Path,Dir,Name,Ext);
  95. if length(Dir)>1 then
  96. Delete(Dir,length(Dir),1);
  97. DirName:=Dir;
  98. end;
  99. Function StringToPPChar(Var S:String;ReserveEntries:integer):ppchar;
  100. {
  101. Create a PPChar to structure of pchars which are the arguments specified
  102. in the string S. Especially usefull for creating an ArgV for Exec-calls
  103. Note that the string S is destroyed by this call.
  104. }
  105. begin
  106. S:=S+#0;
  107. StringToPPChar:=StringToPPChar(pchar(@S[1]),ReserveEntries);
  108. end;
  109. Function StringToPPChar(Var S:AnsiString;ReserveEntries:integer):ppchar;
  110. {
  111. Create a PPChar to structure of pchars which are the arguments specified
  112. in the string S. Especially usefull for creating an ArgV for Exec-calls
  113. }
  114. begin
  115. StringToPPChar:=StringToPPChar(PChar(S),ReserveEntries);
  116. end;
  117. Function StringToPPChar(S: PChar;ReserveEntries:integer):ppchar;
  118. var
  119. i,nr : longint;
  120. Buf : ^char;
  121. p : ppchar;
  122. InQuote : Boolean;
  123. begin
  124. buf:=s;
  125. nr:=1;
  126. InQuote:=false;
  127. while (buf^<>#0) do // count nr of args
  128. begin
  129. while (buf^ in [' ',#9,#10]) do // Kill separators.
  130. inc(buf);
  131. inc(nr);
  132. if buf^='"' Then // quotes argument?
  133. begin
  134. inc(buf);
  135. while not (buf^ in [#0,'"']) do // then end of argument is end of string or next quote
  136. inc(buf);
  137. if buf^='"' then // skip closing quote.
  138. inc(buf);
  139. end
  140. else
  141. begin // else std
  142. while not (buf^ in [' ',#0,#9,#10]) do
  143. inc(buf);
  144. end;
  145. end;
  146. getmem(p,(ReserveEntries+nr)*sizeof(pchar));
  147. StringToPPChar:=p;
  148. if p=nil then
  149. begin
  150. {$ifdef xunix}
  151. fpseterrno(ESysEnomem);
  152. {$endif}
  153. exit;
  154. end;
  155. for i:=1 to ReserveEntries do inc(p); // skip empty slots
  156. buf:=s;
  157. while (buf^<>#0) do
  158. begin
  159. while (buf^ in [' ',#9,#10]) do // Kill separators.
  160. begin
  161. buf^:=#0;
  162. inc(buf);
  163. end;
  164. if buf^='"' Then // quotes argument?
  165. begin
  166. inc(buf);
  167. p^:=buf;
  168. inc(p);
  169. p^:=nil;
  170. while not (buf^ in [#0,'"']) do // then end of argument is end of string or next quote
  171. inc(buf);
  172. if buf^='"' then // skip closing quote.
  173. begin
  174. buf^:=#0;
  175. inc(buf);
  176. end;
  177. end
  178. else
  179. begin
  180. p^:=buf;
  181. inc(p);
  182. p^:=nil;
  183. while not (buf^ in [' ',#0,#9,#10]) do
  184. inc(buf);
  185. end;
  186. end;
  187. end;
  188. Function Basename(Const path:pathstr;Const suf:pathstr):pathstr;
  189. {
  190. This function returns the filename part of a complete path. If suf is
  191. supplied, it is cut off the filename.
  192. }
  193. var
  194. Dir : PathStr;
  195. Name : NameStr;
  196. Ext : ExtStr;
  197. begin
  198. FSplit(Path,Dir,Name,Ext);
  199. if Suf<>Ext then
  200. Name:=Name+Ext;
  201. BaseName:=Name;
  202. end;
  203. Function FNMatch(const Pattern,Name:string):Boolean;
  204. Var
  205. LenPat,LenName : longint;
  206. Function DoFNMatch(i,j:longint):Boolean;
  207. Var
  208. Found : boolean;
  209. Begin
  210. Found:=true;
  211. While Found and (i<=LenPat) Do
  212. Begin
  213. Case Pattern[i] of
  214. '?' : Found:=(j<=LenName);
  215. '*' : Begin
  216. {find the next character in pattern, different of ? and *}
  217. while Found do
  218. begin
  219. inc(i);
  220. if i>LenPat then Break;
  221. case Pattern[i] of
  222. '*' : ;
  223. '?' : begin
  224. if j>LenName then begin DoFNMatch:=false; Exit; end;
  225. inc(j);
  226. end;
  227. else
  228. Found:=false;
  229. end;
  230. end;
  231. Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
  232. {Now, find in name the character which i points to, if the * or ?
  233. wasn't the last character in the pattern, else, use up all the
  234. chars in name}
  235. Found:=false;
  236. if (i<=LenPat) then
  237. begin
  238. repeat
  239. {find a letter (not only first !) which maches pattern[i]}
  240. while (j<=LenName) and (name[j]<>pattern[i]) do
  241. inc (j);
  242. if (j<LenName) then
  243. begin
  244. if DoFnMatch(i+1,j+1) then
  245. begin
  246. i:=LenPat;
  247. j:=LenName;{we can stop}
  248. Found:=true;
  249. Break;
  250. end else
  251. inc(j);{We didn't find one, need to look further}
  252. end else
  253. if j=LenName then
  254. begin
  255. Found:=true;
  256. Break;
  257. end;
  258. { This 'until' condition must be j>LenName, not j>=LenName.
  259. That's because when we 'need to look further' and
  260. j = LenName then loop must not terminate. }
  261. until (j>LenName);
  262. end else
  263. begin
  264. j:=LenName;{we can stop}
  265. Found:=true;
  266. end;
  267. end;
  268. else {not a wildcard character in pattern}
  269. Found:=(j<=LenName) and (pattern[i]=name[j]);
  270. end;
  271. inc(i);
  272. inc(j);
  273. end;
  274. DoFnMatch:=Found and (j>LenName);
  275. end;
  276. Begin {start FNMatch}
  277. LenPat:=Length(Pattern);
  278. LenName:=Length(Name);
  279. FNMatch:=DoFNMatch(1,1);
  280. End;
  281. Function GetFS (var T:Text):longint;
  282. {
  283. Get File Descriptor of a text file.
  284. }
  285. begin
  286. if textrec(t).mode=fmclosed then
  287. exit(-1)
  288. else
  289. GETFS:=textrec(t).Handle
  290. end;
  291. Function GetFS(Var F:File):longint;
  292. {
  293. Get File Descriptor of an unTyped file.
  294. }
  295. begin
  296. { Handle and mode are on the same place in textrec and filerec. }
  297. if filerec(f).mode=fmclosed then
  298. exit(-1)
  299. else
  300. GETFS:=filerec(f).Handle
  301. end;
  302. Const
  303. {Date Translation}
  304. C1970=2440588;
  305. D0 = 1461;
  306. D1 = 146097;
  307. D2 =1721119;
  308. Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
  309. Var
  310. YYear,XYear,Temp,TempMonth : LongInt;
  311. Begin
  312. Temp:=((JulianDN-D2) shl 2)-1;
  313. JulianDN:=Temp Div D1;
  314. XYear:=(Temp Mod D1) or 3;
  315. YYear:=(XYear Div D0);
  316. Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
  317. Day:=((Temp Mod 153)+5) Div 5;
  318. TempMonth:=Temp Div 153;
  319. If TempMonth>=10 Then
  320. Begin
  321. inc(YYear);
  322. dec(TempMonth,12);
  323. End;
  324. inc(TempMonth,3);
  325. Month := TempMonth;
  326. Year:=YYear+(JulianDN*100);
  327. end;
  328. Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
  329. {
  330. Transforms Epoch time into local time (hour, minute,seconds)
  331. }
  332. Var
  333. DateNum: LongInt;
  334. Begin
  335. inc(Epoch,TZSeconds);
  336. Datenum:=(Epoch Div 86400) + c1970;
  337. JulianToGregorian(DateNum,Year,Month,day);
  338. Epoch:=Abs(Epoch Mod 86400);
  339. Hour:=Epoch Div 3600;
  340. Epoch:=Epoch Mod 3600;
  341. Minute:=Epoch Div 60;
  342. Second:=Epoch Mod 60;
  343. End;
  344. Function LocalToEpoch(year,month,day,hour,minute,second:Word):Longint;
  345. {
  346. Transforms local time (year,month,day,hour,minutes,second) to Epoch time
  347. (seconds since 00:00, january 1 1970, corrected for local time zone)
  348. }
  349. Begin
  350. LocalToEpoch:=((GregorianToJulian(Year,Month,Day)-c1970)*86400)+
  351. (LongInt(Hour)*3600)+(Longint(Minute)*60)+Second-TZSeconds;
  352. End;
  353. Function GregorianToJulian(Year,Month,Day:Longint):LongInt;
  354. Var
  355. Century,XYear: LongInt;
  356. Begin
  357. If Month<=2 Then
  358. Begin
  359. Dec(Year);
  360. Inc(Month,12);
  361. End;
  362. Dec(Month,3);
  363. Century:=(longint(Year Div 100)*D1) shr 2;
  364. XYear:=(longint(Year Mod 100)*D0) shr 2;
  365. GregorianToJulian:=((((Month*153)+2) div 5)+Day)+D2+XYear+Century;
  366. End;
  367. end.
  368. {
  369. $Log$
  370. Revision 1.6 2004-06-12 13:48:08 michael
  371. + Patch from Michalis Kamburelis for FNMatch
  372. revision 1.5
  373. date: 2004/03/15 20:43:07; author: peter; state: Exp; lines: +1 -1
  374. * fix memory allocation in stringtoppchar
  375. revision 1.4
  376. date: 2004/02/13 10:50:23; author: marco; state: Exp; lines: +80 -22
  377. * Hopefully last large changes to fpexec and friends.
  378. - naming conventions changes from Michael.
  379. - shell functions get alternative under ifdef.
  380. - arraystring function moves to unixutil
  381. - unixutil now regards quotes in stringtoppchar.
  382. - sysutils/unix get executeprocess(ansi,array of ansi), and
  383. both executeprocess functions are fixed
  384. - Sysutils/win32 get executeprocess(ansi,array of ansi)
  385. revision 1.3
  386. date: 2003/11/03 09:42:28; author: marco; state: Exp; lines: +3 -3
  387. * Peter's Cardinal<->Longint fixes patch
  388. revision 1.2
  389. date: 2003/09/17 19:07:44; author: marco; state: Exp; lines: +80 -0
  390. * more fixes for Unix<->unixutil
  391. revision 1.1
  392. date: 2003/09/17 17:24:45; author: marco; state: Exp;
  393. * Initial version. Plain vanilla copy and paste from unix.pp
  394. }