-
Rob Swindell authored
Increasing size of mode[] element by 2 bytes eliminated these GCC warnings that seem like false-positives to me: sbbs.h:194:48: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=] 194 | (ret)[JSSTSpos]=(char)JSSTSstrval[JSSTSpos]; \ | ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~ js_file.c:225:25: note: in expansion of macro ‘JSSTRING_TO_STRBUF’ 225 | JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL); | ^~~~~~~~~~~~~~~~~~ js_file.c:42:17: note: at offset 5 into destination object ‘mode’ of size 5 42 | char mode[5]; | ^~~~ Similar use of JSSTRING_TO_STRBUF in other files (js_console.cpp, js_archive.c) (with larger target buffers) does not trigger the same warnings.
Rob Swindell authoredIncreasing size of mode[] element by 2 bytes eliminated these GCC warnings that seem like false-positives to me: sbbs.h:194:48: warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=] 194 | (ret)[JSSTSpos]=(char)JSSTSstrval[JSSTSpos]; \ | ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~ js_file.c:225:25: note: in expansion of macro ‘JSSTRING_TO_STRBUF’ 225 | JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL); | ^~~~~~~~~~~~~~~~~~ js_file.c:42:17: note: at offset 5 into destination object ‘mode’ of size 5 42 | char mode[5]; | ^~~~ Similar use of JSSTRING_TO_STRBUF in other files (js_console.cpp, js_archive.c) (with larger target buffers) does not trigger the same warnings.
js_file.c 83.48 KiB
/* Synchronet JavaScript "File" Object */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 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 *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include "sbbs.h"
#include "xpendian.h"
#include "md5.h"
#include "base64.h"
#include "uucode.h"
#include "yenc.h"
#include "ini_file.h"
#if !defined(__unix__)
#include <conio.h> /* for kbhit() */
#endif
#ifdef JAVASCRIPT
#include "js_request.h"
typedef struct
{
FILE* fp;
char name[MAX_PATH+1];
char mode[7];
uchar etx;
BOOL debug;
BOOL rot13;
BOOL yencoded;
BOOL uuencoded;
BOOL b64encoded;
BOOL network_byte_order;
BOOL pipe; /* Opened with popen() use pclose() to close */
ini_style_t ini_style;
} private_t;
static void dbprintf(BOOL error, private_t* p, char* fmt, ...)
{
va_list argptr;
char sbuf[1024];
if(p==NULL || (!p->debug && !error))
return;
va_start(argptr,fmt);
vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
sbuf[sizeof(sbuf)-1]=0;
va_end(argptr);
lprintf(LOG_DEBUG,"%04d File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
}
/* Converts fopen() style 'mode' string into open() style 'flags' integer */
static int fopenflags(char *mode)
{
int flags=0;
if(strchr(mode,'b'))
flags|=O_BINARY;
else
flags|=O_TEXT;
if(strchr(mode,'x'))
flags|=O_EXCL;
if(strchr(mode,'w')) {
flags|=O_CREAT|O_TRUNC;
if(strchr(mode,'+'))
flags|=O_RDWR;
else
flags|=O_WRONLY;
return(flags);
}
if(strchr(mode,'a')) {
flags|=O_CREAT|O_APPEND;
if(strchr(mode,'+'))
flags|=O_RDWR;
else
flags|=O_WRONLY;
return(flags);
}
if(strchr(mode,'r')) {
if(strchr(mode,'+'))
flags|=O_RDWR;
else
flags|=O_RDONLY;
}
return(flags);
}
/* File Object Methods */
extern JSClass js_file_class;
static JSBool
js_open(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
BOOL shareable=FALSE;
int file = -1;
uintN i;
jsint bufsize=2*1024;
JSString* str;
private_t* p;
jsrefcount rc;
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if(p->fp!=NULL)
return(JS_TRUE);
SAFECOPY(p->mode,"w+"); /* default mode */
for(i=0;i<argc;i++) {
if(JSVAL_IS_STRING(argv[i])) { /* mode */
if((str = JS_ValueToString(cx, argv[i]))==NULL) {
JS_ReportError(cx,"Invalid mode specified: %s",str);
return(JS_TRUE);
}
JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
}
else if(JSVAL_IS_BOOLEAN(argv[i])) /* shareable */
shareable=JSVAL_TO_BOOLEAN(argv[i]);
else if(JSVAL_IS_NUMBER(argv[i])) { /* bufsize */
if(!JS_ValueToInt32(cx,argv[i],&bufsize))
return(JS_FALSE);
}
}
rc=JS_SUSPENDREQUEST(cx);
if(shareable)
p->fp=fopen(p->name,p->mode);
else {
if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
char *fdomode=strdup(p->mode);
char *e=fdomode;
if(fdomode && e) {
/* Remove deprecated (never-worked, non-standard) 'e'xclusive mode char (and warn): */
for(e=strchr(fdomode, 'e'); e ; e=strchr(e, 'e')) {
JS_ReportWarning(cx, "Deprecated file open mode: 'e'");
memmove(e, e+1, strlen(e));
}
/* Remove (C11 standard) 'x'clusive mode char to avoid MSVC assertion: */
for(e=strchr(fdomode, 'x'); e ; e=strchr(e, 'x'))
memmove(e, e+1, strlen(e));
if((p->fp=fdopen(file,fdomode)) == NULL) {
JS_ReportWarning(cx, "fdopen(%s, %s) ERROR %d: %s", p->name, fdomode, errno, strerror(errno));
}
}
free(fdomode);
}
}
if(p->fp!=NULL) {
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
dbprintf(FALSE, p, "opened: %s",p->name);
if(!bufsize)
setvbuf(p->fp,NULL,_IONBF,0); /* no buffering */
else {
#ifdef _WIN32
if(bufsize < 2)
bufsize = 2;
#endif
setvbuf(p->fp,NULL,_IOFBF,bufsize);
}
} else if(file >= 0)
close(file);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_popen(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
uintN i;
jsint bufsize=2*1024;
JSString* str;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp!=NULL)
return(JS_TRUE);
SAFECOPY(p->mode,"r+"); /* default mode */
for(i=0;i<argc;i++) {
if(JSVAL_IS_STRING(argv[i])) { /* mode */
if((str = JS_ValueToString(cx, argv[i]))==NULL) {
JS_ReportError(cx,"Invalid mode specified: %s",str);
return(JS_TRUE);
}
JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
}
else if(JSVAL_IS_NUMBER(argv[i])) { /* bufsize */
if(!JS_ValueToInt32(cx,argv[i],&bufsize))
return(JS_FALSE);
}
}
rc=JS_SUSPENDREQUEST(cx);
p->fp=popen(p->name,p->mode);
if(p->fp!=NULL) {
p->pipe=TRUE;
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
dbprintf(FALSE, p, "popened: %s",p->name);
if(!bufsize)
setvbuf(p->fp,NULL,_IONBF,0); /* no buffering */
else
setvbuf(p->fp,NULL,_IOFBF,bufsize);
}
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_close(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
private_t* p;
jsrefcount rc;
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if(p->fp==NULL)
return(JS_TRUE);
rc=JS_SUSPENDREQUEST(cx);
#ifdef __unix__
if(p->pipe)
pclose(p->fp);
else
#endif
fclose(p->fp);
p->fp=NULL;
dbprintf(FALSE, p, "closed: %s", p->name);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_raw_pollin(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
private_t* p;
jsrefcount rc;
int32 timeout = -1;
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if(!JS_ValueToInt32(cx,argv[0],&timeout))
return(JS_FALSE);
}
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(FALSE));
rc=JS_SUSPENDREQUEST(cx);
#ifdef __unix__
/*
* TODO: macOS poll() page has the ominous statement that "The poll() system call currently does not support devices."
* But, since we don't support OS X in Synchronet that's likely OK?
*/
if (socket_readable(fileno(p->fp), timeout))
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
#else
while(timeout) {
if (isatty(fileno(p->fp))) {
if (kbhit()) {
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
rc=JS_SUSPENDREQUEST(cx);
break;
}
SLEEP(1);
if (timeout > 0)
timeout--;
}
else {
if (!eof(fileno(p->fp))) {
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
rc=JS_SUSPENDREQUEST(cx);
break;
}
SLEEP(1);
if (timeout > 0)
timeout--;
}
}
#endif
JS_RESUMEREQUEST(cx, rc);
return JS_TRUE;
}
static JSBool
js_raw_read(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* buf;
int32 len;
JSString* str;
private_t* p;
jsrefcount rc;
int fd;
off_t pos;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if(!JS_ValueToInt32(cx,argv[0],&len))
return(JS_FALSE);
} else
len = 1;
if(len<0)
len=1;
if((buf=malloc(len))==NULL)
return(JS_TRUE);
rc=JS_SUSPENDREQUEST(cx);
// https://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_05.html#tag_02_05_01
/* For the first handle, the first applicable condition below applies. After the actions
* required below are taken, if the handle is still open, the application can close it.
* If it is a file descriptor, no action is required.
* If the only further action to be performed on any handle to this open file descriptor
* is to close it, no action need be taken.
* If it is a stream which is unbuffered, no action need be taken.
* If it is a stream which is line buffered, and the last byte written to the stream was a
* <newline> (that is, as if a: putc('\n') was the most recent operation on that stream),
* no action need be taken.
* If it is a stream which is open for writing or appending (but not also open for reading),
* the application shall either perform an fflush(), or the stream shall be closed.
* If the stream is open for reading and it is at the end of the file ( feof() is true), no
* action need be taken.
* If the stream is open with a mode that allows reading and the underlying open file
* description refers to a device that is capable of seeking, the application shall
* either perform an fflush(), or the stream shall be closed.
* Otherwise, the result is undefined.
* For the second handle:
* If any previous active handle has been used by a function that explicitly changed the file
* offset, except as required above for the first handle, the application shall perform an
* lseek() or fseek() (as appropriate to the type of handle) to an appropriate location.
*/
/*
* Since we don't want to overcomplicate this, it basically boils down to:
* Call fflush() on the stream, lseek() on the descriptor, diddle the descriptor, then fseek() the
* stream.
*
* The only option bit is the fflush() on the stream, but it never hurts and is sometimes
* required by POSIX.
*/
fflush(p->fp);
pos = ftello(p->fp);
if(pos < 0)
len = 0;
else {
fd = fileno(p->fp);
lseek(fd, pos, SEEK_SET);
len = read(fileno(p->fp),buf,len);
fseeko(p->fp, pos + (len >= 0 ? len : 0), SEEK_SET);
dbprintf(FALSE, p, "read %d raw bytes",len);
if(len<0)
len=0;
}
JS_RESUMEREQUEST(cx, rc);
str = JS_NewStringCopyN(cx, buf, len);
free(buf);
if(str==NULL)
return(JS_FALSE);
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
return(JS_TRUE);
}
static JSBool
js_read(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* cp;
char* buf;
char* uubuf;
int32 len;
int32 offset;
int32 uulen;
JSString* str;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if(!JS_ValueToInt32(cx,argv[0],&len))
return(JS_FALSE);
} else {
rc=JS_SUSPENDREQUEST(cx);
len=(long)filelength(fileno(p->fp));
offset=(long)ftell(p->fp);
if(offset>0)
len-=offset;
JS_RESUMEREQUEST(cx, rc);
}
if(len<0)
len=512;
if((buf=malloc(len+1))==NULL)
return(JS_TRUE);
rc=JS_SUSPENDREQUEST(cx);
len = fread(buf,1,len,p->fp);
dbprintf(FALSE, p, "read %u bytes",len);
if(len<0)
len=0;
buf[len]=0;
if(p->etx) {
cp=strchr(buf,p->etx);
if(cp) *cp=0;
len=strlen(buf);
}
if(p->rot13)
rot13(buf);
if(p->uuencoded || p->b64encoded || p->yencoded) {
uulen=len*2;
if((uubuf=malloc(uulen))==NULL) {
free(buf);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
if(p->uuencoded)
uulen=uuencode(uubuf,uulen,buf,len);
else if(p->yencoded)
uulen=yencode(uubuf,uulen,buf,len);
else
uulen=b64_encode(uubuf,uulen,buf,len);
if(uulen>=0) {
free(buf);
buf=uubuf;
len=uulen;
}
else
free(uubuf);
}
JS_RESUMEREQUEST(cx, rc);
str = JS_NewStringCopyN(cx, buf, len);
free(buf);
if(str==NULL)
return(JS_FALSE);
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
return(JS_TRUE);
}
static JSBool
js_readln(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* cp;
char* buf;
int32 len=512;
JSString* js_str;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if(!JS_ValueToInt32(cx,argv[0],&len))
return(JS_FALSE);
}
if((buf=malloc(len + 1))==NULL)
return(JS_FALSE);
rc=JS_SUSPENDREQUEST(cx);
if(fgets(buf,len + 1,p->fp)!=NULL) {
len=strlen(buf);
while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
len--;
buf[len]=0;
if(p->etx) {
cp=strchr(buf,p->etx);
if(cp) *cp=0;
}
if(p->rot13)
rot13(buf);
JS_RESUMEREQUEST(cx, rc);
if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL) /* exception here Feb-12-2005 */
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
} else {
JS_RESUMEREQUEST(cx, rc);
}
free(buf);
return(JS_TRUE);
}
static JSBool
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
BYTE *b;
WORD *w;
DWORD *l;
uint64_t *q;
int32 size=sizeof(DWORD);
private_t* p;
int32 count=1;
size_t retlen;
void *buffer=NULL;
size_t i;
JSObject* array;
jsval v;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if(!JS_ValueToInt32(cx,argv[0],&size))
return(JS_FALSE);
if(argc>1 && !JSVAL_NULL_OR_VOID(argv[1])) {
if(!JS_ValueToInt32(cx,argv[1],&count))
return(JS_FALSE);
}
}
rc=JS_SUSPENDREQUEST(cx);
if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD) && size != sizeof(uint64_t)) {
/* unknown size */
dbprintf(TRUE, p, "unsupported binary read size: %d",size);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
buffer=malloc(size*count);
if(buffer==NULL) {
dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
JS_RESUMEREQUEST(cx, rc);
return(JS_FALSE);
}
b=buffer;
w=buffer;
l=buffer;
q=buffer;
retlen=fread(buffer, size, count, p->fp);
if(count==1) {
if(retlen==1) {
switch(size) {
case sizeof(BYTE):
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
break;
case sizeof(WORD):
if (p->network_byte_order)
*w = BE_SHORT(*w);
else
*w = LE_SHORT(*w);
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
break;
case sizeof(DWORD):
if (p->network_byte_order)
*l = BE_LONG(*l);
else
*l = LE_LONG(*l);
JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
break;
case sizeof(uint64_t):
if (p->network_byte_order)
*q = BE_INT64(*q);
else
*q = LE_INT64(*q);
JS_SET_RVAL(cx, arglist, DOUBLE_TO_JSVAL((double)*q));
break;
}
}
}
else {
JS_RESUMEREQUEST(cx, rc);
array = JS_NewArrayObject(cx, 0, NULL);
for(i=0; i<retlen; i++) {
switch(size) {
case sizeof(BYTE):
v = INT_TO_JSVAL(*(b++));
break;
case sizeof(WORD):
if (p->network_byte_order)
*w = BE_SHORT(*w);
else
*w = LE_SHORT(*w);
v = INT_TO_JSVAL(*(w++));
break;
case sizeof(DWORD):
if (p->network_byte_order)
*l = BE_LONG(*l);
else
*l = LE_LONG(*l);
v=UINT_TO_JSVAL(*(l++));
break;
case sizeof(uint64_t):
if (p->network_byte_order)
*q = BE_INT64(*q);
else
*q = LE_INT64(*q);
v = DOUBLE_TO_JSVAL((double)*(q++));
break;
}
if(!JS_SetElement(cx, array, i, &v)) {
rc=JS_SUSPENDREQUEST(cx);
goto end;
}
}
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
}
end:
free(buffer);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_readall(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsint len=0;
JSObject* array;
private_t* p;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
array = JS_NewArrayObject(cx, 0, NULL);
while(!feof(p->fp)) {
js_readln(cx, argc, arglist);
if(JS_RVAL(cx, arglist)==JSVAL_NULL)
break;
if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
break;
}
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
return(JS_TRUE);
}
static jsval get_value(JSContext *cx, char* value, bool blanks)
{
char* p;
BOOL f=FALSE;
jsval val;
if(value==NULL || (*value==0 && !blanks))
return(JSVAL_VOID);
/* integer or float? */
for(p=value;*p;p++) {
if(*p=='.' && !f)
f=TRUE;
else if(!IS_DIGIT(*p))
break;
}
if(p!=value && *p==0) {
if(f)
val=DOUBLE_TO_JSVAL(atof(value));
else
val=UINT_TO_JSVAL(strtoul(value,NULL,10));
return(val);
}
/* hexadecimal number? */
if(!strncmp(value,"0x",2)) {
for(p=value+2;*p;p++)
if(!isxdigit((uchar)*p))
break;
if(*p==0) {
val=UINT_TO_JSVAL(strtoul(value,NULL,0));
return(val);
}
}
/* Boolean? */
if(!stricmp(value,"true"))
return(JSVAL_TRUE);
if(!stricmp(value,"false"))
return(JSVAL_FALSE);
/* String */
return(STRING_TO_JSVAL(JS_NewStringCopyZ(cx,value)));
}
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
jsval rval;
if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
return ((double)time(NULL))*1000;
}
return JSVAL_TO_DOUBLE(rval);
}
static JSBool
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* section=ROOT_SECTION;
char* key;
char** list;
char buf[INI_MAX_VALUE_LEN];
int32 i;
jsval val;
jsval dflt=argv[2];
private_t* p;
JSObject* array;
JSObject* dflt_obj;
JSObject* date_obj;
jsrefcount rc;
double dbl;
time_t tt;
char* cstr=NULL;
char* cstr2;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
if(JS_IsExceptionPending(cx)) {
FREE_AND_NULL(section);
FREE_AND_NULL(key);
return JS_FALSE;
}
/*
* Although section can be NULL (ie: root), a NULL key will cause a
* segfault.
*/
if(key==NULL) {
JS_ReportError(cx, "Invalid NULL key specified");
FREE_AND_NULL(section);
return JS_FALSE;
}
str_list_t ini = iniReadFile(p->fp);
if(argc < 3 || dflt==JSVAL_VOID) { /* unspecified default value */
rc=JS_SUSPENDREQUEST(cx);
cstr=iniGetString(ini,section,key,NULL,buf);
FREE_AND_NULL(section);
FREE_AND_NULL(key);
strListFree(&ini);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, get_value(cx, cstr, /* blanks */false));
return(JS_TRUE);
}
if(JSVAL_IS_BOOLEAN(dflt)) {
JS_SET_RVAL(cx,arglist,BOOLEAN_TO_JSVAL(
iniGetBool(ini,section,key,JSVAL_TO_BOOLEAN(dflt))));
}
else if(JSVAL_IS_OBJECT(dflt)) {
if((dflt_obj = JSVAL_TO_OBJECT(dflt))!=NULL && (strcmp("Date",JS_GetClass(cx, dflt_obj)->name)==0)) {
tt=(time_t)(js_DateGetMsecSinceEpoch(cx,dflt_obj)/1000.0);
rc=JS_SUSPENDREQUEST(cx);
dbl=(double)iniGetDateTime(ini,section,key,tt);
dbl *= 1000;
JS_RESUMEREQUEST(cx, rc);
date_obj = JS_NewDateObjectMsec(cx, dbl);
if(date_obj!=NULL) {
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(date_obj));
}
}
else {
array = JS_NewArrayObject(cx, 0, NULL);
cstr=NULL;
JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
if(JS_IsExceptionPending(cx)) {
FREE_AND_NULL(cstr);
FREE_AND_NULL(section);
FREE_AND_NULL(key);
strListFree(&ini);
return JS_FALSE;
}
rc=JS_SUSPENDREQUEST(cx);
list=iniGetStringList(ini,section,key,",",cstr);
FREE_AND_NULL(cstr);
JS_RESUMEREQUEST(cx, rc);
for(i=0;list && list[i];i++) {
val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
if(!JS_SetElement(cx, array, i, &val))
break;
}
rc=JS_SUSPENDREQUEST(cx);
iniFreeStringList(list);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
}
}
else if(JSVAL_IS_DOUBLE(dflt)) {
rc=JS_SUSPENDREQUEST(cx);
dbl=iniGetFloat(ini,section,key,JSVAL_TO_DOUBLE(dflt));
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist,DOUBLE_TO_JSVAL(dbl));
}
else if(JSVAL_IS_NUMBER(dflt)) {
if(!JS_ValueToInt32(cx,dflt,&i)) {
FREE_AND_NULL(section);
FREE_AND_NULL(key);
strListFree(&ini);
return(JS_FALSE);
}
rc=JS_SUSPENDREQUEST(cx);
i=iniGetInteger(ini,section,key,i);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist,INT_TO_JSVAL(i));
} else {
cstr=NULL;
JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
if(JS_IsExceptionPending(cx)) {
FREE_AND_NULL(cstr);
FREE_AND_NULL(section);
FREE_AND_NULL(key);
strListFree(&ini);
return JS_FALSE;
}
rc=JS_SUSPENDREQUEST(cx);
cstr2=iniGetString(ini,section,key,cstr,buf);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, cstr2)));
FREE_AND_NULL(cstr);
}
FREE_AND_NULL(section);
FREE_AND_NULL(key);
strListFree(&ini);
return(JS_TRUE);
}
static JSBool
js_iniSetValue_internal(JSContext *cx, JSObject *obj, uintN argc, jsval* argv, str_list_t* list)
{
char* section=ROOT_SECTION;
char* key=NULL;
char* result=NULL;
int32 i;
jsval value=argv[2];
private_t* p;
JSObject* value_obj;
jsrefcount rc;
char* cstr;
time_t tt;
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
if(JS_IsExceptionPending(cx)) {
FREE_AND_NULL(section);
FREE_AND_NULL(key);
return JS_FALSE;
}
if(value==JSVAL_VOID) { /* unspecified value */
rc=JS_SUSPENDREQUEST(cx);
result = iniSetString(list,section,key,"",&p->ini_style);
JS_RESUMEREQUEST(cx, rc);
}
else if(JSVAL_IS_BOOLEAN(value)) {
result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),&p->ini_style);
}
else if(JSVAL_IS_DOUBLE(value)) {
result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),&p->ini_style);
}
else if(JSVAL_IS_NUMBER(value)) {
if(!JS_ValueToInt32(cx,value,&i)) {
FREE_AND_NULL(section);
FREE_AND_NULL(key);
return JS_FALSE;
}
rc=JS_SUSPENDREQUEST(cx);
result = iniSetInteger(list,section,key,i,&p->ini_style);
JS_RESUMEREQUEST(cx, rc);
} else if(JSVAL_IS_OBJECT(value)
&& (value_obj = JSVAL_TO_OBJECT(value))!=NULL
&& (strcmp("Date",JS_GetClass(cx, value_obj)->name)==0)) {
tt=(time_t)(js_DateGetMsecSinceEpoch(cx,value_obj)/1000.0);
rc=JS_SUSPENDREQUEST(cx);
result = iniSetDateTime(list,section,key,/* include_time */TRUE, tt, &p->ini_style);
JS_RESUMEREQUEST(cx, rc);
} else {
cstr=NULL;
JSVALUE_TO_MSTRING(cx, value, cstr, NULL);
if(JS_IsExceptionPending(cx)) {
FREE_AND_NULL(cstr);
FREE_AND_NULL(section);
FREE_AND_NULL(key);
return JS_FALSE;
}
rc=JS_SUSPENDREQUEST(cx);
result = iniSetString(list,section,key, cstr, &p->ini_style);
FREE_AND_NULL(cstr);
JS_RESUMEREQUEST(cx, rc);
}
FREE_AND_NULL(section);
FREE_AND_NULL(key);
return(result != NULL);
}
static JSBool
js_iniSetValue(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
jsval rval=JSVAL_FALSE;
private_t* p;
str_list_t list;
jsrefcount rc;
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
rc=JS_SUSPENDREQUEST(cx);
if((list=iniReadFile(p->fp)) != NULL) {
if(js_iniSetValue_internal(cx, obj, argc, argv, &list))
rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));
}
strListFree(&list);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, rval);
return JS_TRUE;
}
static JSBool
js_iniRemoveKey(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* section=ROOT_SECTION;
char* key=NULL;
private_t* p;
str_list_t list;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL) {
JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
HANDLE_PENDING(cx, section);
}
JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
if(JS_IsExceptionPending(cx)) {
FREE_AND_NULL(key);
FREE_AND_NULL(section);
return JS_FALSE;
}
if(key==NULL) {
JS_ReportError(cx, "Invalid NULL key specified");
FREE_AND_NULL(section);
return JS_FALSE;
}
rc=JS_SUSPENDREQUEST(cx);
if((list=iniReadFile(p->fp))==NULL) {
JS_RESUMEREQUEST(cx, rc);
FREE_AND_NULL(section);
FREE_AND_NULL(key);
return(JS_TRUE);
}
if(iniRemoveKey(&list,section,key))
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list)));
FREE_AND_NULL(section);
FREE_AND_NULL(key);
strListFree(&list);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_iniRemoveSection(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* section=ROOT_SECTION;
private_t* p;
str_list_t list;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL) {
JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
HANDLE_PENDING(cx, section);
}
rc=JS_SUSPENDREQUEST(cx);
if((list=iniReadFile(p->fp))==NULL) {
JS_RESUMEREQUEST(cx, rc);
FREE_AND_NULL(section);
return(JS_TRUE);
}
if(iniRemoveSection(&list,section))
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list)));
FREE_AND_NULL(section);
strListFree(&list);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_iniRemoveSections(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* prefix=NULL;
private_t* p;
str_list_t list;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
return JS_FALSE ;
}
if(p->fp == NULL)
return JS_TRUE;
if(argc && argv[0] != JSVAL_VOID && argv[0] != JSVAL_NULL) {
JSVALUE_TO_MSTRING(cx, argv[0], prefix, NULL);
HANDLE_PENDING(cx, prefix);
}
rc = JS_SUSPENDREQUEST(cx);
if((list = iniReadFile(p->fp)) == NULL) {
JS_RESUMEREQUEST(cx, rc);
FREE_AND_NULL(prefix);
return JS_TRUE;
}
if(iniRemoveSections(&list, prefix))
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(iniWriteFile(p->fp, list)));
FREE_AND_NULL(prefix);
strListFree(&list);
JS_RESUMEREQUEST(cx, rc);
return JS_TRUE;
}
static JSBool
js_iniGetSections(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* prefix=NULL;
char** list;
jsint i;
jsval val;
JSObject* array;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc) {
JSVALUE_TO_MSTRING(cx, argv[0], prefix, NULL);
HANDLE_PENDING(cx, prefix);
}
array = JS_NewArrayObject(cx, 0, NULL);
rc=JS_SUSPENDREQUEST(cx);
list = iniReadSectionList(p->fp,prefix);
FREE_AND_NULL(prefix);
JS_RESUMEREQUEST(cx, rc);
for(i=0;list && list[i];i++) {
val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
if(!JS_SetElement(cx, array, i, &val))
break;
}
rc=JS_SUSPENDREQUEST(cx);
iniFreeStringList(list);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
return(JS_TRUE);
}
static JSBool
js_iniGetKeys(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* section=ROOT_SECTION;
char** list;
jsint i;
jsval val;
JSObject* array;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL) {
JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
HANDLE_PENDING(cx, section);
}
array = JS_NewArrayObject(cx, 0, NULL);
rc=JS_SUSPENDREQUEST(cx);
str_list_t ini = iniReadFile(p->fp);
list = iniGetKeyList(ini, section);
strListFree(&ini);
FREE_AND_NULL(section);
JS_RESUMEREQUEST(cx, rc);
for(i=0;list && list[i];i++) {
val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
if(!JS_SetElement(cx, array, i, &val))
break;
}
rc=JS_SUSPENDREQUEST(cx);
iniFreeStringList(list);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
return(JS_TRUE);
}
static JSBool
js_iniGetObject(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* section=ROOT_SECTION;
jsint i;
JSObject* object;
private_t* p;
named_string_t** list;
jsrefcount rc;
bool lowercase = false;
bool blanks = false;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
uintN argn = 0;
if(argc > argn && !JSVAL_IS_BOOLEAN(argv[argn]) && !JSVAL_NULL_OR_VOID(argv[argn])) {
JSVALUE_TO_MSTRING(cx, argv[argn], section, NULL);
HANDLE_PENDING(cx, section);
argn++;
}
if(argc > argn && JSVAL_IS_BOOLEAN(argv[argn])) {
lowercase = JSVAL_TO_BOOLEAN(argv[argn]);
argn++;
}
if(argc > argn && JSVAL_IS_BOOLEAN(argv[argn])) {
blanks = JSVAL_TO_BOOLEAN(argv[argn]);
argn++;
}
rc=JS_SUSPENDREQUEST(cx);
str_list_t ini = iniReadFile(p->fp);
list = iniGetNamedStringList(ini, section);
strListFree(&ini);
FREE_AND_NULL(section);
JS_RESUMEREQUEST(cx, rc);
if(list==NULL)
return(JS_TRUE);
object = JS_NewObject(cx, NULL, NULL, obj);
for(i=0;list && list[i];i++) {
if(lowercase)
strlwr(list[i]->name);
JS_DefineProperty(cx, object, list[i]->name
,get_value(cx,list[i]->value, blanks)
,NULL,NULL,JSPROP_ENUMERATE);
}
rc=JS_SUSPENDREQUEST(cx);
iniFreeNamedStringList(list);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(object));
return(JS_TRUE);
}
static JSBool
js_iniSetObject(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
jsint i;
JSObject* object;
JSIdArray* id_array;
jsval set_argv[3];
jsval rval;
char* cp;
private_t* p;
str_list_t list;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
set_argv[0]=argv[0]; /* section */
if(!JSVAL_IS_OBJECT(argv[1]) || argv[1]==JSVAL_NULL)
return(JS_TRUE);
object = JSVAL_TO_OBJECT(argv[1]);
if(object == NULL || (id_array=JS_Enumerate(cx,object))==NULL)
return(JS_TRUE);
rc=JS_SUSPENDREQUEST(cx);
if((list=iniReadFile(p->fp))==NULL) {
JS_RESUMEREQUEST(cx, rc);
JS_DestroyIdArray(cx,id_array);
return JS_TRUE;
}
JS_RESUMEREQUEST(cx, rc);
rval = JSVAL_TRUE;
for(i=0; i<id_array->length; i++) {
/* property */
JS_IdToValue(cx,id_array->vector[i],&set_argv[1]);
/* value */
cp=NULL;
JSVALUE_TO_MSTRING(cx, set_argv[1], cp, NULL);
if(cp==NULL) {
JS_DestroyIdArray(cx,id_array);
JS_ReportError(cx, "Invalid NULL property");
return JS_FALSE;
}
if(JS_IsExceptionPending(cx)) {
FREE_AND_NULL(cp);
JS_DestroyIdArray(cx,id_array);
return JS_FALSE;
}
(void)JS_GetProperty(cx,object,cp,&set_argv[2]);
FREE_AND_NULL(cp);
if(!js_iniSetValue_internal(cx,obj,3,set_argv,&list)) {
rval = JSVAL_FALSE;
break;
}
}
rc=JS_SUSPENDREQUEST(cx);
if(rval == JSVAL_TRUE)
rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));
strListFree(&list);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, rval);
JS_DestroyIdArray(cx,id_array);
return(JS_TRUE);
}
static JSBool
js_iniGetAllObjects(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
const char *name_def="name";
char* name=(char *)name_def;
char* sec_name;
char* prefix=NULL;
char** sec_list;
str_list_t ini;
jsint i,k;
jsval val;
JSObject* array;
JSObject* object;
private_t* p;
named_string_t** key_list;
jsrefcount rc;
bool lowercase = false;
bool blanks = false;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
uintN argn = 0;
if(argc > argn && JSVAL_IS_STRING(argv[argn])) {
JSVALUE_TO_MSTRING(cx, argv[argn], name, NULL);
HANDLE_PENDING(cx, name);
if(name == NULL) {
JS_ReportError(cx, "Invalid name argument");
return JS_FALSE;
}
argn++;
}
if(argc > argn && JSVAL_IS_STRING(argv[argn])) {
JSVALUE_TO_MSTRING(cx, argv[argn], prefix, NULL);
argn++;
}
if(argc > argn && JSVAL_IS_BOOLEAN(argv[argn])) {
lowercase = JSVAL_TO_BOOLEAN(argv[argn]);
argn++;
}
if(argc > argn && JSVAL_IS_BOOLEAN(argv[argn])) {
blanks = JSVAL_TO_BOOLEAN(argv[argn]);
argn++;
}
if(JS_IsExceptionPending(cx)) {
FREE_AND_NULL(prefix);
if(name != name_def)
free(name);
return JS_FALSE;
}
array = JS_NewArrayObject(cx, 0, NULL);
rc=JS_SUSPENDREQUEST(cx);
ini = iniReadFile(p->fp);
sec_list = iniGetSectionList(ini, prefix);
JS_RESUMEREQUEST(cx, rc);
for(i=0;sec_list && sec_list[i];i++) {
object = JS_NewObject(cx, NULL, NULL, obj);
sec_name=sec_list[i];
if(prefix!=NULL)
sec_name+=strlen(prefix);
if(lowercase)
strlwr(sec_name);
JS_DefineProperty(cx, object, name
,STRING_TO_JSVAL(JS_NewStringCopyZ(cx,sec_name))
,NULL,NULL,JSPROP_ENUMERATE);
rc=JS_SUSPENDREQUEST(cx);
key_list = iniGetNamedStringList(ini,sec_list[i]);
JS_RESUMEREQUEST(cx, rc);
for(k=0;key_list && key_list[k];k++) {
if(lowercase)
strlwr(key_list[k]->name);
JS_DefineProperty(cx, object, key_list[k]->name
,get_value(cx,key_list[k]->value,blanks)
,NULL,NULL,JSPROP_ENUMERATE);
}
rc=JS_SUSPENDREQUEST(cx);
iniFreeNamedStringList(key_list);
JS_RESUMEREQUEST(cx, rc);
val=OBJECT_TO_JSVAL(object);
if(!JS_SetElement(cx, array, i, &val))
break;
}
rc=JS_SUSPENDREQUEST(cx);
FREE_AND_NULL(prefix);
if(name != name_def)
free(name);
iniFreeStringList(sec_list);
iniFreeStringList(ini);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
return(JS_TRUE);
}
static JSBool
js_iniSetAllObjects(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
const char *name_def = "name";
char* name=(char *)name_def;
jsuint i;
jsint j;
jsuint count;
JSObject* array;
JSObject* object;
jsval oval;
jsval set_argv[3];
JSIdArray* id_array;
jsval rval;
char* cp=NULL;
str_list_t list;
jsrefcount rc;
private_t* p;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if(JSVAL_IS_NULL(argv[0]) || !JSVAL_IS_OBJECT(argv[0]))
return(JS_TRUE);
array = JSVAL_TO_OBJECT(argv[0]);
if(array == NULL || !JS_IsArrayObject(cx, array))
return(JS_TRUE);
if(!JS_GetArrayLength(cx, array, &count))
return(JS_TRUE);
if(argc>1) {
JSVALUE_TO_MSTRING(cx, argv[1], name, NULL);
HANDLE_PENDING(cx, name);
if(name==NULL) {
JS_ReportError(cx, "Invalid NULL name property");
return JS_FALSE;
}
}
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
if(name != name_def)
free(name);
return(JS_FALSE);
}
if(p->fp==NULL) {
if(name != name_def)
free(name);
return(JS_TRUE);
}
rc=JS_SUSPENDREQUEST(cx);
if((list=iniReadFile(p->fp))==NULL) {
JS_RESUMEREQUEST(cx, rc);
if(name != name_def)
free(name);
return JS_TRUE;
}
JS_RESUMEREQUEST(cx, rc);
/* enumerate the array */
rval = JSVAL_TRUE;
for(i=0; i<count && rval==JSVAL_TRUE; i++) {
if(!JS_GetElement(cx, array, i, &oval))
break;
if(!JSVAL_IS_OBJECT(oval)) /* must be an array of objects */
break;
object=JSVAL_TO_OBJECT(oval);
if(object == NULL || !JS_GetProperty(cx, object, name, &set_argv[0]))
continue;
if((id_array=JS_Enumerate(cx,object))==NULL) {
if(name != name_def)
free(name);
return(JS_TRUE);
}
for(j=0; j<id_array->length; j++) {
/* property */
JS_IdToValue(cx,id_array->vector[j],&set_argv[1]);
/* check if not name */
JSVALUE_TO_MSTRING(cx, set_argv[1], cp, NULL);
if(JS_IsExceptionPending(cx)) {
FREE_AND_NULL(cp);
JS_DestroyIdArray(cx,id_array);
if(name != name_def)
free(name);
return JS_FALSE;
}
if(cp==NULL)
continue;
if(strcmp(cp,name)==0) {
FREE_AND_NULL(cp);
continue;
}
/* value */
if(!JS_GetProperty(cx,object,cp,&set_argv[2])) {
FREE_AND_NULL(cp);
continue;
}
FREE_AND_NULL(cp); /* Moved from before JS_GetProperty() call */
if(!js_iniSetValue_internal(cx,obj,3,set_argv,&list)) {
rval = JSVAL_FALSE;
break;
}
}
JS_DestroyIdArray(cx,id_array);
}
if(name != name_def)
free(name);
rc=JS_SUSPENDREQUEST(cx);
if(rval == JSVAL_TRUE)
rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));
strListFree(&list);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, rval);
return(JS_TRUE);
}
static JSBool
js_iniReadAll(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj = JS_THIS_OBJECT(cx, arglist);
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL)
return JS_FALSE;
if(p->fp == NULL)
return JS_TRUE;
JSObject* array = JS_NewArrayObject(cx, 0, NULL);
if(array == NULL)
return JS_FALSE;
rc=JS_SUSPENDREQUEST(cx);
str_list_t list = iniReadFile(p->fp);
JS_RESUMEREQUEST(cx, rc);
for(size_t i = 0; list[i] != NULL; i++) {
JSString* js_str;
if((js_str = JS_NewStringCopyZ(cx, list[i])) == NULL)
break;
jsval val = STRING_TO_JSVAL(js_str);
if(!JS_SetElement(cx, array, i, &val))
break;
}
strListFree(&list);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
return(JS_TRUE);
}
static JSBool
js_raw_write(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* cp = NULL;
size_t len; /* string length */
JSString* str;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if((str = JS_ValueToString(cx, argv[0]))==NULL)
return(JS_FALSE);
JSSTRING_TO_MSTRING(cx, str, cp, &len);
HANDLE_PENDING(cx, cp);
if(cp==NULL)
return JS_TRUE;
rc=JS_SUSPENDREQUEST(cx);
if(write(fileno(p->fp),cp,len)==(size_t)len) {
free(cp);
dbprintf(FALSE, p, "wrote %lu raw bytes",len);
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
} else {
free(cp);
dbprintf(TRUE, p, "raw write of %lu bytes failed",len);
}
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_write(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* cp = NULL;
char* uubuf=NULL;
size_t len; /* string length */
int decoded_len;
size_t tlen; /* total length to write (may be greater than len) */
int32 i;
JSString* str;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if((str = JS_ValueToString(cx, argv[0]))==NULL)
return(JS_FALSE);
JSSTRING_TO_MSTRING(cx, str, cp, &len);
HANDLE_PENDING(cx, cp);
if(cp==NULL)
return JS_TRUE;
rc=JS_SUSPENDREQUEST(cx);
if((p->uuencoded || p->b64encoded || p->yencoded)
&& len && (uubuf=malloc(len))!=NULL) {
if(p->uuencoded)
decoded_len=uudecode(uubuf,len,cp,len);
else if(p->yencoded)
decoded_len=ydecode(uubuf,len,cp,len);
else
decoded_len=b64_decode(uubuf,len,cp,len);
if(decoded_len<0) {
free(uubuf);
free(cp);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
free(cp);
cp=uubuf;
len = decoded_len;
}
if(p->rot13)
rot13(cp);
JS_RESUMEREQUEST(cx, rc);
tlen=len;
if(argc>1 && !JSVAL_NULL_OR_VOID(argv[1])) {
if(!JS_ValueToInt32(cx,argv[1],&i)) {
free(cp);
return(JS_FALSE);
}
tlen=i;
if(len>tlen)
len=tlen;
}
rc=JS_SUSPENDREQUEST(cx);
if(fwrite(cp,1,len,p->fp)==(size_t)len) {
free(cp);
if(tlen>len) {
len=tlen-len;
if((cp=malloc(len))==NULL) {
JS_RESUMEREQUEST(cx, rc);
JS_ReportError(cx, "malloc failure of %u bytes", len);
return(JS_FALSE);
}
memset(cp,p->etx,len);
if(fwrite(cp,1,len,p->fp) < len) {
free(cp);
JS_RESUMEREQUEST(cx, rc);
return JS_TRUE;
}
free(cp);
}
dbprintf(FALSE, p, "wrote %lu bytes", (ulong)tlen);
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
} else {
free(cp);
dbprintf(TRUE, p, "write of %lu bytes failed", (ulong)len);
}
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_writeln_internal(JSContext *cx, JSObject *obj, jsval *arg, jsval *rval)
{
const char *cp_def="";
char* cp=(char *)cp_def;
JSString* str;
private_t* p;
jsrefcount rc;
*rval = JSVAL_FALSE;
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(arg) {
if((str = JS_ValueToString(cx, *arg))==NULL) {
JS_ReportError(cx,"JS_ValueToString failed");
return(JS_FALSE);
}
JSSTRING_TO_MSTRING(cx, str, cp, NULL);
HANDLE_PENDING(cx, cp);
if(cp==NULL)
cp=(char *)cp_def;
}
rc=JS_SUSPENDREQUEST(cx);
if(p->rot13)
rot13(cp);
if(fprintf(p->fp,"%s\n",cp)!=0)
*rval = JSVAL_TRUE;
if(cp != cp_def)
free(cp);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_writeln(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
jsval rval;
JSBool ret;
if(argc) {
ret=js_writeln_internal(cx, obj, &argv[0], &rval);
}
else {
ret=js_writeln_internal(cx, obj, NULL, &rval);
}
JS_SET_RVAL(cx, arglist, rval);
return(ret);
}
static JSBool
js_writebin(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
union {
uint8_t *b;
uint16_t *w;
uint32_t *l;
uint64_t *q;
int8_t *sb;
int16_t *sw;
int32_t *sl;
int64_t *sq;
} o;
size_t wr=0;
int32 size=sizeof(int32_t);
jsuint count=1;
void *buffer;
private_t* p;
JSObject* array=NULL;
jsval elemval;
jsdouble val=0;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(JSVAL_IS_OBJECT(argv[0]) && !JSVAL_IS_NULL(argv[0])) {
array = JSVAL_TO_OBJECT(argv[0]);
if(array != NULL && JS_IsArrayObject(cx, array)) {
if(!JS_GetArrayLength(cx, array, &count))
return(JS_TRUE);
}
else
array=NULL;
}
if(array==NULL) {
if(!JS_ValueToNumber(cx,argv[0],&val))
return(JS_FALSE);
}
if(argc>1 && !JSVAL_NULL_OR_VOID(argv[1])) {
if(!JS_ValueToInt32(cx,argv[1],&size))
return(JS_FALSE);
}
if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD) && size != sizeof(uint64_t)) {
rc=JS_SUSPENDREQUEST(cx);
dbprintf(TRUE, p, "unsupported binary write size: %d",size);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
buffer=calloc(size, count);
if(buffer==NULL) {
rc=JS_SUSPENDREQUEST(cx);
dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
JS_RESUMEREQUEST(cx, rc);
return(JS_FALSE);
}
o.b=buffer;
if(array==NULL) {
switch(size) {
case sizeof(int8_t):
if(val < 0)
*o.sb=(int8_t)val;
else
*o.b=(uint8_t)val;
break;
case sizeof(int16_t):
if(val < 0)
*o.sw=(int16_t)val;
else
*o.w=(uint16_t)val;
if (p->network_byte_order)
*o.w = BE_SHORT(*o.w);
else
*o.w = LE_SHORT(*o.w);
break;
case sizeof(int32_t):
if(val < 0)
*o.sl=(int32_t)val;
else
*o.l=(uint32_t)val;
if (p->network_byte_order)
*o.l = BE_LONG(*o.l);
else
*o.l = LE_LONG(*o.l);
break;
case sizeof(int64_t):
if(val < 0)
*o.sq = (int64_t)val;
else
*o.q = (uint64_t)val;
if (p->network_byte_order)
*o.q = BE_INT64(*o.q);
else
*o.q = LE_INT64(*o.q);
break;
}
}
else {
for(wr=0; wr<count; wr++) {
if(!JS_GetElement(cx, array, wr, &elemval))
goto end;
if(!JS_ValueToNumber(cx,elemval,&val))
goto end;
switch(size) {
case sizeof(int8_t):
if(val < 0)
*o.sb=(int8_t)val;
else
*o.b=(uint8_t)val;
o.b++;
break;
case sizeof(int16_t):
if(val < 0)
*o.sw=(int16_t)val;
else
*o.w=(uint16_t)val;
if (p->network_byte_order)
*o.w = BE_SHORT(*o.w);
else
*o.w = LE_SHORT(*o.w);
o.w++;
break;
case sizeof(int32_t):
if(val < 0)
*o.sl=(int32_t)val;
else
*o.l=(uint32_t)val;
if (p->network_byte_order)
*o.l = BE_LONG(*o.l);
else
*o.l = LE_LONG(*o.l);
o.l++;
break;
case sizeof(int64_t):
if(val < 0)
*o.sq = (int64_t)val;
else
*o.q = (uint64_t)val;
if (p->network_byte_order)
*o.q = BE_INT64(*o.q);
else
*o.q = LE_INT64(*o.q);
o.q++;
break;
}
}
}
rc=JS_SUSPENDREQUEST(cx);
wr=fwrite(buffer,size,count,p->fp);
JS_RESUMEREQUEST(cx, rc);
if(wr==count)
JS_SET_RVAL(cx, arglist,JSVAL_TRUE);
end:
free(buffer);
return(JS_TRUE);
}
static JSBool
js_writeall(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
jsuint i;
jsuint limit;
JSObject* array;
jsval elemval;
private_t* p;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if(JSVAL_IS_NULL(argv[0]) || !JSVAL_IS_OBJECT(argv[0]))
return(JS_TRUE);
array = JSVAL_TO_OBJECT(argv[0]);
if(array == NULL || !JS_IsArrayObject(cx, array))
return(JS_TRUE);
if(!JS_GetArrayLength(cx, array, &limit))
return(JS_FALSE);
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
for(i=0;i<limit;i++) {
jsval rval;
if(!JS_GetElement(cx, array, i, &elemval))
break;
js_writeln_internal(cx, obj, &elemval, &rval);
JS_SET_RVAL(cx, arglist, rval);
if(rval!=JSVAL_TRUE)
break;
}
return(JS_TRUE);
}
static JSBool
js_lock(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
off_t offset=0;
off_t len=0;
private_t* p;
jsrefcount rc;
jsdouble val;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
/* offset */
if(argc) {
if(!JS_ValueToNumber(cx,argv[0],&val))
return(JS_FALSE);
offset=(off_t)val;
}
/* length */
if(argc>1) {
if(!JS_ValueToNumber(cx,argv[1],&val))
return(JS_FALSE);
len=(off_t)val;
}
rc=JS_SUSPENDREQUEST(cx);
if(len==0)
len=filelength(fileno(p->fp))-offset;
if(lock(fileno(p->fp),offset,len)==0)
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_unlock(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
off_t offset=0;
off_t len=0;
private_t* p;
jsrefcount rc;
jsdouble val;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
/* offset */
if(argc) {
if(!JS_ValueToNumber(cx,argv[0],&val))
return(JS_FALSE);
offset=(off_t)val;
}
/* length */
if(argc>1) {
if(!JS_ValueToNumber(cx,argv[1],&val))
return(JS_FALSE);
len=(off_t)val;
}
rc=JS_SUSPENDREQUEST(cx);
if(len==0)
len=filelength(fileno(p->fp))-offset;
if(unlock(fileno(p->fp),offset,len)==0)
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_delete(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp!=NULL) { /* close it if it's open */
fclose(p->fp);
p->fp=NULL;
}
rc=JS_SUSPENDREQUEST(cx);
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(remove(p->name)==0));
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_flush(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
rc=JS_SUSPENDREQUEST(cx);
if(p->fp==NULL)
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
else
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(fflush(p->fp)==0));
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_rewind(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
rc=JS_SUSPENDREQUEST(cx);
if(p->fp==NULL)
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
else {
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
rewind(p->fp);
}
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_truncate(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
private_t* p;
int32 len=0;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if(!JS_ValueToInt32(cx,argv[0],&len))
return(JS_FALSE);
}
rc=JS_SUSPENDREQUEST(cx);
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if(p->fp!=NULL && chsize(fileno(p->fp),len)==0) {
fseek(p->fp,len,SEEK_SET);
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
}
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_clear_error(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
rc=JS_SUSPENDREQUEST(cx);
if(p->fp==NULL)
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
else {
clearerr(p->fp);
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
}
JS_RESUMEREQUEST(cx, rc);
return(JS_TRUE);
}
static JSBool
js_fprintf(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
char* cp;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
return(JS_FALSE);
}
if(p->fp==NULL)
return(JS_TRUE);
if((cp=js_sprintf(cx, 0, argc, argv))==NULL) {
JS_ReportError(cx,"js_sprintf failed");
return(JS_FALSE);
}
rc=JS_SUSPENDREQUEST(cx);
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(fwrite(cp,1,strlen(cp),p->fp)));
JS_RESUMEREQUEST(cx, rc);
js_sprintf_free(cp);
return(JS_TRUE);
}
/* File Object Properties */
enum {
FILE_PROP_NAME
,FILE_PROP_MODE
,FILE_PROP_ETX
,FILE_PROP_EXISTS
,FILE_PROP_DATE
,FILE_PROP_IS_OPEN
,FILE_PROP_EOF
,FILE_PROP_ERROR
,FILE_PROP_DESCRIPTOR
,FILE_PROP_DEBUG
,FILE_PROP_POSITION
,FILE_PROP_LENGTH
,FILE_PROP_ATTRIBUTES
,FILE_PROP_YENCODED
,FILE_PROP_UUENCODED
,FILE_PROP_B64ENCODED
,FILE_PROP_ROT13
,FILE_PROP_NETWORK_ORDER
/* dynamically calculated */
,FILE_PROP_CHKSUM
,FILE_PROP_CRC16
,FILE_PROP_CRC32
,FILE_PROP_MD5_HEX
,FILE_PROP_MD5_B64
,FILE_PROP_SHA1_HEX
,FILE_PROP_SHA1_B64
/* ini style */
,FILE_INI_KEY_LEN
,FILE_INI_KEY_PREFIX
,FILE_INI_SECTION_SEPARATOR
,FILE_INI_VALUE_SEPARATOR
,FILE_INI_BIT_SEPARATOR
,FILE_INI_LITERAL_SEPARATOR
};
static JSBool js_file_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
{
jsval idval;
int result;
int32 i=0;
uint32 u=0;
jsint tiny;
private_t* p;
jsrefcount rc;
char* str = NULL;
if((p=(private_t*)JS_GetInstancePrivate(cx, obj, &js_file_class, NULL))==NULL) {
return(JS_TRUE);
}
JS_IdToValue(cx, id, &idval);
tiny = JSVAL_TO_INT(idval);
rc=JS_SUSPENDREQUEST(cx);
dbprintf(FALSE, p, "setting property %d",tiny);
JS_RESUMEREQUEST(cx, rc);
switch(tiny) {
case FILE_PROP_DEBUG:
JS_ValueToBoolean(cx,*vp,&(p->debug));
break;
case FILE_PROP_YENCODED:
JS_ValueToBoolean(cx,*vp,&(p->yencoded));
break;
case FILE_PROP_UUENCODED:
JS_ValueToBoolean(cx,*vp,&(p->uuencoded));
break;
case FILE_PROP_B64ENCODED:
JS_ValueToBoolean(cx,*vp,&(p->b64encoded));
break;
case FILE_PROP_ROT13:
JS_ValueToBoolean(cx,*vp,&(p->rot13));
break;
case FILE_PROP_NETWORK_ORDER:
JS_ValueToBoolean(cx,*vp,&(p->network_byte_order));
break;
case FILE_PROP_POSITION:
if(p->fp!=NULL) {
if(!JS_ValueToECMAUint32(cx, *vp, &u))
return(JS_FALSE);
rc=JS_SUSPENDREQUEST(cx);
fseek(p->fp, u, SEEK_SET);
JS_RESUMEREQUEST(cx, rc);
}
break;
case FILE_PROP_DATE:
if(!JS_ValueToECMAUint32(cx, *vp, &u))
return(JS_FALSE);
rc=JS_SUSPENDREQUEST(cx);
setfdate(p->name, u);
JS_RESUMEREQUEST(cx, rc);
break;
case FILE_PROP_LENGTH:
if(p->fp!=NULL) {
if(!JS_ValueToECMAUint32(cx, *vp, &u))
return(JS_FALSE);
rc=JS_SUSPENDREQUEST(cx);
result = chsize(fileno(p->fp), u);
JS_RESUMEREQUEST(cx, rc);
if(result != 0) {
JS_ReportError(cx, "Error %d changing file size", errno);
return JS_FALSE;
}
}
break;
case FILE_PROP_ATTRIBUTES:
if(!JS_ValueToInt32(cx,*vp,&i))
return(JS_FALSE);
rc=JS_SUSPENDREQUEST(cx);
(void)CHMOD(p->name,i);
JS_RESUMEREQUEST(cx, rc);
break;
case FILE_PROP_ETX:
if(!JS_ValueToInt32(cx,*vp,&i))
return(JS_FALSE);
p->etx = (uchar)i;
break;
case FILE_INI_KEY_LEN:
if(!JS_ValueToInt32(cx,*vp,&i))
return(JS_FALSE);
p->ini_style.key_len = i;
break;
case FILE_INI_KEY_PREFIX:
FREE_AND_NULL(p->ini_style.key_prefix);
if(!JSVAL_NULL_OR_VOID(*vp)) {
JSVALUE_TO_MSTRING(cx, *vp, str, NULL);
HANDLE_PENDING(cx, str);
p->ini_style.key_prefix = str;
}
break;
case FILE_INI_SECTION_SEPARATOR:
FREE_AND_NULL(p->ini_style.section_separator);
if(!JSVAL_NULL_OR_VOID(*vp)) {
JSVALUE_TO_MSTRING(cx, *vp, str, NULL);
HANDLE_PENDING(cx, str);
p->ini_style.section_separator = str;
}
break;
case FILE_INI_VALUE_SEPARATOR:
FREE_AND_NULL(p->ini_style.value_separator);
if(!JSVAL_NULL_OR_VOID(*vp)) {
JSVALUE_TO_MSTRING(cx, *vp, str, NULL);
HANDLE_PENDING(cx, str);
p->ini_style.value_separator = str;
}
break;
case FILE_INI_BIT_SEPARATOR:
FREE_AND_NULL(p->ini_style.bit_separator);
if(!JSVAL_NULL_OR_VOID(*vp)) {
JSVALUE_TO_MSTRING(cx, *vp, str, NULL);
HANDLE_PENDING(cx, str);
p->ini_style.bit_separator = str;
}
break;
case FILE_INI_LITERAL_SEPARATOR:
FREE_AND_NULL(p->ini_style.literal_separator);
if(!JSVAL_NULL_OR_VOID(*vp)) {
JSVALUE_TO_MSTRING(cx, *vp, str, NULL);
HANDLE_PENDING(cx, str);
p->ini_style.literal_separator = str;
}
break;
}
return(JS_TRUE);
}
static JSBool js_file_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
jsval idval;
char str[128];
char* s = NULL;
size_t i;
size_t rd;
off_t offset;
ulong sum=0;
ushort c16=0;
uint32 c32=~0;
MD5 md5_ctx;
SHA1_CTX sha1_ctx;
BYTE block[4096];
BYTE digest[SHA1_DIGEST_SIZE];
jsint tiny;
JSString* js_str=NULL;
private_t* p;
jsrefcount rc;
time_t tt;
off_t lng;
int in;
if((p=(private_t*)JS_GetPrivate(cx, obj))==NULL)
return(JS_TRUE);
JS_IdToValue(cx, id, &idval);
tiny = JSVAL_TO_INT(idval);
switch(tiny) {
case FILE_PROP_NAME:
s = p->name;
break;
case FILE_PROP_MODE:
s = p->mode;
break;
case FILE_PROP_EXISTS:
if(p->fp) /* open? */
*vp = JSVAL_TRUE;
else {
rc=JS_SUSPENDREQUEST(cx);
*vp = BOOLEAN_TO_JSVAL(fexistcase(p->name));
JS_RESUMEREQUEST(cx, rc);
}
break;
case FILE_PROP_DATE:
rc=JS_SUSPENDREQUEST(cx);
tt=fdate(p->name);
JS_RESUMEREQUEST(cx, rc);
*vp=DOUBLE_TO_JSVAL((double)tt);
break;
case FILE_PROP_IS_OPEN:
*vp = BOOLEAN_TO_JSVAL(p->fp!=NULL);
break;
case FILE_PROP_EOF:
if(p->fp) {
rc=JS_SUSPENDREQUEST(cx);
*vp = BOOLEAN_TO_JSVAL(feof(p->fp)!=0);
JS_RESUMEREQUEST(cx, rc);
}
else
*vp = JSVAL_TRUE;
break;
case FILE_PROP_ERROR:
if(p->fp) {
rc=JS_SUSPENDREQUEST(cx);
*vp = INT_TO_JSVAL(ferror(p->fp));
JS_RESUMEREQUEST(cx, rc);
}
else
*vp = INT_TO_JSVAL(errno);
break;
case FILE_PROP_POSITION:
if(p->fp) {
rc=JS_SUSPENDREQUEST(cx);
lng=ftell(p->fp);
JS_RESUMEREQUEST(cx, rc);
*vp=DOUBLE_TO_JSVAL((double)lng);
}
else
*vp = INT_TO_JSVAL(-1);
break;
case FILE_PROP_LENGTH:
rc=JS_SUSPENDREQUEST(cx);
if(p->fp) /* open? */
lng = filelength(fileno(p->fp));
else
lng = flength(p->name);
JS_RESUMEREQUEST(cx, rc);
*vp=DOUBLE_TO_JSVAL((double)lng);
break;
case FILE_PROP_ATTRIBUTES:
rc=JS_SUSPENDREQUEST(cx);
in=getfmode(p->name);
JS_RESUMEREQUEST(cx, rc);
*vp=INT_TO_JSVAL(in);
break;
case FILE_PROP_DEBUG:
*vp = BOOLEAN_TO_JSVAL(p->debug);
break;
case FILE_PROP_YENCODED:
*vp = BOOLEAN_TO_JSVAL(p->yencoded);
break;
case FILE_PROP_UUENCODED:
*vp = BOOLEAN_TO_JSVAL(p->uuencoded);
break;
case FILE_PROP_B64ENCODED:
*vp = BOOLEAN_TO_JSVAL(p->b64encoded);
break;
case FILE_PROP_ROT13:
*vp = BOOLEAN_TO_JSVAL(p->rot13);
break;
case FILE_PROP_NETWORK_ORDER:
*vp = BOOLEAN_TO_JSVAL(p->network_byte_order);
break;
case FILE_PROP_DESCRIPTOR:
if(p->fp)
*vp = INT_TO_JSVAL(fileno(p->fp));
else
*vp = INT_TO_JSVAL(-1);
break;
case FILE_PROP_ETX:
*vp = INT_TO_JSVAL(p->etx);
break;
case FILE_PROP_CHKSUM:
case FILE_PROP_CRC16:
case FILE_PROP_CRC32:
*vp = JSVAL_ZERO;
if(p->fp==NULL)
break;
/* fall-through */
case FILE_PROP_MD5_HEX:
case FILE_PROP_MD5_B64:
case FILE_PROP_SHA1_HEX:
case FILE_PROP_SHA1_B64:
*vp = JSVAL_VOID;
if(p->fp==NULL)
break;
rc=JS_SUSPENDREQUEST(cx);
offset=ftell(p->fp); /* save current file position */
fseek(p->fp,0,SEEK_SET);
/* Initialization */
switch(tiny) {
case FILE_PROP_MD5_HEX:
case FILE_PROP_MD5_B64:
MD5_open(&md5_ctx);
break;
case FILE_PROP_SHA1_HEX:
case FILE_PROP_SHA1_B64:
SHA1Init(&sha1_ctx);
break;
}
/* calculate */
while(!feof(p->fp)) {
if((rd=fread(block,1,sizeof(block),p->fp))<1)
break;
switch(tiny) {
case FILE_PROP_CHKSUM:
for(i=0;i<rd;i++)
sum+=block[i];
break;
case FILE_PROP_CRC16:
for(i=0;i<rd;i++)
c16=ucrc16(block[i],c16);
break;
case FILE_PROP_CRC32:
for(i=0;i<rd;i++)
c32=ucrc32(block[i],c32);
break;
case FILE_PROP_MD5_HEX:
case FILE_PROP_MD5_B64:
MD5_digest(&md5_ctx,block,rd);
break;
case FILE_PROP_SHA1_HEX:
case FILE_PROP_SHA1_B64:
SHA1Update(&sha1_ctx,block,rd);
break;
}
}
JS_RESUMEREQUEST(cx, rc);
/* finalize */
switch(tiny) {
case FILE_PROP_CHKSUM:
*vp=DOUBLE_TO_JSVAL((double)sum);
break;
case FILE_PROP_CRC16:
*vp=UINT_TO_JSVAL(c16);
break;
case FILE_PROP_CRC32:
*vp=UINT_TO_JSVAL(~c32);
break;
case FILE_PROP_MD5_HEX:
case FILE_PROP_MD5_B64:
MD5_close(&md5_ctx,digest);
if(tiny==FILE_PROP_MD5_HEX)
MD5_hex(str,digest);
else
b64_encode(str,sizeof(str)-1,(char *)digest,sizeof(digest));
js_str=JS_NewStringCopyZ(cx, str);
break;
case FILE_PROP_SHA1_HEX:
case FILE_PROP_SHA1_B64:
SHA1Final(&sha1_ctx,digest);
if(tiny==FILE_PROP_SHA1_HEX)
SHA1_hex(str,digest);
else
b64_encode(str,sizeof(str)-1,(char *)digest,sizeof(digest));
js_str=JS_NewStringCopyZ(cx, str);
break;
}
rc=JS_SUSPENDREQUEST(cx);
fseeko(p->fp,offset,SEEK_SET); /* restore saved file position */
JS_RESUMEREQUEST(cx, rc);
if(js_str!=NULL)
*vp = STRING_TO_JSVAL(js_str);
break;
case FILE_INI_KEY_LEN:
*vp = INT_TO_JSVAL(p->ini_style.key_len);
break;
case FILE_INI_KEY_PREFIX:
s = p->ini_style.key_prefix;
if(s == NULL)
*vp = JSVAL_NULL;
break;
case FILE_INI_SECTION_SEPARATOR:
s = p->ini_style.section_separator;
if(s == NULL)
*vp = JSVAL_NULL;
break;
case FILE_INI_VALUE_SEPARATOR:
s = p->ini_style.value_separator;
if(s == NULL)
*vp = JSVAL_NULL;
break;
case FILE_INI_BIT_SEPARATOR:
s = p->ini_style.bit_separator;
if(s == NULL)
*vp = JSVAL_NULL;
break;
case FILE_INI_LITERAL_SEPARATOR:
s = p->ini_style.literal_separator;
if(s == NULL)
*vp = JSVAL_NULL;
break;
}
if(s != NULL) {
if((js_str = JS_NewStringCopyZ(cx, s)) == NULL)
return JS_FALSE;
*vp = STRING_TO_JSVAL(js_str);
}
return(JS_TRUE);
}
#define FILE_PROP_FLAGS JSPROP_ENUMERATE|JSPROP_READONLY
static jsSyncPropertySpec js_file_properties[] = {
/* name ,tinyid ,flags, ver */
{ "name" ,FILE_PROP_NAME ,FILE_PROP_FLAGS, 310},
{ "mode" ,FILE_PROP_MODE ,FILE_PROP_FLAGS, 310},
{ "exists" ,FILE_PROP_EXISTS ,FILE_PROP_FLAGS, 310},
{ "is_open" ,FILE_PROP_IS_OPEN ,FILE_PROP_FLAGS, 310},
{ "eof" ,FILE_PROP_EOF ,FILE_PROP_FLAGS, 310},
{ "error" ,FILE_PROP_ERROR ,FILE_PROP_FLAGS, 310},
{ "descriptor" ,FILE_PROP_DESCRIPTOR ,FILE_PROP_FLAGS, 310},
/* writeable */
{ "etx" ,FILE_PROP_ETX ,JSPROP_ENUMERATE, 310},
{ "debug" ,FILE_PROP_DEBUG ,JSPROP_ENUMERATE, 310},
{ "position" ,FILE_PROP_POSITION ,JSPROP_ENUMERATE, 310},
{ "date" ,FILE_PROP_DATE ,JSPROP_ENUMERATE, 311},
{ "length" ,FILE_PROP_LENGTH ,JSPROP_ENUMERATE, 310},
{ "attributes" ,FILE_PROP_ATTRIBUTES ,JSPROP_ENUMERATE, 310},
{ "network_byte_order",FILE_PROP_NETWORK_ORDER,JSPROP_ENUMERATE, 311},
{ "rot13" ,FILE_PROP_ROT13 ,JSPROP_ENUMERATE, 311},
{ "uue" ,FILE_PROP_UUENCODED ,JSPROP_ENUMERATE, 311},
{ "yenc" ,FILE_PROP_YENCODED ,JSPROP_ENUMERATE, 311},
{ "base64" ,FILE_PROP_B64ENCODED ,JSPROP_ENUMERATE, 311},
/* dynamically calculated */
{ "crc16" ,FILE_PROP_CRC16 ,FILE_PROP_FLAGS, 311},
{ "crc32" ,FILE_PROP_CRC32 ,FILE_PROP_FLAGS, 311},
{ "chksum" ,FILE_PROP_CHKSUM ,FILE_PROP_FLAGS, 311},
{ "md5_hex" ,FILE_PROP_MD5_HEX ,FILE_PROP_FLAGS, 311},
{ "md5_base64" ,FILE_PROP_MD5_B64 ,FILE_PROP_FLAGS, 311},
{ "sha1_hex" ,FILE_PROP_SHA1_HEX ,FILE_PROP_FLAGS, 31900},
{ "sha1_base64" ,FILE_PROP_SHA1_B64 ,FILE_PROP_FLAGS, 31900},
/* ini style elements */
{ "ini_key_len" ,FILE_INI_KEY_LEN ,JSPROP_ENUMERATE, 317},
{ "ini_key_prefix" ,FILE_INI_KEY_PREFIX ,JSPROP_ENUMERATE, 317},
{ "ini_section_separator" ,FILE_INI_SECTION_SEPARATOR ,JSPROP_ENUMERATE, 317},
{ "ini_value_separator" ,FILE_INI_VALUE_SEPARATOR ,JSPROP_ENUMERATE, 317},
{ "ini_bit_separator" ,FILE_INI_BIT_SEPARATOR ,JSPROP_ENUMERATE, 317},
{ "ini_literal_separator" ,FILE_INI_LITERAL_SEPARATOR ,JSPROP_ENUMERATE, 317},
{0}
};
#ifdef BUILD_JSDOCS
static const char* file_prop_desc[] = {
"Filename specified in constructor - <small>READ ONLY</small>"
,"Mode string specified in <i>open</i> call - <small>READ ONLY</small>"
,"<i>true</i> if the file is open or exists (case-insensitive) - <small>READ ONLY</small>"
,"<i>true</i> if the file has been opened successfully - <small>READ ONLY</small>"
,"<i>true</i> if the current file position is at the <i>end of file</i> - <small>READ ONLY</small>"
,"The last occurred error value (use <i>clear_error</i> to clear) - <small>READ ONLY</small>"
,"The open file descriptor (advanced use only) - <small>READ ONLY</small>"
,"End-of-text character (advanced use only), if non-zero used by <i>read</i>, <i>readln</i>, and <i>write</i>"
,"Set to <i>true</i> to enable debug log output"
,"The current file position (offset in bytes), change value to seek within file"
,"Last modified date/time (in time_t format)"
,"The current length of the file (in bytes)"
,"File type/mode flags (i.e. <tt>struct stat.st_mode</tt> value, compatible with <tt>file_chmod()</tt>)"
,"Set to <i>true</i> if binary data is to be written and read in Network Byte Order (big end first)"
,"Set to <i>true</i> to enable automatic ROT13 translation of text"
,"Set to <i>true</i> to enable automatic Unix-to-Unix encode and decode on <tt>read</tt> and <tt>write</tt> calls"
,"Set to <i>true</i> to enable automatic yEnc encode and decode on <tt>read</tt> and <tt>write</tt> calls"
,"Set to <i>true</i> to enable automatic Base64 encode and decode on <tt>read</tt> and <tt>write</tt> calls"
,"Calculated 16-bit CRC of file contents - <small>READ ONLY</small>"
,"Calculated 32-bit CRC of file contents - <small>READ ONLY</small>"
,"Calculated 32-bit checksum of file contents - <small>READ ONLY</small>"
,"Calculated 128-bit MD5 digest of file contents as hexadecimal string - <small>READ ONLY</small>"
,"Calculated 128-bit MD5 digest of file contents as base64-encoded string - <small>READ ONLY</small>"
,"Calculated 160-bit SHA1 digest of file contents as hexadecimal string - <small>READ ONLY</small>"
,"Calculated 160-bit SHA1 digest of file contents as base64-encoded string - <small>READ ONLY</small>"
,"Ini style: minimum key length (for left-justified white-space padded keys)"
,"Ini style: key prefix (e.g. '\\t', null = default prefix)"
,"Ini style: section separator (e.g. '\\n', null = default separator)"
,"Ini style: value separator (e.g. ' = ', null = default separator)"
,"Ini style: bit separator (e.g. ' | ', null = default separator)"
,"Ini style: literal separator (null = default separator)"
,NULL
};
#endif
static jsSyncMethodSpec js_file_functions[] = {
{"open", js_open, 1, JSTYPE_BOOLEAN, JSDOCSTR("[<i>string</i> mode=\"w+\"] [,<i>bool</i> shareable=false] [,<i>number</i> buffer_length]")
,JSDOCSTR("Open file, <i>shareable</i> defaults to <i>false</i>, <i>buffer_length</i> defaults to 2048 bytes, "
"mode (default: <tt>'w+'</tt>) specifies the type of access requested for the file, as follows:<br>"
"<tt>r </tt> open for reading; if the file does not exist or cannot be found, the open call fails<br>"
"<tt>w </tt> open an empty file for writing; if the given file exists, its contents are destroyed<br>"
"<tt>a </tt> open for writing at the end of the file (appending); creates the file first if it doesn't exist<br>"
"<tt>r+</tt> open for both reading and writing (the file must exist)<br>"
"<tt>w+</tt> open an empty file for both reading and writing; if the given file exists, its contents are destroyed<br>"
"<tt>a+</tt> open for reading and appending<br>"
"<tt>b </tt> open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed (e.g. <tt>r+b</tt>)<br>"
"<tt>x </tt> open a <i>non-shareable</i> file (that must not already exist) for <i>exclusive</i> access<br>"
"<br><b>Note:</b> When using the <tt>iniSet</tt> methods to modify a <tt>.ini</tt> file, "
"the file must be opened for both reading <b>and</b> writing.<br>"
"<br><b>Note:</b> To open an existing or create a new file for both reading and writing "
"(e.g. updating an <tt>.ini</tt> file) "
"use the <i>exists</i> property like so:<br>"
"<tt>file.open(file.exists ? 'r+':'w+');</tt><br>"
"<br><b>Note:</b> When <i>shareable</i> is <tt>false</tt>, uses the Synchronet <tt>nopen()</tt> function which will lock the file "
"and perform automatic retries. The lock mode is as follows:<br>"
"<tt>r </tt> DENYWRITE - Allows other scripts to open the file for reading, but not for writing.<br>"
"<tt>w </tt> DENYALL - Does not allow other scripts to open the file when <i>shareable</i> is set to true<br>"
"<tt>a </tt> DENYALL - Does not allow other scripts to open the file when <i>shareable</i> is set to true<br>"
"<tt>r+</tt> DENYALL - Does not allow other scripts to open the file when <i>shareable</i> is set to true<br>"
"<tt>w+</tt> DENYALL - Does not allow other scripts to open the file when <i>shareable</i> is set to true<br>"
"<tt>a+</tt> DENYALL - Does not allow other scripts to open the file when <i>shareable</i> is set to true<br>"
"<br>When <i>shareable</i> is <tt>true</tt> uses the standard C <tt>fopen()</tt> function, "
"and will only attempt to open the file once and will perform no locking.<br>"
"The behavior when one script has a file opened with <i>shareable</i> set to a different value than is used "
"with a new call is OS specific. On Windows, the second open will always fail and on *nix, "
"the second open will always succeed.<br>"
)
,310
},
{"popen", js_popen, 1, JSTYPE_BOOLEAN, JSDOCSTR("[<i>string</i> mode=\"r+\"] [,<i>number</i> buffer_length]")
,JSDOCSTR("Open pipe to command, <i>buffer_length</i> defaults to 2048 bytes, "
"mode (default: <tt>'r+'</tt>) specifies the type of access requested for the file, as follows:<br>"
"<tt>r </tt> read the programs stdout;<br>"
"<tt>w </tt> write to the programs stdin<br>"
"<tt>r+</tt> open for both reading stdout and writing stdin<br>"
"(<b>only functional on UNIX systems</b>)"
)
,315
},
{"close", js_close, 0, JSTYPE_VOID, JSDOCSTR("")
,JSDOCSTR("Close file")
,310
},
{"remove", js_delete, 0, JSTYPE_BOOLEAN, JSDOCSTR("")
,JSDOCSTR("Remove the file from the disk")
,310
},
{"clearError", js_clear_error, 0, JSTYPE_ALIAS },
{"clear_error", js_clear_error, 0, JSTYPE_BOOLEAN, JSDOCSTR("")
,JSDOCSTR("Clears the current error value (AKA clearError)")
,310
},
{"flush", js_flush, 0, JSTYPE_BOOLEAN, JSDOCSTR("")
,JSDOCSTR("Flush/commit buffers to disk")
,310
},
{"rewind", js_rewind, 0, JSTYPE_BOOLEAN, JSDOCSTR("")
,JSDOCSTR("Repositions the file pointer (<i>position</i>) to the beginning of a file "
"and clears error and end-of-file indicators")
,311
},
{"truncate", js_truncate, 0, JSTYPE_BOOLEAN, JSDOCSTR("[length=0]")
,JSDOCSTR("Changes the file <i>length</i> (default: 0) and repositions the file pointer "
"(<i>position</i>) to the new end-of-file")
,314
},
{"lock", js_lock, 2, JSTYPE_BOOLEAN, JSDOCSTR("[offset=0] [,length=<i>file_length</i>-<i>offset</i>]")
,JSDOCSTR("Lock file record for exclusive access (file must be opened <i>shareable</i>)")
,310
},
{"unlock", js_unlock, 2, JSTYPE_BOOLEAN, JSDOCSTR("[offset=0] [,length=<i>file_length</i>-<i>offset</i>]")
,JSDOCSTR("Unlock file record for exclusive access")
,310
},
{"read", js_read, 0, JSTYPE_STRING, JSDOCSTR("[maxlen=<i>file_length</i>-<i>file_position</i>]")
,JSDOCSTR("Read a string from file (optionally unix-to-unix or base64 decoding in the process), "
"<i>maxlen</i> defaults to the current length of the file minus the current file position")
,310
},
{"readln", js_readln, 0, JSTYPE_STRING, JSDOCSTR("[maxlen=512]")
,JSDOCSTR("Read a line-feed terminated string, <i>maxlen</i> defaults to 512 characters. "
"Returns <i>null</i> upon end of file.")
,310
},
{"readBin", js_readbin, 0, JSTYPE_NUMBER, JSDOCSTR("[bytes=4 [,count=1]]")
,JSDOCSTR("Read one or more binary integers from the file, default number of <i>bytes</i> is 4 (32-bits). "
"if count is not equal to 1, an array is returned (even if no integers were read)")
,310
},
{"readAll", js_readall, 0, JSTYPE_ARRAY, JSDOCSTR("[maxlen=512]")
,JSDOCSTR("Read all lines into an array of strings, <i>maxlen</i> defaults to 512 characters")
,310
},
{"raw_read", js_raw_read, 0, JSTYPE_STRING, JSDOCSTR("[maxlen=1]")
,JSDOCSTR("Read a string from underlying file descriptor. "
"Undefined results when mixed with any other read/write methods except raw_write, including indirect ones. "
"<i>maxlen</i> defaults to one")
,317
},
{"raw_pollin", js_raw_pollin, 0, JSTYPE_BOOLEAN, JSDOCSTR("[timeout]")
,JSDOCSTR("Waits up to <i>timeout</i> milliseconds (or forever if timeout is not specified) for data to be available "
"via raw_read().")
,317
},
{"write", js_write, 1, JSTYPE_BOOLEAN, JSDOCSTR("text [,length=<i>text_length</i>]")
,JSDOCSTR("Write a string to the file (optionally unix-to-unix or base64 decoding in the process). "
"If the specified <i>length</i> is longer than the <i>text</i>, the remaining length will be written as NUL bytes.")
,310
},
{"writeln", js_writeln, 0, JSTYPE_BOOLEAN, JSDOCSTR("[text]")
,JSDOCSTR("Write a new-line terminated string (a line of text) to the file")
,310
},
{"writeBin", js_writebin, 1, JSTYPE_BOOLEAN, JSDOCSTR("value(s) [,bytes=4]")
,JSDOCSTR("Write one or more binary integers to the file, default number of <i>bytes</i> is 4 (32-bits). "
"If value is an array, writes the entire array to the file.")
,310
},
{"writeAll", js_writeall, 0, JSTYPE_BOOLEAN, JSDOCSTR("array lines")
,JSDOCSTR("Write an array of new-line terminated strings (lines of text) to the file")
,310
},
{"raw_write", js_raw_write, 1, JSTYPE_BOOLEAN, JSDOCSTR("text")
,JSDOCSTR("Write a string to the underlying file descriptor. "
"Undefined results when mixed with any other read/write methods except raw_read, including indirect ones.")
,317
},
{"printf", js_fprintf, 0, JSTYPE_NUMBER, JSDOCSTR("format [,args]")
,JSDOCSTR("Write a C-style formatted string to the file (ala the standard C <tt>fprintf</tt> function)")
,310
},
{"iniGetSections", js_iniGetSections, 0, JSTYPE_ARRAY, JSDOCSTR("[prefix=<i>none</i>]")
,JSDOCSTR("Parse all section names from a <tt>.ini</tt> file (format = '<tt>[section]</tt>') "
"and return the section names as an <i>array of strings</i>, "
"optionally, only those section names that begin with the specified <i>prefix</i>")
,311
},
{"iniGetKeys", js_iniGetKeys, 1, JSTYPE_ARRAY, JSDOCSTR("[section=<i>root</i>]")
,JSDOCSTR("Parse all key names from the specified <i>section</i> in a <tt>.ini</tt> file "
"and return the key names as an <i>array of strings</i>. "
"if <i>section</i> is undefined, returns key names from the <i>root</i> section")
,311
},
{"iniGetValue", js_iniGetValue, 3, JSTYPE_UNDEF, JSDOCSTR("section, key [,default=<i>none</i>]")
,JSDOCSTR("Parse a key from a <tt>.ini</tt> file and return its value (format = '<tt>key = value</tt>'). "
"To parse a key from the <i>root</i> section, pass <i>null</i> for <i>section</i>. "
"Returns the specified <i>default</i> value if the key or value is missing or invalid.<br>"
"Returns a <i>bool</i>, <i>number</i>, <i>string</i>, or an <i>array of strings</i> "
"determined by the type of <i>default</i> value specified. "
"<br><b>Note:</b> To insure that any/all values are returned as a string (e.g. numeric passwords are <b>not</b> returned as a <i>number</i>), "
"pass an empty string ('') for the <i>default</i> value." )
,311
},
{"iniSetValue", js_iniSetValue, 3, JSTYPE_BOOLEAN, JSDOCSTR("section, key, [value=<i>none</i>]")
,JSDOCSTR("Set the specified <i>key</i> to the specified <i>value</i> in the specified <i>section</i> "
"of a <tt>.ini</tt> file. "
"to set a key in the <i>root</i> section, pass <i>null</i> for <i>section</i>. ")
,312
},
{"iniGetObject", js_iniGetObject, 1, JSTYPE_OBJECT, JSDOCSTR("[section=<i>root</i>] [,<i>bool</i> lowercase=false] "
"[,<i>bool</i> blanks=false]")
,JSDOCSTR("Parse an entire section from a .ini file "
"and return all of its keys (optionally lowercased) and values as properties of an object.<br>"
"If <i>section</i> is <tt>null</tt> or <tt>undefined</tt>, returns keys and values from the <i>root</i> section.<br>"
"If <i>blanks</i> is <tt>true</tt> then empty string (instead of <tt>undefined</tt>) values may included in the returned object.<br>"
"Returns <i>null</i> if the specified <i>section</i> does not exist in the file or the file has not been opened.")
,311
},
{"iniSetObject", js_iniSetObject, 2, JSTYPE_BOOLEAN, JSDOCSTR("section, <i>object</i> object")
,JSDOCSTR("Write all the properties of the specified <i>object</i> as separate <tt>key=value</tt> pairs "
"in the specified <i>section</i> of a <tt>.ini</tt> file.<br>"
"To write an object in the <i>root</i> section, pass <i>null</i> for <i>section</i>."
"<br><b>Note:</b> this method does not remove unreferenced keys from an existing section. "
"If your intention is to <i>replace</i> an existing section, use the <tt>iniRemoveSection</tt> function first." )
,312
},
{"iniGetAllObjects",js_iniGetAllObjects,1, JSTYPE_ARRAY, JSDOCSTR("[<i>string</i> name_property] [,<i>bool</i> prefix=<i>none</i>] [,<i>bool</i> lowercase=false] "
"[,blanks=false]")
,JSDOCSTR("Parse all sections from a .ini file and return all (non-<i>root</i>) sections "
"in an array of objects with each section's keys (optionally lowercased) as properties of each object.<br>"
"<i>name_property</i> is the name of the property to create to contain the section's name "
"(optionally lowercased, default is <tt>\"name\"</tt>), "
"the optional <i>prefix</i> has the same use as in the <tt>iniGetSections</tt> method.<br>"
"If a (String) <i>prefix</i> is specified, it is removed from each section's name.<br>"
"If <i>blanks</i> is <tt>true</tt> then empty string (instead of <tt>undefined</tt>) values may be included in the returned objects."
)
,311
},
{"iniSetAllObjects",js_iniSetAllObjects,1, JSTYPE_BOOLEAN, JSDOCSTR("<i>object</i> array [,name_property=\"name\"]")
,JSDOCSTR("Write an array of objects to a .ini file, each object in its own section named "
"after the object's <i>name_property</i> (default: <tt>name</tt>)")
,312
},
{"iniRemoveKey", js_iniRemoveKey, 2, JSTYPE_BOOLEAN, JSDOCSTR("section, key")
,JSDOCSTR("Remove specified <i>key</i> from specified <i>section</i> in <tt>.ini</tt> file.")
,314
},
{"iniRemoveSection",js_iniRemoveSection,1, JSTYPE_BOOLEAN, JSDOCSTR("section")
,JSDOCSTR("Remove specified <i>section</i> from <tt>.ini</tt> file.")
,314
},
{"iniRemoveSections",js_iniRemoveSections,1, JSTYPE_BOOLEAN, JSDOCSTR("[prefix]")
,JSDOCSTR("Remove all sections from <tt>.ini</tt> file, optionally only sections with the specified section name <i>prefix</i>.")
,32000
},
{"iniReadAll", js_iniReadAll, 0, JSTYPE_ARRAY, JSDOCSTR("")
,JSDOCSTR("Read entire <tt>.ini</tt> file into an array of strings (with <tt>!include</tt>ed files).")
,31802
},
{0}
};
/* File Destructor */
static void js_finalize_file(JSContext *cx, JSObject *obj)
{
private_t* p;
if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL)
return;
if(p->fp!=NULL)
fclose(p->fp);
dbprintf(FALSE, p, "finalized: %s",p->name);
FREE_AND_NULL(p->ini_style.key_prefix);
FREE_AND_NULL(p->ini_style.section_separator);
FREE_AND_NULL(p->ini_style.value_separator);
FREE_AND_NULL(p->ini_style.bit_separator);
FREE_AND_NULL(p->ini_style.literal_separator);
free(p);
JS_SetPrivate(cx, obj, NULL);
}
static JSBool js_file_resolve(JSContext *cx, JSObject *obj, jsid id)
{
char* name=NULL;
JSBool ret;
if(id != JSID_VOID && id != JSID_EMPTY) {
jsval idval;
JS_IdToValue(cx, id, &idval);
if(JSVAL_IS_STRING(idval))
JSSTRING_TO_MSTRING(cx, JSVAL_TO_STRING(idval), name, NULL);
}
ret=js_SyncResolve(cx, obj, name, js_file_properties, js_file_functions, NULL, 0);
if(name)
free(name);
return ret;
}
static JSBool js_file_enumerate(JSContext *cx, JSObject *obj)
{
return(js_file_resolve(cx, obj, JSID_VOID));
}
JSClass js_file_class = {
"File" /* name */
,JSCLASS_HAS_PRIVATE /* flags */
,JS_PropertyStub /* addProperty */
,JS_PropertyStub /* delProperty */
,js_file_get /* getProperty */
,js_file_set /* setProperty */
,js_file_enumerate /* enumerate */
,js_file_resolve /* resolve */
,JS_ConvertStub /* convert */
,js_finalize_file /* finalize */
};
/* File Constructor (creates file descriptor) */
static JSBool
js_file_constructor(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject *obj=JS_THIS_OBJECT(cx, arglist);
jsval *argv=JS_ARGV(cx, arglist);
JSString* str;
private_t* p;
obj=JS_NewObject(cx, &js_file_class, NULL, NULL);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj));
if(argc < 1 || (str = JS_ValueToString(cx, argv[0]))==NULL) {
JS_ReportError(cx,"No filename specified");
return(JS_FALSE);
}
if((p=(private_t*)calloc(1,sizeof(private_t)))==NULL) {
JS_ReportError(cx,"calloc failed");
return(JS_FALSE);
}
JSSTRING_TO_STRBUF(cx, str, p->name, sizeof(p->name), NULL);
if(!JS_SetPrivate(cx, obj, p)) {
dbprintf(TRUE, p, "JS_SetPrivate failed");
return(JS_FALSE);
}
#ifdef BUILD_JSDOCS
js_DescribeSyncObject(cx,obj,"Class used for opening, creating, reading, or writing files on the local file system<p>"
"Special features include:</h2><ol style=list-style-type:disc>"
"<li>Exclusive-access files (default) or shared files<ol type=circle>"
"<li>optional record-locking"
"<li>buffered or non-buffered I/O"
"</ol>"
"<li>Support for binary files<ol style=list-style-type:circle>"
"<li>native or network byte order (endian)"
"<li>automatic Unix-to-Unix (<i>UUE</i>), yEncode (<i>yEnc</i>) or Base64 encoding/decoding"
"</ol>"
"<li>Support for ASCII text files<ol style=list-style-type:circle>"
"<li>supports line-based I/O<ol style=list-style-type:square>"
"<li>entire file may be read or written as an array of strings"
"<li>individual lines may be read or written one line at a time"
"</ol>"
"<li>supports fixed-length records<ol style=list-style-type:square>"
"<li>optional end-of-text (<i>etx</i>) character for automatic record padding/termination"
"<li>Synchronet <tt>.dat</tt> files use an <i>etx</i> value of 3 (Ctrl-C)"
"</ol>"
"<li>supports <tt>.ini</tt> formatted configuration files"
"</ol>"
"<li>Dynamically-calculated industry standard checksums (e.g. CRC-16, CRC-32, MD5)"
"</ol>"
,310
);
js_DescribeSyncConstructor(cx,obj,"To create a new File object: <tt>var f = new File(<i>filename</i>)</tt>");
js_CreateArrayOfStrings(cx, obj, "_property_desc_list", file_prop_desc, JSPROP_READONLY);
#endif
dbprintf(FALSE, p, "object constructed");
return(JS_TRUE);
}
JSObject* js_CreateFileClass(JSContext* cx, JSObject* parent)
{
JSObject* obj;
obj = JS_InitClass(cx, parent, NULL
,&js_file_class
,js_file_constructor
,1 /* number of constructor args */
,NULL /* props, set in constructor */
,NULL /* funcs, set in constructor */
,NULL,NULL);
return(obj);
}
JSObject* js_CreateFileObject(JSContext* cx, JSObject* parent, char *name, int fd, const char* mode)
{
JSObject* obj;
private_t* p;
int newfd = dup(fd);
FILE* fp;
if (newfd == -1)
return NULL;
fp = fdopen(newfd, mode);
if(fp == NULL) {
close(newfd);
return NULL;
}
obj = JS_DefineObject(cx, parent, name, &js_file_class, NULL
,JSPROP_ENUMERATE|JSPROP_READONLY);
if(obj==NULL) {
fclose(fp);
return(NULL);
}
if((p=(private_t*)calloc(1,sizeof(private_t)))==NULL) {
fclose(fp);
return(NULL);
}
p->fp=fp;
p->debug=JS_FALSE;
if(!JS_SetPrivate(cx, obj, p)) {
fclose(fp);
dbprintf(TRUE, p, "JS_SetPrivate failed");
return(NULL);
}
dbprintf(FALSE, p, "object created");
return(obj);
}
#endif /* JAVSCRIPT */