File indexing completed on 2024-05-12 15:43:25
0001 /* 0002 * This file is part of the KDE libraries 0003 * Copyright (C) 2006 Harri Porten (porten@kde.org) 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, write to 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 * 0020 */ 0021 0022 #include "JSLock.h" 0023 #include "interpreter.h" 0024 #include "object.h" 0025 #include "package.h" 0026 #include "function.h" 0027 0028 #include <cstring> 0029 #include <stdlib.h> 0030 #include <stdio.h> 0031 #include <sys/stat.h> 0032 #include <fcntl.h> 0033 0034 #if PLATFORM(WIN_OS) 0035 # include <windows.h> 0036 # include <io.h> 0037 #else 0038 # include <unistd.h> 0039 #endif 0040 0041 #include <kjs_version.h> 0042 0043 enum ExitCode { ErrorNone, 0044 ErrorUnknownSwitch, 0045 ErrorMissingArg, 0046 ErrorReadFile, 0047 ErrorEval 0048 }; 0049 0050 using std::strcmp; 0051 0052 using namespace KJS; 0053 0054 static void printUsage(const char *app) 0055 { 0056 fprintf(stderr, 0057 "Usage: %s\n" 0058 " [ -h | -help | --help ]\n" 0059 " [ -e <statement> | <script> ]\n" 0060 " [-v | -version | --version]\n", 0061 app); 0062 } 0063 0064 static UString readFile(const char *fileName) 0065 { 0066 int fd = open(fileName, O_RDONLY); 0067 if (fd < 0) { 0068 fprintf(stderr, "Error opening %s", fileName); 0069 return UString(); 0070 } 0071 struct stat buf; 0072 if (fstat(fd, &buf) == -1) { 0073 fprintf(stderr, "Error stat'ing %s", fileName); 0074 close(fd); 0075 return UString(); 0076 } 0077 int siz = buf.st_size; 0078 char *c = new char[siz + 1]; 0079 int dataRead = read(fd, c, siz); 0080 if (dataRead == -1) { 0081 fprintf(stderr, "Error reading from %s", fileName); 0082 delete[] c; 0083 close(fd); 0084 return UString(); 0085 } 0086 c[dataRead] = '\0'; 0087 UString s = c; 0088 delete[] c; 0089 close(fd); 0090 return s; 0091 } 0092 0093 static ExitCode evaluateFile(Interpreter *interp, const char *fileName); 0094 0095 class GlobalImp : public JSGlobalObject 0096 { 0097 public: 0098 UString className() const override 0099 { 0100 return "global"; 0101 } 0102 }; 0103 0104 class TestFunctionImp : public JSObject 0105 { 0106 public: 0107 TestFunctionImp(int i, int length); 0108 bool implementsCall() const override 0109 { 0110 return true; 0111 } 0112 JSValue *callAsFunction(ExecState *exec, 0113 JSObject *thisObj, const List &args) override; 0114 enum { Print, Quit, Load, GC }; 0115 0116 private: 0117 int id; 0118 }; 0119 0120 TestFunctionImp::TestFunctionImp(int i, int length) 0121 : JSObject(), id(i) 0122 { 0123 putDirect(Identifier("length"), length, DontDelete | ReadOnly | DontEnum); 0124 } 0125 0126 JSValue *TestFunctionImp::callAsFunction(ExecState *exec, 0127 JSObject * /* thisObj */, 0128 const List &args) 0129 { 0130 switch (id) { 0131 case Print: 0132 printf("%s\n", JSValue::toString(args[0], exec).UTF8String().c_str()); 0133 return jsUndefined(); 0134 case Quit: 0135 exit(0); 0136 case GC: 0137 while (Interpreter::collect()) {} 0138 break; 0139 case Load: 0140 evaluateFile(exec->dynamicInterpreter(), JSValue::toString(args[0], exec).UTF8String().c_str()); 0141 break; 0142 default: 0143 abort(); 0144 } 0145 return jsUndefined(); 0146 } 0147 0148 static ExitCode evaluateString(Interpreter *interp, const char *fileName, 0149 const UString &code, 0150 bool printResult = false) 0151 { 0152 ExecState *exec = interp->globalExec(); 0153 0154 Completion res = interp->evaluate(fileName, 0, code); 0155 0156 if (res.complType() == Throw) { 0157 CString msg = JSValue::toString(res.value(), exec).UTF8String(); 0158 JSObject *resObj = JSValue::toObject(res.value(), exec); 0159 CString message = resObj->toString(exec).UTF8String(); 0160 int line = JSValue::toUInt32(resObj->toObject(exec)->get(exec, "line"), exec); 0161 0162 if (fileName) { 0163 fprintf(stderr, "%s (line %d): ", fileName, line); 0164 } 0165 fprintf(stderr, "%s\n", msg.c_str()); 0166 return ErrorEval; 0167 } else if (printResult) { 0168 if (res.isValueCompletion() && !JSValue::isUndefined(res.value())) { 0169 CString s8 = JSValue::toString(res.value(), exec).UTF8String(); 0170 if (s8.size() != 0) { 0171 fprintf(stdout, "%s\n", s8.c_str()); 0172 } 0173 } 0174 } 0175 0176 return ErrorNone; 0177 } 0178 0179 static ExitCode evaluateFile(Interpreter *interp, const char *fileName) 0180 { 0181 UString code = readFile(fileName); 0182 if (code.isNull()) { 0183 return ErrorReadFile; 0184 } 0185 0186 return evaluateString(interp, fileName, code); 0187 } 0188 0189 // primitive readline-like function 0190 static char *readLine(const char *prompt) 0191 { 0192 if (prompt) { 0193 fprintf(stdout, "%s", prompt); 0194 } 0195 0196 const int bsize = 2 << 10; 0197 char *buffer = static_cast<char *>(malloc(bsize)); 0198 char *s = fgets(buffer, bsize, stdin); 0199 if (s == nullptr) { 0200 // EOF 0201 fprintf(stdout, "\n"); 0202 free(buffer); 0203 } 0204 return s; 0205 } 0206 0207 static ExitCode evaluateInteractive(Interpreter *interp) 0208 { 0209 char *line; 0210 while ((line = readLine("JS> ")) != nullptr) { 0211 UString code(line); 0212 free(line); 0213 evaluateString(interp, nullptr, code, true); 0214 } 0215 0216 return ErrorNone; 0217 } 0218 0219 static ExitCode parseArgs(int argc, char **argv) 0220 { 0221 JSLock lock; 0222 0223 GlobalImp *global = new GlobalImp(); 0224 0225 // create interpreter 0226 RefPtr<Interpreter> interp = new Interpreter(global); 0227 0228 // add some global extension functions 0229 ExecState *gexec = interp->globalExec(); 0230 global->put(gexec, "print", 0231 new TestFunctionImp(TestFunctionImp::Print, 1)); 0232 global->put(gexec, "quit", 0233 new TestFunctionImp(TestFunctionImp::Quit, 0)); 0234 global->put(gexec, "load", 0235 new TestFunctionImp(TestFunctionImp::Load, 1)); 0236 global->put(gexec, "gc", 0237 new TestFunctionImp(TestFunctionImp::GC, 0)); 0238 0239 // enable package support 0240 StandardGlobalPackage package; 0241 interp->setGlobalPackage(&package); 0242 0243 const char *script = nullptr, *command = nullptr; 0244 int ai = 1; 0245 bool ranOtherScript = false; 0246 for (ai = 1; ai < argc; ++ai) { 0247 const char *a = argv[ai]; 0248 if (strcmp(a, "-v") == 0 || strcmp(a, "-version") == 0 || 0249 strcmp(a, "--version") == 0) { 0250 printf("KDE: %s\n", KJS_VERSION_STRING); 0251 return ErrorNone; 0252 } else if (strcmp(a, "-h") == 0 || strcmp(a, "-help") == 0 || 0253 strcmp(a, "--help") == 0) { 0254 printUsage(argv[0]); 0255 return ErrorNone; 0256 } else if (strcmp(a, "-e") == 0) { 0257 ++ai; 0258 if (argc <= ai) { 0259 fprintf(stderr, "Missing -e argument.\n"); 0260 return ErrorMissingArg; 0261 } 0262 command = argv[ai]; 0263 ++ai; 0264 break; 0265 } else if (strcmp(a, "-f") == 0) { // Compatibility mode, for SunSpider 0266 ++ai; 0267 if (argc <= ai) { 0268 fprintf(stderr, "Missing -f argument.\n"); 0269 return ErrorMissingArg; 0270 } 0271 ExitCode result = evaluateFile(interp.get(), argv[ai]); 0272 if (result != ErrorNone) { 0273 return result; 0274 } 0275 ranOtherScript = true; 0276 } else if (a[0] == '-') { 0277 fprintf(stderr, "Unknown switch %s.\n", a); 0278 return ErrorUnknownSwitch; 0279 } else { 0280 script = a; 0281 ++ai; 0282 break; 0283 } 0284 } 0285 0286 // ### 0287 if (argc > ai) { 0288 fprintf(stderr, "Warning: ignoring extra arguments\n"); 0289 } 0290 0291 if (script) { 0292 return evaluateFile(interp.get(), script); 0293 } else if (command) { 0294 return evaluateString(interp.get(), "(eval)", command); 0295 } else if (!ranOtherScript) { 0296 return evaluateInteractive(interp.get()); 0297 } 0298 return ErrorNone; 0299 } 0300 0301 int main(int argc, char **argv) 0302 { 0303 return int(parseArgs(argc, argv)); 0304 }