js_file.c 58.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)		*
 *																			*
rswindell's avatar
rswindell committed
11
 * Copyright 2009 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
#include "jsdate.h"	/* Yes, I know this is a private header file */

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

} private_t;

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

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

85
86
87
88
89
90
91
92
/* 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;
93
94
	else
		flags|=O_TEXT;
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
120

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

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

124
125
	return(flags);
}
126
127
128
129
130
131
132

/* File Object Methods */

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

141
	*rval = JSVAL_FALSE;
142

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

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

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

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

	return(JS_TRUE);
}

189
190
191
192
193
194
195
196
static JSBool
js_popen(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		mode="r+";	/* default mode */
	uintN		i;
	jsint		bufsize=2*1024;
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
197
	jsrefcount	rc;
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

	*rval = 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);
			}
			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);

224
	rc=JS_SUSPENDREQUEST(cx);
225
226
227
228
229
230
231
232
233
234
	p->fp=popen(p->name,p->mode);
	if(p->fp!=NULL) {
		p->pipe=TRUE;
		*rval = 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);
	}
235
	JS_RESUMEREQUEST(cx, rc);
236
237
238

	return(JS_TRUE);
}
239
240
241
242
243

static JSBool
js_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	private_t*	p;
deuce's avatar
deuce committed
244
	jsrefcount	rc;
245

246
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
247
		JS_ReportError(cx,getprivate_failure,WHERE);
248
		return(JS_FALSE);
249
	}
250
251
252
253

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

254
	rc=JS_SUSPENDREQUEST(cx);
255
256
257
258
259
260
#ifdef __unix__
	if(p->pipe)
		pclose(p->fp);
	else
#endif
		fclose(p->fp);
261
262
263
264

	dbprintf(FALSE, p, "closed");

	p->fp=NULL; 
265
	JS_RESUMEREQUEST(cx, rc);
266
267
268
269
270

	return(JS_TRUE);
}

static JSBool
271
js_read(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
272
273
{
	char*		cp;
274
	char*		buf;
275
	char*		uubuf;
276
277
	int32		len;
	int32		offset;
278
	int32		uulen;
279
280
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
281
	jsrefcount	rc;
282

283
284
	*rval = JSVAL_NULL;

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

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

293
294
295
296
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
297
		rc=JS_SUSPENDREQUEST(cx);
298
299
300
301
		len=filelength(fileno(p->fp));
		offset=ftell(p->fp);
		if(offset>0)
			len-=offset;
302
		JS_RESUMEREQUEST(cx, rc);
303
304
305
	}
	if(len<0)
		len=512;
306

307
	if((buf=malloc(len+1))==NULL)
308
309
		return(JS_TRUE);

310
	rc=JS_SUSPENDREQUEST(cx);
311
312
313
314
315
316
317
318
	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; 
319
		len=strlen(buf);
320
321
	}

322
323
324
	if(p->rot13)
		rot13(buf);

325
	if(p->uuencoded || p->b64encoded || p->yencoded) {
326
		uulen=len*2;
deuce's avatar
deuce committed
327
		if((uubuf=malloc(uulen))==NULL) {
328
			free(buf);
329
			JS_RESUMEREQUEST(cx, rc);
330
			return(JS_TRUE);
331
		}
332
333
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
334
335
		else if(p->yencoded)
			uulen=yencode(uubuf,uulen,buf,len);
336
337
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
338
		if(uulen>=0) {
339
			free(buf);
340
			buf=uubuf;
341
			len=uulen;
deuce's avatar
deuce committed
342
		}
343
344
		else
			free(uubuf);
345
	}
346
	JS_RESUMEREQUEST(cx, rc);
347

348
	str = JS_NewStringCopyN(cx, buf, len);
349
	free(buf);
350

351
352
353
	if(str==NULL)
		return(JS_FALSE);

354
355
	*rval = STRING_TO_JSVAL(str);

356
	rc=JS_SUSPENDREQUEST(cx);
357
	dbprintf(FALSE, p, "read %u bytes",len);
358
	JS_RESUMEREQUEST(cx, rc);
359
360
361
362
363
		
	return(JS_TRUE);
}

