Skip to content
Snippets Groups Projects
js_file.c 65.7 KiB
Newer Older
/* js_file.c */

/* Synchronet JavaScript "File" Object */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.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				*
 * 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										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * 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.	*
 ****************************************************************************/

#include "sbbs.h"
	FILE*	fp;
	char	name[MAX_PATH+1];
	char	mode[4];
	BOOL	external;	/* externally created, don't close */
	BOOL	debug;
	BOOL	b64encoded;
	BOOL	network_byte_order;
	BOOL	pipe;		/* Opened with popen() use pclose() to close */
static const char* getprivate_failure = "line %d %s JS_GetPrivate failed";

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;
	lprintf(LOG_DEBUG,"%04u 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,'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;
	}


/* File Object Methods */

static JSBool
js_open(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	char*		mode="w+";	/* default mode */
	jsint		bufsize=2*1024;
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);

	if(p->fp!=NULL)  
		return(JS_TRUE);

	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_STRING(cx, str, 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);
		}
	SAFECOPY(p->mode,mode);
	if(shareable)
		p->fp=fopen(p->name,p->mode);
	else {
		if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
			char fdomode[4];
			SAFECOPY(fdomode,p->mode);
			fdomode[strspn(fdomode,"abrwt+")]=0;	/* MSVC10 fdopen() asserts when passed a mode with an unsupported char (e.g. 'e') */
			if((p->fp=fdopen(file,fdomode))==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
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
js_popen(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	char*		mode="r+";	/* default mode */
	uintN		i;
	jsint		bufsize=2*1024;
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

	if(p->fp!=NULL)  
		return(JS_TRUE);

	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_STRING(cx, str, mode, NULL);
		}
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
	}
	SAFECOPY(p->mode,mode);

	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_close(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
	jsrefcount	rc;
deuce's avatar
deuce committed
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);

	if(p->fp==NULL)
		return(JS_TRUE);

#ifdef __unix__
	if(p->pipe)
		pclose(p->fp);
	else
#endif
		fclose(p->fp);

	dbprintf(FALSE, p, "closed");

	p->fp=NULL; 
js_read(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	if(p->fp==NULL)
		return(JS_TRUE);
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
		len=(long)filelength(fileno(p->fp));
		offset=(long)ftell(p->fp);
	if((buf=malloc(len+1))==NULL)
	len = fread(buf,1,len,p->fp);
	if(len<0) 
		len=0;
	buf[len]=0;

	if(p->etx) {
		cp=strchr(buf,p->etx);
		if(cp) *cp=0; 
	if(p->uuencoded || p->b64encoded || p->yencoded) {
deuce's avatar
deuce committed
		if((uubuf=malloc(uulen))==NULL) {
		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);
deuce's avatar
deuce committed
		}
	str = JS_NewStringCopyN(cx, buf, len);
	if(str==NULL)
		return(JS_FALSE);

	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
	dbprintf(FALSE, p, "read %u bytes",len);
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;
	JSString*	js_str;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);

	if(p->fp==NULL)
		return(JS_TRUE);
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
	if((buf=alloca(len))==NULL)
	if(fgets(buf,len,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((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	size_t		size=sizeof(DWORD);
	private_t*	p;
	size_t		count=1;
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
	size_t		i;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);

	if(p->fp==NULL)
		return(JS_TRUE);

	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],(int32*)&size))
			return(JS_FALSE);
		if(argc>1) {
			if(!JS_ValueToInt32(cx,argv[1],(int32*)&count))
				return(JS_FALSE);
		}
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
		return(JS_TRUE);
	}

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
		return(JS_FALSE);
	}
	b=buffer;
	w=buffer;
	l=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));
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
					break;
				case sizeof(DWORD):
					JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
    	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):
					v = INT_TO_JSVAL(*(w++));
					break;
				case sizeof(DWORD):
