1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 // jsshell.cpp - Utilities for the JS shell
8 
9 #include "shell/jsshell.h"
10 
11 #include "mozilla/Sprintf.h"
12 
13 #include "jsapi.h"
14 #include "jsfriendapi.h"
15 
16 #include "util/StringBuffer.h"
17 
18 using namespace JS;
19 
20 namespace js {
21 namespace shell {
22 
23 // Generate 'usage' and 'help' properties for the given object.
24 // JS_DefineFunctionsWithHelp will define individual function objects with both
25 // of those properties (eg getpid.usage = "getpid()" and getpid.help = "return
26 // the process id"). This function will generate strings for an "interface
27 // object", eg os.file, which contains some number of functions.
28 //
29 // .usage will be set to "<name> - interface object".
30 //
31 // .help will be set to a newline-separated list of functions that have either
32 // 'help' or 'usage' properties. Functions are described with their usage
33 // strings, if they have them, else with just their names.
34 //
GenerateInterfaceHelp(JSContext * cx,HandleObject obj,const char * name)35 bool GenerateInterfaceHelp(JSContext* cx, HandleObject obj, const char* name) {
36   AutoIdVector idv(cx);
37   if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &idv))
38     return false;
39 
40   StringBuffer buf(cx);
41   int numEntries = 0;
42   for (size_t i = 0; i < idv.length(); i++) {
43     RootedId id(cx, idv[i]);
44     RootedValue v(cx);
45     if (!JS_GetPropertyById(cx, obj, id, &v)) return false;
46     if (!v.isObject()) continue;
47     RootedObject prop(cx, &v.toObject());
48 
49     RootedValue usage(cx);
50     RootedValue help(cx);
51     if (!JS_GetProperty(cx, prop, "usage", &usage)) return false;
52     if (!JS_GetProperty(cx, prop, "help", &help)) return false;
53     if (!usage.isString() && !help.isString()) continue;
54 
55     if (numEntries && !buf.append("\n")) return false;
56     numEntries++;
57 
58     if (!buf.append("  ", 2)) return false;
59 
60     if (!buf.append(usage.isString() ? usage.toString()
61                                      : JSID_TO_FLAT_STRING(id)))
62       return false;
63   }
64 
65   RootedString s(cx, buf.finishString());
66   if (!s || !JS_DefineProperty(cx, obj, "help", s, 0)) return false;
67 
68   buf.clear();
69   if (!buf.append(name, strlen(name)) ||
70       !buf.append(" - interface object with ", 25))
71     return false;
72   char cbuf[100];
73   SprintfLiteral(cbuf, "%d %s", numEntries,
74                  numEntries == 1 ? "entry" : "entries");
75   if (!buf.append(cbuf, strlen(cbuf))) return false;
76   s = buf.finishString();
77   if (!s || !JS_DefineProperty(cx, obj, "usage", s, 0)) return false;
78 
79   return true;
80 }
81 
CreateAlias(JSContext * cx,const char * dstName,JS::HandleObject namespaceObj,const char * srcName)82 bool CreateAlias(JSContext* cx, const char* dstName,
83                  JS::HandleObject namespaceObj, const char* srcName) {
84   RootedObject global(cx, JS_GetGlobalForObject(cx, namespaceObj));
85   if (!global) return false;
86 
87   RootedValue val(cx);
88   if (!JS_GetProperty(cx, namespaceObj, srcName, &val)) return false;
89 
90   if (!val.isObject()) {
91     JS_ReportErrorASCII(cx, "attempted to alias nonexistent function");
92     return false;
93   }
94 
95   RootedObject function(cx, &val.toObject());
96   if (!JS_DefineProperty(cx, global, dstName, function, 0)) return false;
97 
98   return true;
99 }
100 
101 }  // namespace shell
102 }  // namespace js
103