unixutil.pp 12 KB

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