mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 04:31:35 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1222 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			1222 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     $Id$
 | |
|     This file is part of the Free Pascal run time library.
 | |
|     Copyright (c) 1999-2000 by Florian Klaempfl
 | |
|     member of the Free Pascal development team
 | |
| 
 | |
|     Sysutils unit for linux
 | |
| 
 | |
|     See the file COPYING.FPC, included in this distribution,
 | |
|     for details about the copyright.
 | |
| 
 | |
|     This program is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | |
| 
 | |
|  **********************************************************************}
 | |
| unit sysutils;
 | |
| interface
 | |
| 
 | |
| {$MODE objfpc}
 | |
| { force ansistrings }
 | |
| {$H+}
 | |
| 
 | |
| {$DEFINE HAS_SLEEP}
 | |
| {$DEFINE HAS_OSERROR}
 | |
| {$DEFINE HAS_OSCONFIG}
 | |
| {$DEFINE HAS_TEMPDIR}
 | |
| {$DEFINE HASUNIX}
 | |
| 
 | |
| uses
 | |
|   Unix,errors,sysconst,Unixtype;
 | |
| 
 | |
| { Include platform independent interface part }
 | |
| {$i sysutilh.inc}
 | |
| 
 | |
| Procedure AddDisk(const path:string);
 | |
| 
 | |
| 
 | |
| implementation
 | |
| 
 | |
| Uses
 | |
|   {$ifdef FPC_USE_LIBC}initc{$ELSE}Syscall{$ENDIF}, Baseunix;
 | |
| 
 | |
| {$Define OS_FILEISREADONLY} // Specific implementation for Unix.
 | |
| 
 | |
| Function getenv(name:string):Pchar; external name 'FPC_SYSC_FPGETENV';
 | |
| 
 | |
| Type
 | |
|   ComStr  = String[255];
 | |
|   PathStr = String[255];
 | |
|   DirStr  = String[255];
 | |
|   NameStr = String[255];
 | |
|   ExtStr  = String[255];
 | |
| 
 | |
| 
 | |
