[msvcrt] Testcase and implementation for __getmainargs

Uwe Bonnes bon at elektron.ikp.physik.tu-darmstadt.de
Mon Jan 25 11:14:22 CST 2010


---
 dlls/msvcrt/data.c       |  188 +++++++++++++++++++++++++++++++++++++++++++++-
 dlls/msvcrt/tests/data.c |   99 ++++++++++++++++++++++++
 2 files changed, 283 insertions(+), 4 deletions(-)

diff --git a/dlls/msvcrt/data.c b/dlls/msvcrt/data.c
index c91980d..b082153 100644
--- a/dlls/msvcrt/data.c
+++ b/dlls/msvcrt/data.c
@@ -2,6 +2,7 @@
  * msvcrt.dll dll data items
  *
  * Copyright 2000 Jon Griffiths
+ * Copyright 2010 Uwe Bonnes
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,6 +23,7 @@
 #include "wine/port.h"
 
 #include <math.h>
+#include <stdlib.h>
 #include "msvcrt.h"
 #include "wine/library.h"
 #include "wine/unicode.h"
@@ -266,12 +268,10 @@ void msvcrt_init_args(void)
 
   MSVCRT__acmdln = _strdup( GetCommandLineA() );
   MSVCRT__wcmdln = msvcrt_wstrdupa(MSVCRT__acmdln);
-  MSVCRT___argc = __wine_main_argc;
-  MSVCRT___argv = __wine_main_argv;
-  MSVCRT___wargv = __wine_main_wargv;
+  MSVCRT___argc = 0;
 
   TRACE("got %s, wide = %s argc=%d\n", debugstr_a(MSVCRT__acmdln),
-        debugstr_w(MSVCRT__wcmdln),MSVCRT___argc);
+        debugstr_w(MSVCRT__wcmdln), __wine_main_argc);
 
   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
   GetVersionExW( &osvi );
@@ -321,6 +321,15 @@ void msvcrt_init_args(void)
 /* INTERNAL: free memory used by args */
 void msvcrt_free_args(void)
 {
+  int i;
+
+  for(i=0; i< MSVCRT___argc; i++)
+    {
+      HeapFree(GetProcessHeap(), 0, MSVCRT___argv[i]);
+      HeapFree(GetProcessHeap(), 0, MSVCRT___wargv[i]);
+    }
+  HeapFree(GetProcessHeap(), 0, MSVCRT___argv);
+  HeapFree(GetProcessHeap(), 0, MSVCRT___wargv);
   /* FIXME: more things to free */
   HeapFree(GetProcessHeap(), 0, MSVCRT___initenv);
   HeapFree(GetProcessHeap(), 0, MSVCRT___winitenv);
@@ -330,6 +339,147 @@ void msvcrt_free_args(void)
   HeapFree(GetProcessHeap(), 0, MSVCRT__wpgmptr);
 }
 
