js_file.c 64.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* 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)		*
 *																			*
11
 * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html		*
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 *																			*
 * 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"
39
40
#include "md5.h"
#include "base64.h"
41
#include "uucode.h"
42
#include "yenc.h"
43
#include "ini_file.h"
44
45
46

#ifdef JAVASCRIPT

47
#include "js_request.h"
48

49
50
typedef struct
{
51
	FILE*	fp;
52
53
	char	name[MAX_PATH+1];
	char	mode[4];
54
	uchar	etx;
55
56
	BOOL	external;	/* externally created, don't close */
	BOOL	debug;
57
	BOOL	rot13;
58
	BOOL	yencoded;
59
	BOOL	uuencoded;
60
61
	BOOL	b64encoded;
	BOOL	network_byte_order;
62
	BOOL	pipe;		/* Opened with popen() use pclose() to close */
63
64
65

} private_t;

66
static const char* getprivate_failure = "line %d %s JS_GetPrivate failed";
67
68
69
70
71
72
73
74
75
76

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);
77
78
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
79
80
    va_end(argptr);
	
81
	lprintf(LOG_DEBUG,"%04u File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
82
83
}

84
85
86
87
88
89
90
91
/* 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;
92
93
	else
		flags|=O_TEXT;
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

	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;
	}

120
121
122
	if(strchr(mode,'e'))
		flags|=O_EXCL;

123
124
	return(flags);
}
125
126
127
128

/* File Object Methods */

static JSBool
129
js_open(JSContext *cx, uintN argc, jsval *arglist)
130
{
131
132
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
133
	char*		mode="w+";	/* default mode */
134
135
	BOOL		shareable=FALSE;
	int			file;
136
	uintN		i;
137
	jsint		bufsize=2*1024;
138
139
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
140
	jsrefcount	rc;
141

142
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
143

144
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
145
		JS_ReportError(cx,getprivate_failure,WHERE);
146
		return(JS_FALSE);
147
	}
148
149
150

	if(p->fp!=NULL)  
		return(JS_TRUE);
151
152
153
154

	for(i=0;i<argc;i++) {
		if(JSVAL_IS_STRING(argv[i])) {	/* mode */
			if((str = JS_ValueToString(cx, argv[i]))==NULL) {
155
156
				JS_ReportError(cx,"Invalid mode specified: %s",str);
				return(JS_TRUE);
157
158
			}
			mode=JS_GetStringBytes(str);
159
160
		} else if(JSVAL_IS_BOOLEAN(argv[i]))	/* shareable */
			shareable=JSVAL_TO_BOOLEAN(argv[i]);
161
162
163
164
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
165
	}
166
	SAFECOPY(p->mode,mode);
167

168
	rc=JS_SUSPENDREQUEST(cx);
169
170
171
172
	if(shareable)
		p->fp=fopen(p->name,p->mode);
	else {
		if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
173
174
175
176
			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)
177
178
179
				close(file);
		}
	}
180
	if(p->fp!=NULL) {
181
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
182
		dbprintf(FALSE, p, "opened: %s",p->name);
183
184
185
186
187
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
		else
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
188
	JS_RESUMEREQUEST(cx, rc);
189
190
191
192

	return(JS_TRUE);
}

193
static JSBool
194
js_popen(JSContext *cx, uintN argc, jsval *arglist)
195
{
196
197
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
198
199
200
201
202
	char*		mode="r+";	/* default mode */
	uintN		i;
	jsint		bufsize=2*1024;
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
203
	jsrefcount	rc;
204

205
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

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

230
	rc=JS_SUSPENDREQUEST(cx);
231
232
233
	p->fp=popen(p->name,p->mode);
	if(p->fp!=NULL) {
		p->pipe=TRUE;
234
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
235
236
237
238
239
240
		dbprintf(FALSE, p, "popened: %s",p->name);
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
		else
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
241
	JS_RESUMEREQUEST(cx, rc);
242
243
244

	return(JS_TRUE);
}
245
246

static JSBool
247
js_close(JSContext *cx, uintN argc, jsval *arglist)
248
{
249
250
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
251
	private_t*	p;
deuce's avatar
deuce committed
252
	jsrefcount	rc;
253

254
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
255
		JS_ReportError(cx,getprivate_failure,WHERE);
256
		return(JS_FALSE);
257
	}
258
259
260
261

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

262
	rc=JS_SUSPENDREQUEST(cx);
263
264
265
266
267
268
#ifdef __unix__
	if(p->pipe)
		pclose(p->fp);
	else
#endif
		fclose(p->fp);
269
270
271
272

	dbprintf(FALSE, p, "closed");

	p->fp=NULL; 
273
	JS_RESUMEREQUEST(cx, rc);
274
275
276
277
278

	return(JS_TRUE);
}

