genericopenlibs/openenvcore/libc/src/libc_init/ucrt0.cpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Common code useful to all crt0 variants. This is kept in the DLL to allow us to
       
    15 // change it in future releases.
       
    16 // 
       
    17 //
       
    18 
       
    19 #include <e32std.h>
       
    20 #include <e32base.h>
       
    21 #include <unistd.h>	// for chdir, environ
       
    22 #include <stdlib.h>	// for calloc
       
    23 #include <string.h>	// for strdup
       
    24 #include <wchar.h>	// for wcsdup
       
    25 #include <fcntl.h>	// for O_RDONLY, O_WRONLY and O_CREAT
       
    26 #include "estlib.h"
       
    27 #include "sysif.h"
       
    28 #include "libc_private.h"
       
    29 
       
    30 
       
    31 extern "C" {
       
    32 void SetupEnviron();
       
    33 void GetTmpDirName();
       
    34 }
       
    35 
       
    36 const TInt KMaxArgC=20;
       
    37 
       
    38 static char* wcstombs_alloc (const wchar_t* aString)
       
    39 	{
       
    40 	if (aString==NULL)
       
    41 		return NULL;
       
    42 
       
    43 	size_t size = wcstombs(0, aString, 0);
       
    44 	char* buf = (char*)User::Alloc((size+1) * sizeof(char));
       
    45 	size = wcstombs(buf, aString, size);
       
    46 
       
    47 	if (size == (size_t)-1)
       
    48 		{
       
    49 		User::Free(buf);
       
    50 		return NULL;
       
    51 		}
       
    52 	buf[size] = '\0';
       
    53 	return buf;
       
    54 	}
       
    55 
       
    56 #ifdef EKA2
       
    57 
       
    58 static wchar_t* allocCommandLine(const TDesC& aPath)
       
    59 	{
       
    60     TInt cmdLength = User::CommandLineLength()+1;	// for zero termination
       
    61 	TText16* cmdbuf = (TText16*)User::Alloc(cmdLength*sizeof(TText16));
       
    62 	if (cmdbuf==0)
       
    63 		return (wchar_t*)cmdbuf;		// we are just doomed, so give up now
       
    64 
       
    65 	TPtr16 cmdline(cmdbuf, cmdLength);
       
    66     User::CommandLine(cmdline);
       
    67 
       
    68 	// The .EXE recogniser supplies a command line which is the name of the file,
       
    69 	// followed by a space. This is usually not what's wanted, so remove the
       
    70 	// filename if it is an exact match for the start of the command line.
       
    71 
       
    72 	if (cmdline.Find(aPath)==0)
       
    73 		{
       
    74 		cmdline.Delete(0, aPath.Length());
       
    75 		}
       
    76 	cmdline.ZeroTerminate();
       
    77 	return (wchar_t*)cmdbuf;
       
    78 	}
       
    79 
       
    80 #else//EKA2
       
    81 
       
    82 static wchar_t* allocCommandLine(const TDesC& aPath)
       
    83 	{
       
    84 	RProcess me;
       
    85 	TInt cmdLength = me.CommandLineLength()+1;	// for zero termination
       
    86 	TText16* cmdbuf = (TText16*)User::Alloc(cmdLength*sizeof(TText16));
       
    87 	if (cmdbuf==0)
       
    88 		return (wchar_t*)cmdbuf;		// we are just doomed, so give up now
       
    89 
       
    90 	TPtr16 cmdline(cmdbuf, cmdLength);
       
    91 	me.CommandLine(cmdline);
       
    92 
       
    93 	// The .EXE recogniser supplies a command line which is the name of the file,
       
    94 	// followed by a space. This is usually not what's wanted, so remove the
       
    95 	// filename if it is an exact match for the start of the command line.
       
    96 
       
    97 	if (cmdline.Find(aPath)==0)
       
    98 		{
       
    99 		cmdline.Delete(0, aPath.Length());
       
   100 		}
       
   101 	cmdline.ZeroTerminate();
       
   102 	return (wchar_t*)cmdbuf;
       
   103 	}
       
   104 
       
   105 #endif//EKA2
       
   106 
       
   107 EXPORT_C void __crt0(int& argc, char**& argv, char**& envp)
       
   108 	{
       
   109 	wchar_t** wenvp = 0;
       
   110 	int envcnt = 0;
       
   111 
       
   112 	// Check to see if I was the product of a popen/popen3/posix_spawn/system op.
       
   113 	Backend()->CheckOrigins(wenvp, envcnt);
       
   114 
       
   115 	if (wenvp)
       
   116 		{
       
   117 		// Parent has passed in the an environ for the child. Update envp
       
   118 		envp = (char **)User::Alloc((envcnt+1) * sizeof(char*));
       
   119 		if (envp)
       
   120 			{
       
   121 			for (int i = 0; i < envcnt; ++i)
       
   122 				{
       
   123 				int len = wcslen(wenvp[i]) + 1;
       
   124 				envp[i] = (char *)User::Alloc(len * sizeof(char));
       
   125 				if (!envp[i] || (wcstombs(envp[i], wenvp[i], len) == (size_t)-1))
       
   126 					{
       
   127 					// if envp[i] is NULL, Free does nothing
       
   128 					User::Free(envp[i]);
       
   129 					envp[i] = 0;
       
   130 					break;
       
   131 					}
       
   132 				}
       
   133 			// set the terminal zero
       
   134 			envp[envcnt] = 0;
       
   135 			}
       
   136 
       
   137 		// Cleanup wenvp allocated in CheckOrigins
       
   138 		for (int i = 0; i < envcnt; ++i)
       
   139 			{
       
   140 			User::Free(wenvp[i]);
       
   141 			}
       
   142 		User::Free(wenvp);
       
   143 		}
       
   144 	else
       
   145 		{
       
   146 		// set envp from environ
       
   147 		char** temp = environ;
       
   148 		for (envcnt = 0; temp[envcnt]; ++envcnt) { }
       
   149 		// account for the terminal zero in alloc
       
   150 		envp = (char**)User::Alloc((envcnt+1) * sizeof(char*));
       
   151 		if (envp)
       
   152 			{
       
   153 			for(int i = 0; i < envcnt; ++i)
       
   154 				{
       
   155 				int len = strlen(temp[i]) + 1;
       
   156 				envp[i] = (char*)User::Alloc(len * sizeof(char));
       
   157 				if (!envp[i])
       
   158 					{
       
   159 					envp[i] = NULL;
       
   160 					break;
       
   161 					}
       
   162 				strncpy(envp[i], temp[i], len);
       
   163 				}
       
   164 			// set the terminal zero
       
   165 			envp[envcnt] = NULL;
       
   166 			}
       
   167 		}
       
   168 
       
   169 	// Find out the filename for argv[0]
       
   170 	TBuf16<KMaxFileName+1> exepath(RProcess().FileName());
       
   171 
       
   172 	// Sort out argc/argv, creating an array of pointers into a copy of
       
   173 	// the commandline.
       
   174 
       
   175 	wchar_t* cmdbuf = allocCommandLine(exepath);
       
   176 	char* cmd = wcstombs_alloc(cmdbuf);
       
   177 	User::Free(cmdbuf);
       
   178 	char* filename = wcstombs_alloc((const wchar_t *)exepath.PtrZ());
       
   179 
       
   180 	//Copy program name now so that it can be accessed by others
       
   181 	__progname = filename;
       
   182 
       
   183 	argv = (char**)calloc(KMaxArgC, sizeof(char*));
       
   184 	if (argv==0 || cmd==0 || filename== 0)
       
   185 		return;		// it's basically doomed at this point anyway
       
   186 
       
   187 	//Check if there are redirection operators in the arguments
       
   188 	char* ptr = strpbrk(cmd, "<>");
       
   189 	if (ptr)
       
   190 		{
       
   191 		char* p1 = ptr, *p2;
       
   192 		int opfd, ipfd;
       
   193 
       
   194 		switch (*p1)
       
   195 			{
       
   196 		case '<':
       
   197 			p2 = strchr(++p1, '>');
       
   198 			if (p2)
       
   199 				{
       
   200 				*p2++ = 0;
       
   201 				if (*p2 == '>')
       
   202 					{
       
   203 					opfd = open(++p2, O_WRONLY|O_CREAT|O_APPEND);
       
   204 					}
       
   205 				else
       
   206 					{
       
   207 					opfd = open(p2, O_WRONLY|O_CREAT|O_TRUNC);
       
   208 					}
       
   209 
       
   210 				if (opfd > 0)
       
   211 					{
       
   212 					dup2(opfd, 1);
       
   213 					}
       
   214 				}
       
   215 
       
   216 			ipfd = open(p1, O_RDONLY);
       
   217 			if (ipfd > 0)
       
   218 				{
       
   219 				dup2(ipfd, 0);
       
   220 				}
       
   221 			break;
       
   222 		case '>':
       
   223 			p2 = strchr(++p1, '<');
       
   224 			if (p2)
       
   225 				{
       
   226 				*p2++ = 0;
       
   227 				ipfd = open(p2, O_RDONLY);
       
   228 				if (ipfd > 0)
       
   229 					{
       
   230 					dup2(ipfd, 0);
       
   231 					}
       
   232 				}
       
   233 
       
   234 			if (*p1 == '>')
       
   235 				{
       
   236 				opfd = open(++p1, O_WRONLY|O_CREAT|O_APPEND);
       
   237 				}
       
   238 			else
       
   239 				{
       
   240 				opfd = open(p1, O_WRONLY|O_CREAT|O_TRUNC);
       
   241 				}
       
   242 
       
   243 			if (opfd > 0)
       
   244 				{
       
   245 				dup2(opfd, 1);
       
   246 				}
       
   247 			break;
       
   248 		default:
       
   249 			break;
       
   250 			}
       
   251 
       
   252 		// Ensure that only the string until the first redirection operator
       
   253 		// is considered for command args processing
       
   254 		*ptr = 0;
       
   255 		}
       
   256 
       
   257 	// Split the command line into the separate arguments
       
   258 	// Follow the stdarg.c rules in the Win32 runtime, namely
       
   259 	// 1. space and tab are whitespace separators, except inside "..." pairs
       
   260 	// 2. strings of \ are literal unless followed by " (see below)
       
   261 	// 3. a pair of "" in a quoted string is a literal "
       
   262 
       
   263 	const char KSpace= ' ';
       
   264 	const char KTab  = '\t';
       
   265 	const char KQuote= '"';
       
   266 	const char KSlash= '\\';
       
   267 
       
   268 	argv[0]=filename;
       
   269 	argc = 1;
       
   270 	char *q = cmd;
       
   271 	const char* p = cmd;
       
   272 	int currentMaxArgc = KMaxArgC;
       
   273 	FOREVER
       
   274 		{
       
   275 		char c;
       
   276 		TInt quoted=0;
       
   277 
       
   278 		// skip leading whitespace
       
   279 		do
       
   280 			c=*p++;
       
   281 		while (c && (c==KSpace || c==KTab));
       
   282 
       
   283 		// update the argv,argc
       
   284 		if (c=='\0')
       
   285 			break;
       
   286 		else if(argc >= currentMaxArgc)
       
   287 			{
       
   288 			currentMaxArgc += KMaxArgC;
       
   289 			argv = (char**)realloc(argv, currentMaxArgc * sizeof(char*));
       
   290 			}
       
   291 
       
   292 		argv[argc] = q;
       
   293 		argc++;
       
   294 
       
   295 		// copy the argument from p to q
       
   296 		for (;c!='\0';c=*p++)
       
   297 			{
       
   298 
       
   299 			// Poor buggers have to cope with UNC filenames, e.g. \\host\dir\file
       
   300 			// Hence the rather odd rules: for N>=0
       
   301 			// 2N+1 slash + " => N slash + literal "
       
   302 			// 2N   slash + " => N slash, start/end quoted substring
       
   303 			// N    slash + ? => N slash + ?
       
   304 
       
   305 			int slashcount=0;
       
   306 			while (c==KSlash)
       
   307 				{
       
   308 				*q++=c;		// copy the slashes (might be too many)
       
   309 				slashcount++;
       
   310 				c=*p++;
       
   311 				}
       
   312 			if (c=='\0')
       
   313 				break;
       
   314 			if (c==KQuote)
       
   315 				{
       
   316 				q-=(slashcount-(slashcount/2));	// slashes followed by quote - adjust
       
   317 				if (slashcount&1)
       
   318 					{
       
   319 					*q++=c;		// literal quote
       
   320 					continue;
       
   321 					}
       
   322 				if (quoted && *p==KQuote)
       
   323 					{
       
   324 					p++;
       
   325 					*q++=c;		// "" inside quoted section = literal quote
       
   326 					continue;
       
   327 					}
       
   328 				quoted=!quoted;
       
   329 				continue;
       
   330 				}
       
   331 			if (!quoted && (c==KSpace || c==KTab))
       
   332 				break;
       
   333 			*q++=c;
       
   334 			}
       
   335 		*q++='\0';	// terminate the copy
       
   336 
       
   337 		if (c=='\0')
       
   338 			break;	// end of command line
       
   339 		}
       
   340 
       
   341 	//If environ is not yet initialized for this Process
       
   342 	SetupEnviron();
       
   343 	}
       
   344 
       
   345 EXPORT_C void __crt0(int& argc, wchar_t**& wargv, wchar_t**& wenvp)
       
   346 	{
       
   347 	int envcnt = 0;
       
   348 
       
   349 	// Check to see if I was the product of a popen/popen3/posix_spawn/system op.
       
   350 	Backend()->CheckOrigins(wenvp, envcnt);
       
   351 
       
   352 	if (!wenvp)
       
   353 		{
       
   354 		// set wenvp from environ
       
   355 		char** temp = environ;
       
   356 		for (envcnt = 0; temp[envcnt]; ++envcnt) { }
       
   357 		// account for the terminal zero during alloc
       
   358 		wenvp = (wchar_t**)User::Alloc((envcnt+1) * sizeof(wchar_t*));
       
   359 		if (wenvp)
       
   360 			{
       
   361 			for(int i = 0; i < envcnt; ++i)
       
   362 				{
       
   363 				int len = strlen(temp[i])+1;
       
   364 				wenvp[i] = (wchar_t*)User::Alloc(len * sizeof(wchar_t));
       
   365 				if (!wenvp[i] || (mbstowcs(wenvp[i], temp[i], len) == (size_t)-1))
       
   366 					{
       
   367 					// if wenvp[i] is NULL, Free does nothing
       
   368 					User::Free(wenvp[i]);
       
   369 					wenvp[i] = NULL;
       
   370 					break;
       
   371 					}
       
   372 				}
       
   373 				// set the terminal 0
       
   374 			wenvp[envcnt] = NULL;
       
   375 			}
       
   376 		}
       
   377 
       
   378 	// Find out the filename for argv[0]
       
   379 	TBuf16<KMaxFileName+1> exepath(RProcess().FileName());
       
   380 
       
   381 	// Sort out argc/argv, creating an array of pointers into a copy of
       
   382 	// the commandline.
       
   383 
       
   384 	wchar_t* cmd = allocCommandLine(exepath);
       
   385 	//coverity[alloc_fn]
       
   386 	//coverity[assign]
       
   387 	wchar_t* filename = wcsdup((const wchar_t *)exepath.PtrZ());
       
   388 	wargv = (wchar_t**)calloc(KMaxArgC, sizeof(wchar_t*));
       
   389 
       
   390 	if (wargv==0 || cmd==0 || filename==0)
       
   391 	//coverity[memory_leak]
       
   392 		return;		// it's basically doomed at this point anyway
       
   393 
       
   394 	// Split the command line into the separate arguments
       
   395 	// Follow the stdarg.c rules in the Win32 runtime, namely
       
   396 	// 1. space and tab are whitespace separators, except inside "..." pairs
       
   397 	// 2. strings of \ are literal unless followed by " (see below)
       
   398 	// 3. a pair of "" in a quoted string is a literal "
       
   399 
       
   400 	const wchar_t KSpace= L' ';
       
   401 	const wchar_t KTab  = L'\t';
       
   402 	const wchar_t KQuote= L'"';
       
   403 	const wchar_t KSlash= L'\\';
       
   404 
       
   405 	wargv[0]=filename;
       
   406 	argc = 1;
       
   407 	wchar_t *q = cmd;
       
   408 	wchar_t *p = cmd;
       
   409 	int currentMaxArgc = KMaxArgC;
       
   410 	FOREVER
       
   411 		{
       
   412 		wchar_t c;
       
   413 		TInt quoted=0;
       
   414 
       
   415 		// skip leading whitespace
       
   416 		do
       
   417 			c=*p++;
       
   418 		while (c && (c==KSpace || c==KTab));
       
   419 
       
   420 		// update the argv,argc
       
   421 		if (c=='\0')
       
   422 			break;
       
   423 		else if(argc >= currentMaxArgc)
       
   424 			{
       
   425 			currentMaxArgc += KMaxArgC;
       
   426 			wargv = (wchar_t**)realloc(wargv, currentMaxArgc * sizeof(wchar_t*));
       
   427 			}
       
   428 
       
   429 		wargv[argc] = q;
       
   430 		argc++;
       
   431 
       
   432 		// copy the argument from p to q
       
   433 		for (;c!=L'\0';c=*p++)
       
   434 			{
       
   435 
       
   436 			// Poor buggers have to cope with UNC filenames, e.g. \\host\dir\file
       
   437 			// Hence the rather odd rules: for N>=0
       
   438 			// 2N+1 slash + " => N slash + literal "
       
   439 			// 2N   slash + " => N slash, start/end quoted substring
       
   440 			// N    slash + ? => N slash + ?
       
   441 
       
   442 			int slashcount=0;
       
   443 			while (c==KSlash)
       
   444 				{
       
   445 				*q++=c;		// copy the slashes (might be too many)
       
   446 				slashcount++;
       
   447 				c=*p++;
       
   448 				}
       
   449 			if (c==L'\0')
       
   450 				break;
       
   451 			if (c==KQuote)
       
   452 				{
       
   453 				q-=(slashcount-(slashcount/2));	// slashes followed by quote - adjust
       
   454 				if (slashcount&1)
       
   455 					{
       
   456 					*q++=c;		// literal quote
       
   457 					continue;
       
   458 					}
       
   459 				if (quoted && *p==KQuote)
       
   460 					{
       
   461 					p++;
       
   462 					*q++=c;		// "" inside quoted section = literal quote
       
   463 					continue;
       
   464 					}
       
   465 				quoted=!quoted;
       
   466 				continue;
       
   467 				}
       
   468 			if (!quoted && (c==KSpace || c==KTab))
       
   469 				break;
       
   470 			*q++=c;
       
   471 			}
       
   472 		*q++=L'\0';	// terminate the copy
       
   473 
       
   474 		if (c==L'\0')
       
   475 			break;	// end of command line
       
   476 		}
       
   477 
       
   478 	//If environ is not yet initialized for this Process
       
   479 	SetupEnviron();
       
   480 	GetTmpDirName();
       
   481 	}