+static int  cmpstringp(const void *p1, const void *p2)
+{
+  return strcmp(* (char * const *) p1, * (char * const *) p2);
+}
+
+
+static int find_all(int *allocated, char ***glob_argv, char * farg)
+{
+  int found = 0;
+  WIN32_FIND_DATAA find_data;
+  HANDLE hFind = INVALID_HANDLE_VALUE;
+  char fname[MAX_PATH];
+  char *p , *p1,*p2;
+  
+  strcpy(fname, farg);
+  /* we need to parse for ../ ..\\ etc */
+  p = strchr(fname,'*');
+  if (!p)
+    p = strchr(fname,'?');
+  if(p)
+    *p= 0;
+  if(!p)
+    p = fname + strlen(fname);
+  /* no go back to a slash, if any */
+  p1 = strrchr(fname, '/');
+  p2 = strrchr(fname,'\\');
+  if (p1 || p2)
+    {
+      if(p1 > p2)
+	{
+	  if(p1 > p2)
+	    p = p1;
+	  else
+	    p = p2;
+	  p++;
+	  *(p) = 0;
+	}
+    }
+  else
+    {
+      p = fname;
+      *p = 0;
+    }
+  
+  hFind = FindFirstFileA(farg, &find_data);
+  while (hFind  != INVALID_HANDLE_VALUE)
+    {
+      BOOL valid_file;
+      valid_file= (strcmp(find_data.cFileName,"." )) && (strcmp(find_data.cFileName,".." ));
+      if (valid_file)
+	{
+	  if (found +1 > *allocated)
+	    {
+	      if (*allocated == 0)
+		*glob_argv = HeapAlloc(GetProcessHeap(), 0, 256* sizeof(char*));
+	      else
+		*glob_argv= HeapReAlloc(GetProcessHeap(), 0, *glob_argv, 
+					(*allocated+256)* sizeof(char*));
+	      *allocated += 256;
+	    }
+	  strcpy(p, find_data.cFileName);
+	  if(*glob_argv)
+	    (*glob_argv)[found] = strdup(fname);
+	  found++;
+	}
+      if(!FindNextFileA(hFind, &find_data))
+	{
+	  FindClose(hFind);
+	  hFind = INVALID_HANDLE_VALUE;
+	}
+    }
+  if(found)
+    {
+      (*glob_argv)[found] = NULL;
+      qsort(*glob_argv, found, sizeof(char *), cmpstringp);
+    }
+  return found;
+}
+
+/* If there is a wildcard in the argument list, expand it if expand_wildcards
+   is given. Sort the expanded entries*/
+
+static void glob_args(int expand_wildcards)
+{
+  int n_expanded = 0;
+  int i;
+  int allocated = 0;
+  char **glob_argv = NULL;
+  
+  MSVCRT___argv = HeapAlloc(GetProcessHeap(), 0, ( __wine_main_argc + 1) * sizeof(char*));
+  MSVCRT___wargv = HeapAlloc(GetProcessHeap(), 0, (__wine_main_argc + 1) * sizeof(MSVCRT_wchar_t*));
+  
+  for (i=0; i<  __wine_main_argc; i++)
+    {
+      char *p;
+      int found = 0;
+      p = strchr(__wine_main_argv[i],'*');
+      if(!p)
+	p = strchr(__wine_main_argv[i],'?');
+      if ((i != 0) && p && expand_wildcards) 
+	/* Don't expand the program name at position 0 or when no wildcard or no expansion requested*/
+	{
+	  found = find_all(&allocated, &glob_argv, __wine_main_argv[i]);
+        }
+      if(!found)
+	{
+	  if(MSVCRT___argv)
+	    MSVCRT___argv[i+n_expanded] = strdup(__wine_main_argv[i]);
+	  if(MSVCRT___wargv)
+	    MSVCRT___wargv[i+n_expanded] = msvcrt_wstrdupa(__wine_main_argv[i]);
+	}
+      else
+	{
+	  if (found > 1)
+	    {
+	      int k;
+	      /* now sort the entries */
+	      MSVCRT___argv  = HeapReAlloc(GetProcessHeap(), 0,MSVCRT___argv,  (__wine_main_argc + n_expanded + found) * sizeof(char*));
+	      MSVCRT___wargv = HeapReAlloc(GetProcessHeap(), 0,MSVCRT___wargv, (__wine_main_argc + n_expanded + found) * sizeof(MSVCRT_wchar_t*));
+	      for(k=0; k< found; k++)
+		{
+		  if(MSVCRT___argv)  MSVCRT___argv[i + n_expanded + k] = glob_argv[k];
+		  if(MSVCRT___wargv) MSVCRT___wargv[i + n_expanded + k] = msvcrt_wstrdupa(glob_argv[k]);
+		}
+	      n_expanded += found-1;
+	    }
+	  else
+	    {
+	      MSVCRT___argv[i + n_expanded] = glob_argv[0];
+	      MSVCRT___wargv[i + n_expanded] = msvcrt_wstrdupa(glob_argv[0]);
+	    }
+	}
+    }
+  if(MSVCRT___argv)
+    MSVCRT___argv[i+n_expanded] = NULL;
+  if(MSVCRT___wargv)
+    MSVCRT___wargv[i+n_expanded] = NULL;
+  MSVCRT___argc = __wine_main_argc + n_expanded;
+  HeapFree(GetProcessHeap(), 0, glob_argv);
+}
+
 /*********************************************************************
  *		__getmainargs (MSVCRT.@)
  */