| {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
 | |
| {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
 | |
| 
 | |
| {$I fexpand.inc}
 | |
| 
 | |
| {$UNDEF FPC_FEXPAND_GETENVPCHAR}
 | |
| {$UNDEF FPC_FEXPAND_TILDE}
 | |
| 
 | |
| { Include platform independent implementation part }
 | |
| {$i sysutils.inc}
 | |
| 
 | |
| Const
 | |
| {Date Translation}
 | |
|   C1970=2440588;
 | |
|   D0   =   1461;
 | |
|   D1   = 146097;
 | |
|   D2   =1721119;
 | |
| 
 | |
| 
 | |
| Procedure JulianToGregorian(JulianDN:LongInt;Var Year,Month,Day:Word);
 | |
| Var
 | |
|   YYear,XYear,Temp,TempMonth : LongInt;
 | |
| Begin
 | |
|   Temp:=((JulianDN-D2) shl 2)-1;
 | |
|   JulianDN:=Temp Div D1;
 | |
|   XYear:=(Temp Mod D1) or 3;
 | |
|   YYear:=(XYear Div D0);
 | |
|   Temp:=((((XYear mod D0)+4) shr 2)*5)-3;
 | |
|   Day:=((Temp Mod 153)+5) Div 5;
 | |
|   TempMonth:=Temp Div 153;
 | |
|   If TempMonth>=10 Then
 | |
|    Begin
 | |
|      inc(YYear);
 | |
|      dec(TempMonth,12);
 | |
|    End;
 | |
|   inc(TempMonth,3);  
 | |
|   Month := TempMonth;
 | |
|   Year:=YYear+(JulianDN*100);
 | |
| end;
 | |
| 
 | |
| 
 | |
| 
 | |
| Procedure EpochToLocal(epoch:longint;var year,month,day,hour,minute,second:Word);
 | |
| {
 | |
|   Transforms Epoch time into local time (hour, minute,seconds)
 | |
| }
 | |
| Var
 | |
|   DateNum: LongInt;
 | |
| Begin
 | |
|   inc(Epoch,TZSeconds);
 | |
|   Datenum:=(Epoch Div 86400) + c1970;
 | |
|   JulianToGregorian(DateNum,Year,Month,day);
 | |
|   Epoch:=Abs(Epoch Mod 86400);
 | |
|   Hour:=Epoch Div 3600;
 | |
|   Epoch:=Epoch Mod 3600;
 | |
|   Minute:=Epoch Div 60;
 | |
|   Second:=Epoch Mod 60;
 | |
| End;
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| {****************************************************************************
 | |
|                               File Functions
 | |
| ****************************************************************************}
 | |
| 
 | |
| 
 | |
| 
 | |
| Procedure FSplit(const Path:PathStr;Var Dir:DirStr;Var Name:NameStr;Var Ext:ExtStr);
 | |
| Var
 | |
|   DotPos,SlashPos,i : longint;
 | |
| Begin
 | |
|   SlashPos:=0;
 | |
|   DotPos:=256;
 | |
|   i:=Length(Path);
 | |
|   While (i>0) and (SlashPos=0) Do
 | |
|    Begin
 | |
|      If (DotPos=256) and (Path[i]='.') Then
 | |
|       begin
 | |
|         DotPos:=i;
 | |
|       end;
 | |
|      If (Path[i]='/') Then
 | |
|       SlashPos:=i;
 | |
|      Dec(i);
 | |
|    End;
 | |
|   Ext:=Copy(Path,DotPos,255);
 | |
|   Dir:=Copy(Path,1,SlashPos);
 | |
|   Name:=Copy(Path,SlashPos + 1,DotPos - SlashPos - 1);
 | |
| End;
 | |
| 
 | |
| 
 | |
| Function FileOpen (Const FileName : string; Mode : Integer) : Longint;
 | |
| 
 | |
| Var LinuxFlags : longint;
 | |
| 
 | |
| BEGIN
 | |
|   LinuxFlags:=0;
 | |
|   Case (Mode and 3) of
 | |
|     0 : LinuxFlags:=LinuxFlags or O_RdOnly;
 | |
|     1 : LinuxFlags:=LinuxFlags or O_WrOnly;
 | |
|     2 : LinuxFlags:=LinuxFlags or O_RdWr;
 | |
|   end;
 | |
|   FileOpen:=fpOpen (FileName,LinuxFlags);
 | |
|   //!! We need to set locking based on Mode !!
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileCreate (Const FileName : String) : Longint;
 | |
| 
 | |
| begin
 | |
|   FileCreate:=fpOpen(FileName,O_RdWr or O_Creat or O_Trunc);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileCreate (Const FileName : String;Mode : Longint) : Longint;
 | |
| 
 | |
| Var LinuxFlags : longint;
 | |
| 
 | |
| BEGIN
 | |
|   LinuxFlags:=0;
 | |
|   Case (Mode and 3) of
 | |
|     0 : LinuxFlags:=LinuxFlags or O_RdOnly;
 | |
|     1 : LinuxFlags:=LinuxFlags or O_WrOnly;
 | |
|     2 : LinuxFlags:=LinuxFlags or O_RdWr;
 | |
|   end;
 | |
|   FileCreate:=fpOpen(FileName,LinuxFlags or O_Creat or O_Trunc);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileRead (Handle : Longint; Var Buffer; Count : longint) : Longint;
 | |
| 
 | |
| begin
 | |
|   FileRead:=fpRead (Handle,Buffer,Count);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileWrite (Handle : Longint; const Buffer; Count : Longint) : Longint;
 | |
| 
 | |
| begin
 | |
|   FileWrite:=fpWrite (Handle,Buffer,Count);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileSeek (Handle,FOffset,Origin : Longint) : Longint;
 | |
| 
 | |
| begin
 | |
|   FileSeek:=fplSeek (Handle,FOffset,Origin);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileSeek (Handle : Longint; FOffset,Origin : Int64) : Int64;
 | |
| 
 | |
| begin
 | |
|   {$warning need to add 64bit call }
 | |
|   FileSeek:=fplSeek (Handle,FOffset,Origin);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Procedure FileClose (Handle : Longint);
 | |
| 
 | |
| begin
 | |
|   fpclose(Handle);
 | |
| end;
 | |
| 
 | |
| Function FileTruncate (Handle,Size: Longint) : boolean;
 | |
| 
 | |
| begin
 | |
|   FileTruncate:=fpftruncate(Handle,Size)>=0;
 | |
| end;
 | |
| 
 | |
| Function UnixToWinAge(UnixAge : time_t): Longint;
 | |
| 
 | |
| Var
 | |
|   Y,M,D,hh,mm,ss : word;
 | |
|   
 | |
| begin
 | |
|   EpochToLocal(UnixAge,y,m,d,hh,mm,ss);
 | |
|   Result:=DateTimeToFileDate(EncodeDate(y,m,d)+EncodeTime(hh,mm,ss,0));
 | |
| end;
 | |
|     
 | |
| 
 | |
| Function FileAge (Const FileName : String): Longint;
 | |
| 
 | |
| Var Info : Stat;
 | |
|     Y,M,D,hh,mm,ss : word;
 | |
| 
 | |
| begin
 | |
|   If  fpstat (FileName,Info)<0 then
 | |
|     exit(-1)
 | |
|   else
 | |
|     Result:=UnixToWinAge(info.st_mtime);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileExists (Const FileName : String) : Boolean;
 | |
| 
 | |
| Var Info : Stat;
 | |
| 
 | |
| begin
 | |
|   FileExists:=fpstat(filename,Info)>=0;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function DirectoryExists (Const Directory : String) : Boolean;
 | |
| 
 | |
| Var Info : Stat;
 | |
| 
 | |
| begin
 | |
|   DirectoryExists:=(fpstat(Directory,Info)>=0) and fpS_ISDIR(Info.st_mode);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function LinuxToWinAttr (FN : Pchar; Const Info : Stat) : Longint;
 | |
| 
 | |
| begin
 | |
|   Result:=faArchive;
 | |
|   If fpS_ISDIR(Info.st_mode) then
 | |
|     Result:=Result or faDirectory;
 | |
|   If (FN[0]='.') and (not (FN[1] in [#0,'.']))  then
 | |
|     Result:=Result or faHidden;
 | |
|   If (Info.st_Mode and S_IWUSR)=0 Then
 | |
|      Result:=Result or faReadOnly;
 | |
|   If fpS_ISSOCK(Info.st_mode) or fpS_ISBLK(Info.st_mode) or fpS_ISCHR(Info.st_mode) or fpS_ISFIFO(Info.st_mode) Then
 | |
|      Result:=Result or faSysFile;
 | |
| end;
 | |
| 
 | |
| type
 | |
| 
 | |
|  pglob = ^tglob;
 | |
|   tglob = record
 | |
|     name : pchar;
 | |
|     next : pglob;
 | |
|   end;
 | |
| 
 | |
| Function Dirname(Const path:pathstr):pathstr;
 | |
| {
 | |
|   This function returns the directory part of a complete path.
 | |
|   Unless the directory is root '/', The last character is not
 | |
|   a slash.
 | |
| }
 | |
| var
 | |
|   Dir  : PathStr;
 | |
|   Name : NameStr;
 | |
|   Ext  : ExtStr;
 | |
| begin
 | |
|   FSplit(Path,Dir,Name,Ext);
 | |
|   if length(Dir)>1 then
 | |
|    Delete(Dir,length(Dir),1);
 | |
|   DirName:=Dir;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function Basename(Const path:pathstr;Const suf:pathstr):pathstr;
 | |
| {
 | |
|   This function returns the filename part of a complete path. If suf is
 | |
|   supplied, it is cut off the filename.
 | |
| }
 | |
| var
 | |
|   Dir  : PathStr;
 | |
|   Name : NameStr;
 | |
|   Ext  : ExtStr;
 | |
| begin
 | |
|   FSplit(Path,Dir,Name,Ext);
 | |
|   if Suf<>Ext then
 | |
|    Name:=Name+Ext;
 | |
|   BaseName:=Name;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FNMatch(const Pattern,Name:shortstring):Boolean;
 | |
| Var
 | |
|   LenPat,LenName : longint;
 | |
| 
 | |
|   Function DoFNMatch(i,j:longint):Boolean;
 | |
|   Var
 | |
|     Found : boolean;
 | |
|   Begin
 | |
|   Found:=true;
 | |
|   While Found and (i<=LenPat) Do
 | |
|    Begin
 | |
|      Case Pattern[i] of
 | |
|       '?' : Found:=(j<=LenName);
 | |
|       '*' : Begin
 | |
|             {find the next character in pattern, different of ? and *}
 | |
|               while Found do
 | |
|                 begin
 | |
|                 inc(i);
 | |
|                 if i>LenPat then Break;
 | |
|                 case Pattern[i] of
 | |
|                   '*' : ;
 | |
|                   '?' : begin
 | |
|                           if j>LenName then begin DoFNMatch:=false; Exit; end;
 | |
|                           inc(j);
 | |
|                         end;
 | |
|                 else
 | |
|                   Found:=false;
 | |
|                 end;
 | |
|                end;
 | |
|               Assert((i>LenPat) or ( (Pattern[i]<>'*') and (Pattern[i]<>'?') ));
 | |
|             {Now, find in name the character which i points to, if the * or ?
 | |
|              wasn't the last character in the pattern, else, use up all the
 | |
|              chars in name}
 | |
|               Found:=false;
 | |
|               if (i<=LenPat) then
 | |
|               begin
 | |
|                 repeat
 | |
|                   {find a letter (not only first !) which maches pattern[i]}
 | |
|                   while (j<=LenName) and (name[j]<>pattern[i]) do
 | |
|                     inc (j);
 | |
|                   if (j<LenName) then
 | |
|                   begin
 | |
|                     if DoFnMatch(i+1,j+1) then
 | |
|                     begin
 | |
|                       i:=LenPat;
 | |
|                       j:=LenName;{we can stop}
 | |
|                       Found:=true;
 | |
|                       Break;
 | |
|                     end else
 | |
|                       inc(j);{We didn't find one, need to look further}
 | |
|                   end else
 | |
|                   if j=LenName then
 | |
|                   begin
 | |
|                     Found:=true;
 | |
|                     Break;
 | |
|                   end;
 | |
|                   { This 'until' condition must be j>LenName, not j>=LenName.
 | |
|                     That's because when we 'need to look further' and
 | |
|                     j = LenName then loop must not terminate. }
 | |
|                 until (j>LenName);
 | |
|               end else
 | |
|               begin
 | |
|                 j:=LenName;{we can stop}
 | |
|                 Found:=true;
 | |
|               end;
 | |
|             end;
 | |
|      else {not a wildcard character in pattern}
 | |
|        Found:=(j<=LenName) and (pattern[i]=name[j]);
 | |
|      end;
 | |
|      inc(i);
 | |
|      inc(j);
 | |
|    end;
 | |
|   DoFnMatch:=Found and (j>LenName);
 | |
|   end;
 | |
| 
 | |
| Begin {start FNMatch}
 | |
|   LenPat:=Length(Pattern);
 | |
|   LenName:=Length(Name);
 | |
|   FNMatch:=DoFNMatch(1,1);
 | |
| End;
 | |
| 
 | |
| 
 | |
| Procedure Globfree(var p : pglob);
 | |
| {
 | |
|   Release memory occupied by pglob structure, and names in it.
 | |
|   sets p to nil.
 | |
| }
 | |
| var
 | |
|   temp : pglob;
 | |
| begin
 | |
|   while assigned(p) do
 | |
|    begin
 | |
|      temp:=p^.next;
 | |
|      if assigned(p^.name) then
 | |
|       freemem(p^.name);
 | |
|      dispose(p);
 | |
|      p:=temp;
 | |
|    end;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function Glob(Const path:pathstr):pglob;
 | |
| {
 | |
|   Fills a tglob structure with entries matching path,
 | |
|   and returns a pointer to it. Returns nil on error,
 | |
|   linuxerror is set accordingly.
 | |
| }
 | |
| var
 | |
|   temp,
 | |
|   temp2   : string[255];
 | |
|   thedir  : pdir;
 | |
|   buffer  : pdirent;
 | |
|   root,
 | |
|   current : pglob;
 | |
| begin
 | |
| { Get directory }
 | |
|   temp:=dirname(path);
 | |
|   if temp='' then
 | |
|    temp:='.';
 | |
|   temp:=temp+#0;
 | |
|   thedir:=fpopendir(@temp[1]);
 | |
|   if thedir=nil then
 | |
|     exit(nil);
 | |
|   temp:=basename(path,''); { get the pattern }
 | |
|   if thedir^.dd_fd<0 then
 | |
|      exit(nil);
 | |
| {get the entries}
 | |
|   root:=nil;
 | |
|   current:=nil;
 | |
|   repeat
 | |
|     buffer:=fpreaddir(thedir^);
 | |
|     if buffer=nil then
 | |
|      break;
 | |
|     temp2:=strpas(@(buffer^.d_name[0]));
 | |
|     if fnmatch(temp,temp2) then
 | |
|      begin
 | |
|        if root=nil then
 | |
|         begin
 | |
|           new(root);
 | |
|           current:=root;
 | |
|         end
 | |
|        else
 | |
|         begin
 | |
|           new(current^.next);
 | |
|           current:=current^.next;
 | |
|         end;
 | |
|        if current=nil then
 | |
|         begin
 | |
|            fpseterrno(ESysENOMEM);
 | |
|           globfree(root);
 | |
|           break;
 | |
|         end;
 | |
|        current^.next:=nil;
 | |
|        getmem(current^.name,length(temp2)+1);
 | |
|        if current^.name=nil then
 | |
|         begin
 | |
|           fpseterrno(ESysENOMEM);
 | |
|           globfree(root);
 | |
|           break;
 | |
|         end;
 | |
|        move(buffer^.d_name[0],current^.name^,length(temp2)+1);
 | |
|      end;
 | |
|   until false;
 | |
|   fpclosedir(thedir^);
 | |
|   glob:=root;
 | |
| end;
 | |
| 
 | |
| 
 | |
| {
 | |
|  GlobToSearch takes a glob entry, stats the file.
 | |
|  The glob entry is removed.
 | |
|  If FileAttributes match, the entry is reused
 | |
| }
 | |
| 
 | |
| Type
 | |
|   TGlobSearchRec = Record
 | |
|     Path       : shortString;
 | |
|     GlobHandle : PGlob;
 | |
|   end;
 | |
|   PGlobSearchRec = ^TGlobSearchRec;
 | |
| 
 | |
| Function GlobToTSearchRec (Var Info : TSearchRec) : Boolean;
 | |
| 
 | |
| Var SInfo : Stat;
 | |
|     p     : Pglob;
 | |
|     GlobSearchRec : PGlobSearchrec;
 | |
| 
 | |
| begin
 | |
|   GlobSearchRec:=Info.FindHandle;
 | |
|   P:=GlobSearchRec^.GlobHandle;
 | |
|   Result:=P<>Nil;
 | |
|   If Result then
 | |
|     begin
 | |
|     GlobSearchRec^.GlobHandle:=P^.Next;
 | |
|     Result:=Fpstat(GlobSearchRec^.Path+StrPas(p^.name),SInfo)>=0;
 | |
|     If Result then
 | |
|       begin
 | |
|       Info.Attr:=LinuxToWinAttr(p^.name,SInfo);
 | |
|       Result:=(Info.ExcludeAttr and Info.Attr)=0;
 | |
|       If Result Then
 | |
|          With Info do
 | |
|            begin
 | |
|            Attr:=Info.Attr;
 | |
|            If P^.Name<>Nil then
 | |
|            Name:=strpas(p^.name);
 | |
|            Time:=UnixToWinAge(Sinfo.st_mtime);
 | |
|            Size:=Sinfo.st_Size;
 | |
|            end;
 | |
|       end;
 | |
|     P^.Next:=Nil;
 | |
|     GlobFree(P);
 | |
|     end;
 | |
| end;
 | |
| 
 | |
| Function DoFind(Var Rslt : TSearchRec) : Longint;
 | |
| 
 | |
| Var
 | |
|   GlobSearchRec : PGlobSearchRec;
 | |
| 
 | |
| begin
 | |
|   Result:=-1;
 | |
|   GlobSearchRec:=Rslt.FindHandle;
 | |
|   If (GlobSearchRec^.GlobHandle<>Nil) then
 | |
|     While (GlobSearchRec^.GlobHandle<>Nil) and not (Result=0) do
 | |
|       If GlobToTSearchRec(Rslt) Then Result:=0;
 | |
| end;
 | |
| 
 | |
| 
 | |
| 
 | |
| Function FindFirst (Const Path : String; Attr : Longint; Var Rslt : TSearchRec) : Longint;
 | |
| 
 | |
| Var
 | |
|   GlobSearchRec : PGlobSearchRec;
 | |
| 
 | |
| begin
 | |
|   New(GlobSearchRec);
 | |
|   GlobSearchRec^.Path:=ExpandFileName(ExtractFilePath(Path));
 | |
|   GlobSearchRec^.GlobHandle:=Glob(Path);
 | |
|   Rslt.ExcludeAttr:=Not Attr and (faHidden or faSysFile or faVolumeID or faDirectory); //!! Not correct !!
 | |
|   Rslt.FindHandle:=GlobSearchRec;
 | |
|   Result:=DoFind (Rslt);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FindNext (Var Rslt : TSearchRec) : Longint;
 | |
| 
 | |
| begin
 | |
|   Result:=DoFind (Rslt);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Procedure FindClose (Var F : TSearchrec);
 | |
| 
 | |
| Var
 | |
|   GlobSearchRec : PGlobSearchRec;
 | |
| 
 | |
| begin
 | |
|   GlobSearchRec:=F.FindHandle;
 | |
|   GlobFree (GlobSearchRec^.GlobHandle);
 | |
|   Dispose(GlobSearchRec);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileGetDate (Handle : Longint) : Longint;
 | |
| 
 | |
| Var Info : Stat;
 | |
| 
 | |
| begin
 | |
|   If (fpFStat(Handle,Info))<0 then
 | |
|     Result:=-1
 | |
|   else
 | |
|     Result:=Info.st_Mtime;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileSetDate (Handle,Age : Longint) : Longint;
 | |
| 
 | |
| begin
 | |
|   // Impossible under Linux from FileHandle !!
 | |
|   FileSetDate:=-1;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileGetAttr (Const FileName : String) : Longint;
 | |
| 
 | |
| Var Info : Stat;
 | |
| 
 | |
| begin
 | |
|   If  FpStat (FileName,Info)<0 then
 | |
|     Result:=-1
 | |
|   Else
 | |
|     Result:=LinuxToWinAttr(Pchar(FileName),Info);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function FileSetAttr (Const Filename : String; Attr: longint) : Longint;
 | |
| 
 | |
| begin
 | |
|   Result:=-1;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function DeleteFile (Const FileName : String) : Boolean;
 | |
| 
 | |
| begin
 | |
|   Result:=fpUnLink (FileName)>=0;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function RenameFile (Const OldName, NewName : String) : Boolean;
 | |
| 
 | |
| begin
 | |
|   RenameFile:=BaseUnix.FpRename(OldNAme,NewName)>=0;
 | |
| end;
 | |
| 
 | |
| Function FileIsReadOnly(const FileName: String): Boolean;
 | |
| 
 | |
| begin
 | |
|   Result := fpAccess(PChar(FileName),W_OK)<>0;
 | |
| end;
 | |
| 
 | |
| {****************************************************************************
 | |
|                               Disk Functions
 | |
| ****************************************************************************}
 | |
| 
 | |
| {
 | |
|   The Diskfree and Disksize functions need a file on the specified drive, since this
 | |
|   is required for the statfs system call.
 | |
|   These filenames are set in drivestr[0..26], and have been preset to :
 | |
|    0 - '.'      (default drive - hence current dir is ok.)
 | |
|    1 - '/fd0/.'  (floppy drive 1 - should be adapted to local system )
 | |
|    2 - '/fd1/.'  (floppy drive 2 - should be adapted to local system )
 | |
|    3 - '/'       (C: equivalent of dos is the root partition)
 | |
|    4..26          (can be set by you're own applications)
 | |
|   ! Use AddDisk() to Add new drives !
 | |
|   They both return -1 when a failure occurs.
 | |
| }
 | |
| Const
 | |
|   FixDriveStr : array[0..3] of pchar=(
 | |
|     '.',
 | |
|     '/fd0/.',
 | |
|     '/fd1/.',
 | |
|     '/.'
 | |
|     );
 | |
| var
 | |
|   Drives   : byte;
 | |
|   DriveStr : array[4..26] of pchar;
 | |
| 
 | |
| Procedure AddDisk(const path:string);
 | |
| begin
 | |
|   if not (DriveStr[Drives]=nil) then
 | |
|    FreeMem(DriveStr[Drives],StrLen(DriveStr[Drives])+1);
 | |
|   GetMem(DriveStr[Drives],length(Path)+1);
 | |
|   StrPCopy(DriveStr[Drives],path);
 | |
|   inc(Drives);
 | |
|   if Drives>26 then
 | |
|    Drives:=4;
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function DiskFree(Drive: Byte): int64;
 | |
| var
 | |
|   fs : tstatfs;
 | |
| Begin
 | |
|   if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
 | |
|      ((not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
 | |
|    Diskfree:=int64(fs.bavail)*int64(fs.bsize)
 | |
|   else
 | |
|    Diskfree:=-1;
 | |
| End;
 | |
| 
 | |
| 
 | |
| 
 | |
| Function DiskSize(Drive: Byte): int64;
 | |
| var
 | |
|   fs : tstatfs;
 | |
| Begin
 | |
|   if ((Drive<4) and (not (fixdrivestr[Drive]=nil)) and (statfs(StrPas(fixdrivestr[drive]),fs)<>-1)) or
 | |
|      ((not (drivestr[Drive]=nil)) and (statfs(StrPas(drivestr[drive]),fs)<>-1)) then
 | |
|    DiskSize:=int64(fs.blocks)*int64(fs.bsize)
 | |
|   else
 | |
|    DiskSize:=-1;
 | |
| End;
 | |
| 
 | |
| 
 | |
| Function GetCurrentDir : String;
 | |
| begin
 | |
|   GetDir (0,Result);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function SetCurrentDir (Const NewDir : String) : Boolean;
 | |
| begin
 | |
|   {$I-}
 | |
|    ChDir(NewDir);
 | |
|   {$I+}
 | |
|   result := (IOResult = 0);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function CreateDir (Const NewDir : String) : Boolean;
 | |
| begin
 | |
|   {$I-}
 | |
|    MkDir(NewDir);
 | |
|   {$I+}
 | |
|   result := (IOResult = 0);
 | |
| end;
 | |
| 
 | |
| 
 | |
| Function RemoveDir (Const Dir : String) : Boolean;
 | |
| begin
 | |
|   {$I-}
 | |
|    RmDir(Dir);
 | |
|   {$I+}
 | |
|   result := (IOResult = 0);
 | |
| end;
 | |
| 
 | |
| 
 | |
| {****************************************************************************
 | |
|                               Misc Functions
 | |
| ****************************************************************************}
 | |
| 
 | |
| procedure Beep;
 | |
| begin
 | |
| end;
 | |
| 
 | |
| 
 | |
| {****************************************************************************
 | |
|                               Locale Functions
 | |
| ****************************************************************************}
 | |
| 
 | |
| 
 | |
| Function GetEpochTime: cint;
 | |
| {
 | |
|   Get the number of seconds since 00:00, January 1 1970, GMT
 | |
|   the time NOT corrected any way
 | |
| }
 | |
| begin
 | |
|   GetEpochTime:=fptime;
 | |
| end;
 | |
| 
 | |
| procedure GetTime(var hour,min,sec,msec,usec:word);
 | |
| {
 | |
|   Gets the current time, adjusted to local time
 | |
| }
 | |
| var
 | |
|   year,day,month:Word;
 | |
|   tz:timeval;
 | |
| begin
 | |
|   fpgettimeofday(@tz,nil);
 | |
|   EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
 | |
|   msec:=tz.tv_usec div 1000;
 | |
|   usec:=tz.tv_usec mod 1000;
 | |
| end;
 | |
| 
 | |
| procedure GetTime(var hour,min,sec,sec100:word);
 | |
| {
 | |
|   Gets the current time, adjusted to local time
 | |
| }
 | |
| var
 | |
|   usec : word;
 | |
| begin
 | |
|   gettime(hour,min,sec,sec100,usec);
 | |
|   sec100:=sec100 div 10;
 | |
| end;
 | |
| 
 | |
| Procedure GetTime(Var Hour,Min,Sec:Word);
 | |
| {
 | |
|   Gets the current time, adjusted to local time
 | |
| }
 | |
| var
 | |
|   msec,usec : Word;
 | |
| Begin
 | |
|   gettime(hour,min,sec,msec,usec);
 | |
| End;
 | |
| 
 | |
| Procedure GetDate(Var Year,Month,Day:Word);
 | |
| {
 | |
|   Gets the current date, adjusted to local time
 | |
| }
 | |
| var
 | |
|   hour,minute,second : word;
 | |
| Begin
 | |
|   EpochToLocal(fptime,year,month,day,hour,minute,second);
 | |
| End;
 | |
| 
 | |
| Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
 | |
| {
 | |
|   Gets the current date, adjusted to local time
 | |
| }
 | |
| Begin
 | |
|   EpochToLocal(fptime,year,month,day,hour,minute,second);
 | |
| End;
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| Procedure GetLocalTime(var SystemTime: TSystemTime);
 | |
| begin
 | |
|   GetTime(SystemTime.Hour, SystemTime.Minute, SystemTime.Second);
 | |
|   GetDate(SystemTime.Year, SystemTime.Month, SystemTime.Day);
 | |
|   SystemTime.MilliSecond := 0;
 | |
| end ;
 | |
| 
 | |
| 
 | |
| Procedure InitAnsi;
 | |
| Var
 | |
|   i : longint;
 | |
| begin
 | |
|   {  Fill table entries 0 to 127  }
 | |
|   for i := 0 to 96 do
 | |
|     UpperCaseTable[i] := chr(i);
 | |
|   for i := 97 to 122 do
 | |
|     UpperCaseTable[i] := chr(i - 32);
 | |
|   for i := 123 to 191 do
 | |
|     UpperCaseTable[i] := chr(i);
 | |
|   Move (CPISO88591UCT,UpperCaseTable[192],SizeOf(CPISO88591UCT));
 | |
| 
 | |
|   for i := 0 to 64 do
 | |
|     LowerCaseTable[i] := chr(i);
 | |
|   for i := 65 to 90 do
 | |
|     LowerCaseTable[i] := chr(i + 32);
 | |
|   for i := 91 to 191 do
 | |
|     LowerCaseTable[i] := chr(i);
 | |
|   Move (CPISO88591LCT,LowerCaseTable[192],SizeOf(CPISO88591UCT));
 | |
| end;
 | |
| 
 | |
| 
 | |
| Procedure InitInternational;
 | |
| begin
 | |
|   InitAnsi;
 | |
| end;
 | |
| 
 | |
| function SysErrorMessage(ErrorCode: Integer): String;
 | |
| 
 | |
| begin
 | |
|   Result:=StrError(ErrorCode);
 | |
| end;
 | |
| 
 | |
| {****************************************************************************
 | |
|                               OS utility functions
 | |
| ****************************************************************************}
 | |
| 
 | |
| Function GetEnvironmentVariable(Const EnvVar : String) : String;
 | |
| 
 | |
| begin
 | |
|   Result:=StrPas(BaseUnix.FPGetenv(PChar(EnvVar)));
 | |
| end;
 | |
| 
 | |
| {$define FPC_USE_FPEXEC}  // leave the old code under IFDEF for a while.
 | |
| function ExecuteProcess(Const Path: AnsiString; Const ComLine: AnsiString):integer;
 | |
| var
 | |
|   pid    : longint;
 | |
|   err    : longint;
 | |
|   e      : EOSError;
 | |
|   CommandLine: AnsiString;
 | |
|   cmdline2 : ppchar;
 | |
| 
 | |
| Begin
 | |
|   { always surround the name of the application by quotes
 | |
|     so that long filenames will always be accepted. But don't
 | |
|     do it if there are already double quotes!
 | |
|   }
 | |
|   {$ifdef FPC_USE_FPEXEC}       // Only place we still parse
 | |
|    cmdline2:=nil;
 | |
|    if Comline<>'' Then
 | |
|      begin
 | |
|        CommandLine:=ComLine;
 | |
|        cmdline2:=StringtoPPChar(CommandLine,1);
 | |
|        cmdline2^:=pchar(Path);
 | |
|      end
 | |
|    else
 | |
|      begin
 | |
|        getmem(cmdline2,2*sizeof(pchar));
 | |
|        cmdline2^:=pchar(Path);
 | |
|        cmdline2[1]:=nil;
 | |
|      end;
 | |
|   {$else}
 | |
|   if Pos ('"', Path) = 0 then
 | |
|     CommandLine := '"' + Path + '"'
 | |
|   else
 | |
|     CommandLine := Path;
 | |
|   if ComLine <> '' then
 | |
|     CommandLine := Commandline + ' ' + ComLine;
 | |
|   {$endif}
 | |
|   pid:=fpFork;
 | |
|   if pid=0 then
 | |
|    begin
 | |
|    {The child does the actual exec, and then exits}
 | |
|     {$ifdef FPC_USE_FPEXEC}
 | |
|       fpexecv(pchar(Path),Cmdline2);
 | |
|     {$else}
 | |
|       Execl(CommandLine);
 | |
|     {$endif}
 | |
|      { If the execve fails, we return an exitvalue of 127, to let it be known}
 | |
|      fpExit(127);
 | |
|    end
 | |
|   else
 | |
|    if pid=-1 then         {Fork failed}
 | |
|     begin
 | |
|       e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
 | |
|       e.ErrorCode:=-1;
 | |
|       raise e;
 | |
|     end;
 | |
| 
 | |
|   { We're in the parent, let's wait. }
 | |
|   result:=WaitProcess(pid); // WaitPid and result-convert
 | |
| 
 | |
|   if (result<0) or (result=127) then
 | |
|     begin
 | |
|     E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
 | |
|     E.ErrorCode:=result;
 | |
|     Raise E;
 | |
|     end;
 | |
| End;
 | |
| 
 | |
| function ExecuteProcess(Const Path: AnsiString; Const ComLine: Array Of AnsiString):integer;
 | |
| 
 | |
| var
 | |
|   pid    : longint;
 | |
|   err    : longint;
 | |
|   e : EOSError;
 | |
| 
 | |
| Begin
 | |
|   { always surround the name of the application by quotes
 | |
|     so that long filenames will always be accepted. But don't
 | |
|     do it if there are already double quotes!
 | |
|   }
 | |
|   pid:=fpFork;
 | |
|   if pid=0 then
 | |
|    begin
 | |
|      {The child does the actual exec, and then exits}
 | |
|       fpexecl(Path,Comline);
 | |
|      { If the execve fails, we return an exitvalue of 127, to let it be known}
 | |
|      fpExit(127);
 | |
|    end
 | |
|   else
 | |
|    if pid=-1 then         {Fork failed}
 | |
|     begin
 | |
|       e:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,-1]);
 | |
|       e.ErrorCode:=-1;
 | |
|       raise e;
 | |
|     end;
 | |
| 
 | |
|   { We're in the parent, let's wait. }
 | |
|   result:=WaitProcess(pid); // WaitPid and result-convert
 | |
| 
 | |
|   if (result<0) or (result=127) then
 | |
|     begin
 | |
|     E:=EOSError.CreateFmt(SExecuteProcessFailed,[Path,result]);
 | |
|     E.ErrorCode:=result;
 | |
|     raise E;
 | |
|     end;
 | |
| End;
 | |
| 
 | |
| 
 | |
| procedure Sleep(milliseconds: Cardinal);
 | |
| 
 | |
| Var
 | |
|   fd : Integer;
 | |
|   fds : TfdSet;
 | |
|   timeout : TimeVal;
 | |
| 
 | |
| begin
 | |
|   fd:=FileOpen('/dev/null',fmOpenRead);
 | |
|   If Not(Fd<0) then
 | |
|     try
 | |
|       fpfd_zero(fds);
 | |
|       fpfd_set(0,fds);
 | |
|       timeout.tv_sec:=Milliseconds div 1000;
 | |
|       timeout.tv_usec:=(Milliseconds mod 1000) * 1000;
 | |
|       fpSelect(1,Nil,Nil,@fds,@timeout);
 | |
|     finally
 | |
|       FileClose(fd);
 | |
|     end;
 | |
| end;
 | |
| 
 | |
| Function GetLastOSError : Integer;
 | |
| 
 | |
| begin
 | |
|   Result:=fpgetErrNo;
 | |
| end;
 | |
| 
 | |
| { ---------------------------------------------------------------------
 | |
|     Application config files
 | |
|   ---------------------------------------------------------------------}
 | |
|   
 | |
| 
 | |
| Function GetHomeDir : String;
 | |
| 
 | |
| begin
 | |
|   Result:=GetEnvironmentVariable('HOME');
 | |
|   If (Result<>'') then
 | |
|   Result:=IncludeTrailingPathDelimiter(Result);
 | |
| end;
 | |
| 
 | |
| Function GetAppConfigDir(Global : Boolean) : String;
 | |
| 
 | |
| begin
 | |
|   If Global then
 | |
|     Result:=SysConfigDir
 | |
|   else  
 | |
|     Result:=GetHomeDir+ApplicationName;
 | |
| end;
 | |
| 
 | |
| Function GetAppConfigFile(Global : Boolean; SubDir : Boolean) : String;
 | |
| 
 | |
| begin
 | |
|   if Global then
 | |
|     begin
 | |
|     Result:=IncludeTrailingPathDelimiter(SysConfigDir);
 | |
|     if SubDir then
 | |
|       Result:=IncludeTrailingPathDelimiter(Result+ApplicationName);
 | |
|     Result:=Result+ApplicationName+ConfigExtension;
 | |
|     end 
 | |
|   else
 | |
|     begin
 | |
|     if SubDir then
 | |
|       begin
 | |
|       Result:=IncludeTrailingPathDelimiter(GetAppConfigDir(False));
 | |
|       Result:=Result+ApplicationName+ConfigExtension;
 | |
|       end
 | |
|     else  
 | |
|       begin
 | |
|       Result:=GetHomeDir;
 | |
|       Result:=Result+'.'+ApplicationName;
 | |
|       end;
 | |
|     end;
 | |
| end;
 | |
| 
 | |
| {****************************************************************************
 | |
|                               Initialization code
 | |
| ****************************************************************************}
 | |
| 
 | |
| 
 | |
| Function GetTempDir(Global : Boolean) : String;
 | |
| 
 | |
| begin
 | |
|   If Assigned(OnGetTempDir) then
 | |
|     Result:=OnGetTempDir(Global)
 | |
|   else
 | |
|     begin  
 | |
|     Result:=GetEnvironmentVariable('TEMP');
 | |
|     If (Result='') Then
 | |
|       Result:=GetEnvironmentVariable('TMP');
 | |
|     if (Result='') then
 | |
|       Result:='/tmp/' // fallback.
 | |
|     end;  
 | |
|   if (Result<>'') then
 | |
|     Result:=IncludeTrailingPathDelimiter(Result);
 | |
| end;
 | |
| 
 | |
| {****************************************************************************
 | |
|                               Initialization code
 | |
| ****************************************************************************}
 | |
| 
 | |
| Initialization
 | |
|   InitExceptions;       { Initialize exceptions. OS independent }
 | |
|   InitInternational;    { Initialize internationalization settings }
 | |
|   SysConfigDir:='/etc'; { Initialize system config dir }
 | |
| Finalization
 | |
|   DoneExceptions;
 | |
| end.
 | |
| {
 | |
| 
 | |
|   $Log$
 | |
|   Revision 1.52  2004-11-02 13:59:42  marco
 | |
|    * timezone stuff back to unix
 | |
| 
 | |
|   Revision 1.51  2004/11/01 07:10:56  peter
 | |
|     * 1.0.x bootstrap fix
 | |
| 
 | |
|   Revision 1.50  2004/10/31 22:25:31  olle
 | |
|     * Fix for FPC_USE_LIBC
 | |
| 
 | |
|   Revision 1.49  2004/10/30 20:55:54  marco
 | |
|    * unix interface cleanup
 | |
| 
 | |
|   Revision 1.48  2004/10/12 15:22:23  michael
 | |
|   + Fixed sleep: file needs to be closed again
 | |
| 
 | |
|   Revision 1.47  2004/10/10 10:28:34  michael
 | |
|   + Implementation of GetTempDir and GetTempFileName
 | |
| 
 | |
|   Revision 1.46  2004/08/30 11:20:39  michael
 | |
|   + Give path, not comline in ExecuteProcess
 | |
| 
 | |
|   Revision 1.45  2004/08/30 11:13:20  michael
 | |
|   + Fixed ExecuteProcess. Now returns the exit code or raises an exception on failure
 | |
| 
 | |
|   Revision 1.44  2004/08/05 07:32:51  michael
 | |
|   Added getappconfig calls
 | |
| 
 | |
|   Revision 1.43  2004/07/03 21:50:31  daniel
 | |
|     * Modified bootstrap code so separate prt0.as/prt0_10.as files are no
 | |
|       longer necessary
 | |
| 
 | |
|   Revision 1.42  2004/06/15 07:36:03  michael
 | |
|   + Fixed Globtosearchrec to use unixtowinage
 | |
| 
 | |
|   Revision 1.41  2004/05/22 14:25:03  michael
 | |
|   + Fixed FindFirst/FindNext so it treats the attributes correctly
 | |
| 
 | |
|   Revision 1.40  2004/04/28 20:48:20  peter
 | |
|     * ordinal-pointer conversions fixed
 | |
| 
 | |
|   Revision 1.39  2004/04/26 14:50:19  peter
 | |
|     * FileIsReadOnly fixed
 | |
| 
 | |
|   Revision 1.38  2004/04/20 18:24:32  marco
 | |
|    * small fix for NIL arg ptr in first executeprocess
 | |
| 
 | |
|   Revision 1.37  2004/03/04 22:15:16  marco
 | |
|    * UnixType changes. Please report problems to me.
 | |
| 
 | |
|   Revision 1.36  2004/02/13 10:50:23  marco
 | |
|    * Hopefully last large changes to fpexec and friends.
 | |
|         - naming conventions changes from Michael.
 | |
|         - shell functions get alternative under ifdef.
 | |
|         - arraystring function moves to unixutil
 | |
|         - unixutil now regards quotes in stringtoppchar.
 | |
|         - sysutils/unix get executeprocess(ansi,array of ansi), and
 | |
|                 both executeprocess functions are fixed
 | |
|         - Sysutils/win32 get executeprocess(ansi,array of ansi)
 | |
| 
 | |
|   Revision 1.35  2004/02/12 15:31:06  marco
 | |
|    * First version of fpexec change. Still under ifdef or silently overloaded
 | |
| 
 | |
|   Revision 1.34  2004/02/09 17:11:17  marco
 | |
|    * fixed for 1.0 errno->fpgeterrno
 | |
| 
 | |
|   Revision 1.33  2004/02/08 14:50:51  michael
 | |
|   + Added fileIsReadOnly
 | |
| 
 | |
|   Revision 1.32  2004/02/08 11:01:17  michael
 | |
|   + Implemented getlastoserror
 | |
| 
 | |
|   Revision 1.31  2004/01/20 23:13:53  hajny
 | |
|     * ExecuteProcess fixes, ProcessID and ThreadID added
 | |
| 
 | |
|   Revision 1.30  2004/01/10 17:34:36  michael
 | |
|   + Implemented sleep() on Unix.
 | |
| 
 | |
|   Revision 1.29  2004/01/05 22:42:35  florian
 | |
|     * compilation error fixed
 | |
| 
 | |
|   Revision 1.28  2004/01/05 22:37:15  florian
 | |
|     * changed sysutils.exec to ExecuteProcess
 | |
| 
 | |
|   Revision 1.27  2004/01/03 09:09:11  marco
 | |
|    * Unix exec(ansistring)
 | |
| 
 | |
|   Revision 1.26  2003/11/26 20:35:14  michael
 | |
|   + Some fixes to have everything compile again
 | |
| 
 | |
|   Revision 1.25  2003/11/17 10:05:51  marco
 | |
|    * threads for FreeBSD. Not working tho
 | |
| 
 | |
|   Revision 1.24  2003/10/25 23:43:59  hajny
 | |
|     * THandle in sysutils common using System.THandle
 | |
| 
 | |
|   Revision 1.23  2003/10/07 08:28:49  marco
 | |
|    * fix from Vincent to casetables
 | |
| 
 | |
|   Revision 1.22  2003/09/27 12:51:33  peter
 | |
|     * fpISxxx macros renamed to C compliant fpS_ISxxx
 | |
| 
 | |
|   Revision 1.21  2003/09/17 19:07:44  marco
 | |
|    * more fixes for Unix<->unixutil
 | |
| 
 | |
|   Revision 1.20  2003/09/17 12:41:31  marco
 | |
|    * Uses more baseunix, less unix now
 | |
| 
 | |
|   Revision 1.19  2003/09/14 20:15:01  marco
 | |
|    * Unix reform stage two. Remove all calls from Unix that exist in Baseunix.
 | |
| 
 | |
|   Revision 1.18  2003/04/01 15:57:41  peter
 | |
|     * made THandle platform dependent and unique type
 | |
| 
 | |
|   Revision 1.17  2003/03/30 10:38:00  armin
 | |
|   * corrected typo in DirectoryExists
 | |
| 
 | |
|   Revision 1.16  2003/03/29 18:21:42  hajny
 | |
|     * DirectoryExists declaration changed to that one from fixes branch
 | |
| 
 | |
|   Revision 1.15  2003/03/28 19:06:59  peter
 | |
|     * directoryexists added
 | |
| 
 | |
|   Revision 1.14  2003/01/03 20:41:04  peter
 | |
|     * FileCreate(string,mode) overload added
 | |
| 
 | |
|   Revision 1.13  2002/09/07 16:01:28  peter
 | |
|     * old logs removed and tabs fixed
 | |
| 
 | |
|   Revision 1.12  2002/01/25 16:23:03  peter
 | |
|     * merged filesearch() fix
 | |
| 
 | |
| } | 