static JSBool
364
js_readln(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
365
{
366
367
	char*		cp;
	char*		buf;
368
	int32		len=512;
369
	JSString*	js_str;
370
	private_t*	p;
deuce's avatar
deuce committed
371
	jsrefcount	rc;
372

373
	*rval = JSVAL_NULL;
374

375
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
376
		JS_ReportError(cx,getprivate_failure,WHERE);
377
		return(JS_FALSE);
378
	}
379
380
381

	if(p->fp==NULL)
		return(JS_TRUE);
382
	
383
384
385
386
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
387

388
	if((buf=alloca(len))==NULL)
389
390
		return(JS_TRUE);

391
	rc=JS_SUSPENDREQUEST(cx);
392
	if(fgets(buf,len,p->fp)!=NULL) {
393
394
395
396
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
397
398
399
400
		if(p->etx) {
			cp=strchr(buf,p->etx);
			if(cp) *cp=0; 
		}
401
402
		if(p->rot13)
			rot13(buf);
403
		JS_RESUMEREQUEST(cx, rc);
404
405
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
			*rval = STRING_TO_JSVAL(js_str);			/* _CrtDbgBreak from _heap_alloc_dbg */
406
407
	} else {
		JS_RESUMEREQUEST(cx, rc);
408
409
410
411
412
413
	}

	return(JS_TRUE);
}

static JSBool
414
js_readbin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
415
{
416
417
418
	BYTE		*b;
	WORD		*w;
	DWORD		*l;
419
420
	size_t		size=sizeof(DWORD);
	private_t*	p;
421
422
423
	size_t		count=1;
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
424
	size_t		i;
425
426
    JSObject*	array;
    jsval       v;
deuce's avatar
deuce committed
427
	jsrefcount	rc;
428

429
	*rval = INT_TO_JSVAL(-1);
430

431
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
432
		JS_ReportError(cx,getprivate_failure,WHERE);
433
		return(JS_FALSE);
434
	}
435
436
437
438

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

439
440
441
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],(int32*)&size))
			return(JS_FALSE);
442
443
444
445
		if(argc>1) {
			if(!JS_ValueToInt32(cx,argv[1],(int32*)&count))
				return(JS_FALSE);
		}
446
	}
447

448
	rc=JS_SUSPENDREQUEST(cx);
449
450
451
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
452
		JS_RESUMEREQUEST(cx, rc);
453
454
455
456
457
458
		return(JS_TRUE);
	}

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
459
		JS_RESUMEREQUEST(cx, rc);
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
		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):
					*rval = INT_TO_JSVAL(*b);
					break;
				case sizeof(WORD):
					*rval = INT_TO_JSVAL(*w);
					break;
				case sizeof(DWORD):
476
					JS_RESUMEREQUEST(cx, rc);
477
					JS_NewNumberValue(cx,*l,rval);
478
					rc=JS_SUSPENDREQUEST(cx);
479
					break;
480
			}
481
482
483
		}
	}
	else {
484
		JS_RESUMEREQUEST(cx, rc);
485
486
487
488
489
490
491
492
493
494
495
496
497
    	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):
					JS_NewNumberValue(cx,*(l++),&v);
					break;
498
			}
deuce's avatar
deuce committed
499
        	if(!JS_SetElement(cx, array, i, &v)) {
500
				rc=JS_SUSPENDREQUEST(cx);
501
				goto end;
deuce's avatar
deuce committed
502
			}
503
504
		}
    	*rval = OBJECT_TO_JSVAL(array);
505
	}
506
507
508

end:
	free(buffer);
509
	JS_RESUMEREQUEST(cx, rc);
510
511
512
513
	return(JS_TRUE);
}

static JSBool
514
js_readall(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
515
{
516
517
518
    jsint       len=0;
    jsval       line;
    JSObject*	array;
519
520
	private_t*	p;

521
522
	*rval = JSVAL_NULL;

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

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

531
    array = JS_NewArrayObject(cx, 0, NULL);
532

533
    while(!feof(p->fp)) {
534
		js_readln(cx, obj, argc, argv, &line);
535
536
		if(line==JSVAL_NULL)
			break;
537
538
        if(!JS_SetElement(cx, array, len++, &line))
			break;
539
	}
540
    *rval = OBJECT_TO_JSVAL(array);
541

542
543
    return(JS_TRUE);
}
544

545
546
547
548
549
550
551
552
553
554
555
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++) {
556
		if(*p=='.' && !f)
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
			f=TRUE;
		else if(!isdigit(*p))
			break;
	}
	if(*p==0) {	
		JS_NewNumberValue(cx, f ? atof(value) : strtoul(value,NULL,10), &val);
		return(val);
	}
	/* hexadecimal number? */
	if(!strncmp(value,"0x",2)) {	
		for(p=value+2;*p;p++)
			if(!isxdigit(*p))
				break;
		if(*p==0) {	
			JS_NewNumberValue(cx,strtoul(value,NULL,0),&val);
			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)));
}