static JSBool
279
js_read(JSContext *cx, uintN argc, jsval *arglist)
280
{
281
282
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
283
	char*		cp;
284
	char*		buf;
285
	char*		uubuf;
286
287
	int32		len;
	int32		offset;
288
	int32		uulen;
289
290
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
291
	jsrefcount	rc;
292

293
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
294

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

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

303
304
305
306
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
307
		rc=JS_SUSPENDREQUEST(cx);
308
309
		len=(long)filelength(fileno(p->fp));
		offset=(long)ftell(p->fp);
310
311
		if(offset>0)
			len-=offset;
312
		JS_RESUMEREQUEST(cx, rc);
313
314
315
	}
	if(len<0)
		len=512;
316

317
	if((buf=malloc(len+1))==NULL)
318
319
		return(JS_TRUE);

320
	rc=JS_SUSPENDREQUEST(cx);
321
322
323
324
325
326
327
328
	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; 
329
		len=strlen(buf);
330
331
	}

332
333
334
	if(p->rot13)
		rot13(buf);

335
	if(p->uuencoded || p->b64encoded || p->yencoded) {
336
		uulen=len*2;
deuce's avatar
deuce committed
337
		if((uubuf=malloc(uulen))==NULL) {
338
			free(buf);
339
			JS_RESUMEREQUEST(cx, rc);
340
			return(JS_TRUE);
341
		}
342
343
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
344
345
		else if(p->yencoded)
			uulen=yencode(uubuf,uulen,buf,len);
346
347
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
348
		if(uulen>=0) {
349
			free(buf);
350
			buf=uubuf;
351
			len=uulen;
deuce's avatar
deuce committed
352
		}
353
354
		else
			free(uubuf);
355
	}
356
	JS_RESUMEREQUEST(cx, rc);
357

358
	str = JS_NewStringCopyN(cx, buf, len);
359
	free(buf);
360

361
362
363
	if(str==NULL)
		return(JS_FALSE);

364
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
365

366
	rc=JS_SUSPENDREQUEST(cx);
367
	dbprintf(FALSE, p, "read %u bytes",len);
368
	JS_RESUMEREQUEST(cx, rc);
369
370
371
372
373
		
	return(JS_TRUE);
}

static JSBool
374
js_readln(JSContext *cx, uintN argc, jsval *arglist)
375
{
376
377
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
378
379
	char*		cp;
	char*		buf;
380
	int32		len=512;
381
	JSString*	js_str;
382
	private_t*	p;
deuce's avatar
deuce committed
383
	jsrefcount	rc;
384

385
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
386

387
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
388
		JS_ReportError(cx,getprivate_failure,WHERE);
389
		return(JS_FALSE);
390
	}
391
392
393

	if(p->fp==NULL)
		return(JS_TRUE);
394
	
395
396
397
398
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
399

400
	if((buf=alloca(len))==NULL)
401
402
		return(JS_TRUE);

403
	rc=JS_SUSPENDREQUEST(cx);
404
	if(fgets(buf,len,p->fp)!=NULL) {
405
406
407
408
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
409
410
411
412
		if(p->etx) {
			cp=strchr(buf,p->etx);
			if(cp) *cp=0; 
		}
413
414
		if(p->rot13)
			rot13(buf);
415
		JS_RESUMEREQUEST(cx, rc);
416
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
417
			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
418
419
	} else {
		JS_RESUMEREQUEST(cx, rc);
420
421
422
423
424
425
	}

	return(JS_TRUE);
}

