From 09f20c7fbd7769bed440ea32a5fda3f5f4535027 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Sun, 18 Jan 2009 12:01:15 -0500 Subject: [PATCH] bug 470914 - add a __LOCATION__ field to the global object for files loaded on the commandline in xpcshell. r=timeless --- js/src/xpconnect/shell/xpcshell.cpp | 133 +++++++++++++++++- .../xpcshell-simple/example/location_load.js | 2 + .../example/unit/test_location.js | 44 ++++++ 3 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 tools/test-harness/xpcshell-simple/example/location_load.js create mode 100644 tools/test-harness/xpcshell-simple/example/unit/test_location.js diff --git a/js/src/xpconnect/shell/xpcshell.cpp b/js/src/xpconnect/shell/xpcshell.cpp index 322755d1fd99..637354c97309 100644 --- a/js/src/xpconnect/shell/xpcshell.cpp +++ b/js/src/xpconnect/shell/xpcshell.cpp @@ -55,6 +55,8 @@ #include "nsIServiceManager.h" #include "nsIComponentManager.h" #include "nsIComponentRegistrar.h" +#include "nsILocalFile.h" +#include "nsStringAPI.h" #include "jsapi.h" #include "jsdbgapi.h" #include "jsprf.h" @@ -68,6 +70,9 @@ #ifdef XP_MACOSX #include "xpcshellMacUtils.h" #endif +#ifdef XP_WIN +#include +#endif #ifndef XPCONNECT_STANDALONE #include "nsIScriptSecurityManager.h" @@ -98,6 +103,8 @@ /***************************************************************************/ +static const char kXPConnectServiceContractID[] = "@mozilla.org/js/xpc/XPConnect;1"; + #define EXITCODE_RUNTIME_ERROR 3 #define EXITCODE_FILE_NOT_FOUND 4 @@ -111,6 +118,85 @@ static JSBool reportWarnings = JS_TRUE; static JSBool compileOnly = JS_FALSE; JSPrincipals *gJSPrincipals = nsnull; +nsAutoString *gWorkingDirectory = nsnull; + +static JSBool +GetLocationProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +{ +#if !defined(XP_WIN) && !defined(XP_UNIX) + //XXX: your platform should really implement this + return JS_FALSE +#endif + JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL); + JSScript *script = JS_GetFrameScript(cx, fp); + const char *filename = JS_GetScriptFilename(cx, script); + + if (filename) { + nsresult rv; + nsCOMPtr xpc = + do_GetService(kXPConnectServiceContractID, &rv); + +#if defined(XP_WIN) + // convert from the system codepage to UTF-16 + int bufferSize = MultiByteToWideChar(CP_ACP, 0, filename, + -1, NULL, 0); + nsAutoString filenameString; + filenameString.SetLength(bufferSize); + MultiByteToWideChar(CP_ACP, 0, filename, + -1, (LPWSTR)filenameString.BeginWriting(), + filenameString.Length()); + // remove the null terminator + filenameString.SetLength(bufferSize - 1); + + // replace forward slashes with backslashes, + // since nsLocalFileWin chokes on them + PRUnichar *start, *end; + + filenameString.BeginWriting(&start, &end); + + while (start != end) { + if (*start == L'/') + *start = L'\\'; + start++; + } +#elif defined(XP_UNIX) + NS_ConvertUTF8toUTF16 filenameString(filename); +#endif + + nsCOMPtr location; + if (NS_SUCCEEDED(rv)) { + rv = NS_NewLocalFile(filenameString, + PR_FALSE, getter_AddRefs(location)); + } + + if (!location && gWorkingDirectory) { + // could be a relative path, try appending it to the cwd + // and then normalize + nsAutoString absolutePath(*gWorkingDirectory); + absolutePath.Append(filenameString); + + rv = NS_NewLocalFile(absolutePath, + PR_FALSE, getter_AddRefs(location)); + } + + if (location) { + nsCOMPtr locationHolder; + JSObject *locationObj = NULL; + + location->Normalize(); + rv = xpc->WrapNative(cx, obj, location, + NS_GET_IID(nsILocalFile), + getter_AddRefs(locationHolder)); + + if (NS_SUCCEEDED(rv) && + NS_SUCCEEDED(locationHolder->GetJSObject(&locationObj))) { + *vp = OBJECT_TO_JSVAL(locationObj); + } + } + } + + return JS_TRUE; +} static JSBool GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) { @@ -702,7 +788,6 @@ extern void add_history(char *line); } #endif - static void ProcessFile(JSContext *cx, JSObject *obj, const char *filename, FILE *file, JSBool forceTTY) @@ -1399,6 +1484,45 @@ ContextCallback(JSContext *cx, uintN contextOp) return JS_TRUE; } +static bool +GetCurrentWorkingDirectory(nsAString& workingDirectory) +{ +#if !defined(XP_WIN) && !defined(XP_UNIX) + //XXX: your platform should really implement this + return false; +#endif +#ifdef XP_WIN + DWORD requiredLength = GetCurrentDirectoryW(0, NULL); + workingDirectory.SetLength(requiredLength); + GetCurrentDirectoryW(workingDirectory.Length(), + (LPWSTR)workingDirectory.BeginWriting()); + // we got a trailing null there + workingDirectory.SetLength(requiredLength); + workingDirectory.Replace(workingDirectory.Length() - 1, 1, L'\\'); +#elif defined(XP_UNIX) + nsCAutoString cwd; + // 1024 is just a guess at a sane starting value + size_t bufsize = 1024; + char* result = nsnull; + while (result == nsnull) { + if (!cwd.SetLength(bufsize)) + return false; + result = getcwd(cwd.BeginWriting(), cwd.Length()); + if (!result) { + if (errno != ERANGE) + return false; + // need to make the buffer bigger + bufsize *= 2; + } + } + // size back down to the actual string length + cwd.SetLength(strlen(result) + 1); + cwd.Replace(cwd.Length() - 1, 1, '/'); + workingDirectory = NS_ConvertUTF8toUTF16(cwd); +#endif + return true; +} + int main(int argc, char **argv, char **envp) { @@ -1545,6 +1669,13 @@ main(int argc, char **argv, char **envp) return 1; } + nsAutoString workingDirectory; + if (GetCurrentWorkingDirectory(workingDirectory)) + gWorkingDirectory = &workingDirectory; + + JS_DefineProperty(cx, glob, "__LOCATION__", JSVAL_VOID, + GetLocationProperty, NULL, 0); + argc--; argv++; diff --git a/tools/test-harness/xpcshell-simple/example/location_load.js b/tools/test-harness/xpcshell-simple/example/location_load.js new file mode 100644 index 000000000000..d27a92191660 --- /dev/null +++ b/tools/test-harness/xpcshell-simple/example/location_load.js @@ -0,0 +1,2 @@ +// Gets loaded via test_location.js +do_check_eq(__LOCATION__.leafName, "location_load.js"); diff --git a/tools/test-harness/xpcshell-simple/example/unit/test_location.js b/tools/test-harness/xpcshell-simple/example/unit/test_location.js new file mode 100644 index 000000000000..c72cf99e8ee4 --- /dev/null +++ b/tools/test-harness/xpcshell-simple/example/unit/test_location.js @@ -0,0 +1,44 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * The Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ted Mielczarek + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +function run_test() { + do_check_eq(__LOCATION__.leafName, "test_location.js"); + // also check that __LOCATION__ works via load() + do_import_script("tools/test-harness/xpcshell-simple/example/location_load.js"); +}