2 // Tizen Web Device API
3 // Copyright (c) 2013 Samsung Electronics Co., Ltd.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <JavaScriptCore/JavaScript.h>
21 #include "StandaloneConsole.h"
22 #include "JSConsole.h"
24 #include <GlobalContextManager.h>
32 #define LOG_TAG "TIZEN_DEVICEAPI"
35 using namespace DeviceAPI::Common;
42 StandaloneConsole *mConsole;
43 pthread_mutex_t *mLock;
44 _Command(const char * cmd, StandaloneConsole *console, pthread_mutex_t* lock){
53 mConsole->RunLine(mLine);
54 pthread_mutex_unlock(mLock);
61 StandaloneConsole *console;
64 static Eina_Bool tick(void *data){
68 static Eina_Bool commandDispath(void *data){
69 _Command *cmd = (_Command*)data;
75 Eina_Bool StandaloneConsole::timerCb(void *data){
76 CallbackData *callback = (CallbackData*)data;
77 StandaloneConsole *console = callback->console;
78 map<int,int>::iterator itr;
79 itr = console->mTimerMap.find(callback->id);
80 if( itr == console->mTimerMap.end() ){
81 JSValueUnprotect(console->getGlobalContext(), callback->callback);
85 if( itr->second == 0){
86 console->mTimerMap.erase(itr);
87 JSValueUnprotect(console->getGlobalContext(), callback->callback);
91 if( callback->callback != NULL){
92 JSObjectCallAsFunction(console->getGlobalContext(), callback->callback, NULL, 0, 0, NULL);
95 if( itr->second == 2 ){
96 console->mTimerMap.erase(itr);
97 JSValueUnprotect(console->getGlobalContext(), callback->callback);
106 JSValueRef StandaloneConsole::alert(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
107 if( argumentCount < 1 )
108 return JSValueMakeUndefined(ctx);
111 //JSContextRef globalCtx = GlobalContextManager::getInstance()->getGlobalContext(ctx);
112 //printf(" local : %p, global : %p \n", ctx, globalCtx);
114 JSStringRef str = JSValueToStringCopy(ctx, arguments[0], NULL);
116 return JSValueMakeUndefined(ctx);
118 int n = JSStringGetLength(str);
121 JSStringGetUTF8CString(str, cstr,n+1);
122 printf("<alert>%s\n", cstr);
124 return JSValueMakeUndefined(ctx);
127 JSValueRef StandaloneConsole::setInterval(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
129 StandaloneConsole *console = static_cast<StandaloneConsole*>(JSObjectGetPrivate(thisObject));
130 if( argumentCount < 2 ){
131 if( exception != NULL){
134 return JSValueMakeUndefined(ctx);
137 double interval = JSValueToNumber(ctx, arguments[1], NULL);
138 interval = interval/1000;
140 console->mTimerMap.insert(pair<int,int>(handleid, 1));
141 CallbackData *data = new CallbackData();
142 JSValueProtect(console->getGlobalContext(), arguments[0]);
143 data->callback = JSValueToObject(ctx, arguments[0], NULL);
145 data->console = console;
147 ecore_timer_add( interval, StandaloneConsole::timerCb , data);
148 return JSValueMakeNumber(ctx, handleid);
152 JSValueRef StandaloneConsole::setTimeout(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
154 StandaloneConsole *console = static_cast<StandaloneConsole*>(JSObjectGetPrivate(thisObject));
156 if( argumentCount < 2 ){
157 if( exception != NULL){
160 return JSValueMakeUndefined(ctx);
163 double interval = JSValueToNumber(ctx, arguments[1], NULL);
164 interval = interval/1000;
166 console->mTimerMap.insert(pair<int,int>(handleid, 2));
167 CallbackData *data = new CallbackData();
168 JSValueProtect(console->getGlobalContext(), arguments[0]);
169 data->callback = JSValueToObject(ctx, arguments[0], NULL);
171 data->console = console;
173 ecore_timer_add( interval, StandaloneConsole::timerCb , data);
174 return JSValueMakeNumber(ctx, handleid);
179 JSValueRef StandaloneConsole::clearInterval(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
180 StandaloneConsole *console = static_cast<StandaloneConsole*>(JSObjectGetPrivate(thisObject));
181 if(console == NULL) return JSValueMakeUndefined(ctx);
182 if( argumentCount < 1 ){
183 printf("error clearInterval\n");
184 if( exception != NULL){
187 return JSValueMakeUndefined(ctx);
190 int handleid = JSValueToNumber(ctx, arguments[0], NULL);
191 map<int,int>::iterator it;
192 it = console->mTimerMap.find(handleid);
193 if( it != console->mTimerMap.end())
194 console->mTimerMap[handleid] = 0;
195 return JSValueMakeUndefined(ctx);
199 static JSValueRef test(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception){
200 return JSValueMakeUndefined(ctx);
204 static void setProperty(JSContextRef ctx , JSObjectRef object, const char *name, JSValueRef value, JSPropertyAttributes attributes)
206 JSStringRef propertyName = JSStringCreateWithUTF8CString(name);
207 JSObjectSetProperty(ctx, object, propertyName, value,attributes, NULL );
208 JSStringRelease(propertyName);
211 static JSValueRef getProperty(JSContextRef ctx , JSObjectRef object, const char *name){
213 JSStringRef propertyName = JSStringCreateWithUTF8CString(name);
214 value = JSObjectGetProperty(ctx, object, propertyName, NULL);
215 JSStringRelease(propertyName);
219 static char * toString(JSContextRef ctx , JSValueRef jsV){
220 JSValueRef exception = NULL;
221 JSStringRef jsStr = JSValueToStringCopy(ctx, jsV, &exception);
222 if( exception != NULL )
224 int n = JSStringGetMaximumUTF8CStringSize(jsStr);
225 char *buf = new char[n+1];
226 JSStringGetUTF8CString(jsStr, buf, n+1);
227 JSStringRelease(jsStr);
231 StandaloneConsole::StandaloneConsole():mGlobalContext(NULL),mGlobalObject(NULL){
234 StandaloneConsole::~StandaloneConsole(){
237 void StandaloneConsole::initialize(){
239 JSStaticFunction functions[] = {
240 { "alert", StandaloneConsole::alert , kJSPropertyAttributeNone },
241 { "setInterval", StandaloneConsole::setInterval , kJSPropertyAttributeNone },
242 { "setTimeout", StandaloneConsole::setTimeout , kJSPropertyAttributeNone },
243 { "clearInterval", StandaloneConsole::clearInterval , kJSPropertyAttributeNone },
244 { "clearTimeout", StandaloneConsole::clearInterval , kJSPropertyAttributeNone },
245 { "test", test, kJSPropertyAttributeNone },
250 JSClassDefinition def = {
251 0, // current (and only) version is 0
252 kJSClassAttributeNone, //attributes
253 "global", //class name
254 NULL, // parent class
255 NULL, //static values
256 functions, // static functions
262 NULL, //deleteProperty
263 NULL, //getPropertyNames
264 NULL, // callAsConstructor
267 NULL // convertToType
270 JSClassRef globalClass = JSClassCreate(&def);
272 mGlobalContext = JSGlobalContextCreate(globalClass);
273 mGlobalObject = JSContextGetGlobalObject(mGlobalContext);
274 JSObjectSetPrivate(mGlobalObject, this);
275 JSObjectRef console = JSConsole::createJSObject(mGlobalContext);
276 setProperty(mGlobalContext, mGlobalObject, "console", console, kJSPropertyAttributeReadOnly);
279 //is it ecore bug? event was not invoke, it was added in another thread
280 ecore_timer_add(0.001, tick, NULL);
284 JSObjectRef StandaloneConsole::getGlobalObject(){
285 return mGlobalObject;
288 JSContextRef StandaloneConsole::getGlobalContext(){
289 return mGlobalContext;
293 JSValueRef StandaloneConsole::RunLineEx(const char* line, JSValueRef *exception){
294 JSStringRef jsScript = JSStringCreateWithUTF8CString(line);
295 int size = strlen(line);
296 if( size != static_cast <int>(JSStringGetLength(jsScript))){
297 cout <<"error - fail to converting JSStringRef"<<endl;
299 JSValueRef ret = JSEvaluateScript(mGlobalContext, jsScript, NULL, NULL, 0, exception);
300 JSStringRelease(jsScript);
304 JSValueRef StandaloneConsole::RunScriptEx(const char* path, JSValueRef *exception){
306 FILE* f = fopen(path, "r");
311 fseek(f, 0, SEEK_END);
312 int length = ftell(f);
313 fseek(f, 0, SEEK_SET);
318 memset(buff, '\0', length+1);
319 int r = fread(buff, 1, length, f);
323 printf("error read\n");
324 return JSValueMakeUndefined(mGlobalContext);
326 return RunLineEx(buff, exception);
329 return JSValueMakeUndefined(mGlobalContext);
332 void StandaloneConsole::RunLine(const char * line){
333 JSValueRef exception = NULL;
334 JSValueRef v = RunLineEx(line, &exception);
335 reportingResult(v,exception);
338 void StandaloneConsole::RunScript(const char * path){
339 JSValueRef exception = NULL;
340 JSValueRef v = RunScriptEx(path, &exception);
341 reportingResult(v,exception);
344 void StandaloneConsole::GarbageCollect(){
345 printf("GarbageCollect\n");
346 JSGarbageCollect(mGlobalContext);
348 void StandaloneConsole::reportingResult(JSValueRef v, JSValueRef exception){
349 if( exception != NULL ){
350 char *errStr = toString(mGlobalContext, exception);
351 if( errStr != NULL ){
352 printf("< error - %s\n", errStr);
355 JSObjectRef errObj = JSValueToObject(mGlobalContext, exception, NULL);
356 if( errObj != NULL ){
357 JSValueRef stack = getProperty(mGlobalContext, errObj, "stack");
358 char *stackStr = NULL;
359 if( !JSValueIsUndefined(mGlobalContext, stack) && (stackStr = toString(mGlobalContext, stack )) != NULL){
360 printf("stack:%s\n", stackStr);
365 char *resultStr = toString(mGlobalContext, v);
366 if( resultStr != NULL ){
367 printf("< %s\n", resultStr);
373 JSObjectRef StandaloneConsole::registModule(const char * name, JSClassRef module, void * priv){
374 JSObjectRef obj = JSObjectMake(mGlobalContext, module, priv);
375 setProperty(mGlobalContext, mGlobalObject, name, obj, kJSPropertyAttributeReadOnly);
379 void StandaloneConsole::appendModule(const char * name, JSObjectRef module){
380 setProperty(mGlobalContext, mGlobalObject, name, module, kJSPropertyAttributeReadOnly);
392 buf.c_lflag &= ~(ICANON|ECHO);
395 tcsetattr(0, TCSAFLUSH, &buf);
397 tcsetattr(0, TCSAFLUSH, &save);
401 struct termios gSave;
405 tcsetattr(0, TCSAFLUSH, &gSave);
409 vector<string> mHistory;
412 unsigned int mCurrentPos;
413 unsigned int mCurrentPosTmp;
416 LineBuffer():mHistoryIndex(0), mCurrentPos(0){
417 tcgetattr(0, &gSave);
421 tcsetattr(0, TCSAFLUSH, &gSave);
424 void backSpace( int length ){
425 for( int i =0 ; i < length ; i++){
433 int diff = mLineLength - mCurrentPosTmp;
437 backSpace(mLineLength);
440 void applyHistory( unsigned int index ){
441 if( mHistory.size() > index ){
442 mLine = mHistory[index];
443 mCurrentPos = mLine.size();
447 void moveCursor( bool Left ){
448 putchar(27);putchar(91);
455 void moveCurrentCursorPosition(){
456 int diff = mLine.size() - mCurrentPos;
463 bool checkSpecialKeys(int a){
465 if( mLine.size() != 0 && mCurrentPos != 0){
467 mLine.erase(mCurrentPos,1);
477 if( mHistoryIndex > 0 ){
478 applyHistory(--mHistoryIndex);
483 if( (unsigned)mHistoryIndex < mHistory.size() ){
484 applyHistory(++mHistoryIndex);
489 if( mCurrentPos < mLine.size())
494 if( mCurrentPos > 0 )
500 if( mCurrentPos < mLine.size())
501 mLine.erase(mCurrentPos,1);
506 mCurrentPos = mLine.size();
522 string Prompt(const char * prompt){
523 printf("%s", prompt);
526 mLineLength = mLine.size();
527 mCurrentPosTmp = mCurrentPos;
534 if(!checkSpecialKeys(a)){
535 mLine.insert(mCurrentPos,1, a);
539 moveCurrentCursorPosition();
540 mLineLength = mLine.size();
541 mCurrentPosTmp = mCurrentPos;
544 if( mLine.size() > 0 ){
545 mHistory.push_back(mLine);
546 mHistoryIndex = mHistory.size();
555 void StandaloneConsole::commandline(StandaloneConsole* console){
556 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
557 printf("command line mode ( \"quit\" for exit )\n");
560 pthread_mutex_lock(&lock);
561 string line = linebuff.Prompt(">");
567 console->GarbageCollect();
570 if( line.size() == 0 )
572 _Command *cmd = new _Command(line.c_str(), console, &lock);
574 ecore_idler_add(commandDispath, cmd);