static JSBool
426
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
427
{
428
429
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
430
431
432
	BYTE		*b;
	WORD		*w;
	DWORD		*l;
433
434
	size_t		size=sizeof(DWORD);
	private_t*	p;
435
436
437
	size_t		count=1;
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
438
	size_t		i;
439
440
    JSObject*	array;
    jsval       v;
deuce's avatar
deuce committed
441
	jsrefcount	rc;
442

443
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
444

445
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
446
		JS_ReportError(cx,getprivate_failure,WHERE);
447
		return(JS_FALSE);
448
	}
449
450
451
452

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

453
454
455
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],(int32*)&size))
			return(JS_FALSE);
456
457
458
459
		if(argc>1) {
			if(!JS_ValueToInt32(cx,argv[1],(int32*)&count))
				return(JS_FALSE);
		}
460
	}
461

462
	rc=JS_SUSPENDREQUEST(cx);
463
464
465
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
466
		JS_RESUMEREQUEST(cx, rc);
467
468
469
470
471
472
		return(JS_TRUE);
	}

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
473
		JS_RESUMEREQUEST(cx, rc);
474
475
476
477
478
479
480
481
482
483
		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):
484
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
485
486
					break;
				case sizeof(WORD):
487
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
488
489
					break;
				case sizeof(DWORD):
490
					JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
491
					break;
492
			}
493
494
495
		}
	}
	else {
496
		JS_RESUMEREQUEST(cx, rc);
497
498
499
500
501
502
503
504
505
506
507
    	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):
508
					v=UINT_TO_JSVAL(*(l++));
509
					break;
510
			}
deuce's avatar
deuce committed
511
        	if(!JS_SetElement(cx, array, i, &v)) {
512
				rc=JS_SUSPENDREQUEST(cx);
513
				goto end;
deuce's avatar
deuce committed
514
			}
515
		}
516
    	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
517
	}
518
519
520

end:
	free(buffer);
521
	JS_RESUMEREQUEST(cx, rc);
522
523
524
525
	return(JS_TRUE);
}

static JSBool
526
js_readall(JSContext *cx, uintN argc, jsval *arglist)
527
{
528
529
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
530
531
    jsint       len=0;
    JSObject*	array;
532
533
	private_t*	p;

534
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
535

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

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

544
    array = JS_NewArrayObject(cx, 0, NULL);
545

546
    while(!feof(p->fp)) {
547
548
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
549
			break;
550
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
551
			break;
552
	}
553
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
554

555
556
    return(JS_TRUE);
}
557

558
559
560
561
562
563
564
565
566
567
568
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++) {
569
		if(*p=='.' && !f)
570
571
572
573
			f=TRUE;
		else if(!isdigit(*p))
			break;
	}
574
575
576
577
578
	if(*p==0) {
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
579
580
581
582
583
584
585
586
		return(val);
	}
	/* hexadecimal number? */
	if(!strncmp(value,"0x",2)) {	
		for(p=value+2;*p;p++)
			if(!isxdigit(*p))
				break;
		if(*p==0) {	
587
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,0));
588
589
590
591
592
593
594
595
596
597
598
599
600
			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)));
}