deuce's avatar
deuce committed
        	if(!JS_SetElement(cx, array, i, &v)) {
    	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
	return(JS_TRUE);
}

static JSBool
js_readall(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
    jsint       len=0;
    JSObject*	array;
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		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)
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
static jsval get_value(JSContext *cx, char* value)
{
	char*	p;
	BOOL	f=FALSE;
	jsval	val;

	if(value==NULL || *value==0)
		return(JSVAL_VOID);

	/* integer or float? */
	for(p=value;*p;p++) {
	if(*p==0) {
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
		return(val);
	}
	/* hexadecimal number? */
	if(!strncmp(value,"0x",2)) {	
		for(p=value+2;*p;p++)
			if(!isxdigit(*p))
				break;
		if(*p==0) {	
			val=DOUBLE_TO_JSVAL((double)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)));
}

deuce's avatar
deuce committed
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
	jsval	rval;

deuce's avatar
deuce committed
	if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
deuce's avatar
deuce committed
		return ((double)time(NULL))*1000;
deuce's avatar
deuce committed
	}
deuce's avatar
deuce committed
	return JSVAL_TO_DOUBLE(rval);
}

js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
	char*	section=ROOT_SECTION;
	char	buf[INI_MAX_VALUE_LEN];
deuce's avatar
deuce committed
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
	char*		cstr;
	char*		cstr2;
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		JSVALUE_TO_STRING(cx, argv[0], section, NULL);
	JSVALUE_TO_STRING(cx, argv[1], key, NULL);

	if(dflt==JSVAL_VOID) {	/* unspecified default value */
		JS_SET_RVAL(cx, arglist,get_value(cx,iniReadString(p->fp,section,key,NULL,buf)));
deuce's avatar
deuce committed
	if(JSVAL_IS_BOOLEAN(dflt)) {
		JS_SET_RVAL(cx,arglist,BOOLEAN_TO_JSVAL(
			iniReadBool(p->fp,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);
deuce's avatar
deuce committed
			dbl=iniReadDateTime(p->fp,section,key,tt);
deuce's avatar
deuce committed
			dbl *= 1000;
deuce's avatar
deuce committed
			date_obj = JS_NewDateObjectMsec(cx, dbl);
			if(date_obj!=NULL) {
deuce's avatar
deuce committed
				JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(date_obj));
deuce's avatar
deuce committed
			}
deuce's avatar
deuce committed
		}
		else {
		    array = JS_NewArrayObject(cx, 0, NULL);
			JSVALUE_TO_STRING(cx, dflt, cstr, NULL);
deuce's avatar
deuce committed
			list=iniReadStringList(p->fp,section,key,",",cstr);
			for(i=0;list && list[i];i++) {
				val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
				if(!JS_SetElement(cx, array, i, &val))
					break;
			}
			JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
deuce's avatar
deuce committed
		}
	}
	else if(JSVAL_IS_DOUBLE(dflt)) {
		rc=JS_SUSPENDREQUEST(cx);
		dbl=iniReadFloat(p->fp,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))
			return(JS_FALSE);
		rc=JS_SUSPENDREQUEST(cx);
		i=iniReadInteger(p->fp,section,key,i);
		JS_RESUMEREQUEST(cx, rc);
		JS_SET_RVAL(cx, arglist,INT_TO_JSVAL(i));
	} else {
		JSVALUE_TO_STRING(cx, dflt, cstr, NULL);
deuce's avatar
deuce committed
		rc=JS_SUSPENDREQUEST(cx);
		cstr2=iniReadString(p->fp,section,key,cstr,buf);
		JS_RESUMEREQUEST(cx, rc);
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, cstr2)));
deuce's avatar
deuce committed
js_iniSetValue_internal(JSContext *cx, JSObject *obj, uintN argc, jsval* argv, jsval *rval)
rswindell's avatar
rswindell committed
	char*	section=ROOT_SECTION;
	char*	key;
	char*	result=NULL;
	int32	i;
	jsval	value=argv[2];
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
	jsrefcount	rc;
	char*		cstr;
	time_t		tt;
