|
|
1.1 root 1: /* jsexec.c */
2:
3: /* Execute a Synchronet JavaScript module from the command-line */
4:
5: /* $Id: jsexec.c,v 1.75 2004/12/09 08:07:13 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #ifndef JAVASCRIPT
39: #define JAVASCRIPT
40: #endif
41:
42: #ifdef __unix__
43: #include <signal.h>
44: #endif
45:
46: #include "sbbs.h"
47:
48: #define DEFAULT_LOG_MASK 0xff /* Display all LOG levels */
49: #define DEFAULT_ERR_LOG_LVL LOG_WARNING
50:
51: JSRuntime* js_runtime;
52: JSContext* js_cx;
53: JSObject* js_glob;
54: js_branch_t branch;
55: scfg_t scfg;
56: ulong js_max_bytes=JAVASCRIPT_MAX_BYTES;
57: ulong js_cx_stack=JAVASCRIPT_CONTEXT_STACK;
58: FILE* confp;
59: FILE* errfp;
60: FILE* nulfp;
61: FILE* statfp;
62: char revision[16];
63: char* host_name=NULL;
64: char host_name_buf[128];
65: BOOL pause_on_exit=FALSE;
66: BOOL pause_on_error=FALSE;
67: BOOL terminated=FALSE;
68: DWORD log_mask=DEFAULT_LOG_MASK;
69: int err_level=DEFAULT_ERR_LOG_LVL;
70:
71: void banner(FILE* fp)
72: {
73: fprintf(fp,"\nJSexec v%s%c-%s (rev %s) - "
74: "Execute Synchronet JavaScript Module\n"
75: ,VERSION,REVISION
76: ,PLATFORM_DESC
77: ,revision
78: );
79: }
80:
81: void usage(FILE* fp)
82: {
83: banner(fp);
84:
85: fprintf(fp,"\nusage: jsexec [-opts] [path]module[.js] [args]\n"
86: "\navailable opts:\n\n"
87: "\t-c<ctrl_dir> specify path to Synchronet CTRL directory\n"
88: "\t-m<bytes> set maximum heap size (default=%u bytes)\n"
89: "\t-s<bytes> set context stack size (default=%u bytes)\n"
90: "\t-b<limit> set branch limit (default=%u, 0=unlimited)\n"
91: "\t-y<interval> set yield interval (default=%u, 0=never)\n"
92: "\t-g<interval> set garbage collection interval (default=%u, 0=never)\n"
93: "\t-h[hostname] use local or specified host name (instead of SCFG value)\n"
94: "\t-L<mask> set log level mask (default=0x%x)\n"
95: "\t-E<level> set error log level threshold (default=%d)\n"
96: "\t-a append instead of overwriting message output files\n"
97: "\t-e<filename> send error messages to file in addition to stderr\n"
98: "\t-o<filename> send console messages to file instead of stdout\n"
99: "\t-n send status messages to %s instead of stderr\n"
100: "\t-q send console messages to %s instead of stdout\n"
101: "\t-x disable auto-termination on local abort signal\n"
102: "\t-l loop until intentionally terminated\n"
103: "\t-p wait for keypress (pause) on exit\n"
104: "\t-! wait for keypress (pause) on error\n"
105: ,JAVASCRIPT_MAX_BYTES
106: ,JAVASCRIPT_CONTEXT_STACK
107: ,JAVASCRIPT_BRANCH_LIMIT
108: ,JAVASCRIPT_YIELD_INTERVAL
109: ,JAVASCRIPT_GC_INTERVAL
110: ,DEFAULT_LOG_MASK
111: ,DEFAULT_ERR_LOG_LVL
112: ,_PATH_DEVNULL
113: ,_PATH_DEVNULL
114: );
115: }
116:
117: /* Log printf */
118: int lprintf(int level, char *fmt, ...)
119: {
120: va_list argptr;
121: char sbuf[1024];
122: int ret=0;
123:
124: if(!(log_mask&(1<<level)))
125: return(0);
126:
127: va_start(argptr,fmt);
128: vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
129: sbuf[sizeof(sbuf)-1]=0;
130: va_end(argptr);
131: if(level<=err_level)
132: ret=fprintf(errfp,"%s",sbuf);
133: if(level>err_level || (errfp!=stderr && errfp!=confp))
134: ret=fprintf(confp,"%s",sbuf);
135: return(ret);
136: }
137:
138: #if defined(_WINSOCKAPI_)
139:
140: WSADATA WSAData;
141: #define SOCKLIB_DESC WSAData.szDescription
142: static BOOL WSAInitialized=FALSE;
143:
144: static BOOL winsock_startup(void)
145: {
146: int status; /* Status Code */
147:
148: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
149: /* fprintf(statfp,"%s %s\n",WSAData.szDescription, WSAData.szSystemStatus); */
150: WSAInitialized=TRUE;
151: return(TRUE);
152: }
153:
154: lprintf(LOG_ERR,"!WinSock startup ERROR %d\n", status);
155: return(FALSE);
156: }
157:
158: #else /* No WINSOCK */
159:
160: #define winsock_startup() (TRUE)
161: #define SOCKLIB_DESC NULL
162:
163: #endif
164:
165: void bail(int code)
166: {
167:
168: #if defined(_WINSOCKAPI_)
169: if(WSAInitialized && WSACleanup()!=0)
170: lprintf(LOG_ERR,"!WSACleanup ERROR %d\n",ERROR_VALUE);
171: #endif
172:
173: if(pause_on_exit || (code && pause_on_error)) {
174: fprintf(statfp,"\nHit enter to continue...");
175: getchar();
176: }
177:
178: if(code)
179: fprintf(statfp,"\nReturning error code: %d\n",code);
180: exit(code);
181: }
182:
183: static JSBool
184: js_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
185: {
186: uintN i=0;
187: int32 level=LOG_INFO;
188: JSString* str=NULL;
189:
190: if(JSVAL_IS_NUMBER(argv[i]))
191: JS_ValueToInt32(cx,argv[i++],&level);
192:
193: for(; i<argc; i++) {
194: if((str=JS_ValueToString(cx, argv[i]))==NULL)
195: return(JS_FALSE);
196: lprintf(level,"%s",JS_GetStringBytes(str));
197: }
198: if(argc)
199: lprintf(level,"\n");
200:
201: if(str==NULL)
202: *rval = JSVAL_VOID;
203: else
204: *rval = STRING_TO_JSVAL(str);
205:
206: return(JS_TRUE);
207: }
208:
209: static JSBool
210: js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
211: {
212: char* buf;
213: int rd;
214: int32 len=128;
215:
216: *rval = JSVAL_VOID;
217:
218: if(argc)
219: JS_ValueToInt32(cx,argv[0],&len);
220: if((buf=malloc(len))==NULL)
221: return(JS_TRUE);
222:
223: rd=fread(buf,sizeof(char),len,stdin);
224:
225: if(rd>=0)
226: *rval = STRING_TO_JSVAL(JS_NewStringCopyN(cx,buf,rd));
227:
228: free(buf);
229: return(JS_TRUE);
230: }
231:
232: static JSBool
233: js_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
234: {
235: char* buf;
236: char* p;
237: int32 len=128;
238:
239: *rval = JSVAL_VOID;
240:
241: if(argc)
242: JS_ValueToInt32(cx,argv[0],&len);
243: if((buf=malloc(len+1))==NULL)
244: return(JS_TRUE);
245:
246: p=fgets(buf,len+1,stdin);
247:
248: if(p!=NULL)
249: *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,truncnl(p)));
250:
251: free(buf);
252: return(JS_TRUE);
253: }
254:
255:
256: static JSBool
257: js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
258: {
259: uintN i;
260: JSString* str=NULL;
261:
262: for (i = 0; i < argc; i++) {
263: if((str=JS_ValueToString(cx, argv[i]))==NULL)
264: return(JS_FALSE);
265: fprintf(confp,"%s",JS_GetStringBytes(str));
266: }
267:
268: if(str==NULL)
269: *rval = JSVAL_VOID;
270: else
271: *rval = STRING_TO_JSVAL(str);
272: return(JS_TRUE);
273: }
274:
275: static JSBool
276: js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
277: {
278: if(!js_write(cx,obj,argc,argv,rval))
279: return(JS_FALSE);
280:
281: fprintf(confp,"\n");
282: return(JS_TRUE);
283: }
284:
285: static JSBool
286: js_printf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
287: {
288: char* p;
289: uintN i;
290: JSString * fmt;
291: JSString * str;
292: va_list arglist[64];
293:
294: if((fmt = JS_ValueToString(cx, argv[0]))==NULL)
295: return(JS_FALSE);
296:
297: memset(arglist,0,sizeof(arglist)); // Initialize arglist to NULLs
298:
299: for (i = 1; i < argc && i<sizeof(arglist)/sizeof(arglist[0]); i++) {
300: if(JSVAL_IS_DOUBLE(argv[i]))
301: arglist[i-1]=(char*)(unsigned long)*JSVAL_TO_DOUBLE(argv[i]);
302: else if(JSVAL_IS_INT(argv[i]))
303: arglist[i-1]=(char *)JSVAL_TO_INT(argv[i]);
304: else {
305: if((str=JS_ValueToString(cx, argv[i]))==NULL) {
306: JS_ReportError(cx,"JS_ValueToString failed");
307: return(JS_FALSE);
308: }
309: arglist[i-1]=JS_GetStringBytes(str);
310: }
311: }
312:
313: if((p=JS_vsmprintf(JS_GetStringBytes(fmt),(char*)arglist))==NULL)
314: return(JS_FALSE);
315:
316: fprintf(confp,"%s",p);
317:
318: *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, p));
319:
320: JS_smprintf_free(p);
321:
322: return(JS_TRUE);
323: }
324:
325: static JSBool
326: js_alert(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
327: {
328: JSString * str;
329:
330: if((str=JS_ValueToString(cx, argv[0]))==NULL)
331: return(JS_FALSE);
332:
333: fprintf(confp,"!%s\n",JS_GetStringBytes(str));
334:
335: *rval = JSVAL_VOID;
336: return(JS_TRUE);
337: }
338:
339: static JSBool
340: js_confirm(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
341: {
342: JSString * str;
343:
344: if((str=JS_ValueToString(cx, argv[0]))==NULL)
345: return(JS_FALSE);
346:
347: printf("%s (Y/N)?", JS_GetStringBytes(str));
348:
349: *rval = BOOLEAN_TO_JSVAL(FALSE);
350: return(JS_TRUE);
351: }
352:
353: static JSBool
354: js_prompt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
355: {
356: char instr[81];
357: JSString * prompt;
358: JSString * str;
359:
360: if(!JSVAL_IS_VOID(argv[0])) {
361: if((prompt=JS_ValueToString(cx, argv[0]))==NULL)
362: return(JS_FALSE);
363: fprintf(confp,"%s: ",JS_GetStringBytes(prompt));
364: }
365:
366: if(argc>1) {
367: if((str=JS_ValueToString(cx, argv[1]))==NULL)
368: return(JS_FALSE);
369: SAFECOPY(instr,JS_GetStringBytes(str));
370: } else
371: instr[0]=0;
372:
373: if(!fgets(instr,sizeof(instr),stdin)) {
374: *rval = JSVAL_VOID;
375: return(JS_TRUE);
376: }
377:
378: if((str=JS_NewStringCopyZ(cx, instr))==NULL)
379: return(JS_FALSE);
380:
381: *rval = STRING_TO_JSVAL(str);
382: return(JS_TRUE);
383: }
384:
385: static JSBool
386: js_chdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
387: {
388: char* p;
389:
390: if((p=JS_GetStringBytes(JS_ValueToString(cx, argv[0])))==NULL) {
391: *rval = INT_TO_JSVAL(-1);
392: return(JS_TRUE);
393: }
394:
395: *rval = BOOLEAN_TO_JSVAL(chdir(p)==0);
396: return(JS_TRUE);
397: }
398:
399: static JSBool
400: js_putenv(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
401: {
402: char* p;
403:
404: if((p=JS_GetStringBytes(JS_ValueToString(cx, argv[0])))==NULL) {
405: *rval = INT_TO_JSVAL(-1);
406: return(JS_TRUE);
407: }
408:
409: *rval = BOOLEAN_TO_JSVAL(putenv(p)==0);
410: return(JS_TRUE);
411: }
412:
413: static jsSyncMethodSpec js_global_functions[] = {
414: {"log", js_log, 1},
415: {"read", js_read, 1},
416: {"readln", js_readln, 1},
417: {"write", js_write, 0},
418: {"writeln", js_writeln, 0},
419: {"print", js_writeln, 0},
420: {"printf", js_printf, 1},
421: {"alert", js_alert, 1},
422: {"prompt", js_prompt, 1},
423: {"confirm", js_confirm, 1},
424: {"chdir", js_chdir, 1},
425: {"putenv", js_putenv, 1},
426: {0}
427: };
428:
429: static void
430: js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
431: {
432: char line[64];
433: char file[MAX_PATH+1];
434: const char* warning;
435:
436: if(report==NULL) {
437: lprintf(LOG_ERR,"!JavaScript: %s\n", message);
438: return;
439: }
440:
441: if(report->filename)
442: sprintf(file," %s",report->filename);
443: else
444: file[0]=0;
445:
446: if(report->lineno)
447: sprintf(line," line %d",report->lineno);
448: else
449: line[0]=0;
450:
451: if(JSREPORT_IS_WARNING(report->flags)) {
452: if(JSREPORT_IS_STRICT(report->flags))
453: warning="strict warning";
454: else
455: warning="warning";
456: } else
457: warning="";
458:
459: lprintf(LOG_ERR,"!JavaScript %s%s%s: %s\n",warning,file,line,message);
460: }
461:
462: static JSBool
463: js_BranchCallback(JSContext *cx, JSScript *script)
464: {
465: return(js_CommonBranchCallback(cx,&branch));
466: }
467:
468: static BOOL js_CreateEnvObject(JSContext* cx, JSObject* glob, char** env)
469: {
470: char name[256];
471: char* val;
472: uint i;
473: JSObject* js_env;
474:
475: if((js_env=JS_NewObject(js_cx, NULL, NULL, glob))==NULL)
476: return(FALSE);
477:
478: if(!JS_DefineProperty(cx, glob, "env", OBJECT_TO_JSVAL(js_env)
479: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE))
480: return(FALSE);
481:
482: for(i=0;env[i]!=NULL;i++) {
483: SAFECOPY(name,env[i]);
484: truncstr(name,"=");
485: val=strchr(env[i],'=');
486: if(val==NULL)
487: val="";
488: else
489: val++;
490: if(!JS_DefineProperty(cx, js_env, name, STRING_TO_JSVAL(JS_NewStringCopyZ(cx,val))
491: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE))
492: return(FALSE);
493: }
494:
495: return(TRUE);
496: }
497:
498: static BOOL js_init(char** environ)
499: {
500: fprintf(statfp,"%s\n",(char *)JS_GetImplementationVersion());
501:
502: fprintf(statfp,"JavaScript: Creating runtime: %lu bytes\n"
503: ,js_max_bytes);
504:
505: if((js_runtime = JS_NewRuntime(js_max_bytes))==NULL)
506: return(FALSE);
507:
508: fprintf(statfp,"JavaScript: Initializing context (stack: %lu bytes)\n"
509: ,js_cx_stack);
510:
511: if((js_cx = JS_NewContext(js_runtime, js_cx_stack))==NULL)
512: return(FALSE);
513:
514: JS_SetErrorReporter(js_cx, js_ErrorReporter);
515:
516: /* Global Object */
517: if((js_glob=js_CreateCommonObjects(js_cx, &scfg, NULL, js_global_functions
518: ,time(NULL), host_name, SOCKLIB_DESC /* system */
519: ,&branch /* js */
520: ,NULL,INVALID_SOCKET /* client */
521: ,NULL /* server */
522: ))==NULL)
523: return(FALSE);
524:
525: /* Environment Object (associative array) */
526: if(!js_CreateEnvObject(js_cx, js_glob, environ))
527: return(FALSE);
528:
529: return(TRUE);
530: }
531:
532: static const char* js_ext(const char* fname)
533: {
534: if(strchr(fname,'.')==NULL)
535: return(".js");
536: return("");
537: }
538:
539: long js_exec(const char *fname, char** args)
540: {
541: int argc=0;
542: uint line_no;
543: char path[MAX_PATH+1];
544: char line[1024];
545: char compiler[32];
546: char rev_detail[256];
547: size_t len;
548: char* js_buf=NULL;
549: size_t js_buflen;
550: JSScript* js_script=NULL;
551: JSString* arg;
552: JSObject* argv;
553: FILE* fp=stdin;
554: jsval val;
555: jsval rval=JSVAL_VOID;
556: int32 result=0;
557:
558: if(fname!=NULL) {
559: if(strcspn(fname,"/\\")==strlen(fname)) {
560: sprintf(path,"%s%s%s",scfg.mods_dir,fname,js_ext(fname));
561: if(scfg.mods_dir[0]==0 || !fexistcase(path))
562: sprintf(path,"%s%s%s",scfg.exec_dir,fname,js_ext(fname));
563: } else
564: SAFECOPY(path,fname);
565:
566: if(!fexistcase(path)) {
567: lprintf(LOG_ERR,"!Module file (%s) doesn't exist\n",path);
568: return(-1);
569: }
570:
571: if((fp=fopen(path,"r"))==NULL) {
572: lprintf(LOG_ERR,"!Error %d (%s) opening %s\n",errno,STRERROR(errno),path);
573: return(-1);
574: }
575: }
576: JS_ClearPendingException(js_cx);
577:
578:
579: argv=JS_NewArrayObject(js_cx, 0, NULL);
580: JS_DefineProperty(js_cx, js_glob, "argv", OBJECT_TO_JSVAL(argv)
581: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
582:
583: for(argc=0;args[argc];argc++) {
584: arg = JS_NewStringCopyZ(js_cx, args[argc]);
585: if(arg==NULL)
586: break;
587: val=STRING_TO_JSVAL(arg);
588: if(!JS_SetElement(js_cx, argv, argc, &val))
589: break;
590: }
591: JS_DefineProperty(js_cx, js_glob, "argc", INT_TO_JSVAL(argc)
592: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
593:
594: JS_DefineProperty(js_cx, js_glob, "jsexec_revision"
595: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,revision))
596: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
597:
598: DESCRIBE_COMPILER(compiler);
599:
600: sprintf(rev_detail,"JSexec %s%s "
601: "Compiled %s %s with %s"
602: ,revision
603: #ifdef _DEBUG
604: ," Debug"
605: #else
606: ,""
607: #endif
608: ,__DATE__, __TIME__, compiler
609: );
610:
611: JS_DefineProperty(js_cx, js_glob, "jsexec_revision_detail"
612: ,STRING_TO_JSVAL(JS_NewStringCopyZ(js_cx,rev_detail))
613: ,NULL,NULL,JSPROP_READONLY|JSPROP_ENUMERATE);
614:
615: JS_SetBranchCallback(js_cx, js_BranchCallback);
616:
617: if(fp==stdin) /* Using stdin for script source */
618: SAFECOPY(path,"stdin");
619:
620: fprintf(statfp,"Reading script from %s\n",path);
621: line_no=0;
622: js_buflen=0;
623: while(!feof(fp)) {
624: if(!fgets(line,sizeof(line),fp))
625: break;
626: line_no++;
627: #if defined(__unix__) /* Support Unix Shell Scripts that start with #!/path/to/jsexec */
628: if(line_no==1 && strncmp(line,"#!",2)==0)
629: strcpy(line,"\n"); /* To keep line count correct */
630: #endif
631: len=strlen(line);
632: if((js_buf=realloc(js_buf,js_buflen+len))==NULL) {
633: lprintf(LOG_ERR,"!Error allocating %u bytes of memory\n"
634: ,js_buflen+len);
635: return(-1);
636: }
637: memcpy(js_buf+js_buflen,line,len);
638: js_buflen+=len;
639: }
640: if(fp!=NULL && fp!=stdin)
641: fclose(fp);
642:
643: if((js_script=JS_CompileScript(js_cx, js_glob, js_buf, js_buflen, fname==NULL ? NULL : path, 1))==NULL) {
644: lprintf(LOG_ERR,"!Error compiling script from %s\n",path);
645: return(-1);
646: }
647: JS_ExecuteScript(js_cx, js_glob, js_script, &rval);
648:
649: JS_GetProperty(js_cx, js_glob, "exit_code", &rval);
650:
651: if(rval!=JSVAL_VOID) {
652: fprintf(statfp,"Using JavaScript exit_code: %s\n",JS_GetStringBytes(JS_ValueToString(js_cx,rval)));
653: JS_ValueToInt32(js_cx,rval,&result);
654: }
655:
656: JS_DestroyScript(js_cx, js_script);
657:
658: JS_GC(js_cx);
659:
660: if(js_buf!=NULL)
661: free(js_buf);
662:
663: return(result);
664: }
665:
666: void break_handler(int type)
667: {
668: fprintf(statfp,"\n-> Terminated Locally (signal: %d)\n",type);
669: terminated=TRUE;
670: }
671:
672: #if defined(_WIN32)
673: BOOL WINAPI ControlHandler(DWORD CtrlType)
674: {
675: break_handler((int)CtrlType);
676: return TRUE;
677: }
678: #endif
679:
680: /*********************/
681: /* Entry point (duh) */
682: /*********************/
683: int main(int argc, char **argv, char** environ)
684: {
685: char error[512];
686: char* module=NULL;
687: char* p;
688: char* omode="w";
689: int argn;
690: long result;
691: BOOL loop=FALSE;
692:
693: confp=stdout;
694: errfp=stderr;
695: if((nulfp=fopen(_PATH_DEVNULL,"w+"))==NULL) {
696: perror(_PATH_DEVNULL);
697: bail(-1);
698: }
699: if(isatty(fileno(stderr)))
700: statfp=stderr;
701: else /* if redirected, don't send status messages to stderr */
702: statfp=nulfp;
703:
704: branch.limit=JAVASCRIPT_BRANCH_LIMIT;
705: branch.yield_interval=JAVASCRIPT_YIELD_INTERVAL;
706: branch.gc_interval=JAVASCRIPT_GC_INTERVAL;
707: branch.terminated=&terminated;
708: branch.auto_terminate=TRUE;
709:
710: sscanf("$Revision: 1.75 $", "%*s %s", revision);
711:
712: memset(&scfg,0,sizeof(scfg));
713: scfg.size=sizeof(scfg);
714:
715: if(!winsock_startup())
716: bail(2);
717:
718: for(argn=1;argn<argc && module==NULL;argn++) {
719: if(argv[argn][0]=='-') {
720: p=argv[argn]+2;
721: switch(argv[argn][1]) {
722: case 'a':
723: omode="a";
724: break;
725: case 'm':
726: if(*p==0) p=argv[++argn];
727: js_max_bytes=strtoul(p,NULL,0);
728: break;
729: case 's':
730: if(*p==0) p=argv[++argn];
731: js_cx_stack=strtoul(p,NULL,0);
732: break;
733: case 'b':
734: if(*p==0) p=argv[++argn];
735: branch.limit=strtoul(p,NULL,0);
736: break;
737: case 'y':
738: if(*p==0) p=argv[++argn];
739: branch.yield_interval=strtoul(p,NULL,0);
740: break;
741: case 'g':
742: if(*p==0) p=argv[++argn];
743: branch.gc_interval=strtoul(p,NULL,0);
744: break;
745: case 'h':
746: if(*p==0)
747: gethostname(host_name=host_name_buf,sizeof(host_name_buf));
748: else
749: host_name=p;
750: break;
751: case 'L':
752: if(*p==0) p=argv[++argn];
753: log_mask=strtol(p,NULL,0);
754: break;
755: case 'E':
756: if(*p==0) p=argv[++argn];
757: err_level=strtol(p,NULL,0);
758: break;
759: case 'e':
760: if(*p==0) p=argv[++argn];
761: if((errfp=fopen(p,omode))==NULL) {
762: perror(p);
763: bail(1);
764: }
765: break;
766: case 'o':
767: if(*p==0) p=argv[++argn];
768: if((confp=fopen(p,omode))==NULL) {
769: perror(p);
770: bail(1);
771: }
772: break;
773: case 'q':
774: confp=nulfp;
775: break;
776: case 'n':
777: statfp=nulfp;
778: break;
779: case 'x':
780: branch.auto_terminate=FALSE;
781: break;
782: case 'l':
783: loop=TRUE;
784: break;
785: case 'p':
786: pause_on_exit=TRUE;
787: break;
788: case '!':
789: pause_on_error=TRUE;
790: break;
791: case 'c':
792: if(*p==0) p=argv[++argn];
793: SAFECOPY(scfg.ctrl_dir,p);
794: break;
795: default:
796: fprintf(errfp,"\n!Unsupported option: %s\n",argv[argn]);
797: case '?':
798: usage(errfp);
799: bail(1);
800: }
801: continue;
802: }
803: module=argv[argn];
804: }
805:
806: if(scfg.ctrl_dir[0]==0) {
807: if((p=getenv("SBBSCTRL"))==NULL) {
808: lprintf(LOG_ERR,"\nSBBSCTRL environment variable not set and -c option not specified.\n");
809: lprintf(LOG_ERR,"\nExample: SET SBBSCTRL=/sbbs/ctrl\n");
810: lprintf(LOG_ERR,"\n or: %s -c /sbbs/ctrl [module]\n",argv[0]);
811: bail(1);
812: }
813: SAFECOPY(scfg.ctrl_dir,p);
814: }
815:
816: if(module==NULL && isatty(fileno(stdin))) {
817: lprintf(LOG_ERR,"\n!Module name not specified\n");
818: usage(errfp);
819: bail(1);
820: }
821:
822: banner(statfp);
823:
824: if(chdir(scfg.ctrl_dir)!=0)
825: lprintf(LOG_ERR,"!ERROR changing directory to: %s", scfg.ctrl_dir);
826:
827: fprintf(statfp,"\nLoading configuration files from %s\n",scfg.ctrl_dir);
828: if(!load_cfg(&scfg,NULL,TRUE,error)) {
829: lprintf(LOG_ERR,"!ERROR loading configuration files: %s\n",error);
830: bail(1);
831: }
832: prep_dir(scfg.data_dir, scfg.temp_dir, sizeof(scfg.temp_dir));
833:
834: if(host_name==NULL)
835: host_name=scfg.sys_inetaddr;
836:
837: if(!(scfg.sys_misc&SM_LOCAL_TZ))
838: putenv("TZ=UTC0");
839:
840: /* Don't cache error log */
841: setvbuf(errfp,NULL,_IONBF,0);
842:
843: /* Install Ctrl-C/Break signal handler here */
844: #if defined(_WIN32)
845: SetConsoleCtrlHandler(ControlHandler, TRUE /* Add */);
846: #elif defined(__unix__)
847: signal(SIGQUIT,break_handler);
848: signal(SIGINT,break_handler);
849: signal(SIGTERM,break_handler);
850:
851: /* Don't die on SIGPIPE or SIGHUP */
852: signal(SIGPIPE,SIG_IGN);
853: signal(SIGHUP,SIG_IGN);
854: #endif
855:
856: do {
857:
858: if(!js_init(environ)) {
859: lprintf(LOG_ERR,"!JavaScript initialization failure\n");
860: bail(1);
861: }
862: fprintf(statfp,"\n");
863:
864: result=js_exec(module,&argv[argn]);
865:
866: fprintf(statfp,"\n");
867: fprintf(statfp,"JavaScript: Destroying context\n");
868: JS_DestroyContext(js_cx);
869: fprintf(statfp,"JavaScript: Destroying runtime\n");
870: JS_DestroyRuntime(js_runtime);
871:
872: } while(loop && !terminated);
873:
874: bail(result);
875:
876: return(-1); /* never gets here */
877: }
878:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.