601
static JSBool
602
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
603
{
604
605
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
606
	char*	section=ROOT_SECTION;
607
	char*	key;
608
	char**	list;
609
	char	buf[INI_MAX_VALUE_LEN];
610
611
	int32	i;
	jsval	val;
612
613
	jsval	dflt=argv[2];
	private_t*	p;
614
	JSObject*	array;
615
616
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
617
618
619
620
621
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
	char*		cstr;
	char*		cstr2;
622
623
624
625
626
627

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

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

631
632
	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		section=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
633
	key=JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
634
635

	if(dflt==JSVAL_VOID) {	/* unspecified default value */
636
		rc=JS_SUSPENDREQUEST(cx);
637
		JS_SET_RVAL(cx, arglist,get_value(cx,iniReadString(p->fp,section,key,NULL,buf)));
638
		JS_RESUMEREQUEST(cx, rc);
639
640
641
		return(JS_TRUE);
	}

642
643
	switch(JSVAL_TAG(dflt)) {
		case JSVAL_BOOLEAN:
644
645
			JS_SET_RVAL(cx,arglist,BOOLEAN_TO_JSVAL(
				iniReadBool(p->fp,section,key,JSVAL_TO_BOOLEAN(dflt))));
646
647
			break;
		case JSVAL_DOUBLE:
648
			rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
649
			dbl=iniReadFloat(p->fp,section,key,*JSVAL_TO_DOUBLE(dflt));
650
			JS_RESUMEREQUEST(cx, rc);
651
			JS_SET_RVAL(cx, arglist,DOUBLE_TO_JSVAL(dbl));
652
			break;
653
		case JSVAL_OBJECT:
654
			if((dflt_obj = JSVAL_TO_OBJECT(dflt))!=NULL && js_DateIsValid(cx, dflt_obj)) {
deuce's avatar
deuce committed
655
				tt=(time_t)(js_DateGetMsecSinceEpoch(cx,dflt_obj)/1000.0);
656
				rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
657
				dbl=iniReadDateTime(p->fp,section,key,tt);
658
				JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
659
				date_obj = js_NewDateObjectMsec(cx, dbl);
660
				if(date_obj!=NULL)
661
					JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(date_obj));
662
663
				break;
			}
664
		    array = JS_NewArrayObject(cx, 0, NULL);
deuce's avatar
deuce committed
665
			cstr=JS_GetStringBytes(JS_ValueToString(cx,dflt));
666
			rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
667
			list=iniReadStringList(p->fp,section,key,",",cstr);
668
			JS_RESUMEREQUEST(cx, rc);
669
670
671
672
673
			for(i=0;list && list[i];i++) {
				val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
				if(!JS_SetElement(cx, array, i, &val))
					break;
			}
674
			rc=JS_SUSPENDREQUEST(cx);
675
			iniFreeStringList(list);
676
			JS_RESUMEREQUEST(cx, rc);
677
			JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
678
			break;
679
		default:
680
			if(JSVAL_IS_NUMBER(dflt)) {
681
682
				if(!JS_ValueToInt32(cx,dflt,&i))
					return(JS_FALSE);
683
				rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
684
				i=iniReadInteger(p->fp,section,key,i);
685
				JS_RESUMEREQUEST(cx, rc);
686
				JS_SET_RVAL(cx, arglist,INT_TO_JSVAL(i));
deuce's avatar
deuce committed
687
688
			} else {
				cstr=JS_GetStringBytes(JS_ValueToString(cx,dflt));
689
				rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
690
				cstr2=iniReadString(p->fp,section,key,cstr,buf);
691
				JS_RESUMEREQUEST(cx, rc);
692
				JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, cstr2)));
deuce's avatar
deuce committed
693
			}
694
695
696
697
698
699
			break;
	}

	return(JS_TRUE);
}

700
static JSBool
701
js_iniSetValue(JSContext *cx, uintN argc, jsval *arglist)
702
{
703
704
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
705
	char*	section=ROOT_SECTION;
706
707
708
709
710
711
	char*	key;
	char*	result=NULL;
	int32	i;
	jsval	value=argv[2];
	private_t*	p;
	str_list_t	list;
712
	JSObject*	value_obj;
deuce's avatar
deuce committed
713
714
715
	jsrefcount	rc;
	char*		cstr;
	time_t		tt;
716

717
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
718
719
720
721
722
723

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

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

727
728
	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		section=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
729
730
	key=JS_GetStringBytes(JS_ValueToString(cx, argv[1]));

731
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
732
	if((list=iniReadFile(p->fp))==NULL) {
733
		JS_RESUMEREQUEST(cx, rc);
734
		return(JS_TRUE);
deuce's avatar
deuce committed
735
	}
736
	JS_RESUMEREQUEST(cx, rc);
737

deuce's avatar
deuce committed
738
	if(value==JSVAL_VOID) { 	/* unspecified value */
739
		rc=JS_SUSPENDREQUEST(cx);
740
		result = iniSetString(&list,section,key,"",NULL);
741
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
742
	}
743
744
745
746
747
748
749
	else {

		switch(JSVAL_TAG(value)) {
			case JSVAL_BOOLEAN:
				result = iniSetBool(&list,section,key,JSVAL_TO_BOOLEAN(value),NULL);
				break;
			case JSVAL_DOUBLE:
750
				result = iniSetFloat(&list,section,key,JSVAL_TO_DOUBLE(value),NULL);
751
752
753
				break;
			default:
				if(JSVAL_IS_NUMBER(value)) {
754
755
					if(!JS_ValueToInt32(cx,value,&i))
						return(JS_FALSE);
756
					rc=JS_SUSPENDREQUEST(cx);
757
					result = iniSetInteger(&list,section,key,i,NULL);
758
					JS_RESUMEREQUEST(cx, rc);
759
760
761
762
				} else {
					if(JSVAL_IS_OBJECT(value) 
						&& (value_obj = JSVAL_TO_OBJECT(value))!=NULL
						&& js_DateIsValid(cx, value_obj)) {
deuce's avatar
deuce committed
763
						tt=(time_t)(js_DateGetMsecSinceEpoch(cx,value_obj)/1000.0);
764
						rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
765
						result = iniSetDateTime(&list,section,key,/* include_time */TRUE, tt,NULL);
766
						JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
767
768
					} else {
						cstr=JS_GetStringBytes(JS_ValueToString(cx,value));
769
						rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
770
						result = iniSetString(&list,section,key, cstr,NULL);
771
						JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
772
					}
773
				}
774
775
776
777
				break;
		}
	}

778
	rc=JS_SUSPENDREQUEST(cx);
779
	if(result != NULL)
780
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list)));
781
782

	strListFree(&list);
