Skip to content
Snippets Groups Projects
js_file.c 52.4 KiB
Newer Older
static JSBool
js_write(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		cp;
	char*		uubuf=NULL;
	int			len;	/* string length */
	int			tlen;	/* total length to write (may be greater than len) */
	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);

	str = JS_ValueToString(cx, argv[0]);
	cp	= JS_GetStringBytes(str);
	len	= JS_GetStringLength(str);
	if((p->uuencoded || p->b64encoded || p->yencoded)
		&& len && (uubuf=malloc(len))!=NULL) {
		if(p->uuencoded)
			len=uudecode(uubuf,len,cp,len);
		else if(p->yencoded)
			len=ydecode(uubuf,len,cp,len);
		if(!JS_ValueToInt32(cx,argv[1],(int32*)&tlen)) {
			FREE_AND_NULL(uubuf);

	if(fwrite(cp,1,len,p->fp)==(size_t)len) {
			if((cp=malloc(len))==NULL) {
				FREE_AND_NULL(uubuf);
				dbprintf(TRUE, p, "malloc failure of %u bytes", len);
				return(JS_TRUE);
			}
			memset(cp,p->etx,len);
			fwrite(cp,1,len,p->fp);
		}
		dbprintf(FALSE, p, "wrote %u bytes",tlen);
	} else 
		dbprintf(TRUE, p, "write of %u bytes failed",len);
js_writeln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
	char*		cp="";
	JSString*	str;
	private_t*	p;

	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((str = JS_ValueToString(cx, argv[0]))==NULL) {
			JS_ReportError(cx,"JS_ValueToString failed");
			return(JS_FALSE);
		cp = JS_GetStringBytes(str);
	}

	if(fprintf(p->fp,"%s\n",cp)!=0)
	return(JS_TRUE);
}
static JSBool
js_writebin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
	size_t		size=sizeof(DWORD);
	size_t		count=1;
	void		*buffer;
    JSObject*	array=NULL;
    jsval       elemval;
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
	if(p->fp==NULL)
		return(JS_TRUE);
	if(JSVAL_IS_OBJECT(argv[0])) {
		array = JSVAL_TO_OBJECT(argv[0]);
		if(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))
	if(argc>1) {
		if(!JS_ValueToInt32(cx,argv[1],(int32*)&size))
			return(JS_FALSE);
	}
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		dbprintf(TRUE, p, "unsupported binary write 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;
	if(array==NULL) {
		switch(size) {
			case sizeof(BYTE):
				*b=(BYTE)val;
				break;
			case sizeof(WORD):
				*w=(WORD)val;
				break;
			case sizeof(DWORD):
				*l=(DWORD)val;
				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(BYTE):
					*(b++)=(BYTE)val;
					break;
				case sizeof(WORD):
					*(w++)=(WORD)val;
					break;
				case sizeof(DWORD):
rswindell's avatar
rswindell committed
					*(l++)=(DWORD)val;
					break;
			}
		}
	}
	wr=fwrite(buffer,size,count,p->fp);
	if(wr==count)
		*rval=JSVAL_TRUE;

end:
	free(buffer);
static JSBool
js_writeall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    jsuint      i;
    jsuint      limit;
    JSObject*	array;
    jsval       elemval;
	private_t*	p;

	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(!JSVAL_IS_OBJECT(argv[0]))
		return(JS_TRUE);

    array = JSVAL_TO_OBJECT(argv[0]);

    if(!JS_IsArrayObject(cx, array))
		return(JS_TRUE);

    if(!JS_GetArrayLength(cx, array, &limit))
		return(JS_FALSE);
    for(i=0;i<limit;i++) {
        if(!JS_GetElement(cx, array, i, &elemval))
			break;
        js_writeln(cx, obj, 1, &elemval, rval);
js_lock(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
	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],&offset))
			return(JS_FALSE);
	}
	if(argc>1) {
		if(!JS_ValueToInt32(cx,argv[1],&len))
			return(JS_FALSE);
	}

	if(len==0)
		len=filelength(fileno(p->fp))-offset;

	if(lock(fileno(p->fp),offset,len)==0)