@@ -337,6 +487,21 @@ void CDECL __getmainargs(int *argc, char** *argv, char** *envp,
                          int expand_wildcards, int *new_mode)
 {
   TRACE("(%p,%p,%p,%d,%p).\n", argc, argv, envp, expand_wildcards, new_mode);
+  if(MSVCRT___argc) /* free previous allocated resources*/
+    {
+      int i;
+      for(i=0; i<MSVCRT___argc; i++)
+	{
+	  HeapFree(GetProcessHeap(), 0, MSVCRT___argv[i]);
+	  HeapFree(GetProcessHeap(), 0, MSVCRT___wargv[i]);
+	}
+      HeapFree(GetProcessHeap(), 0, MSVCRT___argv);
+      HeapFree(GetProcessHeap(), 0, MSVCRT___wargv);
+      MSVCRT___argc = 0;
+      MSVCRT___argv = NULL;
+      MSVCRT___wargv = NULL;
+    }
+  glob_args(expand_wildcards);
   *argc = MSVCRT___argc;
   *argv = MSVCRT___argv;
   *envp = MSVCRT___initenv;
@@ -351,6 +516,21 @@ void CDECL __wgetmainargs(int *argc, MSVCRT_wchar_t** *wargv, MSVCRT_wchar_t** *
                           int expand_wildcards, int *new_mode)
 {
   TRACE("(%p,%p,%p,%d,%p).\n", argc, wargv, wenvp, expand_wildcards, new_mode);
+  if(MSVCRT___argc) /* free previous allocated resources*/
+    {
+      int i;
+      for(i=0; i<MSVCRT___argc; i++)
+	{
+	  HeapFree(GetProcessHeap(), 0, MSVCRT___argv[i]);
+	  HeapFree(GetProcessHeap(), 0, MSVCRT___wargv[i]);
+	}
+      HeapFree(GetProcessHeap(), 0, MSVCRT___argv);
+      HeapFree(GetProcessHeap(), 0, MSVCRT___wargv);
+      MSVCRT___argc = 0;
+      MSVCRT___argv = NULL;
+      MSVCRT___wargv = NULL;
+    }
+  glob_args(expand_wildcards);
   *argc = MSVCRT___argc;
   *wargv = MSVCRT___wargv;
   *wenvp = MSVCRT___winitenv;
diff --git a/dlls/msvcrt/tests/data.c b/dlls/msvcrt/tests/data.c
index a27ca27..edf39a5 100644
--- a/dlls/msvcrt/tests/data.c
+++ b/dlls/msvcrt/tests/data.c
@@ -25,6 +25,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <io.h>
+#include <direct.h>
 #include <windef.h>
 #include <winbase.h>
 #include <winnls.h>
@@ -33,6 +34,9 @@
 
 typedef void (__cdecl *_INITTERMFUN)(void);
 static void (__cdecl *p_initterm)(_INITTERMFUN *start, _INITTERMFUN *end);
+static void (__cdecl *p__getmainargs)(int *argc, char** *argv, char** *envp,
+				    int expand_wildcards, int *new_mode);
+
 
 static int callbacked;
 
@@ -103,15 +107,110 @@ static void test_initvar( HMODULE hmsvcrt )
             osver, osvi.dwBuildNumber);
 }
 