783
	JS_RESUMEREQUEST(cx, rc);
784
785
786
787

	return(JS_TRUE);
}

788
static JSBool
789
js_iniRemoveKey(JSContext *cx, uintN argc, jsval *arglist)
790
{
791
792
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
793
794
795
796
	char*	section=ROOT_SECTION;
	char*	key;
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
797
	jsrefcount	rc;
798

799
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
800
801
802
803
804
805
806
807
808
809
810
811
812

	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)
		section=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
	key=JS_GetStringBytes(JS_ValueToString(cx, argv[1]));

813
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
814
	if((list=iniReadFile(p->fp))==NULL) {
815
		JS_RESUMEREQUEST(cx, rc);
816
		return(JS_TRUE);
deuce's avatar
deuce committed
817
	}
818
819

	if(iniRemoveKey(&list,section,key))
820
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list)));
821
822

	strListFree(&list);
823
	JS_RESUMEREQUEST(cx, rc);
824
825
826
827
828

	return(JS_TRUE);
}

static JSBool
829
js_iniRemoveSection(JSContext *cx, uintN argc, jsval *arglist)
830
{
831
832
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
833
834
835
	char*	section=ROOT_SECTION;
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
836
	jsrefcount	rc;
837

838
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
839
840
841
842
843
844
845
846
847
848
849
850

	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)
		section=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));

851
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
852
	if((list=iniReadFile(p->fp))==NULL) {
853
		JS_RESUMEREQUEST(cx, rc);
854
		return(JS_TRUE);
deuce's avatar
deuce committed
855
	}
856
857

	if(iniRemoveSection(&list,section))
858
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list)));
859
860

	strListFree(&list);
861
	JS_RESUMEREQUEST(cx, rc);
862
863
864
865

	return(JS_TRUE);
}

866

867
static JSBool
868
js_iniGetSections(JSContext *cx, uintN argc, jsval *arglist)
869
{
870
871
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
872
	char*		prefix=NULL;
873
874
875
876
877
	char**		list;
    jsint       i;
    jsval       val;
    JSObject*	array;
	private_t*	p;
deuce's avatar
deuce committed
878
	jsrefcount	rc;
879

880
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
881
882
883
884
885
886

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

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

890
891
892
	if(argc)
		prefix=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));

893
894
    array = JS_NewArrayObject(cx, 0, NULL);

895
	rc=JS_SUSPENDREQUEST(cx);
896
	list = iniReadSectionList(p->fp,prefix);
897
	JS_RESUMEREQUEST(cx, rc);
898
899
900
901
902
    for(i=0;list && list[i];i++) {
		val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
        if(!JS_SetElement(cx, array, i, &val))
			break;
	}
903
	rc=JS_SUSPENDREQUEST(cx);
904
	iniFreeStringList(list);
905
	JS_RESUMEREQUEST(cx, rc);
906

907
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));