[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