fix logic
[personal-kdelibs.git] / kjs / kjs.cpp
blobc9c65017fc14e09a4278980a11f8daef76c94dbc
1 // -*- c-basic-offset: 2 -*-
2 /*
3 * This file is part of the KDE libraries
4 * Copyright (C) 2006 Harri Porten (porten@kde.org)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 #include "JSLock.h"
24 #include "interpreter.h"
25 #include "object.h"
26 #include "package.h"
27 #include "function.h"
29 #include <cstring>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
35 #if PLATFORM(WIN_OS)
36 # include <windows.h>
37 # include <io.h>
38 #else
39 # include <unistd.h>
40 #endif
42 #include <kdeversion.h>
44 enum ExitCode { ErrorNone,
45 ErrorUnknownSwitch,
46 ErrorMissingArg,
47 ErrorReadFile,
48 ErrorEval
51 using std::strcmp;
53 using namespace KJS;
55 static void printUsage(const char *app)
57 fprintf(stderr,
58 "Usage: %s\n"
59 " [ -h | -help | --help ]\n"
60 " [ -e <statement> | <script> ]\n"
61 " [-v | -version | --version]\n",
62 app);
65 static UString readFile(const char* fileName)
67 int fd = open(fileName, O_RDONLY);
68 if (fd < 0) {
69 fprintf(stderr, "Error opening %s", fileName);
70 return UString();
72 struct stat buf;
73 if (fstat(fd, &buf) == -1) {
74 fprintf(stderr, "Error stat'ing %s", fileName);
75 close(fd);
76 return UString();
78 int siz = buf.st_size;
79 char* c = new char[siz + 1];
80 int dataRead = read(fd, c, siz);
81 if (dataRead == -1) {
82 fprintf(stderr, "Error reading from %s", fileName);
83 delete[] c;
84 close(fd);
85 return UString();
87 c[dataRead] = '\0';
88 UString s = c;
89 delete[] c;
90 return s;
93 static ExitCode evaluateFile(Interpreter *interp, const char *fileName);
95 class GlobalImp : public JSGlobalObject {
96 public:
97 virtual UString className() const { return "global"; }
100 class TestFunctionImp : public JSObject {
101 public:
102 TestFunctionImp(int i, int length);
103 virtual bool implementsCall() const { return true; }
104 virtual JSValue* callAsFunction(ExecState* exec,
105 JSObject* thisObj, const List &args);
106 enum { Print, Quit, Load, GC };
108 private:
109 int id;
112 TestFunctionImp::TestFunctionImp(int i, int length)
113 : JSObject(), id(i)
115 putDirect(Identifier("length"), length, DontDelete | ReadOnly | DontEnum);
118 JSValue* TestFunctionImp::callAsFunction(ExecState* exec,
119 JSObject* /* thisObj */,
120 const List &args)
122 switch (id) {
123 case Print:
124 printf("%s\n", args[0]->toString(exec).UTF8String().c_str());
125 return jsUndefined();
126 case Quit:
127 exit(0);
128 case GC:
129 while (Interpreter::collect()) {}
130 break;
131 case Load:
132 evaluateFile(exec->dynamicInterpreter(), args[0]->toString(exec).UTF8String().c_str());
133 break;
134 default:
135 abort();
137 return jsUndefined();
140 static ExitCode evaluateString(Interpreter *interp, const char *fileName,
141 const UString& code,
142 bool printResult = false)
144 ExecState *exec = interp->globalExec();
146 Completion res = interp->evaluate(fileName, 0, code);
148 if (res.complType() == Throw) {
149 CString msg = res.value()->toString(exec).UTF8String();
150 JSObject* resObj = res.value()->toObject(exec);
151 CString message = resObj->toString(exec).UTF8String();
152 int line = resObj->toObject(exec)->get(exec, "line")->toUInt32(exec);
154 if (fileName)
155 fprintf(stderr, "%s (line %d): ", fileName, line);
156 fprintf(stderr, "%s\n", msg.c_str());
157 return ErrorEval;
158 } else if (printResult) {
159 if (res.isValueCompletion() && !res.value()->isUndefined()) {
160 CString s8 = res.value()->toString(exec).UTF8String();
161 if (s8.size() != 0)
162 fprintf(stdout, "%s\n", s8.c_str());
166 return ErrorNone;
169 static ExitCode evaluateFile(Interpreter *interp, const char *fileName)
171 UString code = readFile(fileName);
172 if (code.isNull())
173 return ErrorReadFile;
175 return evaluateString(interp, fileName, code);
178 // primitive readline-like function
179 static char *readLine(const char *prompt)
181 if (prompt)
182 fprintf(stdout, "%s", prompt);
184 const int bsize = 2 << 10;
185 char *buffer = static_cast<char*>(malloc(bsize));
186 char *s = fgets(buffer, bsize, stdin);
187 if (s == 0) {
188 // EOF
189 fprintf(stdout, "\n");
190 free(buffer);
192 return s;
195 static ExitCode evaluateInteractive(Interpreter *interp)
197 char *line;
198 while ((line = readLine("JS> ")) != 0) {
199 UString code(line);
200 free(line);
201 evaluateString(interp, 0, code, true);
204 return ErrorNone;
207 static ExitCode parseArgs(int argc, char** argv)
209 JSLock lock;
211 GlobalImp* global = new GlobalImp();
213 // create interpreter
214 RefPtr<Interpreter> interp = new Interpreter(global);
216 // add some global extension functions
217 ExecState *gexec = interp->globalExec();
218 global->put(gexec, "print",
219 new TestFunctionImp(TestFunctionImp::Print, 1));
220 global->put(gexec, "quit",
221 new TestFunctionImp(TestFunctionImp::Quit, 0));
222 global->put(gexec, "load",
223 new TestFunctionImp(TestFunctionImp::Load, 1));
224 global->put(gexec, "gc",
225 new TestFunctionImp(TestFunctionImp::GC, 0));
227 // enable package support
228 StandardGlobalPackage package;
229 interp->setGlobalPackage(&package);
231 const char *script = 0, *command = 0;
232 int ai = 1;
233 bool ranOtherScript = false;
234 for (ai = 1; ai < argc; ++ai) {
235 const char* a = argv[ai];
236 if (strcmp(a, "-v" ) == 0 || strcmp(a, "-version") == 0 ||
237 strcmp(a, "--version") == 0) {
238 printf("KDE: %s\n", KDE_VERSION_STRING);
239 return ErrorNone;
240 } else if (strcmp(a, "-h" ) == 0 || strcmp(a, "-help") == 0 ||
241 strcmp(a, "--help") == 0) {
242 printUsage(argv[0]);
243 return ErrorNone;
244 } else if (strcmp(a, "-e") == 0) {
245 ++ai;
246 if (argc <= ai) {
247 fprintf(stderr, "Missing -e argument.\n");
248 return ErrorMissingArg;
250 command = argv[ai];
251 ++ai;
252 break;
253 } else if (strcmp(a, "-f") == 0) { // Compatibility mode, for SunSpider
254 ++ai;
255 if (argc <= ai) {
256 fprintf(stderr, "Missing -f argument.\n");
257 return ErrorMissingArg;
259 ExitCode result = evaluateFile(interp.get(), argv[ai]);
260 if (result != ErrorNone)
261 return result;
262 ranOtherScript = true;
263 } else if (a[0] == '-') {
264 fprintf(stderr, "Unknown switch %s.\n", a);
265 return ErrorUnknownSwitch;
266 } else {
267 script = a;
268 ++ai;
269 break;
273 // ###
274 if (argc > ai)
275 fprintf(stderr, "Warning: ignoring extra arguments\n");
277 if (script) {
278 return evaluateFile(interp.get(), script);
279 } else if (command) {
280 return evaluateString(interp.get(), "(eval)", command);
281 } else if (!ranOtherScript) {
282 return evaluateInteractive(interp.get());
284 return ErrorNone;
287 int main(int argc, char** argv)
289 return int(parseArgs(argc, argv));