Browse Source

* Improved interpretation of shebang line under linux. Added --set-cache argument

git-svn-id: trunk@17951 -
michael 14 years ago
parent
commit
6ad0a9cc26
2 changed files with 164 additions and 76 deletions
  1. 106 49
      utils/instantfpc/instantfpc.pas
  2. 58 27
      utils/instantfpc/instantfptools.pas

+ 106 - 49
utils/instantfpc/instantfpc.pas

@@ -27,8 +27,52 @@ uses
 const
   Version = '1.0';
 
+
+Procedure Usage;
+
+begin
+  writeln('instantfpc '+Version);
+  writeln;
+  writeln('instantfpc -h');
+  writeln('      This help message.');
+  writeln;
+  writeln('instantfpc -v');
+  writeln('      Print version and exit.');
+  writeln;
+  writeln('instantfpc [compiler options] <source file> [program parameters]');
+  writeln('      Compiles source and runs program.');
+  writeln('      Source is compared with the cache. If cache is not valid then');
+  writeln('      source is copied to cache with the shebang line commented and');
+  writeln('      cached source is compiled.');
+  writeln('      If compilation fails the fpc output is written to stdout and');
+  writeln('      instantfpc exits with error code 1.');
+  writeln('      If compilation was successful the program is executed.');
+  writeln('      If the compiler options contains -B the program is always');
+  writeln('      compiled.');
+  writeln;
+  writeln('instantfpc --get-cache');
+  writeln('      Prints cache directory to stdout.');
+  writeln;
+  writeln('instantfpc --set-cache=<path to cache>');
+  writeln('      Set the cache to be used.');
+  writeln;
+  writeln('instantfpc --compiler=<path to compiler>');
+  writeln('      Normally fpc is searched in PATH and used as compiler.');
+  writeln;
+  writeln('Normal usage is to add as first line ("shebang") "#!/usr/bin/instantfpc"');
+  writeln('to a program source file. Then you can execute the source like a script.');
+  Halt(0);
+end;
+
+Procedure DisplayCache;
+
+begin
+  write(GetCacheDir);
+  Halt(0);
+end ;
+
 var
-  i: Integer;
+  i,j: Integer;
   p: String;
   Filename: String;
   Src: TStringList;
@@ -38,65 +82,78 @@ var
   ExeExt: String;
   E : String;
   
+// Return true if filename found.
+  
+Function InterpretParam(p : String) : boolean;
+  
+begin
+  Result:=False;
+  if (P='') then exit;
+  if p='-v' then 
+    begin
+    writeln('instantfpc '+Version);
+    Halt(1);
+    end
+  else if p='-h' then 
+    usage
+  else if p='--get-cache' then 
+    DisplayCache
+  else if copy(p,1,11)='--compiler=' then 
+    begin
+    delete(P,1,11);
+    SetCompiler(p);
+    end 
+  else if copy(p,1,12)='--set-cache=' then 
+    begin
+    delete(P,1,12);
+    SetCacheDir(p);
+    end 
+  else if (P<>'') and (p[1]<>'-') then 
+    begin
+    Filename:=p;
+    Result:=True;
+    end;
+end;
+  
 begin
   Filename:='';
   { For example:
       /usr/bin/instantfpc -MObjFpc -Sh ./envvars.pas param1
   }
-  for i:=1 to Paramcount do begin
+  for i:=1 to Paramcount do 
+    begin
     p:=ParamStr(i);
-    //writeln('Param: ',i,' ',p);
     if p='' then
       continue
-    else if p='-v' then begin
-      writeln('instantfpc '+Version);
-      Halt(1);
-    end
-    else if p='-h' then begin
-      writeln('instantfpc '+Version);
-      writeln;
-      writeln('instantfpc -h');
-      writeln('      This help message.');
-      writeln;
-      writeln('instantfpc -v');
-      writeln('      Print version and exit.');
-      writeln;
-      writeln('instantfpc [compiler options] <source file> [program parameters]');
-      writeln('      Compiles source and runs program.');
-      writeln('      Source is compared with the cache. If cache is not valid then');
-      writeln('      source is copied to cache with the shebang line commented and');
-      writeln('      cached source is compiled.');
-      writeln('      If compilation fails the fpc output is written to stdout and');
-      writeln('      instantfpc exits with error code 1.');
-      writeln('      If compilation was successful the program is executed.');
-      writeln('      If the compiler options contains -B the program is always');
-      writeln('      compiled.');
-      writeln;
-      writeln('instantfpc --get-cache');
-      writeln('      Prints cache directory to stdout.');
-      writeln;
-      writeln('instantfpc --compiler=<path to compiler>');
-      writeln('      Normally fpc is searched in PATH and used as compiler.');
-      writeln;
-      writeln('Normal usage is to add as first line ("shebang") "#!/usr/bin/instantfpc"');
-      writeln('to a program source file. Then you can execute the source like a script.');
-      Halt(0);
-    end else if p='--get-cache' then begin
-      CacheDir:=GetCacheDir;
-      write(CacheDir);
-      Halt(0);
-    end else if (p[1]<>'-') then begin
-      // the first non flag parameter is the file name of the script
-      // followed by the parameters for the script
-      Filename:=p;
-      break;
-    end;
+    else 
+      begin
+      if (I<>1) then
+        begin
+        if InterpretParam(p) then
+          Break;
+        end  
+      else
+        begin  
+        // The linux kernel passes the whole shebang line as 1 argument. 
+        // We must parse and split it ourselves.
+        Repeat
+          J:=Pos(' ',P);
+          if (J=0) then
+            J:=Length(P)+1;
+          if InterpretParam(Copy(P,1,J-1)) then 
+            Break;
+          Delete(P,1,J);
+        Until (P='');
+        if (FileName<>'') then 
+          Break;
+        end;
+      end;  
   end;
