Explorar el Código

* Rewritten command line parsing. Do not parse command line on startup.

git-svn-id: branches/unicodertl@12132 -
yury hace 17 años
padre
commit
cd98fdefbf
Se han modificado 1 ficheros con 119 adiciones y 117 borrados
  1. 119 117
      rtl/win32/system.pp

+ 119 - 117
rtl/win32/system.pp

@@ -29,6 +29,7 @@ interface
 {$define DISABLE_NO_THREAD_MANAGER}
 {$define DISABLE_NO_THREAD_MANAGER}
 
 
 {$define FPC_RTLSTRING_UTF16}
 {$define FPC_RTLSTRING_UTF16}
+{$define HAS_CMDLINE}
 
 
 { include system-independent routine headers }
 { include system-independent routine headers }
 {$I systemh.inc}
 {$I systemh.inc}
@@ -95,9 +96,6 @@ type
   end;
   end;
 
 
 var
 var
-{ C compatible arguments }
-  argc : longint;
-  argv : ^PRtlChar;
 { Win32 Info }
 { Win32 Info }
   startupinfo : tstartupinfo;
   startupinfo : tstartupinfo;
   hprevinst,
   hprevinst,
@@ -116,6 +114,11 @@ const
   Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
   Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
   Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
   Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
 
 
+function CmdLine: PRtlChar;
+{ C compatible arguments }
+function argc: longint;
+function argv: PPRtlChar;
+
 implementation
 implementation
 
 
 function _W(const s: RtlString): PWideChar; inline;
 function _W(const s: RtlString): PWideChar; inline;
@@ -147,141 +150,139 @@ function SysReAllocStringLen(var bstr:pointer;psz: pointer;
                               Parameter Handling
                               Parameter Handling
 *****************************************************************************}
 *****************************************************************************}
 
 
+var
+  FArgs: PRtlChar;
+  FCmdLine: PRtlChar;
+{$ifndef FPC_RTLSTRING_UTF16}
+  FCmdLineStr: RtlString;
+{$endif FPC_RTLSTRING_UTF16}
+  Fargc: longint;
+  Fargv: PPRtlChar;
+
 procedure setup_arguments;
 procedure setup_arguments;
 var
 var
-  arglen,
-  count   : longint;
-  argstart,
-  pc      : pwidechar;
-  arg     : PRtlChar;
-  quote   : Boolean;
-  argvlen : longint;
+  i, argvlen: longint;
+  pc, dst, argstart: PRtlChar;
+  quote: Boolean;
   buf: array[0..259] of WideChar;  // need MAX_PATH bytes, not 256!
   buf: array[0..259] of WideChar;  // need MAX_PATH bytes, not 256!
-
-  procedure allocarg(idx,len:longint);
-    var
-      oldargvlen : longint;
-    begin
-      if idx>=argvlen then
-       begin
-         oldargvlen:=argvlen;
-         argvlen:=(idx+8) and (not 7);
-         sysreallocmem(argv,argvlen*sizeof(pointer));
-         fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
-       end;
-      { use realloc to reuse already existing memory }
-      { always allocate, even if length is zero, since }
-      { the arg. is still present!                     }
-      sysreallocmem(argv[idx],len+1);
-    end;
-
+{$ifndef FPC_RTLSTRING_UTF16}
+  s: RtlString;
+{$endif FPC_RTLSTRING_UTF16}
 begin
 begin
-  SetupProcVars;
-  { create commandline, it starts with the executed filename which is argv[0] }
-  { Win32 passes the command NOT via the args, but via getmodulefilename}
-  count:=0;
-  argv:=nil;
-  argvlen:=0;
-  ArgLen := GetModuleFileName(0, @buf[0], High(buf)-1);
-  buf[ArgLen] := #0; // be safe
-  allocarg(0,arglen);
-  move(buf,argv[0]^,arglen+1);
-  { Setup cmdline variable }
-  cmdline:=GetCommandLine;
-  { process arguments }
-  pc:=cmdline;
-{$IfDef SYSTEM_DEBUG_STARTUP}
-  Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
-{$EndIf }
-  while pc^<>#0 do
+  if FCmdLine <> nil then exit;
+  // Alloc argv buffer
+  argvlen:=20;
+  Fargv:=SysGetMem(argvlen*SizeOf(pointer));
+  // Get command line
+{$ifdef FPC_RTLSTRING_UTF16}
+  FCmdLine:=GetCommandLine;
+{$else}
+  FCmdLineStr:=GetCommandLine;
+  FCmdLine:=PRtlChar(FCmdLineStr);
+{$endif FPC_RTLSTRING_UTF16}
+  // Get exe name
+  i:=GetModuleFileName(0, buf, High(buf)-1);
+  buf[i]:=#0; // be safe
+{$ifndef FPC_RTLSTRING_UTF16}
+  s:=buf;
+  i:=Length(s);
+{$endif FPC_RTLSTRING_UTF16}
+  Inc(i);
+  // Alloc space for arguments
+  FArgs:=SysGetMem((i + strlen(FCmdLine) + 1)*SizeOf(RtlChar));
+  // Copy exe name
+  Move(buf, FArgs^, i*SizeOf(RtlChar));
+  Fargv[0]:=FArgs;
+  Fargc:=0;
+
+  // Process arguments
+  pc:=FCmdLine;
+  dst:=FArgs + i;
+  while pc^ <> #0 do
    begin
    begin
      { skip leading spaces }
      { skip leading spaces }