js_unlock(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
	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],&offset))
			return(JS_FALSE);
	}
	if(argc>1) {
		if(!JS_ValueToInt32(cx,argv[1],&len))
			return(JS_FALSE);
	}
	if(unlock(fileno(p->fp),offset,len)==0)
static JSBool
js_delete(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

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

	if(p->fp!=NULL) {	/* close it if it's open */
		fclose(p->fp);
		p->fp=NULL;
	}

	*rval = BOOLEAN_TO_JSVAL(remove(p->name)==0);

	return(JS_TRUE);
}

static JSBool
js_flush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
	else 
		*rval = BOOLEAN_TO_JSVAL(fflush(p->fp)==0);

	return(JS_TRUE);
}

static JSBool
js_rewind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

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

	if(p->fp==NULL)
		*rval = JSVAL_FALSE;
	else  {
		*rval = JSVAL_TRUE;
		rewind(p->fp);
	}

	return(JS_TRUE);
}

static JSBool
js_truncate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;
	int32		len=0;

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

	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}

	*rval = JSVAL_FALSE;
	if(p->fp!=NULL && chsize(fileno(p->fp),len)==0) {
		fseek(p->fp,len,SEEK_SET);
		*rval = JSVAL_TRUE;
	}

	return(JS_TRUE);
}

static JSBool
js_clear_error(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
	else  {
		clearerr(p->fp);
static JSBool
js_fprintf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		cp;
	private_t*	p;

	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((cp=js_sprintf(cx, 0, argc, argv))==NULL) {
		JS_ReportError(cx,"js_sprintf failed");
		return(JS_FALSE);

	*rval = INT_TO_JSVAL(fwrite(cp,1,strlen(cp),p->fp));

/* File Object Properites */
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
	/* dynamically calculated */
	,FILE_PROP_CHKSUM
	,FILE_PROP_CRC16
	,FILE_PROP_CRC32
	,FILE_PROP_MD5_HEX
static JSBool js_file_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);

    tiny = JSVAL_TO_INT(id);

	dbprintf(FALSE, p, "setting property %d",tiny);

	switch(tiny) {
		case FILE_PROP_DEBUG:
			JS_ValueToBoolean(cx,*vp,&(p->debug));
		case FILE_PROP_YENCODED:
			JS_ValueToBoolean(cx,*vp,&(p->yencoded));
			break;
			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));
		case FILE_PROP_POSITION:
				if(!JS_ValueToInt32(cx,*vp,&i))
					return(JS_FALSE);
			if(!JS_ValueToInt32(cx,*vp,&i))
				return(JS_FALSE);
		case FILE_PROP_LENGTH:
				if(!JS_ValueToInt32(cx,*vp,&i))
					return(JS_FALSE);
			break;
		case FILE_PROP_ATTRIBUTES:
			if(!JS_ValueToInt32(cx,*vp,&i))
				return(JS_FALSE);
		case FILE_PROP_ETX:
			if(!JS_ValueToInt32(cx,*vp,&i))
				return(JS_FALSE);
	}

	return(JS_TRUE);
}

static JSBool js_file_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
	ulong		sum=0;
	ushort		c16=0;
	ulong		c32=~0;
	MD5			md5_ctx;
	BYTE		block[4096];
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);

    tiny = JSVAL_TO_INT(id);

#if 0 /* just too much */
	dbprintf(FALSE, sock, "getting property %d",tiny);