deuce's avatar
deuce committed
	*rval = JSVAL_FALSE;

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		JSVALUE_TO_STRING(cx, argv[0], section, NULL);
	JSVALUE_TO_STRING(cx, argv[1], key, NULL);
deuce's avatar
deuce committed
	if((list=iniReadFile(p->fp))==NULL) {
deuce's avatar
deuce committed
	if(value==JSVAL_VOID) { 	/* unspecified value */
		result = iniSetString(&list,section,key,"",NULL);
deuce's avatar
deuce committed
	else if(JSVAL_IS_BOOLEAN(value)) {
		result = iniSetBool(&list,section,key,JSVAL_TO_BOOLEAN(value),NULL);
	}
	else if(JSVAL_IS_DOUBLE(value)) {
		result = iniSetFloat(&list,section,key,JSVAL_TO_DOUBLE(value),NULL);
	}
	else if(JSVAL_IS_NUMBER(value)) {
		if(!JS_ValueToInt32(cx,value,&i))
			return(JS_FALSE);
		rc=JS_SUSPENDREQUEST(cx);
		result = iniSetInteger(&list,section,key,i,NULL);
		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,NULL);
		JS_RESUMEREQUEST(cx, rc);
	} else {
		JSVALUE_TO_STRING(cx, value, cstr, NULL);
deuce's avatar
deuce committed
		rc=JS_SUSPENDREQUEST(cx);
		result = iniSetString(&list,section,key, cstr,NULL);
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
		*rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));
deuce's avatar
deuce committed
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;
	JSBool	ret;

	ret=js_iniSetValue_internal(cx, obj, argc, argv, &rval);
	JS_SET_RVAL(cx, arglist, rval);
	return ret;
}

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;
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

	if(p->fp==NULL)
		return(JS_TRUE);

	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		JSVALUE_TO_STRING(cx, argv[0], section, NULL);
	JSVALUE_TO_STRING(cx, argv[1], key, NULL);
deuce's avatar
deuce committed
	if((list=iniReadFile(p->fp))==NULL) {

	if(iniRemoveKey(&list,section,key))
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list)));
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;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

	if(p->fp==NULL)
		return(JS_TRUE);

	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		JSVALUE_TO_STRING(cx, argv[0], section, NULL);
deuce's avatar
deuce committed
	if((list=iniReadFile(p->fp))==NULL) {

	if(iniRemoveSection(&list,section))
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list)));
js_iniGetSections(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	char**		list;
    jsint       i;
    jsval       val;
    JSObject*	array;
	private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

		JSVALUE_TO_STRING(cx, argv[0], prefix, NULL);
	list = iniReadSectionList(p->fp,prefix);
    for(i=0;list && list[i];i++) {
		val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
        if(!JS_SetElement(cx, array, i, &val))
			break;
	}
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
js_iniGetKeys(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
	char*		section=ROOT_SECTION;
	char**		list;
    jsint       i;
    jsval       val;
    JSObject*	array;
	private_t*	p;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		JSVALUE_TO_STRING(cx, argv[0], section, NULL);
	list = iniReadKeyList(p->fp,section);
    for(i=0;list && list[i];i++) {
		val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
        if(!JS_SetElement(cx, array, i, &val))
			break;
	}
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
js_iniGetObject(JSContext *cx, uintN argc, jsval *arglist)
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
	char*		section=ROOT_SECTION;
deuce's avatar
deuce committed
	jsrefcount	rc;
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		JSVALUE_TO_STRING(cx, argv[0], section, NULL);
	list = iniReadNamedStringList(p->fp,section);
	if(list==NULL) {	/* New behavior at request of MCMLXXIX: return NULL/undefined if specified section doesn't exist */
		JS_SET_RVAL(cx, arglist, JSVAL_NULL);