+static void test_getmainargs_child(int arg_c, char ** arg_v)
+{
+  int larg_c;
+  char ** larg_v;
+  char ** env;
+  int mode = 0; /* native msvcrt needs valid mode */
+  
+  if(!strcmp(arg_v[3],"0"))
+    {
+      p__getmainargs(&larg_c, &larg_v, &env, FALSE, &mode);
+      ok(!strcmp(larg_v[4], "*"), "Wildcards should not get expanded\n");
+      p__getmainargs(&larg_c, &larg_v, &env, TRUE, &mode);
+      ok(strcmp(larg_v[4], "*"), "Wildcards should get expanded\n");
+      return;
+    }
+  if(!strcmp(arg_v[3],"1"))
+    {
+      p__getmainargs(&larg_c, &larg_v, &env, TRUE, &mode);
+      if(strcmp(larg_v[4],"todo_wine"))
+	ok(!strcmp(larg_v[5], arg_v[6]), "Path %s not reproduced, res %s\n", 
+	   arg_v[6], larg_v[5]);
+      return;
+    }
+}
+
+static void test_getmainargs ( const char* selfname )
+{
+  const char*  arg_v[8];
+  char fname[MAX_PATH];
+  char ext[MAX_PATH];
+  char buffer1[MAX_PATH];
+  char buffer2[MAX_PATH];
+  
+  arg_v[0] = selfname;
+  arg_v[1] = "tests/data.c";
+  arg_v[2] = "getmainargs";
+  arg_v[3] = "0";
+  arg_v[4] = "*";
+  arg_v[5] = NULL;
+  _spawnvp(_P_WAIT, selfname, arg_v);
+  
+  arg_v[3] = "1";
+  arg_v[4] = "ok";
+  arg_v[5] = "testdi*";
+  arg_v[6] = "testdir";
+  arg_v[7] = NULL;
+  _spawnvp(_P_WAIT, selfname, arg_v);
+  
+  arg_v[5] = "./testdir/*";
+  arg_v[6] = "./testdir/*";  /* file doesn't exist, so reproduce the name */ 
+  _spawnvp(_P_WAIT, selfname, arg_v);
+  
+  /* make sure we get a filename without path that exists*/
+  _splitpath(selfname, NULL, NULL, fname, ext);
+  
+  sprintf(buffer1, "%s%s", fname, ext);
+  strcpy(buffer2, buffer1);
+  buffer2[strlen(buffer2) -4] = '*';
+  arg_v[5] = buffer2;
+  arg_v[6] = buffer1;
+  _spawnvp(_P_WAIT, selfname, arg_v);
+  
+  sprintf(buffer1, "./%s%s", fname, ext);
+  strcpy(buffer2, buffer1);
+  buffer2[strlen(buffer2) -4] = '*';
+  arg_v[5] = buffer2;
+  arg_v[6] = buffer1;
+  _spawnvp(_P_WAIT, selfname, arg_v);
+  
+  sprintf(buffer1, "../*/%s%s", fname, ext);
+  strcpy(buffer2, buffer1);
+  buffer2[strlen(buffer2) -4] = '*';
+  arg_v[5] = buffer2;
+  arg_v[6] = buffer2;                /* not expanded */
+  _spawnvp(_P_WAIT, selfname, arg_v);
+}
+
 START_TEST(data)
 {
+    int arg_c;
+    char** arg_v;
+  
     HMODULE hmsvcrt;
 
+    arg_c = winetest_get_mainargs( &arg_v );
+
     hmsvcrt = GetModuleHandleA("msvcrt.dll");
     if (!hmsvcrt)
         hmsvcrt = GetModuleHandleA("msvcrtd.dll");
     if (hmsvcrt)
+      {
         p_initterm=(void*)GetProcAddress(hmsvcrt, "_initterm");
+	p__getmainargs = (void *)GetProcAddress(hmsvcrt, "__getmainargs");
+	ok(p__getmainargs != 0, "Export __getmainargs not found\n"); 
+      }
+    if (arg_c >= 3)
+      {
+	if (strcmp(arg_v[2], "getmainargs") == 0)
+	  test_getmainargs_child(arg_c, arg_v);
+	return;
+      }
     test_initterm();
     test_initvar(hmsvcrt);
+    ok(mkdir("testdir") == 0,"Failed to create testdirectory\n");
+    test_getmainargs(arg_v[0]);
+    rmdir("testdir");
 }
-- 
1.6.4.2




More information about the wine-patches mailing list