genericopenlibs/openenvcore/libc/src/libc_init/ucrt0.cpp
changeset 0 e4d67989cc36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/genericopenlibs/openenvcore/libc/src/libc_init/ucrt0.cpp	Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,481 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Common code useful to all crt0 variants. This is kept in the DLL to allow us to
+// change it in future releases.
+// 
+//
+
+#include <e32std.h>
+#include <e32base.h>
+#include <unistd.h>	// for chdir, environ
+#include <stdlib.h>	// for calloc
+#include <string.h>	// for strdup
+#include <wchar.h>	// for wcsdup
+#include <fcntl.h>	// for O_RDONLY, O_WRONLY and O_CREAT
+#include "estlib.h"
+#include "sysif.h"
+#include "libc_private.h"
+
+
+extern "C" {
+void SetupEnviron();
+void GetTmpDirName();
+}
+
+const TInt KMaxArgC=20;
+
+static char* wcstombs_alloc (const wchar_t* aString)
+	{
+	if (aString==NULL)
+		return NULL;
+
+	size_t size = wcstombs(0, aString, 0);
+	char* buf = (char*)User::Alloc((size+1) * sizeof(char));
+	size = wcstombs(buf, aString, size);
+
+	if (size == (size_t)-1)
+		{
+		User::Free(buf);
+		return NULL;
+		}
+	buf[size] = '\0';
+	return buf;
+	}
+
+#ifdef EKA2
+
+static wchar_t* allocCommandLine(const TDesC& aPath)
+	{
+    TInt cmdLength = User::CommandLineLength()+1;	// for zero termination
+	TText16* cmdbuf = (TText16*)User::Alloc(cmdLength*sizeof(TText16));
+	if (cmdbuf==0)
+		return (wchar_t*)cmdbuf;		// we are just doomed, so give up now
+
+	TPtr16 cmdline(cmdbuf, cmdLength);
+    User::CommandLine(cmdline);
+
+	// The .EXE recogniser supplies a command line which is the name of the file,
+	// followed by a space. This is usually not what's wanted, so remove the
+	// filename if it is an exact match for the start of the command line.
+
+	if (cmdline.Find(aPath)==0)
+		{
+		cmdline.Delete(0, aPath.Length());
+		}
+	cmdline.ZeroTerminate();
+	return (wchar_t*)cmdbuf;
+	}
+
+#else//EKA2
+
+static wchar_t* allocCommandLine(const TDesC& aPath)
+	{
+	RProcess me;
+	TInt cmdLength = me.CommandLineLength()+1;	// for zero termination
+	TText16* cmdbuf = (TText16*)User::Alloc(cmdLength*sizeof(TText16));
+	if (cmdbuf==0)
+		return (wchar_t*)cmdbuf;		// we are just doomed, so give up now
+
+	TPtr16 cmdline(cmdbuf, cmdLength);
+	me.CommandLine(cmdline);
+
+	// The .EXE recogniser supplies a command line which is the name of the file,
+	// followed by a space. This is usually not what's wanted, so remove the
+	// filename if it is an exact match for the start of the command line.
+
+	if (cmdline.Find(aPath)==0)
+		{
+		cmdline.Delete(0, aPath.Length());
+		}
+	cmdline.ZeroTerminate();
+	return (wchar_t*)cmdbuf;
+	}
+
+#endif//EKA2
+
+EXPORT_C void __crt0(int& argc, char**& argv, char**& envp)
+	{
+	wchar_t** wenvp = 0;
+	int envcnt = 0;
+
+	// Check to see if I was the product of a popen/popen3/posix_spawn/system op.
+	Backend()->CheckOrigins(wenvp, envcnt);
+
+	if (wenvp)
+		{
+		// Parent has passed in the an environ for the child. Update envp
+		envp = (char **)User::Alloc((envcnt+1) * sizeof(char*));
+		if (envp)
+			{
+			for (int i = 0; i < envcnt; ++i)
+				{
+				int len = wcslen(wenvp[i]) + 1;
+				envp[i] = (char *)User::Alloc(len * sizeof(char));
+				if (!envp[i] || (wcstombs(envp[i], wenvp[i], len) == (size_t)-1))
+					{
+					// if envp[i] is NULL, Free does nothing
+					User::Free(envp[i]);
+					envp[i] = 0;
+					break;
+					}
+				}
+			// set the terminal zero
+			envp[envcnt] = 0;
+			}
+
+		// Cleanup wenvp allocated in CheckOrigins
+		for (int i = 0; i < envcnt; ++i)
+			{
+			User::Free(wenvp[i]);
+			}
+		User::Free(wenvp);
+		}
+	else
+		{
+		// set envp from environ
+		char** temp = environ;
+		for (envcnt = 0; temp[envcnt]; ++envcnt) { }
+		// account for the terminal zero in alloc
+		envp = (char**)User::Alloc((envcnt+1) * sizeof(char*));
+		if (envp)
+			{
+			for(int i = 0; i < envcnt; ++i)
+				{
+				int len = strlen(temp[i]) + 1;
+				envp[i] = (char*)User::Alloc(len * sizeof(char));
+				if (!envp[i])
+					{
+					envp[i] = NULL;
+					break;
+					}
+				strncpy(envp[i], temp[i], len);
+				}
+			// set the terminal zero
+			envp[envcnt] = NULL;
+			}
+		}
+
+	// Find out the filename for argv[0]
+	TBuf16<KMaxFileName+1> exepath(RProcess().FileName());
+
+	// Sort out argc/argv, creating an array of pointers into a copy of
+	// the commandline.
+
+	wchar_t* cmdbuf = allocCommandLine(exepath);
+	char* cmd = wcstombs_alloc(cmdbuf);
+	User::Free(cmdbuf);
+	char* filename = wcstombs_alloc((const wchar_t *)exepath.PtrZ());
+
+	//Copy program name now so that it can be accessed by others
+	__progname = filename;
+
+	argv = (char**)calloc(KMaxArgC, sizeof(char*));
+	if (argv==0 || cmd==0 || filename== 0)
+		return;		// it's basically doomed at this point anyway
+
+	//Check if there are redirection operators in the arguments
+	char* ptr = strpbrk(cmd, "<>");
+	if (ptr)
+		{
+		char* p1 = ptr, *p2;
+		int opfd, ipfd;
+
+		switch (*p1)
+			{
+		case '<':
+			p2 = strchr(++p1, '>');
+			if (p2)
+				{
+				*p2++ = 0;
+				if (*p2 == '>')
+					{
+					opfd = open(++p2, O_WRONLY|O_CREAT|O_APPEND);
+					}
+				else
+					{
+					opfd = open(p2, O_WRONLY|O_CREAT|O_TRUNC);
+					}
+
+				if (opfd > 0)
+					{
+					dup2(opfd, 1);
+					}
+				}
+
+			ipfd = open(p1, O_RDONLY);
+			if (ipfd > 0)
+				{
+				dup2(ipfd, 0);
+				}
+			break;
+		case '>':
+			p2 = strchr(++p1, '<');
+			if (p2)
+				{
+				*p2++ = 0;
+				ipfd = open(p2, O_RDONLY);
+				if (ipfd > 0)
+					{
+					dup2(ipfd, 0);
+					}
+				}
+
+			if (*p1 == '>')
+				{
+				opfd = open(++p1, O_WRONLY|O_CREAT|O_APPEND);
+				}
+			else
+				{
+				opfd = open(p1, O_WRONLY|O_CREAT|O_TRUNC);
+				}
+
+			if (opfd > 0)
+				{
+				dup2(opfd, 1);
+				}
+			break;
+		default:
+			break;
+			}
+
+		// Ensure that only the string until the first redirection operator
+		// is considered for command args processing
+		*ptr = 0;
+		}
+
+	// Split the command line into the separate arguments
+	// Follow the stdarg.c rules in the Win32 runtime, namely
+	// 1. space and tab are whitespace separators, except inside "..." pairs
+	// 2. strings of \ are literal unless followed by " (see below)
+	// 3. a pair of "" in a quoted string is a literal "
+
+	const char KSpace= ' ';
+	const char KTab  = '\t';
+	const char KQuote= '"';
+	const char KSlash= '\\';
+
+	argv[0]=filename;
+	argc = 1;
+	char *q = cmd;
+	const char* p = cmd;
+	int currentMaxArgc = KMaxArgC;
+	FOREVER
+		{
+		char c;
+		TInt quoted=0;
+
+		// skip leading whitespace
+		do
+			c=*p++;
+		while (c && (c==KSpace || c==KTab));
+
+		// update the argv,argc
+		if (c=='\0')
+			break;
+		else if(argc >= currentMaxArgc)
+			{
+			currentMaxArgc += KMaxArgC;
+			argv = (char**)realloc(argv, currentMaxArgc * sizeof(char*));
+			}
+
+		argv[argc] = q;
+		argc++;
+
+		// copy the argument from p to q
+		for (;c!='\0';c=*p++)
+			{
+
+			// Poor buggers have to cope with UNC filenames, e.g. \\host\dir\file
+			// Hence the rather odd rules: for N>=0
+			// 2N+1 slash + " => N slash + literal "
+			// 2N   slash + " => N slash, start/end quoted substring
+			// N    slash + ? => N slash + ?
+
+			int slashcount=0;
+			while (c==KSlash)
+				{
+				*q++=c;		// copy the slashes (might be too many)
+				slashcount++;
+				c=*p++;
+				}
+			if (c=='\0')
+				break;
+			if (c==KQuote)
+				{
+				q-=(slashcount-(slashcount/2));	// slashes followed by quote - adjust
+				if (slashcount&1)
+					{
+					*q++=c;		// literal quote
+					continue;
+					}
+				if (quoted && *p==KQuote)
+					{
+					p++;
+					*q++=c;		// "" inside quoted section = literal quote
+					continue;
+					}
+				quoted=!quoted;
+				continue;
+				}
+			if (!quoted && (c==KSpace || c==KTab))
+				break;
+			*q++=c;
+			}
+		*q++='\0';	// terminate the copy
+
+		if (c=='\0')
+			break;	// end of command line
+		}
+
+	//If environ is not yet initialized for this Process
+	SetupEnviron();
+	}
+
+EXPORT_C void __crt0(int& argc, wchar_t**& wargv, wchar_t**& wenvp)
+	{
+	int envcnt = 0;
+
+	// Check to see if I was the product of a popen/popen3/posix_spawn/system op.
+	Backend()->CheckOrigins(wenvp, envcnt);
+
+	if (!wenvp)
+		{
+		// set wenvp from environ
+		char** temp = environ;
+		for (envcnt = 0; temp[envcnt]; ++envcnt) { }
+		// account for the terminal zero during alloc
+		wenvp = (wchar_t**)User::Alloc((envcnt+1) * sizeof(wchar_t*));
+		if (wenvp)
+			{
+			for(int i = 0; i < envcnt; ++i)
+				{
+				int len = strlen(temp[i])+1;
+				wenvp[i] = (wchar_t*)User::Alloc(len * sizeof(wchar_t));
+				if (!wenvp[i] || (mbstowcs(wenvp[i], temp[i], len) == (size_t)-1))
+					{
+					// if wenvp[i] is NULL, Free does nothing
+					User::Free(wenvp[i]);
+					wenvp[i] = NULL;
+					break;
+					}
+				}
+				// set the terminal 0
+			wenvp[envcnt] = NULL;
+			}
+		}
+
+	// Find out the filename for argv[0]
+	TBuf16<KMaxFileName+1> exepath(RProcess().FileName());
+
+	// Sort out argc/argv, creating an array of pointers into a copy of
+	// the commandline.
+
+	wchar_t* cmd = allocCommandLine(exepath);
+	//coverity[alloc_fn]
+	//coverity[assign]
+	wchar_t* filename = wcsdup((const wchar_t *)exepath.PtrZ());
+	wargv = (wchar_t**)calloc(KMaxArgC, sizeof(wchar_t*));
+
+	if (wargv==0 || cmd==0 || filename==0)
+	//coverity[memory_leak]
+		return;		// it's basically doomed at this point anyway
+
+	// Split the command line into the separate arguments
+	// Follow the stdarg.c rules in the Win32 runtime, namely
+	// 1. space and tab are whitespace separators, except inside "..." pairs
+	// 2. strings of \ are literal unless followed by " (see below)
+	// 3. a pair of "" in a quoted string is a literal "
+
+	const wchar_t KSpace= L' ';
+	const wchar_t KTab  = L'\t';
+	const wchar_t KQuote= L'"';
+	const wchar_t KSlash= L'\\';
+
+	wargv[0]=filename;
+	argc = 1;
+	wchar_t *q = cmd;
+	wchar_t *p = cmd;
+	int currentMaxArgc = KMaxArgC;
+	FOREVER
+		{
+		wchar_t c;
+		TInt quoted=0;
+
+		// skip leading whitespace
+		do
+			c=*p++;
+		while (c && (c==KSpace || c==KTab));
+
+		// update the argv,argc
+		if (c=='\0')
+			break;
+		else if(argc >= currentMaxArgc)
+			{
+			currentMaxArgc += KMaxArgC;
+			wargv = (wchar_t**)realloc(wargv, currentMaxArgc * sizeof(wchar_t*));
+			}
+
+		wargv[argc] = q;
+		argc++;
+
+		// copy the argument from p to q
+		for (;c!=L'\0';c=*p++)
+			{
+
+			// Poor buggers have to cope with UNC filenames, e.g. \\host\dir\file
+			// Hence the rather odd rules: for N>=0
+			// 2N+1 slash + " => N slash + literal "
+			// 2N   slash + " => N slash, start/end quoted substring
+			// N    slash + ? => N slash + ?
+
+			int slashcount=0;
+			while (c==KSlash)
+				{
+				*q++=c;		// copy the slashes (might be too many)
+				slashcount++;
+				c=*p++;
+				}
+			if (c==L'\0')
+				break;
+			if (c==KQuote)
+				{
+				q-=(slashcount-(slashcount/2));	// slashes followed by quote - adjust
+				if (slashcount&1)
+					{
+					*q++=c;		// literal quote
+					continue;
+					}
+				if (quoted && *p==KQuote)
+					{
+					p++;
+					*q++=c;		// "" inside quoted section = literal quote
+					continue;
+					}
+				quoted=!quoted;
+				continue;
+				}
+			if (!quoted && (c==KSpace || c==KTab))
+				break;
+			*q++=c;
+			}
+		*q++=L'\0';	// terminate the copy
+
+		if (c==L'\0')
+			break;	// end of command line
+		}
+
+	//If environ is not yet initialized for this Process
+	SetupEnviron();
+	GetTmpDirName();
+	}