|
|
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.