585
static JSBool
586
js_iniGetValue(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
587
{
rswindell's avatar
rswindell committed
588
	char*	section=ROOT_SECTION;
589
	char*	key;
590
	char**	list;
591
	char	buf[INI_MAX_VALUE_LEN];
592
593
	int32	i;
	jsval	val;
594
595
	jsval	dflt=argv[2];
	private_t*	p;
596
	JSObject*	array;
597
598
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
599
600
601
602
603
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
	char*		cstr;
	char*		cstr2;
604
605
606
607
608
609

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

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

613
614
	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		section=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
615
	key=JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
616
617

	if(dflt==JSVAL_VOID) {	/* unspecified default value */
618
		rc=JS_SUSPENDREQUEST(cx);
619
		*rval=get_value(cx,iniReadString(p->fp,section,key,NULL,buf));
620
		JS_RESUMEREQUEST(cx, rc);
621
622
623
		return(JS_TRUE);
	}

624
625
626
	switch(JSVAL_TAG(dflt)) {
		case JSVAL_BOOLEAN:
			*rval = BOOLEAN_TO_JSVAL(
627
				iniReadBool(p->fp,section,key,JSVAL_TO_BOOLEAN(dflt)));
628
629
			break;
		case JSVAL_DOUBLE:
630
			rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
631
			dbl=iniReadFloat(p->fp,section,key,*JSVAL_TO_DOUBLE(dflt));
632
			JS_RESUMEREQUEST(cx, rc);
633
			JS_NewNumberValue(cx
deuce's avatar
deuce committed
634
				,dbl,rval);
635
			break;
636
		case JSVAL_OBJECT:
637
			if((dflt_obj = JSVAL_TO_OBJECT(dflt))!=NULL && js_DateIsValid(cx, dflt_obj)) {
deuce's avatar
deuce committed
638
				tt=(time_t)(js_DateGetMsecSinceEpoch(cx,dflt_obj)/1000.0);
639
				rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
640
				dbl=iniReadDateTime(p->fp,section,key,tt);
641
				JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
642
				date_obj = js_NewDateObjectMsec(cx, dbl);
643
644
645
646
				if(date_obj!=NULL)
					*rval = OBJECT_TO_JSVAL(date_obj);
				break;
			}
647
		    array = JS_NewArrayObject(cx, 0, NULL);
deuce's avatar
deuce committed
648
			cstr=JS_GetStringBytes(JS_ValueToString(cx,dflt));
649
			rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
650
			list=iniReadStringList(p->fp,section,key,",",cstr);
651
			JS_RESUMEREQUEST(cx, rc);
652
653
654
655
656
			for(i=0;list && list[i];i++) {
				val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
				if(!JS_SetElement(cx, array, i, &val))
					break;
			}
657
			rc=JS_SUSPENDREQUEST(cx);
658
			iniFreeStringList(list);
659
			JS_RESUMEREQUEST(cx, rc);
660
661
			*rval = OBJECT_TO_JSVAL(array);
			break;
662
		default:
663
			if(JSVAL_IS_NUMBER(dflt)) {
664
665
				if(!JS_ValueToInt32(cx,dflt,&i))
					return(JS_FALSE);
666
				rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
667
				i=iniReadInteger(p->fp,section,key,i);
668
				JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
669
670
671
				JS_NewNumberValue(cx,i,rval);
			} else {
				cstr=JS_GetStringBytes(JS_ValueToString(cx,dflt));
672
				rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
673
				cstr2=iniReadString(p->fp,section,key,cstr,buf);
674
				JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
675
676
				*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, cstr2));
			}
677
678
679
680
681
682
			break;
	}

	return(JS_TRUE);
}