#endif

	switch(tiny) {
		case FILE_PROP_NAME:
			if((js_str=JS_NewStringCopyZ(cx, p->name))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
			break;
		case FILE_PROP_MODE:
			if((js_str=JS_NewStringCopyZ(cx, p->mode))==NULL)
				return(JS_FALSE);
			*vp = STRING_TO_JSVAL(js_str);
			break;
		case FILE_PROP_EXISTS:
			if(p->fp)	/* open? */
				*vp = BOOLEAN_TO_JSVAL(fexistcase(p->name));
			break;
		case FILE_PROP_DATE:
			JS_NewNumberValue(cx,fdate(p->name),vp);
			break;
		case FILE_PROP_IS_OPEN:
			*vp = BOOLEAN_TO_JSVAL(p->fp!=NULL);
			break;
		case FILE_PROP_EOF:
			if(p->fp)
				*vp = BOOLEAN_TO_JSVAL(feof(p->fp)!=0);
			else
			break;
		case FILE_PROP_ERROR:
			if(p->fp)
				*vp = INT_TO_JSVAL(ferror(p->fp));
			else
			break;
		case FILE_PROP_POSITION:
				JS_NewNumberValue(cx,ftell(p->fp),vp);
			break;
		case FILE_PROP_LENGTH:
			if(p->fp)	/* open? */
				JS_NewNumberValue(cx,filelength(fileno(p->fp)),vp);
				JS_NewNumberValue(cx,flength(p->name),vp);
			break;
		case FILE_PROP_ATTRIBUTES:
			JS_NewNumberValue(cx,getfattr(p->name),vp);
			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);
		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);
		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 */
			*vp = JSVAL_VOID;
			if(p->fp==NULL)
				break;
			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;
			}

			/* calculate */
			while(!feof(p->fp)) {
				if((rd=fread(block,1,sizeof(block),p->fp))<1)
					break;
						for(i=0;i<rd;i++)
							c16=ucrc16(block[i],c16);
						for(i=0;i<rd;i++)
							c32=ucrc32(block[i],c32);
						break;
					case FILE_PROP_MD5_HEX:
					case FILE_PROP_MD5_B64:
					}
			}

			/* finalize */
			switch(tiny) {
				case FILE_PROP_CHKSUM:
					JS_NewNumberValue(cx,sum,vp);
					break;
				case FILE_PROP_CRC16:
					if(!JS_NewNumberValue(cx,c16,vp))
						*vp=JSVAL_ZERO;
					break;
				case FILE_PROP_CRC32:
					if(!JS_NewNumberValue(cx,~c32,vp))
						*vp=JSVAL_ZERO;
					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,digest,sizeof(digest));
					js_str=JS_NewStringCopyZ(cx, str);
					break;
			}
			fseek(p->fp,offset,SEEK_SET);	/* restore saved file position */
			if(js_str!=NULL)
				*vp = STRING_TO_JSVAL(js_str);
			break;
	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},
	{	"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},
	{	"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},
static 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 exists - <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 clear_error 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>"
rswindell's avatar
rswindell committed
	,"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 mode/attributes"
	,"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 translatation 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>"
static jsSyncMethodSpec js_file_functions[] = {
rswindell's avatar
rswindell committed
	{"open",			js_open,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[mode=<tt>\"w+\"</tt>] [,shareable=<tt>false</tt>] [,buffer_length]")
	,JSDOCSTR("open file, <i>shareable</i> defaults to <i>false</i>, <i>buffer_length</i> defaults to 2048 bytes, "
rswindell's avatar
rswindell committed
		"mode (default: <tt>'w+'</tt>) specifies the type of access requested for the file, as follows:<br>"
rswindell's avatar
rswindell committed
		"<tt>r&nbsp</tt> open for reading; if the file does not exist or cannot be found, the open call fails<br>"
		"<tt>w&nbsp</tt> open an empty file for writing; if the given file exists, its contents are destroyed<br>"
		"<tt>a&nbsp</tt> open for writing at the end of the file (appending); creates the file first if it doesnt 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&nbsp</tt> open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed (e.g. <tt>r+b</tt>)<br>"
		"<tt>e&nbsp</tt> open a <i>non-shareable</i> file (that must not already exist) for <i>exclusive</i> access <i>(introduced in v3.12)</i><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 and writing.<br>"
		"<br><b>Note:</b> To open an existing or create a new file for both reading and writing, "
		"use the <i>file_exists</i> function like so:<br>"
		"<tt>file.open(file_exists(file.name) ? 'r+':'w+');</tt>"
	{"popen",			js_popen,			1,	JSTYPE_BOOLEAN,	JSDOCSTR("[mode=<tt>\"r+\"</tt>] [,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&nbsp</tt> read the programs stdout;<br>"
		"<tt>w&nbsp</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>)"
		)
rswindell's avatar
rswindell committed
	{"close",			js_close,			0,	JSTYPE_VOID,	JSDOCSTR("")
	,JSDOCSTR("close file")
rswindell's avatar
rswindell committed
	{"remove",			js_delete,			0,	JSTYPE_BOOLEAN, JSDOCSTR("")
	,JSDOCSTR("remove the file from the disk")
	{"clearError",		js_clear_error,		0,	JSTYPE_ALIAS },
rswindell's avatar
rswindell committed
	{"clear_error",		js_clear_error,		0,	JSTYPE_BOOLEAN, JSDOCSTR("")
	,JSDOCSTR("clears the current error value (AKA clearError)")
rswindell's avatar
rswindell committed
	{"flush",			js_flush,			0,	JSTYPE_BOOLEAN,	JSDOCSTR("")
	,JSDOCSTR("flush/commit buffers to disk")
rswindell's avatar
rswindell committed
	{"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")
rswindell's avatar
rswindell committed
	{"truncate",		js_truncate,		0,	JSTYPE_BOOLEAN,	JSDOCSTR("[length=<tt>0</tt>]")
	,JSDOCSTR("changes the file <i>length</i> (default: 0) and repositions the file pointer "
	"(<i>position</i>) to the new end-of-file")
rswindell's avatar
rswindell committed
	,314
rswindell's avatar
rswindell committed
	{"lock",			js_lock,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("[offset=<tt>0</tt>] [,length=<i>file_length</i>-<i>offset</i>]")
	,JSDOCSTR("lock file record for exclusive access (file must be opened <i>shareable</i>)")
rswindell's avatar
rswindell committed
	{"unlock",			js_unlock,			2,	JSTYPE_BOOLEAN,	JSDOCSTR("[offset=<tt>0</tt>] [,length=<i>file_length</i>-<i>offset</i>]")
	,JSDOCSTR("unlock file record for exclusive access")
rswindell's avatar
rswindell committed
	{"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")
rswindell's avatar
rswindell committed
	{"readln",			js_readln,			0,	JSTYPE_STRING,	JSDOCSTR("[maxlen=<tt>512</tt>]")
	,JSDOCSTR("read a line-feed terminated string, <i>maxlen</i> defaults to 512 characters")
	{"readBin",			js_readbin,			0,	JSTYPE_NUMBER,	JSDOCSTR("[bytes=<tt>4</tt> [,count=<tt>1</tt>]")
	,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)")
	{"readAll",			js_readall,			0,	JSTYPE_ARRAY,	JSDOCSTR("[maxlen=<tt>512</tt>]")
	,JSDOCSTR("read all lines into an array of strings, <i>maxlen</i> defaults to 512 characters")
rswindell's avatar
rswindell committed
	{"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)")
rswindell's avatar
rswindell committed
	{"writeln",			js_writeln,			0,	JSTYPE_BOOLEAN, JSDOCSTR("[text]")
	,JSDOCSTR("write a line-feed terminated string to the file")
	{"writeBin",		js_writebin,		1,	JSTYPE_BOOLEAN,	JSDOCSTR("value(s) [,bytes=<tt>4</tt>]")
	,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.")
	{"writeAll",		js_writeall,		0,	JSTYPE_BOOLEAN,	JSDOCSTR("array lines")
	,JSDOCSTR("write an array of strings to file")
rswindell's avatar
rswindell committed
	{"printf",			js_fprintf,			0,	JSTYPE_NUMBER,	JSDOCSTR("format [,args]")
rswindell's avatar
rswindell committed
	,JSDOCSTR("write a formatted string to the file (ala fprintf) - "
		"<small>CAUTION: for experienced C programmers ONLY</small>")
rswindell's avatar
rswindell committed
	},
rswindell's avatar
rswindell committed
	{"iniGetSections",	js_iniGetSections,	0,	JSTYPE_ARRAY,	JSDOCSTR("[prefix=<i>none</i>]")
rswindell's avatar
rswindell committed
	,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>")
rswindell's avatar
rswindell committed
	},
rswindell's avatar
rswindell committed
	{"iniGetKeys",		js_iniGetKeys,		1,	JSTYPE_ARRAY,	JSDOCSTR("[section=<i>root</i>]")
rswindell's avatar
rswindell committed
	,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")
rswindell's avatar
rswindell committed
	},
rswindell's avatar
rswindell committed
	{"iniGetValue",		js_iniGetValue,		3,	JSTYPE_UNDEF,	JSDOCSTR("section, key [,default=<i>none</i>]")
rswindell's avatar
rswindell committed
	,JSDOCSTR("parse a key from a <tt>.ini</tt> file and return its value (format = '<tt>key = value</tt>'). "
		"returns the specified <i>default</i> value if the key or value is missing or invalid. "
		"to parse a key from the <i>root</i> section, pass <i>null</i> for <i>section</i>. "
rswindell's avatar
rswindell committed
		"will return 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")
rswindell's avatar
rswindell committed
	},
rswindell's avatar
rswindell committed
	{"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>. ")
rswindell's avatar
rswindell committed
	{"iniGetObject",	js_iniGetObject,	1,	JSTYPE_OBJECT,	JSDOCSTR("[section=<i>root</i>]")
rswindell's avatar
rswindell committed
	,JSDOCSTR("parse an entire section from a .ini file "
		"and return all of its keys and values as properties of an object. "
		"if <i>section</i> is undefined, returns key and values from the <i>root</i> section")
rswindell's avatar
rswindell committed
	},
	{"iniSetObject",	js_iniSetObject,	2,	JSTYPE_BOOLEAN,	JSDOCSTR("section, 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. "
		"to write an object in the <i>root</i> section, pass <i>null</i> for <i>section</i>. ")
rswindell's avatar
rswindell committed
	{"iniGetAllObjects",js_iniGetAllObjects,1,	JSTYPE_ARRAY,	JSDOCSTR("[name_property] [,prefix=<i>none</i>]")
	,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 as properties of each object. "
		"<i>name_property</i> is the name of the property to create to contain the section's name "
		"(default is <tt>\"name\"</tt>), "
		"the optional <i>prefix</i> has the same use as in the <tt>iniGetSections</tt> method, "
		"if a <i>prefix</i> is specified, it is removed from each section's name" )
rswindell's avatar
rswindell committed
	{"iniSetAllObjects",js_iniSetAllObjects,1,	JSTYPE_ARRAY,	JSDOCSTR("object array [,name_property=<tt>\"name\"</tt>]")
	,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>)")
	{"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.")
rswindell's avatar
rswindell committed
	,314
	},
	{"iniRemoveSection",js_iniRemoveSection,1,	JSTYPE_BOOLEAN,	JSDOCSTR("section")
	,JSDOCSTR("remove specified <i>section</i> from <tt>.ini</tt> file.")
rswindell's avatar
rswindell committed
	,314
/* 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->external==JS_FALSE && p->fp!=NULL)
		fclose(p->fp);

	dbprintf(FALSE, p, "closed: %s",p->name);

	free(p);

	JS_SetPrivate(cx, obj, NULL);
}

static JSBool js_file_resolve(JSContext *cx, JSObject *obj, jsval id)
{
	char*			name=NULL;

	if(id != JSVAL_NULL)
		name=JS_GetStringBytes(JSVAL_TO_STRING(id));

	return(js_SyncResolve(cx, obj, name, js_file_properties, js_file_functions, NULL, 0));
}

static JSBool js_file_enumerate(JSContext *cx, JSObject *obj)
{