d384d6526a6d127146e0721f5675f05d6ebdfee0
[platform/framework/web/wrt-plugins-tizen.git] / src / Common / StandaloneConsole / StandaloneConsole.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 #include <stdio.h>
19 #include <dlog.h>
20 #include <JavaScriptCore/JavaScript.h>
21 #include "StandaloneConsole.h"
22 #include "JSConsole.h"
23 #include <Ecore.h>
24 #include <GlobalContextManager.h>
25 #include <string>
26 #include <vector>
27
28 #undef LOG_TAG
29 #define LOG_TAG "TIZEN_DEVICEAPI"
30
31 using namespace std;
32 using namespace DeviceAPI::Common;
33
34
35 namespace DeviceAPI {
36 namespace Test {
37
38 struct _Command{
39     char * mLine;
40     StandaloneConsole *mConsole;
41     pthread_mutex_t *mLock;
42     _Command(const char * cmd, StandaloneConsole *console, pthread_mutex_t* lock){
43         mLine = strdup(cmd);
44         mConsole = console;
45         mLock = lock;
46     }
47     ~_Command(){
48         free(mLine);
49     }
50     void run(){
51         mConsole->RunLine(mLine);
52         pthread_mutex_unlock(mLock);
53     }
54 };
55
56 struct CallbackData{
57     JSObjectRef callback;
58     int id;
59     StandaloneConsole *console;
60 };
61
62 static Eina_Bool tick(void *data){
63     return true;
64 }
65
66 static Eina_Bool commandDispath(void *data){
67     _Command *cmd = (_Command*)data;
68     cmd->run();
69     delete cmd;
70     return false;
71 }
72
73 Eina_Bool StandaloneConsole::timerCb(void *data){
74     CallbackData *callback = (CallbackData*)data;
75     StandaloneConsole *console = callback->console;
76     map<int,int>::iterator itr;
77     itr = console->mTimerMap.find(callback->id);
78     if( itr == console->mTimerMap.end() ){
79         JSValueUnprotect(console->getGlobalContext(), callback->callback);
80         delete callback;
81         return false;
82     }
83     if( itr->second == 0){
84         console->mTimerMap.erase(itr);
85         JSValueUnprotect(console->getGlobalContext(), callback->callback);
86         delete callback;
87         return false;
88     }
89     if( callback->callback != NULL){
90         JSObjectCallAsFunction(console->getGlobalContext(), callback->callback, NULL, 0, 0, NULL);
91     }
92
93     if( itr->second == 2 ){
94         console->mTimerMap.erase(itr);
95         JSValueUnprotect(console->getGlobalContext(), callback->callback);
96         delete callback;
97         return false;
98     }
99
100     return true;
101 }
102
103
104 JSValueRef StandaloneConsole::alert(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
105     if( argumentCount < 1 )
106         return JSValueMakeUndefined(ctx);
107
108
109     //JSContextRef globalCtx = GlobalContextManager::getInstance()->getGlobalContext(ctx);
110     //printf(" local : %p, global : %p \n", ctx, globalCtx);
111
112     JSStringRef str = JSValueToStringCopy(ctx, arguments[0], NULL);
113     if(str == NULL){
114         return JSValueMakeUndefined(ctx);
115     }
116     int n = JSStringGetLength(str);
117     {
118         char cstr[n+1];
119         JSStringGetUTF8CString(str, cstr,n+1);
120         printf("<alert>%s\n", cstr);
121     }
122     return JSValueMakeUndefined(ctx);
123 }
124
125 JSValueRef StandaloneConsole::setInterval(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
126     static int id = 0;
127     StandaloneConsole *console = static_cast<StandaloneConsole*>(JSObjectGetPrivate(thisObject));
128     if( argumentCount < 2 ){
129         if( exception != NULL){
130
131         }
132         return JSValueMakeUndefined(ctx);
133     }
134     int handleid = id++;
135     double interval = JSValueToNumber(ctx, arguments[1], NULL);
136     interval = interval/1000;
137
138     console->mTimerMap.insert(pair<int,int>(handleid, 1));
139     CallbackData *data = new CallbackData();
140     JSValueProtect(console->getGlobalContext(), arguments[0]);
141     data->callback = JSValueToObject(ctx, arguments[0], NULL);
142     data->id = handleid;
143     data->console = console;
144
145     ecore_timer_add( interval, StandaloneConsole::timerCb , data);
146     return JSValueMakeNumber(ctx, handleid);
147
148 }
149
150 JSValueRef StandaloneConsole::setTimeout(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
151     static int id = 0;
152     StandaloneConsole *console = static_cast<StandaloneConsole*>(JSObjectGetPrivate(thisObject));
153
154     if( argumentCount < 2 ){
155         if( exception != NULL){
156
157         }
158         return JSValueMakeUndefined(ctx);
159     }
160     int handleid = id++;
161     double interval = JSValueToNumber(ctx, arguments[1], NULL);
162     interval = interval/1000;
163
164     console->mTimerMap.insert(pair<int,int>(handleid, 2));
165     CallbackData *data = new CallbackData();
166     JSValueProtect(console->getGlobalContext(), arguments[0]);
167     data->callback = JSValueToObject(ctx, arguments[0], NULL);
168     data->id = handleid;
169     data->console = console;
170
171     ecore_timer_add( interval, StandaloneConsole::timerCb , data);
172     return JSValueMakeNumber(ctx, handleid);
173
174 }
175
176
177 JSValueRef StandaloneConsole::clearInterval(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
178     StandaloneConsole *console = static_cast<StandaloneConsole*>(JSObjectGetPrivate(thisObject));
179     if(console == NULL) return JSValueMakeUndefined(ctx);
180     if( argumentCount < 1 ){
181         printf("error clearInterval\n");
182         if( exception != NULL){
183
184         }
185         return JSValueMakeUndefined(ctx);
186     }
187
188     int handleid = JSValueToNumber(ctx, arguments[0], NULL);
189     map<int,int>::iterator it;
190     it = console->mTimerMap.find(handleid);
191     if( it != console->mTimerMap.end())
192         console->mTimerMap[handleid] = 0;
193     return JSValueMakeUndefined(ctx);
194 }
195
196
197 static JSValueRef test(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
198     return JSValueMakeUndefined(ctx);
199 }
200
201
202 static void setProperty(JSContextRef ctx , JSObjectRef object, const char *name, JSValueRef value, JSPropertyAttributes attributes)
203 {
204         JSStringRef propertyName = JSStringCreateWithUTF8CString(name);
205         JSObjectSetProperty(ctx, object, propertyName, value,attributes, NULL );
206         JSStringRelease(propertyName);
207 }
208
209 static JSValueRef getProperty(JSContextRef ctx , JSObjectRef object, const char *name){
210         JSValueRef value;
211         JSStringRef propertyName = JSStringCreateWithUTF8CString(name);
212         value = JSObjectGetProperty(ctx, object, propertyName, NULL);
213         JSStringRelease(propertyName);
214         return value;
215 }
216
217 static char * toString(JSContextRef ctx , JSValueRef jsV){
218     JSValueRef exception = NULL;
219     JSStringRef jsStr = JSValueToStringCopy(ctx, jsV, &exception);
220     if( exception != NULL )
221         return NULL;
222     int n = JSStringGetMaximumUTF8CStringSize(jsStr);
223     char *buf = new char[n+1];
224     JSStringGetUTF8CString(jsStr, buf, n+1);
225     JSStringRelease(jsStr);
226     return buf;
227 }
228
229 StandaloneConsole::StandaloneConsole():mGlobalContext(NULL),mGlobalObject(NULL){
230 }
231
232 StandaloneConsole::~StandaloneConsole(){
233 }
234
235 void StandaloneConsole::initialize(){
236     // Function table
237     JSStaticFunction functions[] = {
238         { "alert", StandaloneConsole::alert , kJSPropertyAttributeNone },
239         { "setInterval", StandaloneConsole::setInterval , kJSPropertyAttributeNone },
240         { "setTimeout", StandaloneConsole::setTimeout , kJSPropertyAttributeNone },
241         { "clearInterval", StandaloneConsole::clearInterval , kJSPropertyAttributeNone },
242         { "clearTimeout", StandaloneConsole::clearInterval , kJSPropertyAttributeNone },
243         { "test", test, kJSPropertyAttributeNone },
244         { 0, 0, 0 }
245     };
246
247     // Global class
248     JSClassDefinition def = {
249         0,                                 // current (and only) version is 0
250         kJSClassAttributeNone,   //attributes
251         "global",                        //class name
252         NULL,                            // parent class
253         NULL,                            //static values
254         functions,                      // static functions
255         NULL,                            // initialize
256         NULL,                            //finalize
257         NULL,                            //hasProperty
258         NULL,                            //getProperty
259         NULL,                            //setProperty
260         NULL,                            //deleteProperty
261         NULL,                            //getPropertyNames
262         NULL,                            // callAsConstructor
263         NULL,                            // constructor
264         NULL,
265         NULL                             // convertToType
266     };
267
268     JSClassRef globalClass = JSClassCreate(&def);
269
270     mGlobalContext = JSGlobalContextCreate(globalClass);
271     mGlobalObject = JSContextGetGlobalObject(mGlobalContext);
272     JSObjectSetPrivate(mGlobalObject, this);
273     JSObjectRef console = JSConsole::createJSObject(mGlobalContext);
274     setProperty(mGlobalContext, mGlobalObject, "console", console, kJSPropertyAttributeReadOnly);
275
276
277     //is it ecore bug? event was not invoke, it was added in another thread
278     ecore_timer_add(0.001, tick, NULL);
279 }
280
281
282 JSObjectRef StandaloneConsole::getGlobalObject(){
283     return mGlobalObject;
284 }
285
286 JSContextRef StandaloneConsole::getGlobalContext(){
287     return mGlobalContext;
288 }
289
290
291 JSValueRef StandaloneConsole::RunLineEx(const char* line, JSValueRef *exception){
292     JSStringRef jsScript = JSStringCreateWithUTF8CString(line);
293     JSValueRef ret = JSEvaluateScript(mGlobalContext, jsScript, NULL, NULL, 0, exception);
294     JSStringRelease(jsScript);
295     return ret;
296 }
297
298 JSValueRef StandaloneConsole::RunScriptEx(const char* path, JSValueRef *exception){
299
300     FILE* f = fopen(path, "r");
301     if( f == NULL ){
302         return NULL;
303     }
304
305     fseek(f, 0, SEEK_END);
306     int length = ftell(f);
307     fseek(f, 0, SEEK_SET);
308
309     if( length > 0 )
310     {
311         char buff[length];
312         memset(buff, 0, length);
313         int r = fread(buff, 1, length, f);
314         fclose(f);
315
316         if( r != length ){
317             printf("error read\n");
318             return JSValueMakeUndefined(mGlobalContext);
319         }
320         return RunLineEx(buff, exception);
321     }
322     fclose(f);
323     return JSValueMakeUndefined(mGlobalContext);
324 }
325
326 void StandaloneConsole::RunLine(const char * line){
327     JSValueRef exception = NULL;
328     JSValueRef v = RunLineEx(line, &exception);
329     reportingResult(v,exception);
330 }
331
332 void StandaloneConsole::RunScript(const char * path){
333     JSValueRef exception = NULL;
334     JSValueRef v = RunScriptEx(path, &exception);
335     reportingResult(v,exception);
336 }
337
338 void StandaloneConsole::GarbageCollect(){
339     printf("GarbageCollect\n");
340     JSGarbageCollect(mGlobalContext);
341 }
342 void StandaloneConsole::reportingResult(JSValueRef v, JSValueRef exception){
343     if( exception != NULL ){
344         char *errStr = toString(mGlobalContext, exception);
345         if( errStr != NULL ){
346             printf("< error - %s\n", errStr);
347             delete[] errStr;
348         }
349         JSObjectRef errObj = JSValueToObject(mGlobalContext, exception, NULL);
350         if( errObj != NULL ){
351             JSValueRef stack = getProperty(mGlobalContext, errObj, "stack");
352             char *stackStr = NULL;
353             if( !JSValueIsUndefined(mGlobalContext, stack) && (stackStr = toString(mGlobalContext, stack )) != NULL){
354                 printf("stack:%s\n", stackStr);
355                 delete[] stackStr;
356             }
357         }
358     }else{
359         char *resultStr = toString(mGlobalContext, v);
360         if( resultStr != NULL ){
361             printf("< %s\n", resultStr);
362             delete[] resultStr;
363         }
364     }
365 }
366
367 JSObjectRef StandaloneConsole::registModule(const char * name, JSClassRef module, void * priv){
368     JSObjectRef obj = JSObjectMake(mGlobalContext, module, priv);
369     setProperty(mGlobalContext, mGlobalObject, name, obj, kJSPropertyAttributeReadOnly);
370     return obj;
371 }
372
373 void StandaloneConsole::appendModule(const char * name, JSObjectRef module){
374     setProperty(mGlobalContext, mGlobalObject, name, module, kJSPropertyAttributeReadOnly);
375 }
376
377 void StandaloneConsole::commandline(StandaloneConsole* console){
378     pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
379     pthread_mutex_lock(&lock);
380     printf("command line mode ( \"quit\" for exit  )\n");
381     while(1){
382         char line[1024];
383         printf(">");
384         if( gets(line) == NULL )
385             break;
386         if( strcmp(line, "quit") == 0 )
387             break;
388         if( strcmp(line, "gc") == 0 ){
389             console->GarbageCollect();
390             continue;
391         }
392         if( strcmp(line, "") == 0 )
393             continue;
394         _Command *cmd = new _Command(line, console, &lock);
395         // for thread safety
396         ecore_idler_add(commandDispath, cmd);
397         pthread_mutex_lock(&lock);
398     }
399 }
400
401
402 }
403 }
404