683
684
685
static JSBool
js_iniSetValue(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
rswindell's avatar
rswindell committed
686
	char*	section=ROOT_SECTION;
687
688
689
690
691
692
	char*	key;
	char*	result=NULL;
	int32	i;
	jsval	value=argv[2];
	private_t*	p;
	str_list_t	list;
693
	JSObject*	value_obj;
deuce's avatar
deuce committed
694
695
696
	jsrefcount	rc;
	char*		cstr;
	time_t		tt;
697
698
699
700
701
702
703
704

	*rval = JSVAL_FALSE;

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

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

708
709
	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		section=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
710
711
	key=JS_GetStringBytes(JS_ValueToString(cx, argv[1]));

712
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
713
	if((list=iniReadFile(p->fp))==NULL) {
714
		JS_RESUMEREQUEST(cx, rc);
715
		return(JS_TRUE);
deuce's avatar
deuce committed
716
	}
717
	JS_RESUMEREQUEST(cx, rc);
718

deuce's avatar
deuce committed
719
	if(value==JSVAL_VOID) { 	/* unspecified value */
720
		rc=JS_SUSPENDREQUEST(cx);
721
		result = iniSetString(&list,section,key,"",NULL);
722
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
723
	}
724
725
726
727
728
729
730
731
732
733
734
	else {

		switch(JSVAL_TAG(value)) {
			case JSVAL_BOOLEAN:
				result = iniSetBool(&list,section,key,JSVAL_TO_BOOLEAN(value),NULL);
				break;
			case JSVAL_DOUBLE:
				result = iniSetFloat(&list,section,key,*JSVAL_TO_DOUBLE(value),NULL);
				break;
			default:
				if(JSVAL_IS_NUMBER(value)) {
735
736
					if(!JS_ValueToInt32(cx,value,&i))
						return(JS_FALSE);
737
					rc=JS_SUSPENDREQUEST(cx);
738
					result = iniSetInteger(&list,section,key,i,NULL);
739
					JS_RESUMEREQUEST(cx, rc);
740
741
742
743
				} else {
					if(JSVAL_IS_OBJECT(value) 
						&& (value_obj = JSVAL_TO_OBJECT(value))!=NULL
						&& js_DateIsValid(cx, value_obj)) {
deuce's avatar
deuce committed
744
						tt=(time_t)(js_DateGetMsecSinceEpoch(cx,value_obj)/1000.0);
745
						rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
746
						result = iniSetDateTime(&list,section,key,/* include_time */TRUE, tt,NULL);
747
						JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
748
749
					} else {
						cstr=JS_GetStringBytes(JS_ValueToString(cx,value));
750
						rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
751
						result = iniSetString(&list,section,key, cstr,NULL);
752
						JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
753
					}
754
				}
755
756
757
758
				break;
		}
	}

759
	rc=JS_SUSPENDREQUEST(cx);
760
761
762
763
	if(result != NULL)
		*rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));

	strListFree(&list);
764
	JS_RESUMEREQUEST(cx, rc);
765
766
767
768

	return(JS_TRUE);
}

769
770
771
772
773
774
775
static JSBool
js_iniRemoveKey(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*	section=ROOT_SECTION;
	char*	key;
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
776
	jsrefcount	rc;
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791

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

792
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
793
	if((list=iniReadFile(p->fp))==NULL) {
794
		JS_RESUMEREQUEST(cx, rc);
795
		return(JS_TRUE);
deuce's avatar
deuce committed
796
	}
797
798
799
800
801

	if(iniRemoveKey(&list,section,key))
		*rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));

	strListFree(&list);
802
	JS_RESUMEREQUEST(cx, rc);
803
804
805
806
807
808
809
810
811
812

	return(JS_TRUE);
}

static JSBool
js_iniRemoveSection(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*	section=ROOT_SECTION;
	private_t*	p;
	str_list_t	list;
deuce's avatar
deuce committed
813
	jsrefcount	rc;
814
815
816
817
818
819
820
821
822
823
824
825
826
827

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

828
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
829
	if((list=iniReadFile(p->fp))==NULL) {
830
		JS_RESUMEREQUEST(cx, rc);
831
		return(JS_TRUE);
deuce's avatar
deuce committed
832
	}
833
834
835
836
837

	if(iniRemoveSection(&list,section))
		*rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));

	strListFree(&list);
838
	JS_RESUMEREQUEST(cx, rc);
839
840
841
842

	return(JS_TRUE);
}

843

844
845
846
static JSBool
js_iniGetSections(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
847
	char*		prefix=NULL;
848
849
850
851
852
	char**		list;
    jsint       i;
    jsval       val;
    JSObject*	array;
	private_t*	p;
deuce's avatar
deuce committed
853
	jsrefcount	rc;
854
855
856
857
858
859
860
861

	*rval = JSVAL_NULL;

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

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

865
866
867
	if(argc)
		prefix=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));

868
869
    array = JS_NewArrayObject(cx, 0, NULL);

870
	rc=JS_SUSPENDREQUEST(cx);
871
	list = iniReadSectionList(p->fp,prefix);
872
	JS_RESUMEREQUEST(cx, rc);
873
874
875
876
877
    for(i=0;list && list[i];i++) {
		val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
        if(!JS_SetElement(cx, array, i, &val))
			break;
	}
878
	rc=JS_SUSPENDREQUEST(cx);
