diff -r 000000000000 -r e4d67989cc36 genericopenlibs/openenvcore/libc/src/libc_init/ucrt0.cpp --- /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 +#include +#include // for chdir, environ +#include // for calloc +#include // for strdup +#include // for wcsdup +#include // 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 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 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(); + }