--- sbbs/src/sbbs3/js_global.c 2018/04/24 16:41:23 1.1 +++ sbbs/src/sbbs3/js_global.c 2018/04/24 16:43:06 1.1.1.2 @@ -2,13 +2,13 @@ /* Synchronet JavaScript "global" object properties/methods for all servers */ -/* $Id: js_global.c,v 1.1 2018/04/24 16:41:23 root Exp $ */ +/* $Id: js_global.c,v 1.1.1.2 2018/04/24 16:43:06 root Exp $ */ /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -31,7 +31,7 @@ * * * You are encouraged to submit any modifications (preferably in Unix diff * * format) via e-mail to mods@synchro.net * - * * + * * Note: If this box doesn't appear square, then you need to fix your tabs. * ****************************************************************************/ @@ -42,6 +42,9 @@ #include "base64.h" #include "htmlansi.h" #include "ini_file.h" +#include "js_rtpool.h" +#include "js_request.h" +#include "wordwrap.h" /* SpiderMonkey: */ #include @@ -51,6 +54,12 @@ #ifdef JAVASCRIPT +typedef struct { + scfg_t* cfg; + jsSyncMethodSpec* methods; + js_startup_t* startup; +} private_t; + /* Global Object Properites */ enum { GLOB_PROP_ERRNO @@ -83,12 +92,12 @@ static JSBool js_system_get(JSContext *c #define GLOBOBJ_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_SHARED -static struct JSPropertySpec js_global_properties[] = { -/* name, tinyid, flags */ +static jsSyncPropertySpec js_global_properties[] = { +/* name, tinyid, flags, ver */ - { "errno" ,GLOB_PROP_ERRNO ,GLOBOBJ_FLAGS }, - { "errno_str" ,GLOB_PROP_ERRNO_STR ,GLOBOBJ_FLAGS }, - { "socket_errno" ,GLOB_PROP_SOCKET_ERRNO ,GLOBOBJ_FLAGS }, + { "errno" ,GLOB_PROP_ERRNO ,GLOBOBJ_FLAGS, 310 }, + { "errno_str" ,GLOB_PROP_ERRNO_STR ,GLOBOBJ_FLAGS, 310 }, + { "socket_errno" ,GLOB_PROP_SOCKET_ERRNO ,GLOBOBJ_FLAGS, 310 }, {0} }; @@ -110,16 +119,19 @@ static void background_thread(void* arg) jsval result=JSVAL_VOID; jsval exit_code; + SetThreadName("JS Background"); msgQueueAttach(bg->msg_queue); JS_SetContextThread(bg->cx); + JS_BEGINREQUEST(bg->cx); if(!JS_ExecuteScript(bg->cx, bg->obj, bg->script, &result) && JS_GetProperty(bg->cx, bg->obj, "exit_code", &exit_code)) result=exit_code; js_EvalOnExit(bg->cx, bg->obj, &bg->branch); js_enqueue_value(bg->cx, bg->msg_queue, result, NULL); JS_DestroyScript(bg->cx, bg->script); + JS_ENDREQUEST(bg->cx); JS_DestroyContext(bg->cx); - JS_DestroyRuntime(bg->runtime); + jsrt_Release(bg->runtime); free(bg); } @@ -154,6 +166,19 @@ static JSBool js_BranchCallback(JSContex return js_CommonBranchCallback(cx,&bg->branch); } +#ifdef USE_JS_OPERATION_CALLBACK +static JSBool +js_OperationCallback(JSContext *cx) +{ + JSBool ret; + + JS_SetOperationCallback(cx, NULL); + ret=js_BranchCallback(cx, NULL); + JS_SetOperationCallback(cx, js_OperationCallback); + return ret; +} +#endif + static JSBool js_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { @@ -213,7 +238,7 @@ js_load(JSContext *cx, JSObject *obj, ui uintN argn=0; const char* filename; JSScript* script; - scfg_t* cfg; + private_t* p; jsval val; JSObject* js_argv; JSObject* exec_obj; @@ -221,10 +246,11 @@ js_load(JSContext *cx, JSObject *obj, ui JSBool success; JSBool background=JS_FALSE; background_data_t* bg; + jsrefcount rc; *rval=JSVAL_VOID; - if((cfg=(scfg_t*)JS_GetPrivate(cx,obj))==NULL) + if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) return(JS_FALSE); exec_obj=JS_GetScopeChain(cx); @@ -241,29 +267,33 @@ js_load(JSContext *cx, JSObject *obj, ui bg->parent_cx = cx; /* Setup default values for branch settings */ - bg->branch.limit=JAVASCRIPT_BRANCH_LIMIT; - bg->branch.gc_interval=JAVASCRIPT_GC_INTERVAL; - bg->branch.yield_interval=JAVASCRIPT_YIELD_INTERVAL; + bg->branch.limit=p->startup->branch_limit; + bg->branch.gc_interval=p->startup->gc_interval; + bg->branch.yield_interval=p->startup->yield_interval; +#if 0 if(JS_GetProperty(cx, obj,"js",&val)) /* copy branch settings from parent */ memcpy(&bg->branch,JS_GetPrivate(cx,JSVAL_TO_OBJECT(val)),sizeof(bg->branch)); +#endif bg->branch.terminated=NULL; /* could be bad pointer at any time */ bg->branch.counter=0; bg->branch.gc_attempts=0; - if((bg->runtime = JS_NewRuntime(JAVASCRIPT_MAX_BYTES))==NULL) + if((bg->runtime = jsrt_GetNew(JAVASCRIPT_MAX_BYTES, 1000, __FILE__, __LINE__))==NULL) return(JS_FALSE); if((bg->cx = JS_NewContext(bg->runtime, JAVASCRIPT_CONTEXT_STACK))==NULL) return(JS_FALSE); + JS_BEGINREQUEST(bg->cx); if((bg->obj=js_CreateCommonObjects(bg->cx - ,cfg /* common config */ + ,p->cfg /* common config */ ,NULL /* node-specific config */ ,NULL /* additional global methods */ ,0 /* uptime */ ,"" /* hostname */ ,"" /* socklib_desc */ ,&bg->branch /* js */ + ,p->startup /* js */ ,NULL /* client */ ,INVALID_SOCKET /* client_socket */ ,NULL /* server props */ @@ -281,13 +311,17 @@ js_load(JSContext *cx, JSObject *obj, ui /* Set our branch callback (which calls the generic branch callback) */ JS_SetContextPrivate(bg->cx, bg); +#ifdef USE_JS_OPERATION_CALLBACK + JS_SetOperationCallback(bg->cx, js_OperationCallback); +#else JS_SetBranchCallback(bg->cx, js_BranchCallback); +#endif /* Save parent's 'log' function (for later use by our log function) */ if(JS_GetProperty(cx, obj, "log", &val)) { JSFunction* func; - if((func=JS_ValueToFunction(cx, val))!=NULL && !func->interpreted) { - bg->log=func->u.native; + if((func=JS_ValueToFunction(cx, val))!=NULL && !(func->flags&JSFUN_INTERPRETED)) { + bg->log=func->u.n.native; JS_DefineFunction(bg->cx, bg->obj ,"log", js_log, func->nargs, func->flags); } @@ -324,14 +358,97 @@ js_load(JSContext *cx, JSObject *obj, ui ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY); } + rc=JS_SUSPENDREQUEST(cx); errno = 0; if(isfullpath(filename)) - strcpy(path,filename); + SAFECOPY(path,filename); else { - sprintf(path,"%s%s",cfg->mods_dir,filename); - if(cfg->mods_dir[0]==0 || !fexistcase(path)) - sprintf(path,"%s%s",cfg->exec_dir,filename); + JSObject* js_load_list = NULL; + + path[0]=0; /* Empty path, indicates load file not found (yet) */ + + JS_RESUMEREQUEST(cx, rc); + if(JS_GetProperty(cx, obj, "js", &val) && val!=JSVAL_VOID && JSVAL_IS_OBJECT(val)) { + JSObject* js_obj = JSVAL_TO_OBJECT(val); + + /* if js.exec_dir is defined (location of executed script), search their first */ + if(JS_GetProperty(cx, js_obj, "exec_dir", &val) && val!=JSVAL_VOID && JSVAL_IS_STRING(val)) { + SAFEPRINTF2(path,"%s%s",js_ValueToStringBytes(cx, val, NULL),filename); + rc=JS_SUSPENDREQUEST(cx); + if(!fexistcase(path)) + path[0]=0; + JS_RESUMEREQUEST(cx, rc); + } + if(JS_GetProperty(cx, js_obj, JAVASCRIPT_LOAD_PATH_LIST, &val) && val!=JSVAL_VOID && JSVAL_IS_OBJECT(val)) + js_load_list = JSVAL_TO_OBJECT(val); + + /* if mods_dir is defined, search mods/js.load_path_list[n] next */ + if(path[0]==0 && p->cfg->mods_dir[0]!=0 && js_load_list!=NULL) { + jsuint i; + char prefix[MAX_PATH+1]; + + for(i=0;path[0]==0;i++) { + if(!JS_GetElement(cx, js_load_list, i, &val) || val==JSVAL_VOID) + break; + SAFECOPY(prefix,js_ValueToStringBytes(cx, val, NULL)); + if(prefix[0]==0) + continue; + backslash(prefix); + rc=JS_SUSPENDREQUEST(cx); + if(isfullpath(prefix)) { + SAFEPRINTF2(path,"%s%s",prefix,filename); + if(!fexistcase(path)) + path[0]=0; + } else { + /* relative path */ + SAFEPRINTF3(path,"%s%s%s",p->cfg->mods_dir,prefix,filename); + if(!fexistcase(path)) + path[0]=0; + } + JS_RESUMEREQUEST(cx, rc); + } + } + } + rc=JS_SUSPENDREQUEST(cx); + /* if mods_dir is defined, search there next */ + if(path[0]==0 && p->cfg->mods_dir[0]!=0) { + SAFEPRINTF2(path,"%s%s",p->cfg->mods_dir,filename); + if(!fexistcase(path)) + path[0]=0; + } + /* if js.load_path_list is defined, search exec/load_path_list[n] next */ + if(path[0]==0 && js_load_list!=NULL) { + jsuint i; + char prefix[MAX_PATH+1]; + + for(i=0;path[0]==0;i++) { + JS_RESUMEREQUEST(cx, rc); + if(!JS_GetElement(cx, js_load_list, i, &val) || val==JSVAL_VOID) { + rc=JS_SUSPENDREQUEST(cx); + break; + } + SAFECOPY(prefix,js_ValueToStringBytes(cx, val, NULL)); + rc=JS_SUSPENDREQUEST(cx); + if(prefix[0]==0) + continue; + backslash(prefix); + if(isfullpath(prefix)) { + SAFEPRINTF2(path,"%s%s",prefix,filename); + if(!fexistcase(path)) + path[0]=0; + } else { + /* relative path */ + SAFEPRINTF3(path,"%s%s%s",p->cfg->exec_dir,prefix,filename); + if(!fexistcase(path)) + path[0]=0; + } + } + } + /* lastly, search exec dir */ + if(path[0]==0) + SAFEPRINTF2(path,"%s%s",p->cfg->exec_dir,filename); } + JS_RESUMEREQUEST(cx, rc); JS_ClearPendingException(exec_cx); @@ -342,6 +459,8 @@ js_load(JSContext *cx, JSObject *obj, ui bg->script = script; *rval = OBJECT_TO_JSVAL(js_CreateQueueObject(cx, obj, NULL, bg->msg_queue)); + JS_ENDREQUEST(bg->cx); + JS_ClearContextThread(bg->cx); success = _beginthread(background_thread,0,bg)!=-1; } else { @@ -378,14 +497,17 @@ static JSBool js_yield(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { BOOL forced=TRUE; + jsrefcount rc; if(argc) JS_ValueToBoolean(cx, argv[0], &forced); + rc=JS_SUSPENDREQUEST(cx); if(forced) { YIELD(); } else { MAYBE_YIELD(); } + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -395,10 +517,13 @@ js_mswait(JSContext *cx, JSObject *obj, { int32 val=1; clock_t start=msclock(); + jsrefcount rc; if(argc) JS_ValueToInt32(cx,argv[0],&val); + rc=JS_SUSPENDREQUEST(cx); mswait(val); + JS_RESUMEREQUEST(cx, rc); JS_NewNumberValue(cx,msclock()-start,rval); @@ -430,13 +555,16 @@ js_beep(JSContext *cx, JSObject *obj, ui { int32 freq=500; int32 dur=500; + jsrefcount rc; if(argc) JS_ValueToInt32(cx,argv[0],&freq); if(argc>1) JS_ValueToInt32(cx,argv[1],&dur); + rc=JS_SUSPENDREQUEST(cx); sbbs_beep(freq,dur); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -455,6 +583,7 @@ js_crc16(JSContext *cx, JSObject *obj, u { char* p; size_t len; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -462,7 +591,9 @@ js_crc16(JSContext *cx, JSObject *obj, u if((p=js_ValueToStringBytes(cx, argv[0], &len))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); *rval = INT_TO_JSVAL(crc16(p,len)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -471,6 +602,8 @@ js_crc32(JSContext *cx, JSObject *obj, u { char* p; size_t len; + uint32_t cs; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -478,7 +611,10 @@ js_crc32(JSContext *cx, JSObject *obj, u if((p=js_ValueToStringBytes(cx, argv[0], &len))==NULL) return(JS_FALSE); - JS_NewNumberValue(cx,crc32(p,len),rval); + cs=crc32(p,len); + rc=JS_SUSPENDREQUEST(cx); + JS_NewNumberValue(cx,cs,rval); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -488,6 +624,7 @@ js_chksum(JSContext *cx, JSObject *obj, ulong sum=0; char* p; size_t len; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -495,7 +632,9 @@ js_chksum(JSContext *cx, JSObject *obj, if((p=js_ValueToStringBytes(cx, argv[0], &len))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); /* 3.8 seconds on Deuce's computer when len==UINT_MAX/8 */ while(len--) sum+=*(p++); + JS_RESUMEREQUEST(cx, rc); JS_NewNumberValue(cx,sum,rval); return(JS_TRUE); @@ -606,10 +745,7 @@ js_strip_ctrl(JSContext *cx, JSObject *o if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); - if((buf=strdup(p))==NULL) - return(JS_FALSE); - - strip_ctrl(buf); + buf=strip_ctrl(p, NULL); js_str = JS_NewStringCopyZ(cx, buf); free(buf); @@ -633,10 +769,7 @@ js_strip_exascii(JSContext *cx, JSObject if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); - if((buf=strdup(p))==NULL) - return(JS_FALSE); - - strip_exascii(buf); + buf=strip_exascii(p, NULL); js_str = JS_NewStringCopyZ(cx, buf); free(buf); @@ -680,130 +813,16 @@ js_lfexpand(JSContext *cx, JSObject *obj return(JS_TRUE); } -static int get_prefix(char *text, int *bytes, int *len, int maxlen) -{ - int tmp_prefix_bytes,tmp_prefix_len; - int expect; - int depth; - - *bytes=0; - *len=0; - tmp_prefix_bytes=0; - tmp_prefix_len=0; - depth=0; - expect=1; - if(text[0]!=' ') - expect=2; - while(expect) { - tmp_prefix_bytes++; - /* Skip CTRL-A codes */ - while(text[tmp_prefix_bytes-1]=='\x01') { - tmp_prefix_bytes++; - if(text[tmp_prefix_bytes-1]=='\x01') - break; - tmp_prefix_bytes++; - } - tmp_prefix_len++; - if(text[tmp_prefix_bytes-1]==0 || text[tmp_prefix_bytes-1]=='\n' || text[tmp_prefix_bytes-1]=='\r') - break; - switch(expect) { - case 1: /* At start of possible quote (Next char should be space) */ - if(text[tmp_prefix_bytes-1]!=' ') - expect=0; - else - expect++; - break; - case 2: /* At start of nick (next char should be alphanum or '>') */ - case 3: /* At second nick initial (next char should be alphanum or '>') */ - case 4: /* At third nick initial (next char should be alphanum or '>') */ - if(text[tmp_prefix_bytes-1]==' ' || text[tmp_prefix_bytes-1]==0) - expect=0; - else - if(text[tmp_prefix_bytes-1]=='>') - expect=6; - else - expect++; - break; - case 5: /* After three regular chars, next HAS to be a '>') */ - if(text[tmp_prefix_bytes-1]!='>') - expect=0; - else - expect++; - break; - case 6: /* At '>' next char must be a space */ - if(text[tmp_prefix_bytes-1]!=' ') - expect=0; - else { - expect=1; - *len=tmp_prefix_len; - *bytes=tmp_prefix_bytes; - depth++; - /* Some editors don't put double spaces in between */ - if(text[tmp_prefix_bytes]!=' ') - expect++; - } - break; - default: - expect=0; - break; - } - } - if(*bytes >= maxlen) { - lprintf(LOG_CRIT, "Prefix bytes %u is larger than buffer (%u) here: %*.*s",*bytes,maxlen,maxlen,maxlen,text); - *bytes=maxlen-1; - } - return(depth); -} - -static void outbuf_append(char **outbuf, char **outp, char *append, int len, int *outlen) -{ - char *p; - - /* Terminate outbuf */ - **outp=0; - /* Check if there's room */ - if(*outp - *outbuf + len < *outlen) { - memcpy(*outp, append, len); - *outp+=len; - return; - } - /* Not enough room, double the size. */ - *outlen *= 2; - p=realloc(*outbuf, *outlen); - if(p==NULL) { - /* Can't do it. */ - *outlen/=2; - return; - } - /* Set outp for new buffer */ - *outp=p+(*outp - *outbuf); - *outbuf=p; - memcpy(*outp, append, len); - *outp+=len; - return; -} - static JSBool js_word_wrap(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - int32 l,len=79; + int32 len=79; int32 oldlen=79; - int32 crcount=0; JSBool handle_quotes=JS_TRUE; - long i,k,t; - int ocol=1; - int icol=1; uchar* inbuf; char* outbuf; - char* outp; - char* linebuf; - char* prefix=NULL; - int prefix_len=0; - int prefix_bytes=0; - int quote_count=0; - int old_prefix_bytes=0; - int outbuf_size=0; JSString* js_str; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -811,11 +830,6 @@ js_word_wrap(JSContext *cx, JSObject *ob if((inbuf=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); - outbuf_size=strlen(inbuf)*3+1; - if((outbuf=(char*)malloc(outbuf_size))==NULL) - return(JS_FALSE); - outp=outbuf; - if(argc>1) JS_ValueToInt32(cx,argv[1],&len); @@ -825,220 +839,18 @@ js_word_wrap(JSContext *cx, JSObject *ob if(argc>3 && JSVAL_IS_BOOLEAN(argv[3])) handle_quotes=JSVAL_TO_BOOLEAN(argv[3]); - if((linebuf=(char*)alloca((len*2)+2))==NULL) /* room for ^A codes ToDo: This isn't actually "enough" room */ - return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); - if(handle_quotes) { - if((prefix=(char *)alloca((len*2)+2))==NULL) /* room for ^A codes ToDo: This isn't actually "enough" room */ - return(JS_FALSE); - prefix[0]=0; - } + outbuf=wordwrap(inbuf, len, oldlen, handle_quotes); - outbuf[0]=0; - /* Get prefix from the first line (ouch) */ - l=0; - i=0; - if(handle_quotes && (quote_count=get_prefix(inbuf, &prefix_bytes, &prefix_len, len*2+2))!=0) { - i+=prefix_bytes; - if(prefix_len>len/3*2) { - /* This prefix is insane (more than 2/3rds of the new width) hack it down to size */ - /* Since we're hacking it, we will always end up with a hardcr on this line. */ - /* ToDo: Something prettier would be nice. */ - sprintf(prefix," %d> ",quote_count); - prefix_len=strlen(prefix); - prefix_bytes=strlen(prefix); - } - else { - memcpy(prefix,inbuf,prefix_bytes); - /* Terminate prefix */ - prefix[prefix_bytes]=0; - } - memcpy(linebuf,prefix,prefix_bytes); - l=prefix_bytes; - ocol=prefix_len+1; - icol=prefix_len+1; - old_prefix_bytes=prefix_bytes; - } - for(; inbuf[i]; i++) { - if(l>=len*2+2) { - l-=4; - linebuf[l]=0; - lprintf(LOG_CRIT, "Word wrap line buffer exceeded... munging line %s",linebuf); - } - switch(inbuf[i]) { - case '\r': - crcount++; - break; - case '\n': - if(handle_quotes && (quote_count=get_prefix(inbuf+i+1, &prefix_bytes, &prefix_len, len*2+2))!=0) { - /* Move the input pointer offset to the last char of the prefix */ - i+=prefix_bytes; - } - if(!inbuf[i+1]) { /* EOF */ - linebuf[l++]='\r'; - linebuf[l++]='\n'; - outbuf_append(&outbuf, &outp, linebuf, l, &outbuf_size); - l=0; - ocol=1; - } - /* If there's a new prefix, it is a hardcr */ - else if(prefix_bytes != old_prefix_bytes || (memcmp(prefix,inbuf+i+1-prefix_bytes,prefix_bytes))) { - if(prefix_len>len/3*2) { - /* This prefix is insane (more than 2/3rds of the new width) hack it down to size */ - /* Since we're hacking it, we will always end up with a hardcr on this line. */ - /* ToDo: Something prettier would be nice. */ - sprintf(prefix," %d> ",quote_count); - prefix_len=strlen(prefix); - prefix_bytes=strlen(prefix); - } - else { - memcpy(prefix,inbuf+i+1-prefix_bytes,prefix_bytes); - /* Terminate prefix */ - prefix[prefix_bytes]=0; - } - linebuf[l++]='\r'; - linebuf[l++]='\n'; - outbuf_append(&outbuf, &outp, linebuf, l, &outbuf_size); - memcpy(linebuf,prefix,prefix_bytes); - l=prefix_bytes; - ocol=prefix_len+1; - old_prefix_bytes=prefix_bytes; - } - else if(isspace(inbuf[i+1])) { /* Next line starts with whitespace. This is a "hard" CR. */ - linebuf[l++]='\r'; - linebuf[l++]='\n'; - outbuf_append(&outbuf, &outp, linebuf, l, &outbuf_size); - l=0; - ocol=1; - } - else { - if(icol < oldlen) { /* If this line is overly long, It's impossible for the next word to fit */ - /* k will equal the length of the first word on the next line */ - for(k=0; inbuf[i+1+k] && (!isspace(inbuf[i+1+k])); k++); - if(icol+k+1 < oldlen) { /* The next word would have fit but isn't here. Must be a hard CR */ - linebuf[l++]='\r'; - linebuf[l++]='\n'; - outbuf_append(&outbuf, &outp, linebuf, l, &outbuf_size); - if(prefix) - memcpy(linebuf,prefix,prefix_bytes); - l=prefix_bytes; - ocol=prefix_len+1; - } - else { /* Not a hard CR... add space if needed */ - if(l<1 || !isspace(linebuf[l-1])) { - linebuf[l++]=' '; - ocol++; - } - } - } - else { /* Not a hard CR... add space if needed */ - if(l<1 || !isspace(linebuf[l-1])) { - linebuf[l++]=' '; - ocol++; - } - } - } - icol=prefix_len+1; - break; - case '\x1f': /* Delete... meaningless... strip. */ - break; - case '\b': /* Backspace... handle if possible, but don't go crazy. */ - if(l>0) { - if(l>1 && linebuf[l-2]=='\x01') { - if(linebuf[l-1]=='\x01') { - ocol--; - icol--; - } - l-=2; - } - else { - l--; - ocol--; - icol--; - } - } - break; - case '\t': /* TAB */ - linebuf[l++]=inbuf[i]; - /* Can't ever wrap on whitespace remember. */ - icol++; - ocol++; - while(ocol%8) - ocol++; - while(icol%8) - icol++; - break; - case '\x01': /* CTRL-A */ - linebuf[l++]=inbuf[i++]; - if(inbuf[i]!='\x01') { - linebuf[l++]=inbuf[i]; - break; - } - default: - linebuf[l++]=inbuf[i]; - ocol++; - icol++; - if(ocol>len && !isspace(inbuf[i])) { /* Need to wrap here */ - /* Find the start of the last word */ - k=l; /* Original next char */ - l--; /* Move back to the last char */ - while((!isspace(linebuf[l])) && l>0) /* Move back to the last non-space char */ - l--; - if(l==0) { /* Couldn't wrap... must chop. */ - l=k; - while(l>1 && linebuf[l-2]=='\x01' && linebuf[l-1]!='\x01') - l-=2; - if(l>0 && linebuf[l-1]=='\x01') - l--; - if(l>0) - l--; - } - t=l+1; /* Store start position of next line */ - /* Move to start of whitespace */ - while(l>0 && isspace(l)) - l--; - outbuf_append(&outbuf, &outp, linebuf, l+1, &outbuf_size); - outbuf_append(&outbuf, &outp, "\r\n", 2, &outbuf_size); - /* Move trailing words to start of buffer. */ - l=prefix_bytes; - if(k-t>0) /* k-1 is the last char position. t is the start of the next line position */ - memmove(linebuf+l, linebuf+t, k-t); - l+=k-t; - /* Find new ocol */ - for(ocol=prefix_len+1,t=prefix_bytes; t2) prefix=js_ValueToStringBytes(cx, argv[2], NULL); - if((outbuf=(char*)malloc((strlen(inbuf)*strlen(prefix))+1))==NULL) + if((outbuf=(char*)malloc((strlen(inbuf)*(strlen(prefix)+1))+1))==NULL) return(JS_FALSE); len-=strlen(prefix); if(len<=0) return(JS_FALSE); - if((linebuf=(char*)alloca(len*2+2))==NULL) /* (Hopefully) Room for ^A codes. ToDo */ + if((linebuf=(char*)alloca((len*3)+2))==NULL) /* (Hopefully) Room for ^A codes. ToDo */ return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); outbuf[0]=0; clen=0; for(i=l=0;inbuf[i];i++) { @@ -1099,6 +913,7 @@ js_quote_msg(JSContext *cx, JSObject *ob } if(l) /* remainder */ strncat(outbuf,linebuf,l); + JS_RESUMEREQUEST(cx, rc); js_str = JS_NewStringCopyZ(cx, outbuf); free(outbuf); @@ -1363,17 +1178,18 @@ js_html_encode(JSContext *cx, JSObject * struct tm tm; time_t now; BOOL nodisplay=FALSE; - scfg_t* cfg; + private_t* p; uchar attr_stack[64]; /* Saved attributes (stack) */ int attr_sp=0; /* Attribute stack pointer */ ulong clear_screen=0; JSObject* stateobj=NULL; jsval val; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); - if((cfg=(scfg_t*)JS_GetPrivate(cx,obj))==NULL) /* Will this work? Ask DM */ + if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) /* Will this work? Ask DM */ return(JS_FALSE); if((inbuf=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) @@ -1432,6 +1248,7 @@ js_html_encode(JSContext *cx, JSObject * if((tmpbuf=(char*)malloc((strlen(inbuf)*10)+1))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); for(i=j=0;inbuf[i];i++) { switch(inbuf[i]) { case TAB: @@ -1455,7 +1272,8 @@ js_html_encode(JSContext *cx, JSObject * j+=sprintf(tmpbuf+j,">"); break; case '\b': - j--; + if(j) + j--; break; default: if(inbuf[i]&0x80) { @@ -1481,7 +1299,7 @@ js_html_encode(JSContext *cx, JSObject * esccount++; tmpbuf[j++]=inbuf[i]; } - else if(ctrl_a && inbuf[i]==1) + else if(ctrl_a && inbuf[i]==CTRL_A) { esccount++; tmpbuf[j++]=inbuf[i]; @@ -1509,6 +1327,7 @@ js_html_encode(JSContext *cx, JSObject * if((outbuf=(uchar*)malloc(obsize))==NULL) { free(tmpbuf); + JS_RESUMEREQUEST(cx, rc); return(JS_FALSE); } j=sprintf(outbuf,"",htmlansi[7]); @@ -1521,6 +1340,7 @@ js_html_encode(JSContext *cx, JSObject * { free(tmpbuf); free(outbuf); + JS_RESUMEREQUEST(cx, rc); return(JS_FALSE); } outbuf=param; @@ -1713,7 +1533,7 @@ js_html_encode(JSContext *cx, JSObject * } i+=(int)(lastparam-ansi_seq)+2; } - else if(ctrl_a && tmpbuf[i]==1) /* CTRL-A codes */ + else if(ctrl_a && tmpbuf[i]==CTRL_A) /* CTRL-A codes */ { /* j+=sprintf(outbuf+j,"",tmpbuf[i+1],tmpbuf[i+1]); */ if(nodisplay && tmpbuf[i+1] != ')') @@ -1829,7 +1649,10 @@ js_html_encode(JSContext *cx, JSObject * case '.': case 'S': case '>': - case '<': + break; + case '<': /* convert non-destructive backspace into destructive backspace */ + if(j) + j--; break; case '!': /* This needs to be fixed! (Somehow) */ @@ -1849,7 +1672,7 @@ js_html_encode(JSContext *cx, JSObject * case 'D': now=time(NULL); - j+=sprintf(outbuf+j,"%s",unixtodstr(cfg,now,tmp1)); + j+=sprintf(outbuf+j,"%s",unixtodstr(p->cfg,now,tmp1)); break; case 'T': now=time(NULL); @@ -1868,7 +1691,7 @@ js_html_encode(JSContext *cx, JSObject * break; case ']': currrow++; - if(hpos!=0 && tmpbuf[i+2]!=CR && !(tmpbuf[i+2]==1 && tmpbuf[i+3]=='[')) + if(hpos!=0 && tmpbuf[i+2]!=CR && !(tmpbuf[i+2]==CTRL_A && tmpbuf[i+3]=='[')) { outbuf[j++]='\r'; outbuf[j++]='\n'; @@ -1974,12 +1797,15 @@ js_html_encode(JSContext *cx, JSObject * } } strcpy(outbuf+j,""); + JS_RESUMEREQUEST(cx, rc); js_str = JS_NewStringCopyZ(cx, outbuf); free(outbuf); } - else + else { + JS_RESUMEREQUEST(cx, rc); js_str = JS_NewStringCopyZ(cx, tmpbuf); + } free(tmpbuf); /* assertion here, Feb-20-2006 */ if(js_str==NULL) @@ -2024,6 +1850,7 @@ js_html_decode(JSContext *cx, JSObject * char token[16]; size_t t; JSString* js_str; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2034,6 +1861,7 @@ js_html_decode(JSContext *cx, JSObject * if((outbuf=(char*)malloc(strlen(inbuf)+1))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); for(i=j=0;inbuf[i];i++) { if(inbuf[i]!='&') { outbuf[j++]=inbuf[i]; @@ -2103,6 +1931,7 @@ js_html_decode(JSContext *cx, JSObject * } outbuf[j]=0; + JS_RESUMEREQUEST(cx, rc); js_str = JS_NewStringCopyZ(cx, outbuf); free(outbuf); @@ -2122,6 +1951,7 @@ js_b64_encode(JSContext *cx, JSObject *o uchar* inbuf; uchar* outbuf; JSString* js_str; + jsrefcount rc; *rval = JSVAL_NULL; @@ -2136,7 +1966,9 @@ js_b64_encode(JSContext *cx, JSObject *o if((outbuf=(char*)malloc(len))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); res=b64_encode(outbuf,len,inbuf,inbuf_len); + JS_RESUMEREQUEST(cx, rc); if(res<1) { free(outbuf); @@ -2160,6 +1992,7 @@ js_b64_decode(JSContext *cx, JSObject *o uchar* inbuf; uchar* outbuf; JSString* js_str; + jsrefcount rc; *rval = JSVAL_NULL; @@ -2174,7 +2007,9 @@ js_b64_decode(JSContext *cx, JSObject *o if((outbuf=(char*)malloc(len))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); res=b64_decode(outbuf,len,inbuf,strlen(inbuf)); + JS_RESUMEREQUEST(cx, rc); if(res<1) { free(outbuf); @@ -2199,6 +2034,7 @@ js_md5_calc(JSContext* cx, JSObject* obj char* inbuf; char outbuf[64]; JSString* js_str; + jsrefcount rc; *rval = JSVAL_NULL; @@ -2211,12 +2047,14 @@ js_md5_calc(JSContext* cx, JSObject* obj if(argc>1 && JSVAL_IS_BOOLEAN(argv[1])) hex=JSVAL_TO_BOOLEAN(argv[1]); + rc=JS_SUSPENDREQUEST(cx); MD5_calc(digest,inbuf,inbuf_len); if(hex) MD5_hex(outbuf,digest); else b64_encode(outbuf,sizeof(outbuf),digest,sizeof(digest)); + JS_RESUMEREQUEST(cx, rc); js_str = JS_NewStringCopyZ(cx, outbuf); if(js_str==NULL) @@ -2227,6 +2065,26 @@ js_md5_calc(JSContext* cx, JSObject* obj } static JSBool +js_skipsp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + char* str; + JSString* js_str; + + if(JSVAL_IS_VOID(argv[0])) + return(JS_TRUE); + + if((str=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) + return(JS_FALSE); + + js_str = JS_NewStringCopyZ(cx, skipsp(str)); + if(js_str==NULL) + return(JS_FALSE); + + *rval = STRING_TO_JSVAL(js_str); + return(JS_TRUE); +} + +static JSBool js_truncsp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* p; @@ -2307,6 +2165,32 @@ js_backslash(JSContext *cx, JSObject *ob return(JS_TRUE); } +static JSBool +js_fullpath(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + char path[MAX_PATH+1]; + char* str; + JSString* js_str; + jsrefcount rc; + + if(JSVAL_IS_VOID(argv[0])) + return(JS_TRUE); + + if((str=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) + return(JS_FALSE); + + SAFECOPY(path,str); + rc=JS_SUSPENDREQUEST(cx); + _fullpath(path, str, sizeof(path)); + JS_RESUMEREQUEST(cx, rc); + + if((js_str = JS_NewStringCopyZ(cx, path))==NULL) + return(JS_FALSE); + + *rval = STRING_TO_JSVAL(js_str); + return(JS_TRUE); +} + static JSBool js_getfname(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) @@ -2358,6 +2242,7 @@ js_getfcase(JSContext *cx, JSObject *obj char* str; char path[MAX_PATH+1]; JSString* js_str; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2366,13 +2251,54 @@ js_getfcase(JSContext *cx, JSObject *obj return(JS_FALSE); SAFECOPY(path,str); + rc=JS_SUSPENDREQUEST(cx); if(fexistcase(path)) { + JS_RESUMEREQUEST(cx, rc); + js_str = JS_NewStringCopyZ(cx, path); + if(js_str==NULL) + return(JS_FALSE); + + *rval = STRING_TO_JSVAL(js_str); + } + else + JS_RESUMEREQUEST(cx, rc); + return(JS_TRUE); +} + +static JSBool +js_dosfname(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + char* str; + char path[MAX_PATH+1]; + JSString* js_str; + jsrefcount rc; + + if(JSVAL_IS_VOID(argv[0])) + return(JS_TRUE); + +#if defined(_WIN32) + + if((str=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) + return(JS_FALSE); + + rc=JS_SUSPENDREQUEST(cx); + if(GetShortPathName(str,path,sizeof(path))) { + JS_RESUMEREQUEST(cx, rc); js_str = JS_NewStringCopyZ(cx, path); if(js_str==NULL) return(JS_FALSE); *rval = STRING_TO_JSVAL(js_str); } + else + JS_RESUMEREQUEST(cx, rc); + +#else /* No non-Windows equivalent */ + + *rval = argv[0]; + +#endif + return(JS_TRUE); } @@ -2382,6 +2308,8 @@ js_cfgfname(JSContext *cx, JSObject *obj char* path; char* fname; char result[MAX_PATH+1]; + char* cstr; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2392,7 +2320,10 @@ js_cfgfname(JSContext *cx, JSObject *obj if((fname=js_ValueToStringBytes(cx, argv[1], NULL))==NULL) return(JS_FALSE); - *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,iniFileName(result,sizeof(result),path,fname))); + rc=JS_SUSPENDREQUEST(cx); + cstr = iniFileName(result,sizeof(result),path,fname); + JS_RESUMEREQUEST(cx, rc); + *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,cstr)); return(JS_TRUE); } @@ -2401,6 +2332,7 @@ static JSBool js_fexist(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* p; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2408,7 +2340,9 @@ js_fexist(JSContext *cx, JSObject *obj, if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(fexist(p)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2416,6 +2350,7 @@ static JSBool js_removecase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* p; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2423,7 +2358,9 @@ js_removecase(JSContext *cx, JSObject *o if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(removecase(p)==0); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2431,6 +2368,7 @@ static JSBool js_remove(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* p; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2438,7 +2376,9 @@ js_remove(JSContext *cx, JSObject *obj, if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(remove(p)==0); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2447,6 +2387,7 @@ js_rename(JSContext *cx, JSObject *obj, { char* oldname; char* newname; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2457,7 +2398,9 @@ js_rename(JSContext *cx, JSObject *obj, if((newname=js_ValueToStringBytes(cx, argv[1], NULL))==NULL) return(JS_TRUE); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(rename(oldname,newname)==0); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2466,6 +2409,7 @@ js_fcopy(JSContext *cx, JSObject *obj, u { char* src; char* dest; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2476,7 +2420,9 @@ js_fcopy(JSContext *cx, JSObject *obj, u if((dest=js_ValueToStringBytes(cx, argv[1], NULL))==NULL) return(JS_TRUE); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(fcopy(src,dest)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2485,6 +2431,7 @@ js_fcompare(JSContext *cx, JSObject *obj { char* fn1; char* fn2; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2495,7 +2442,9 @@ js_fcompare(JSContext *cx, JSObject *obj if((fn2=js_ValueToStringBytes(cx, argv[1], NULL))==NULL) return(JS_TRUE); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(fcompare(fn1,fn2)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2505,6 +2454,7 @@ js_backup(JSContext *cx, JSObject *obj, char* fname; int32 level=5; BOOL ren=FALSE; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2518,7 +2468,9 @@ js_backup(JSContext *cx, JSObject *obj, if(argc>2) JS_ValueToBoolean(cx,argv[2],&ren); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(backup(fname,level,ren)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2526,6 +2478,7 @@ static JSBool js_isdir(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* p; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2533,7 +2486,9 @@ js_isdir(JSContext *cx, JSObject *obj, u if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(isdir(p)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2541,6 +2496,8 @@ static JSBool js_fattr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* p; + jsrefcount rc; + int attr; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2548,7 +2505,10 @@ js_fattr(JSContext *cx, JSObject *obj, u if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); - JS_NewNumberValue(cx,getfattr(p),rval); + rc=JS_SUSPENDREQUEST(cx); + attr=getfattr(p); + JS_RESUMEREQUEST(cx, rc); + JS_NewNumberValue(cx,attr,rval); return(JS_TRUE); } @@ -2556,6 +2516,8 @@ static JSBool js_fdate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* p; + time_t fd; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2563,7 +2525,10 @@ js_fdate(JSContext *cx, JSObject *obj, u if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); - JS_NewNumberValue(cx,fdate(p),rval); + rc=JS_SUSPENDREQUEST(cx); + fd=fdate(p); + JS_RESUMEREQUEST(cx, rc); + JS_NewNumberValue(cx,fd,rval); return(JS_TRUE); } @@ -2573,8 +2538,8 @@ js_utime(JSContext *cx, JSObject *obj, u char* fname; int32 actime; int32 modtime; - struct utimbuf tbuf; - struct utimbuf* t=NULL; + struct utimbuf ut; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2584,17 +2549,20 @@ js_utime(JSContext *cx, JSObject *obj, u if((fname=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); + /* use current time as default */ + ut.actime = ut.modtime = time(NULL); + if(argc>1) { - memset(&tbuf,0,sizeof(tbuf)); - actime=modtime=time(NULL); + actime=modtime=ut.actime; JS_ValueToInt32(cx,argv[1],&actime); JS_ValueToInt32(cx,argv[2],&modtime); - tbuf.actime=actime; - tbuf.modtime=modtime; - t=&tbuf; + ut.actime=actime; + ut.modtime=modtime; } - *rval = BOOLEAN_TO_JSVAL(utime(fname,t)==0); + rc=JS_SUSPENDREQUEST(cx); + *rval = BOOLEAN_TO_JSVAL(utime(fname,&ut)==0); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2604,6 +2572,8 @@ static JSBool js_flength(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* p; + off_t fl; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2611,7 +2581,10 @@ js_flength(JSContext *cx, JSObject *obj, if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); - JS_NewNumberValue(cx,flength(p),rval); + rc=JS_SUSPENDREQUEST(cx); + fl=flength(p); + JS_RESUMEREQUEST(cx, rc); + JS_NewNumberValue(cx,(double)fl,rval); return(JS_TRUE); } @@ -2620,6 +2593,7 @@ static JSBool js_ftouch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* fname; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2627,7 +2601,9 @@ js_ftouch(JSContext *cx, JSObject *obj, if((fname=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(ftouch(fname)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2638,6 +2614,7 @@ js_fmutex(JSContext *cx, JSObject *obj, char* text=NULL; int32 max_age=0; uintN argn=0; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2649,7 +2626,9 @@ js_fmutex(JSContext *cx, JSObject *obj, if(argc > argn && JSVAL_IS_NUMBER(argv[argn])) JS_ValueToInt32(cx, argv[argn++], &max_age); + rc=JS_SUSPENDREQUEST(cx); *rval = BOOLEAN_TO_JSVAL(fmutex(fname,text,max_age)); + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2657,6 +2636,7 @@ static JSBool js_sound(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { char* p; + jsrefcount rc; if(!argc) { /* Stop playing sound */ #ifdef _WIN32 @@ -2672,11 +2652,13 @@ js_sound(JSContext *cx, JSObject *obj, u if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); #ifdef _WIN32 *rval = BOOLEAN_TO_JSVAL(PlaySound(p, NULL, SND_ASYNC|SND_FILENAME)); #else *rval = BOOLEAN_TO_JSVAL(JS_FALSE); #endif + JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } @@ -2692,6 +2674,7 @@ js_directory(JSContext *cx, JSObject *ob JSString* js_str; jsint len=0; jsval val; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2707,7 +2690,9 @@ js_directory(JSContext *cx, JSObject *ob if((array = JS_NewArrayObject(cx, 0, NULL))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); glob(p,flags,NULL,&g); + JS_RESUMEREQUEST(cx, rc); for(i=0;i<(int)g.gl_pathc;i++) { if((js_str=JS_NewStringCopyZ(cx,g.gl_pathv[i]))==NULL) break; @@ -2715,7 +2700,9 @@ js_directory(JSContext *cx, JSObject *ob if(!JS_SetElement(cx, array, len++, &val)) break; } + rc=JS_SUSPENDREQUEST(cx); globfree(&g); + JS_RESUMEREQUEST(cx, rc); *rval = OBJECT_TO_JSVAL(array); @@ -2730,6 +2717,7 @@ js_wildmatch(JSContext *cx, JSObject *ob char* fname; char* spec="*"; uintN argn=0; + jsrefcount rc; if(JSVAL_IS_BOOLEAN(argv[argn])) JS_ValueToBoolean(cx, argv[argn++], &case_sensitive); @@ -2744,10 +2732,12 @@ js_wildmatch(JSContext *cx, JSObject *ob if(argn1) JS_ValueToInt32(cx,argv[1],&unit); - JS_NewNumberValue(cx,getfreediskspace(p,unit),rval); + rc=JS_SUSPENDREQUEST(cx); + fd=getfreediskspace(p,unit); + JS_RESUMEREQUEST(cx, rc); + JS_NewNumberValue(cx,fd,rval); return(JS_TRUE); } @@ -2778,6 +2773,8 @@ js_disksize(JSContext *cx, JSObject *obj { int32 unit=0; char* p; + ulong ds; + jsrefcount rc; if(JSVAL_IS_VOID(argv[0])) return(JS_TRUE); @@ -2788,12 +2785,14 @@ js_disksize(JSContext *cx, JSObject *obj if(argc>1) JS_ValueToInt32(cx,argv[1],&unit); - JS_NewNumberValue(cx,getdisksize(p,unit),rval); + rc=JS_SUSPENDREQUEST(cx); + ds=getdisksize(p,unit); + JS_RESUMEREQUEST(cx, rc); + JS_NewNumberValue(cx,ds,rval); return(JS_TRUE); } - static JSBool js_socket_select(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { @@ -2812,6 +2811,7 @@ js_socket_select(JSContext *cx, JSObject SOCKET* index; jsval val; int len=0; + jsrefcount rc; *rval = JSVAL_NULL; @@ -2855,18 +2855,24 @@ js_socket_select(JSContext *cx, JSObject } } - if(select(maxsock+1,rd_set,wr_set,NULL,&tv)<0) - lprintf(LOG_DEBUG,"Error in socket_select() %s (%d)",strerror(errno),errno); + rc=JS_SUSPENDREQUEST(cx); + if(select(maxsock+1,rd_set,wr_set,NULL,&tv) >= 0) { - for(i=0;i1) JS_ValueToInt32(cx,argv[1],&i); + rc=JS_SUSPENDREQUEST(cx); strcpy(str,"-Invalid time-"); t=i; - if(localtime_r(&t,&tm)==NULL) - memset(&tm,0,sizeof(tm)); - strftime(str,sizeof(str),fmt,&tm); + if(localtime_r(&t,&tm)!=NULL) + strftime(str,sizeof(str),fmt,&tm); + JS_RESUMEREQUEST(cx, rc); if((js_str=JS_NewStringCopyZ(cx, str))==NULL) return(JS_FALSE); @@ -2940,6 +2972,7 @@ js_resolve_ip(JSContext *cx, JSObject *o struct in_addr addr; JSString* str; char* p; + jsrefcount rc; *rval = JSVAL_NULL; @@ -2949,7 +2982,10 @@ js_resolve_ip(JSContext *cx, JSObject *o if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); - if((addr.s_addr=resolve_ip(p))==INADDR_NONE) + rc=JS_SUSPENDREQUEST(cx); + addr.s_addr=resolve_ip(p); + JS_RESUMEREQUEST(cx, rc); + if(addr.s_addr==INADDR_NONE) return(JS_TRUE); if((str=JS_NewStringCopyZ(cx, inet_ntoa(addr)))==NULL) @@ -2966,6 +3002,7 @@ js_resolve_host(JSContext *cx, JSObject struct in_addr addr; HOSTENT* h; char* p; + jsrefcount rc; *rval = JSVAL_NULL; @@ -2975,8 +3012,10 @@ js_resolve_host(JSContext *cx, JSObject if((p=js_ValueToStringBytes(cx, argv[0], NULL))==NULL) return(JS_FALSE); + rc=JS_SUSPENDREQUEST(cx); addr.s_addr=inet_addr(p); h=gethostbyaddr((char *)&addr,sizeof(addr),AF_INET); + JS_RESUMEREQUEST(cx, rc); if(h!=NULL && h->h_name!=NULL) *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx,h->h_name)); @@ -2995,17 +3034,26 @@ js_list_named_queues(JSContext *cx, JSOb jsval val; list_node_t* node; msg_queue_t* q; + jsrefcount rc; if((array = JS_NewArrayObject(cx, 0, NULL))==NULL) return(JS_FALSE); - for(node=listFirstNode(&named_queues);node!=NULL;node=listNextNode(node)) { + rc=JS_SUSPENDREQUEST(cx); + listLock(&named_queues); + for(node=named_queues.first;node!=NULL;node=node->next) { if((q=listNodeData(node))==NULL) continue; + JS_RESUMEREQUEST(cx, rc); val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,q->name)); - if(!JS_SetElement(cx, array, len++, &val)) + if(!JS_SetElement(cx, array, len++, &val)) { + rc=JS_SUSPENDREQUEST(cx); break; + } + rc=JS_SUSPENDREQUEST(cx); } + listUnlock(&named_queues); + JS_RESUMEREQUEST(cx, rc); *rval = OBJECT_TO_JSVAL(array); @@ -3042,19 +3090,6 @@ js_flags_str(JSContext *cx, JSObject *ob return(JS_TRUE); } -static JSClass js_global_class = { - "Global" /* name */ - ,JSCLASS_HAS_PRIVATE /* flags */ - ,JS_PropertyStub /* addProperty */ - ,JS_PropertyStub /* delProperty */ - ,js_system_get /* getProperty */ - ,JS_PropertyStub /* setProperty */ - ,JS_EnumerateStub /* enumerate */ - ,JS_ResolveStub /* resolve */ - ,JS_ConvertStub /* convert */ - ,JS_FinalizeStub /* finalize */ -}; - static jsSyncMethodSpec js_global_functions[] = { {"exit", js_exit, 0, JSTYPE_VOID, "[exit_code]" ,JSDOCSTR("stop script execution, " @@ -3074,7 +3109,7 @@ static jsSyncMethodSpec js_global_functi "script/thread by reading from and/or writing to the parent_queue " "(an automatically created Queue object). " "The result (last executed statement) of the executed script " - "(or the optional exit_code passed to the exit()/ function) " + "(or the optional exit_code passed to the exit() function) " "will be automatically written to the parent_queue " "which may be read later by the parent script (using load_result.read(), for example).") ,312 @@ -3128,8 +3163,12 @@ static jsSyncMethodSpec js_global_functi ,JSDOCSTR("strip extended-ASCII characters from string, returns modified string") ,310 }, + {"skipsp", js_skipsp, 1, JSTYPE_STRING, JSDOCSTR("text") + ,JSDOCSTR("skip (trim) white-space characters off beginning of string, returns modified string") + ,315 + }, {"truncsp", js_truncsp, 1, JSTYPE_STRING, JSDOCSTR("text") - ,JSDOCSTR("truncate (trim) white-space characters off end of string, returns modified string") + ,JSDOCSTR("truncate (trim) white-space characters off end of string, returns modified string") ,310 }, {"truncstr", js_truncstr, 2, JSTYPE_STRING, JSDOCSTR("text, charset") @@ -3150,6 +3189,10 @@ static jsSyncMethodSpec js_global_functi "(i.e. \"slash\" or \"backslash\")") ,312 }, + {"fullpath", js_fullpath, 1, JSTYPE_STRING, JSDOCSTR("path") + ,JSDOCSTR("Creates an absolute or full path name for the specified relative path name.") + ,315 + }, {"file_getname", js_getfname, 1, JSTYPE_STRING, JSDOCSTR("path/filename") ,JSDOCSTR("returns filename portion of passed path string") ,311 @@ -3160,7 +3203,7 @@ static jsSyncMethodSpec js_global_functi ,311 }, {"file_getcase", js_getfcase, 1, JSTYPE_STRING, JSDOCSTR("path/filename") - ,JSDOCSTR("returns correct case of filename (long version of filename on Win32) " + ,JSDOCSTR("returns correct case of filename (long version of filename on Windows) " "or undefined if the file doesn't exist") ,311 }, @@ -3170,6 +3213,12 @@ static jsSyncMethodSpec js_global_functi "or path/file.host.ext) if such a variation of the filename exists") ,312 }, + {"file_getdosname", js_dosfname, 1, JSTYPE_STRING, JSDOCSTR("path/filename") + ,JSDOCSTR("returns DOS-compatible (Micros~1 shortened) version of specified path/filename" + "(on Windows only)
" + "returns unmodified path/filename on other platforms") + ,315 + }, {"file_exists", js_fexist, 1, JSTYPE_BOOLEAN, JSDOCSTR("path/filename") ,JSDOCSTR("verify a file's existence") ,310 @@ -3257,13 +3306,17 @@ static jsSyncMethodSpec js_global_functi {"socket_select", js_socket_select, 0, JSTYPE_ARRAY, JSDOCSTR("[array of socket objects or descriptors] [,timeout=0] [,write=false]") ,JSDOCSTR("checks an array of socket objects or descriptors for read or write ability (default is read), " "default timeout value is 0.0 seconds (immediate timeout), " - "returns an array of 0-based index values into the socket array, representing the sockets that were ready for reading or writing") + "returns an array of 0-based index values into the socket array, representing the sockets that were ready for reading or writing, or null on error") ,311 }, {"mkdir", js_mkdir, 1, JSTYPE_BOOLEAN, JSDOCSTR("path/directory") ,JSDOCSTR("make a directory") ,310 }, + {"mkpath", js_mkpath, 1, JSTYPE_BOOLEAN, JSDOCSTR("path/directory") + ,JSDOCSTR("make a path to a directory (creating all necessary sub-directories)") + ,315 + }, {"rmdir", js_rmdir, 1, JSTYPE_BOOLEAN, JSDOCSTR("path/directory") ,JSDOCSTR("remove a directory") ,310 @@ -3431,26 +3484,77 @@ static jsConstIntSpec js_global_const_in {0} }; -JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods) +static void js_global_finalize(JSContext *cx, JSObject *obj) { - JSObject* glob; + private_t* p; - if((glob = JS_NewObject(cx, &js_global_class, NULL, NULL)) ==NULL) - return(NULL); + p=(private_t*)JS_GetPrivate(cx,obj); - if (!JS_InitStandardClasses(cx, glob)) - return(NULL); + if(p!=NULL) + free(p); + + p=NULL; + JS_SetPrivate(cx,obj,p); +} + +static JSBool js_global_resolve(JSContext *cx, JSObject *obj, jsval id) +{ + char* name=NULL; + private_t* p; + JSBool ret=JS_TRUE; + + if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) + return(JS_FALSE); + + if(id != JSVAL_NULL && id != JS_DEFAULT_XML_NAMESPACE_ID) + name=JS_GetStringBytes(JSVAL_TO_STRING(id)); + + if(p->methods) { + if(js_SyncResolve(cx, obj, name, NULL, p->methods, NULL, 0)==JS_FALSE) + ret=JS_FALSE; + } + if(js_SyncResolve(cx, obj, name, js_global_properties, js_global_functions, js_global_const_ints, 0)==JS_FALSE) + ret=JS_FALSE; + return(ret); +} + +static JSBool js_global_enumerate(JSContext *cx, JSObject *obj) +{ + return(js_global_resolve(cx, obj, JSVAL_NULL)); +} + +static JSClass js_global_class = { + "Global" /* name */ + ,JSCLASS_HAS_PRIVATE /* flags */ + ,JS_PropertyStub /* addProperty */ + ,JS_PropertyStub /* delProperty */ + ,js_system_get /* getProperty */ + ,JS_PropertyStub /* setProperty */ + ,js_global_enumerate /* enumerate */ + ,js_global_resolve /* resolve */ + ,JS_ConvertStub /* convert */ + ,js_global_finalize /* finalize */ +}; - if(methods!=NULL && !js_DefineSyncMethods(cx, glob, methods, TRUE)) +JSObject* DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods, js_startup_t* startup) +{ + JSObject* glob; + private_t* p; + + if((p = (private_t*)malloc(sizeof(private_t)))==NULL) return(NULL); - if(!js_DefineSyncMethods(cx, glob, js_global_functions, TRUE)) + p->cfg = cfg; + p->methods = methods; + p->startup = startup; + + if((glob = JS_NewObject(cx, &js_global_class, NULL, NULL)) ==NULL) return(NULL); - if(!JS_DefineProperties(cx, glob, js_global_properties)) + if(!JS_SetPrivate(cx, glob, p)) /* Store a pointer to scfg_t and the new methods */ return(NULL); - if(!JS_SetPrivate(cx, glob, cfg)) /* Store a pointer to scfg_t */ + if (!JS_InitStandardClasses(cx, glob)) return(NULL); #ifdef BUILD_JSDOCS @@ -3458,9 +3562,6 @@ JSObject* DLLCALL js_CreateGlobalObject( ,"Top-level functions and properties (common to all servers and services)",310); #endif - if(!js_DefineConstIntegers(cx, glob, js_global_const_ints, JSPROP_READONLY)) - return(NULL); - return(glob); } @@ -3472,6 +3573,7 @@ JSObject* DLLCALL js_CreateCommonObjects ,char* host_name /* system */ ,char* socklib_desc /* system */ ,js_branch_t* branch /* js */ + ,js_startup_t* js_startup /* js */ ,client_t* client /* client */ ,SOCKET client_socket /* client */ ,js_server_props_t* props /* server */ @@ -3483,7 +3585,7 @@ JSObject* DLLCALL js_CreateCommonObjects node_cfg=cfg; /* Global Object */ - if((js_glob=js_CreateGlobalObject(js_cx, cfg, methods))==NULL) + if((js_glob=js_CreateGlobalObject(js_cx, cfg, methods, js_startup))==NULL) return(NULL); /* System Object */ @@ -3492,7 +3594,7 @@ JSObject* DLLCALL js_CreateCommonObjects /* Internal JS Object */ if(branch!=NULL - && js_CreateInternalJsObject(js_cx, js_glob, branch)==NULL) + && js_CreateInternalJsObject(js_cx, js_glob, branch, js_startup)==NULL) return(NULL); /* Client Object */ @@ -3525,12 +3627,14 @@ JSObject* DLLCALL js_CreateCommonObjects if(js_CreateUserClass(js_cx, js_glob, cfg)==NULL) return(NULL); + /* COM Class */ + if(js_CreateCOMClass(js_cx, js_glob)==NULL) + return(NULL); + /* Area Objects */ - if(!js_CreateUserObjects(js_cx, js_glob, cfg, NULL, NULL, NULL)) + if(!js_CreateUserObjects(js_cx, js_glob, cfg, /* user: */NULL, client, /* html_index_fname: */NULL, /* subscan: */NULL)) return(NULL); return(js_glob); } - - #endif /* JAVSCRIPT */