-     while pc^ in [#1..#32] do
-      inc(pc);
-     if pc^=#0 then
-      break;
-     { calc argument length }
+     while (pc^ <> #0) and (pc^ <= ' ') do
+       Inc(pc);
+     if pc^ = #0 then
+       break;
+
+     argstart:=dst;
+
+     { copy argument }
      quote:=False;
      quote:=False;
-     argstart:=pc;
-     arglen:=0;
-     while (pc^<>#0) do
+     while pc^ <> #0 do
       begin
       begin
         case pc^ of
         case pc^ of
           #1..#32 :
           #1..#32 :
-            begin
-              if quote then
-               inc(arglen)
-              else
-               break;
-            end;
+            if not quote then
+              break;
           '"' :
           '"' :
-            if pc[1]<>'"' then
-              quote := not quote
-              else
-              inc(pc);
-          else
-            inc(arglen);
-        end;
-        inc(pc);
-      end;
-     { copy argument }
-     { Don't copy the first one, it is already there.}
-     If Count<>0 then
-      begin
-        allocarg(count,arglen);
-        quote:=False;
-        pc:=argstart;
-        arg:=argv[count];
-        while (pc^<>#0) do
-         begin
-           case pc^ of
-             #1..#32 :
-               begin
-                 if quote then
-                  begin
-                    arg^:=pc^;
-                    inc(arg);
-                  end
-                 else
-                  break;
-               end;
-             '"' :
-               if pc[1]<>'"' then
-                 quote := not quote
-                  else
-                inc(pc);
-             else
+            begin
+              Inc(pc);
+              if pc^ <> '"' then
                begin
                begin
-                 arg^:=pc^;
-                 inc(arg);
+                 quote := not quote;
+                 continue;
                end;
                end;
-           end;
-           inc(pc);
-         end;
-        arg^:=#0;
+            end;
+        end;
+        // don't copy the first argument. It is exe name
+        if Fargc > 0 then
+          begin
+            dst^:=pc^;
+            Inc(dst);
+          end;
+        Inc(pc);
       end;
       end;
- {$IfDef SYSTEM_DEBUG_STARTUP}
-     Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
- {$EndIf SYSTEM_DEBUG_STARTUP}
-     inc(count);
+
+      if Fargc > 0 then
+        begin
+          // null-terminate the argument
+          dst^:=#0;
+          Inc(dst);
+          if Fargc >= argvlen then
+            begin
+              Inc(argvlen, 20);
+              SysReAllocMem(Fargv, argvlen*SizeOf(pointer));
+            end;
+          Fargv[Fargc]:=argstart;
+        end;
+
+      Inc(Fargc);
    end;
    end;
-  { get argc }
-  argc:=count;
-  { free unused memory, leaving a nil entry at the end }
-  sysreallocmem(argv,(count+1)*sizeof(pointer));
-  argv[count] := nil;
+   // Truncate buffers
+   SysReAllocMem(FArgs, dst - FArgs);
+   SysReAllocMem(Fargv, Fargc*SizeOf(pointer));
 end;
 end;
 
 
+function CmdLine: PRtlChar;
+begin
+  setup_arguments;
+  Result:=FCmdLine;
+end;
+
+function argc: longint;
+begin
+  setup_arguments;
+  Result:=Fargc;
+end;
+
+function argv: PPRtlChar;
+begin
+  setup_arguments;
+  Result:=Fargv;
+end;
 
 
 function paramcount : longint;
 function paramcount : longint;
 begin
 begin
   paramcount := argc - 1;
   paramcount := argc - 1;
 end;
 end;
 
 
-function paramstr(l : longint) : string;
+function paramstr(l : longint) : RtlString;
 begin
 begin
-  if (l>=0) and (l<argc) then
-    paramstr:=strpas(argv[l])
+  setup_arguments;
+  if (l>=0) and (l<Fargc) then
+    paramstr:=Fargv[l]
   else
   else
     paramstr:='';
     paramstr:='';
 end;
 end;
@@ -308,6 +309,8 @@ procedure asm_exit;stdcall;external name 'asm_exit';
 
 
 Procedure system_exit;
 Procedure system_exit;
 begin
 begin
+  SysFreeMem(FArgs);
+  SysFreeMem(FArgv);
   { don't call ExitProcess inside
   { don't call ExitProcess inside
     the DLL exit code !!
     the DLL exit code !!
     This crashes Win95 at least PM }
     This crashes Win95 at least PM }
@@ -1067,9 +1070,7 @@ begin
   SysInitExceptions;
   SysInitExceptions;
   { setup fastmove stuff }
   { setup fastmove stuff }
   fpc_cpucodeinit;
   fpc_cpucodeinit;
-  SysInitStdIO;
-  { Arguments }
-  setup_arguments;
+  SetupProcVars;
   { Reset IO Error }
   { Reset IO Error }
   InOutRes:=0;
   InOutRes:=0;
   ProcessID := GetCurrentProcessID;
   ProcessID := GetCurrentProcessID;
@@ -1084,5 +1085,6 @@ begin
 {$endif VER2_2}
 {$endif VER2_2}
   InitWin32Widestrings;
   InitWin32Widestrings;
   DispCallByIDProc:=@DoDispCallByIDError;
   DispCallByIDProc:=@DoDispCallByIDError;
+  SysInitStdIO;
 end.
 end.