myjs.c

最終更新:2009/11/18

myjs.c

001: /* myjs.c
002:  * SpiderMonkey を C プログラムから使う例
003:  */
004: 
005: #include <stdio.h>
006: #include <stdlib.h>
007: #include <string.h>
008: #include "myjs.h"
009: 
010: #ifndef MY_JS_DEBUG
011: #define MY_JS_DEBUG 0
012: #endif
013: 
014: /* JSRuntime */
015: static JSRuntime *jsrt = NULL;
016: 
017: /* グローバルオブジェクトのクラス */
018: static JSClass global_class = {
019:   "global",
020:   JSCLASS_GLOBAL_FLAGS,
021:   JS_PropertyStub,
022:   JS_PropertyStub,
023:   JS_PropertyStub,
024:   JS_PropertyStub,
025:   JS_EnumerateStub,
026:   JS_ResolveStub,
027:   JS_ConvertStub,
028:   JS_FinalizeStub,
029:   JSCLASS_NO_OPTIONAL_MEMBERS
030: };
031: 
032: /*
033:  * 組込み関数の定義
034:  */
035: static JSBool myjs_print(
036:   JSContext *jsctx
037:   , JSObject *obj
038:   , uintN argc
039:   , jsval *argv
040:   , jsval *rval
041: ) {
042:   uintN i = 0;
043:   JSString *str = NULL;
044:   char *bytes = NULL;
045: 
046:   for (i = 0; i < argc; i++) {
047:     str = JS_ValueToString(jsctx, argv[i]);
048:     if (!str)
049:       return JS_FALSE;
050:     bytes = JS_EncodeString(jsctx, str);
051:     if (!bytes)
052:       return JS_FALSE;
053:     printf("%s%s", i ? " " : "", bytes);
054:     JS_free(jsctx, bytes);
055:   }
056: 
057:   *rval = JSVAL_VOID;  /* return undefined */
058: 
059:   return JS_TRUE;
060: }
061: 
062: static JSFunctionSpec myjs_global_functions[] = {
063:   JS_FS("print",  myjs_print,  0, 0, 0),
064:   JS_FS_END
065: };
066: 
067: /* エラーレポート用コールバック関数 */
068: static void reportError(
069:   JSContext *jsctx
070:   , const char *message
071:   , JSErrorReport *report
072: ) {
073:   fprintf(stderr, "%s:%u:%s\n",
074:     report->filename ? report->filename : "",
075:     (unsigned int) report->lineno,
076:     message);
077: }
078: 
079: /*
080:  * スクリプトファイルを読み込んで実行
081:  * 返り値:
082:  *   1:成功
083:  *   0:失敗
084:  */
085: 
086: int my_js_execute_script(
087:   JSContext *jsctx         /* IN: JSContext */
088:   , char *filename         /* IN: スクリプトファイル */
089:   , JSScript **js_script_p /* OUT: コンパイル済みスクリプト */
090:   , jsval *rval            /* OUT: スクリプトで最後に評価した式の結果 */
091: ) {
092:   int ret = JS_FALSE;
093:   JSScript *js_script=NULL;
094:   
095:   if (!filename) {
096:     return 0;
097:   }
098:   
099:   js_script = JS_CompileFile(jsctx, JS_GetGlobalObject(jsctx), filename);
100:   if (! js_script) {
101:     return 0;
102:   }
103:   
104:   ret = JS_ExecuteScript(jsctx, JS_GetGlobalObject(jsctx), js_script, rval);
105:   if (ret != JS_TRUE) {
106:     return 0;
107:   }
108:   if (js_script_p) {
109:     *js_script_p = js_script;
110:   }
111:   
112:   return 1;
113: }
114: 
115: /* 関数の実行 int[]→int
116:  * 返り値:
117:  *   1:成功
118:  *   0:失敗
119:  */
120:  
121: int my_js_call_function_IA_I (
122:   JSContext *jsctx        /* IN: JSContext */
123:   , const char *func_name /* IN: 関数名 */
124:   , int argc              /* IN: 引数の個数 */
125:   , int *args             /* IN: 引数の配列 */
126:   , int *ret              /* OUT: 関数の実行結果 */
127: ) {
128:   uintN jargc = argc;
129:   jsval *jargs = NULL;
130:   
131:   if (!func_name) {
132:     return 0;
133:   }
134:   
135:   jargs = (jsval*)malloc(sizeof(jsval)*argc);
136:   {
137:     int i=0;
138:     for (; i<argc; i++) {
139:       jargs[i] = INT_TO_JSVAL(args[i]);
140:     }
141:   }
142:   {
143:     jsval rval;
144:     JSBool ok = JS_CallFunctionName(jsctx, JS_GetGlobalObject(jsctx),
145:       func_name, jargc, jargs, &rval);
146:     free(jargs);
147:     if (ok == JS_TRUE) {
148: 
149:       if (MY_JS_DEBUG) {
150:         JSString *str = JS_ValueToString(jsctx, rval);
151:         if (str) {
152:           printf("rval: %s\n", JS_GetStringBytes(str));
153:         }
154:       }
155: 
156:       if (JS_ValueToInt32(jsctx, rval, ret) == JS_TRUE) {
157:         return 1;
158:       }
159:     }
160:   }
161:   return 0;
162: }
163: 
164: /* 関数の実行 char**→char*
165:  * 返り値:
166:  *   1:成功
167:  *   0:失敗
168:  */
169:  
170: int my_js_call_function_SA_S (
171:   JSContext *jsctx        /* IN: JSContext */
172:   , const char *func_name /* IN: 関数名 */
173:   , int argc              /* IN: 引数の個数 */
174:   , char **args           /* IN: 引数の配列 */
175:   , char **ret             /* OUT: 関数の実行結果 */
176: ) {
177:   uintN jargc = argc;
178:   jsval *jargs = NULL;
179:   
180:   if (!func_name) {
181:     return 0;
182:   }
183:   
184:   jargs = (jsval*)malloc(sizeof(jsval)*argc);
185:   {
186:     int i=0;
187:     for (; i<argc; i++) {
188:       JSString *jstr = JS_NewString(jsctx, args[i], strlen(args[i]));
189:       jargs[i] = STRING_TO_JSVAL(jstr);
190:     }
191:   }
192:   {
193:     jsval rval;
194:     JSBool ok = JS_CallFunctionName(jsctx, JS_GetGlobalObject(jsctx),
195:       func_name, jargc, jargs, &rval);
196:     free(jargs);
197:     if (ok == JS_TRUE) {
198:       JSString *str = JS_ValueToString(jsctx, rval);
199:       if (str) {
200:         *ret = JS_GetStringBytes(str);
201:         return 1;
202:       }
203:     }
204:   }
205:   return 0;
206: }
207: 
208: /*
209:  * JSRuntime の初期化
210:  * ・プロセス単位で実行すること
211:  * 返り値:
212:  *   1:成功
213:  *   0:失敗
214:  */
215: 
216: int my_js_rt_init()
217: {
218:   
219:   if (jsrt) {
220:     return 0; /* 初期化済み */
221:   }
222: 
223:   jsrt = JS_NewRuntime(MY_JS_MAXBYTES);
224:   if (!jsrt) {
225:     if(MY_JS_DEBUG)fprintf(stderr, "ERROR: JS_NewRuntime\n");
226:     return 0;
227:   }
228: 
229:   return 1;
230: }
231: 
232: /*
233:  * JSContext の生成
234:  * ・スレッド単位で実行すること
235:  * 返り値:
236:  *   NULL:失敗
237:  */
238: JSContext *my_js_ctx_init()
239: {
240:   int error_flag = 0;
241: 
242:   JSContext *jsctx = NULL;
243:   JSObject  *global = NULL;
244: 
245:   if (!jsrt) {
246:     if(MY_JS_DEBUG)fprintf(stderr, "ERROR: my_js_ctx_init\n");
247:     return NULL; /* JSRuntime 初期化前 */
248:   }
249: 
250:   jsctx = JS_NewContext(jsrt, MY_JS_STACKSIZE);
251:   if (!jsctx) {
252:     if(MY_JS_DEBUG)fprintf(stderr, "ERROR: JS_NewContext\n");
253:     error_flag = 1;
254:     goto _FINALLY_;
255:   }
256:   
257:   JS_SetOptions(jsctx, JSOPTION_VAROBJFIX);
258:   JS_SetVersion(jsctx, JSVERSION_LATEST);
259:   JS_SetErrorReporter(jsctx, reportError);
260:   
261:   /* コンテクスト単位でグローバルオブジェクトを生成 */
262:   global = JS_NewObject(jsctx, &global_class, NULL, NULL);
263:   if (!global) {
264:     if(MY_JS_DEBUG)fprintf(stderr, "ERROR: JS_NewObject\n");
265:     error_flag = 1;
266:     goto _FINALLY_;
267:   }
268:   
269:   if (!JS_InitStandardClasses(jsctx, global)) {
270:     if(MY_JS_DEBUG)fprintf(stderr, "ERROR: JS_InitStandardClasses\n");
271:     error_flag = 1;
272:     goto _FINALLY_;
273:   }
274:   
275:   if (!JS_DefineFunctions(jsctx, global, myjs_global_functions)) {
276:     if(MY_JS_DEBUG)fprintf(stderr, "ERROR: JS_DefineFunctions\n");
277:     error_flag = 1;
278:   }
279: 
280:   _FINALLY_:
281:   if (error_flag) {
282:     return NULL;
283:   }
284:   
285:   return jsctx;
286: }
287: 
288: /*
289:  * JSContext の解放
290:  */
291: void my_js_ctx_clear(
292:   JSContext *jsctx
293: ) {
294:   if (jsctx) {
295:     JS_DestroyContext(jsctx);
296:   }
297: }
298: 
299: /*
300:  * JSRuntime の解放
301:  */
302: void my_js_rt_clear() {
303:   if (jsrt) {
304:     JS_DestroyRuntime(jsrt);
305:     jsrt = NULL;
306:   }
307:   
308:   JS_ShutDown();
309: }
Copyright (C) KAKU PROJECT (2009)KAKU PROJECT (2009)