-  if Filename='' then begin
+  if (Filename='') then 
+    begin
     writeln('missing source file');
     Halt(1);
-  end;
-
+    end;
   CheckSourceName(Filename);
 
   Src:=TStringList.Create;

+ 58 - 27
utils/instantfpc/instantfptools.pas

@@ -24,15 +24,21 @@ uses
 procedure CheckSourceName(const Filename: string);
 procedure CommentShebang(Src: TStringList);
 function GetCacheDir: string;
+procedure SetCacheDir(AValue : string);
 function IsCacheValid(Src: TStringList;
                       const CachedSrcFile, CachedExeFile: string): boolean;
 procedure Compile(const CacheFilename, OutputFilename: string);
 function GetCompiler: string;
+procedure SetCompiler(AValue : string); 
 function GetCompilerParameters(const SrcFilename, OutputFilename: string): string;
 procedure Run(const Filename: string);
 
 implementation
 
+Var
+  CmdCacheDir : String;
+  CmdCompiler : String;
+  
 procedure AddParam(p: string; var Line: string);
 begin
   if p='' then exit;
@@ -71,14 +77,26 @@ begin
   Src[0]:=copy(Line,1,i-1)+'//'+copy(Line,i,length(Line));
 end;
 
+
+procedure SetCacheDir(AValue : string);
+
+begin
+  CmdCacheDir:=AValue;
+end;
+
 function GetCacheDir: string;
 begin
-  Result:=GetEnvironmentVariable('INSTANTFPCCACHE');
-  if Result='' then begin
-    Result:=GetEnvironmentVariable('HOME');
-    if Result<>'' then
-      Result:=IncludeTrailingPathDelimiter(Result)+'.cache'+PathDelim+'instantfpc';
-  end;
+  Result:=CmdCacheDir;
+  if (Result='') then 
+    begin
+    Result:=GetEnvironmentVariable('INSTANTFPCCACHE');
+    if Result='' then 
+      begin
+      Result:=GetEnvironmentVariable('HOME');
+      if Result<>'' then
+        Result:=IncludeTrailingPathDelimiter(Result)+'.cache'+PathDelim+'instantfpc';
+      end;
+    end;  
   if Result='' then begin
     writeln('missing environment variable: HOME or INSTANTFPCCACHE');
     Halt(1);
@@ -113,9 +131,14 @@ begin
   {$ENDIF}
 end;
 
+procedure SetCompiler(AValue : string); 
+
+begin
+  CmdCompiler:=AValue;
+end;
+
 function GetCompiler: string;
-const
-  CompilerParam = '--compiler=';
+
 var
   Path: String;
   p: Integer;
@@ -124,28 +147,28 @@ var
   CompFile: String;
   i: Integer;
   Param: String;
+  
 begin
-  for i:=1 to Paramcount do begin
-    Param:=ParamStr(i);
-    if (Param='') or (Param[1]<>'-') then break;
-    if copy(Param,1,length(CompilerParam))=CompilerParam then begin
-      CompFile:=copy(Param,length(CompilerParam)+1,length(Param));
-      Result:=ExpandFileName(CompFile);
-      if not FileExists(Result) then begin
-        writeln('Error: '+CompFile+' not found, check the ',CompilerParam,' parameter.');
-        Halt(1);
+  Result:=CmdCompiler;
+  if (Result<>'') then
+    begin
+    Result:=ExpandFileName(Result);
+    if not FileExists(Result) then 
+      begin
+      writeln('Error: '+Result+' not found, check the --compiler parameter.');
+      Halt(1);
       end;
-      exit;
+    exit;
     end;
-  end;
 
   {$IFDEF Windows}
   CompFile:='fpc.exe';
   {$ELSE}
   CompFile:='fpc';
   {$ENDIF}
+  Result:=ExeSearch(CompFile);
   Path:=GetEnvironmentVariable('PATH');
-  if PATH<>'' then begin
+{  if PATH<>'' then begin
     p:=1;
     while p<=length(Path) do begin
       StartPos:=p;
@@ -158,8 +181,12 @@ begin
       inc(p);
     end;
   end;
-  writeln('Error: '+CompFile+' not found in PATH');
-  Halt(1);
+}
+  if (Result='') then
+    begin
+    writeln('Error: '+CompFile+' not found in PATH');
+    Halt(1);
+    end;
 end;
 
 procedure Compile(const CacheFilename, OutputFilename: string);
@@ -204,13 +231,17 @@ function GetCompilerParameters(const SrcFilename, OutputFilename: string): strin
 }
 var
   p: String;
+  i : integer;
 begin
   Result:='';
-  if (Paramcount>0) then begin
-    p:=ParamStr(1);
-    if (p<>'') and (p[1]='-') then
-      Result:=p; // copy compile params from the script
-  end;
+  I:=1;
+  While (I<=ParamCount) and (Copy(ParamStr(i),1,1)='-') do
+    begin
+    p:=ParamStr(i);
+    if (Copy(p,1,1)='-') and (copy(p,1,2)<>'--') then
+      AddParam(P,Result);
+    inc(I);  
+    end;
   AddParam('-o'+OutputFilename {$IFDEF HASEXEEXT} + '.exe' {$ENDIF},Result);
   AddParam(SrcFilename,Result);
 end;