879
	iniFreeStringList(list);
880
	JS_RESUMEREQUEST(cx, rc);
881
882
883
884
885
886
887
888
889

    *rval = OBJECT_TO_JSVAL(array);

    return(JS_TRUE);
}

static JSBool
js_iniGetKeys(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
rswindell's avatar
rswindell committed
890
	char*		section=ROOT_SECTION;
891
892
893
894
895
	char**		list;
    jsint       i;
    jsval       val;
    JSObject*	array;
	private_t*	p;
deuce's avatar
deuce committed
896
	jsrefcount	rc;
897
898
899
900
901
902
903
904

	*rval = JSVAL_NULL;

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

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

908
909
	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		section=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
910
911
    array = JS_NewArrayObject(cx, 0, NULL);

912
	rc=JS_SUSPENDREQUEST(cx);
913
	list = iniReadKeyList(p->fp,section);
914
	JS_RESUMEREQUEST(cx, rc);
915
916
917
918
919
    for(i=0;list && list[i];i++) {
		val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
        if(!JS_SetElement(cx, array, i, &val))
			break;
	}
920
	rc=JS_SUSPENDREQUEST(cx);
921
	iniFreeStringList(list);
922
	JS_RESUMEREQUEST(cx, rc);
923
924
925
926
927
928
929
930
931

    *rval = OBJECT_TO_JSVAL(array);

    return(JS_TRUE);
}

static JSBool
js_iniGetObject(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
rswindell's avatar
rswindell committed
932
	char*		section=ROOT_SECTION;
933
934
935
    jsint       i;
    JSObject*	object;
	private_t*	p;
936
	named_string_t** list;
deuce's avatar
deuce committed
937
	jsrefcount	rc;
938
939
940
941
942
943
944
945

	*rval = JSVAL_NULL;

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

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

949
950
	if(argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
		section=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
951
952
    object = JS_NewObject(cx, NULL, NULL, obj);

953
	rc=JS_SUSPENDREQUEST(cx);
954
	list = iniReadNamedStringList(p->fp,section);
955
	JS_RESUMEREQUEST(cx, rc);
956
    for(i=0;list && list[i];i++) {
957
		JS_DefineProperty(cx, object, list[i]->name
958
			,get_value(cx,list[i]->value)
959
960
961
			,NULL,NULL,JSPROP_ENUMERATE);

	}
962
	rc=JS_SUSPENDREQUEST(cx);
963
	iniFreeNamedStringList(list);
964
	JS_RESUMEREQUEST(cx, rc);
965
966
967
968
969
970

    *rval = OBJECT_TO_JSVAL(object);

    return(JS_TRUE);
}

971
972
973
974
975
976
977
978
979
980
981
982
static JSBool
js_iniSetObject(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
    jsint       i;
    JSObject*	object;
	JSIdArray*	id_array;
	jsval		set_argv[3];

	*rval = JSVAL_FALSE;

	set_argv[0]=argv[0];	/* section */

983
	if(!JSVAL_IS_OBJECT(argv[1]) || argv[1]==JSVAL_NULL)
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
		return(JS_TRUE);

    object = JSVAL_TO_OBJECT(argv[1]);

	if((id_array=JS_Enumerate(cx,object))==NULL)
		return(JS_TRUE);

	for(i=0; i<id_array->length; i++)  {
		/* property */
		JS_IdToValue(cx,id_array->vector[i],&set_argv[1]);	
		/* value */
		JS_GetProperty(cx,object,JS_GetStringBytes(JSVAL_TO_STRING(set_argv[1])),&set_argv[2]);
		if(!js_iniSetValue(cx,obj,3,set_argv,rval))
			break;
	}

1000
1001
	JS_DestroyIdArray(cx,id_array);

1002
1003
1004
1005
    return(JS_TRUE);
}


1006
1007
1008
1009
static JSBool
js_iniGetAllObjects(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
	char*		name="name";
1010
	char*		sec_name;
1011
1012
1013
1014
1015
1016
1017
1018
	char*		prefix=NULL;
	char**		sec_list;
    jsint       i,k;
    jsval       val;
    JSObject*	array;
    JSObject*	object;
	private_t*	p;
	named_string_t** key_list;
deuce's avatar
deuce committed
1019
	jsrefcount	rc;
1020
1021
1022
1023
1024
1025
1026
1027

	*rval = JSVAL_NULL;

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

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

1031
1032
1033
1034
1035
1036
1037
1038
	if(argc)
		name=JS_GetStringBytes(JS_ValueToString(cx, argv[0]));

	if(argc>