js_file.c 79.3 KB
Newer Older
1
/* Synchronet JavaScript "File" Object */
2
// vi: tabstop=4
3
4
5
6
7
8
9

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
10
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
11
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
 *																			*
 * 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"
38
#include "xpendian.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
47
48
#if !defined(__unix__)
	#include <conio.h>		/* for kbhit() */
#endif

49
50
#ifdef JAVASCRIPT

51
#include "js_request.h"
52

53
54
typedef struct
{
55
	FILE*	fp;
56
57
	char	name[MAX_PATH+1];
	char	mode[4];
58
	uchar	etx;
59
60
	BOOL	external;	/* externally created, don't close */
	BOOL	debug;
61
	BOOL	rot13;
62
	BOOL	yencoded;
63
	BOOL	uuencoded;
64
65
	BOOL	b64encoded;
	BOOL	network_byte_order;
66
	BOOL	pipe;		/* Opened with popen() use pclose() to close */
67
	ini_style_t ini_style;
68
69
70
71
72
73
74
75
76
77
78
79

} private_t;

static void dbprintf(BOOL error, private_t* p, char* fmt, ...)
{
	va_list argptr;
	char sbuf[1024];

	if(p==NULL || (!p->debug && !error))
		return;

    va_start(argptr,fmt);
80
81
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
82
    va_end(argptr);
83

84
	lprintf(LOG_DEBUG,"%04u File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
85
86
}

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

97
98
99
	if(strchr(mode,'x'))
		flags|=O_EXCL;

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
	if(strchr(mode,'w')) {
		flags|=O_CREAT|O_TRUNC;
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_WRONLY;
		return(flags);
	}

	if(strchr(mode,'a')) {
		flags|=O_CREAT|O_APPEND;
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_WRONLY;
		return(flags);
	}

	if(strchr(mode,'r')) {
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_RDONLY;
	}

	return(flags);
}
127
128
129

/* File Object Methods */

130
extern JSClass js_file_class;
131
static JSBool
132
js_open(JSContext *cx, uintN argc, jsval *arglist)
133
{
134
135
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
136
	BOOL		shareable=FALSE;
137
	int			file = -1;
138
	uintN		i;
139
	jsint		bufsize=2*1024;
140
141
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
142
	jsrefcount	rc;
143

144
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
145
		return(JS_FALSE);
146
	}
147

148
149
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

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

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

170
	rc=JS_SUSPENDREQUEST(cx);
171
172
173
174
	if(shareable)
		p->fp=fopen(p->name,p->mode);
	else {
		if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
175
176
177
178
			char *fdomode=strdup(p->mode);
			char *e=fdomode;

			if(fdomode && e) {
179
180
				/* Remove deprecated (never-worked, non-standard) 'e'xclusive mode char (and warn): */
				for(e=strchr(fdomode, 'e'); e ; e=strchr(e, 'e')) {
181
					JS_ReportWarning(cx, "Deprecated file open mode: 'e'");
182
183
184
185
					memmove(e, e+1, strlen(e));
				}
				/* Remove (C11 standard) 'x'clusive mode char to avoid MSVC assertion: */
				for(e=strchr(fdomode, 'x'); e ; e=strchr(e, 'x'))
186
					memmove(e, e+1, strlen(e));
187
188
189
				if((p->fp=fdopen(file,fdomode)) == NULL) {
					JS_ReportWarning(cx, "fdopen(%s, %s) ERROR %d: %s", p->name, fdomode, errno, strerror(errno));
				}
190
191
			}
			free(fdomode);
192
193
		}
	}
194
	if(p->fp!=NULL) {
195
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
196
		dbprintf(FALSE, p, "opened: %s",p->name);
197
198
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
199
200
201
202
203
		else {
#ifdef _WIN32
			if(bufsize < 2)
				bufsize = 2;
#endif
204
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
205
		}
206
207
	} else if(file >= 0)
		close(file);
208
	JS_RESUMEREQUEST(cx, rc);
209
210
211
212

	return(JS_TRUE);
}

213
static JSBool
214
js_popen(JSContext *cx, uintN argc, jsval *arglist)
215
{
216
217
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
218
219
220
221
	uintN		i;
	jsint		bufsize=2*1024;
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
222
	jsrefcount	rc;
223

224
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
225

226
227
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
228
229
230
		return(JS_FALSE);
	}

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

234
	SAFECOPY(p->mode,"r+");	/* default mode */
235
236
237
238
239
240
	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);
			}
241
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
242
243
244
245
246
247
248
		}
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
	}

249
	rc=JS_SUSPENDREQUEST(cx);
250
251
252
	p->fp=popen(p->name,p->mode);
	if(p->fp!=NULL) {
		p->pipe=TRUE;
253
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
254
255
256
257
258
259
		dbprintf(FALSE, p, "popened: %s",p->name);
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
		else
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
	}
260
	JS_RESUMEREQUEST(cx, rc);
261
262
263

	return(JS_TRUE);
}
264
265

static JSBool
266
js_close(JSContext *cx, uintN argc, jsval *arglist)
267
{
268
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
269
	private_t*	p;
deuce's avatar
deuce committed
270
	jsrefcount	rc;
271

272
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
273
		return(JS_FALSE);
274
	}
275

276
277
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

281
	rc=JS_SUSPENDREQUEST(cx);
282
283
284
285
286
287
#ifdef __unix__
	if(p->pipe)
		pclose(p->fp);
	else
#endif
		fclose(p->fp);
288
289
290

	dbprintf(FALSE, p, "closed");

291
	p->fp=NULL;
292
	JS_RESUMEREQUEST(cx, rc);
293
294
295
296

	return(JS_TRUE);
}

297
298
299
300
301
302
303
304
305
306
307
308
309
static JSBool
js_raw_pollin(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	private_t*	p;
	jsrefcount	rc;
	int32		timeout = -1;
#ifdef __unix__
	fd_set		rd;
	struct	timeval tv = {0, 0};
#endif

310
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
		return(JS_FALSE);
	}

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

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

	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(FALSE));
	rc=JS_SUSPENDREQUEST(cx);
#ifdef __unix__
	if (timeout >= 0) {
		tv.tv_sec = timeout / 1000;
		tv.tv_usec = (timeout%1000)*1000;
	}
	FD_ZERO(&rd);
	FD_SET(fileno(p->fp), &rd);
	if (select(fileno(p->fp)+1, &rd, NULL, NULL, timeout < 0 ? NULL : &tv) == 1)
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
#else
	while(timeout) {
		if (isatty(fileno(p->fp))) {
			if (kbhit()) {
				JS_RESUMEREQUEST(cx, rc);
				JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
				rc=JS_SUSPENDREQUEST(cx);
				break;
			}
			SLEEP(1);
			if (timeout > 0)
				timeout--;
		}
		else {
			if (!eof(fileno(p->fp))) {
				JS_RESUMEREQUEST(cx, rc);
				JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
				rc=JS_SUSPENDREQUEST(cx);
				break;
			}
			SLEEP(1);
			if (timeout > 0)
				timeout--;
		}
	}
#endif
	JS_RESUMEREQUEST(cx, rc);
	return JS_TRUE;
}

363
364
365
366
367
368
369
370
371
372
373
374
375
static JSBool
js_raw_read(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	char*		buf;
	int32		len;
	JSString*	str;
	private_t*	p;
	jsrefcount	rc;

	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

376
377
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
		return(JS_FALSE);
	}

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

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

	if((buf=malloc(len))==NULL)
		return(JS_TRUE);

	rc=JS_SUSPENDREQUEST(cx);
	len = read(fileno(p->fp),buf,len);
397
	if(len<0)
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
		len=0;

	JS_RESUMEREQUEST(cx, rc);

	str = JS_NewStringCopyN(cx, buf, len);
	free(buf);

	if(str==NULL)
		return(JS_FALSE);

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

	rc=JS_SUSPENDREQUEST(cx);
	dbprintf(FALSE, p, "read %u raw bytes",len);
	JS_RESUMEREQUEST(cx, rc);
413

414
415
416
417
	return(JS_TRUE);
}


418
static JSBool
419
js_read(JSContext *cx, uintN argc, jsval *arglist)
420
{
421
422
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
423
	char*		cp;
424
	char*		buf;
425
	char*		uubuf;
426
427
	int32		len;
	int32		offset;
428
	int32		uulen;
429
430
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
431
	jsrefcount	rc;
432

433
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
434

435
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
436
		return(JS_FALSE);
437
	}
438

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

442
443
444
445
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
446
		rc=JS_SUSPENDREQUEST(cx);
447
448
		len=(long)filelength(fileno(p->fp));
		offset=(long)ftell(p->fp);
449
450
		if(offset>0)
			len-=offset;
451
		JS_RESUMEREQUEST(cx, rc);
452
453
454
	}
	if(len<0)
		len=512;
455

456
	if((buf=malloc(len+1))==NULL)
457
458
		return(JS_TRUE);

459
	rc=JS_SUSPENDREQUEST(cx);
460
	len = fread(buf,1,len,p->fp);
461
	if(len<0)
462
463
464
465
466
		len=0;
	buf[len]=0;

	if(p->etx) {
		cp=strchr(buf,p->etx);
467
		if(cp) *cp=0;
468
		len=strlen(buf);
469
470
	}

471
472
473
	if(p->rot13)
		rot13(buf);

474
	if(p->uuencoded || p->b64encoded || p->yencoded) {
475
		uulen=len*2;
deuce's avatar
deuce committed
476
		if((uubuf=malloc(uulen))==NULL) {
477
			free(buf);
478
			JS_RESUMEREQUEST(cx, rc);
479
			return(JS_TRUE);
480
		}
481
482
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
483
484
		else if(p->yencoded)
			uulen=yencode(uubuf,uulen,buf,len);
485
486
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
487
		if(uulen>=0) {
488
			free(buf);
489
			buf=uubuf;
490
			len=uulen;
deuce's avatar
deuce committed
491
		}
492
493
		else
			free(uubuf);
494
	}
495
	JS_RESUMEREQUEST(cx, rc);
496

497
	str = JS_NewStringCopyN(cx, buf, len);
498
	free(buf);
499

500
501
502
	if(str==NULL)
		return(JS_FALSE);

503
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
504

505
	rc=JS_SUSPENDREQUEST(cx);
506
	dbprintf(FALSE, p, "read %u bytes",len);
507
	JS_RESUMEREQUEST(cx, rc);
508

509
510
511
512
	return(JS_TRUE);
}

static JSBool
513
js_readln(JSContext *cx, uintN argc, jsval *arglist)
514
{
515
516
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
517
518
	char*		cp;
	char*		buf;
519
	int32		len=512;
520
	JSString*	js_str;
521
	private_t*	p;
deuce's avatar
deuce committed
522
	jsrefcount	rc;
523

524
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
525

526
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
527
		return(JS_FALSE);
528
	}
529
530
531

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

533
534
535
536
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
537

538
	if((buf=malloc(len + 1))==NULL)
deuce's avatar
deuce committed
539
		return(JS_FALSE);
540

541
	rc=JS_SUSPENDREQUEST(cx);
542
	if(fgets(buf,len + 1,p->fp)!=NULL) {
543
544
545
546
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
547
548
		if(p->etx) {
			cp=strchr(buf,p->etx);
549
			if(cp) *cp=0;
550
		}
551
552
		if(p->rot13)
			rot13(buf);
553
		JS_RESUMEREQUEST(cx, rc);
554
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
555
			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
556
557
	} else {
		JS_RESUMEREQUEST(cx, rc);
558
	}
deuce's avatar
deuce committed
559
	free(buf);
560
561
562
563
564

	return(JS_TRUE);
}

static JSBool
565
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
566
{
567
568
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
569
570
571
	BYTE		*b;
	WORD		*w;
	DWORD		*l;
572
	int32		size=sizeof(DWORD);
573
	private_t*	p;
574
	int32		count=1;
575
576
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
577
	size_t		i;
578
579
    JSObject*	array;
    jsval       v;
deuce's avatar
deuce committed
580
	jsrefcount	rc;
581

582
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
583

584
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
585
		return(JS_FALSE);
586
	}
587
588
589
590

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

591
	if(argc) {
592
		if(!JS_ValueToInt32(cx,argv[0],&size))
593
			return(JS_FALSE);
594
		if(argc>1) {
595
			if(!JS_ValueToInt32(cx,argv[1],&count))
596
597
				return(JS_FALSE);
		}
598
	}
599

600
	rc=JS_SUSPENDREQUEST(cx);
601
602
603
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
604
		JS_RESUMEREQUEST(cx, rc);
605
606
607
608
609
610
		return(JS_TRUE);
	}

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
611
		JS_RESUMEREQUEST(cx, rc);
612
613
614
615
616
617
618
619
620
621
		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):
622
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
623
624
					break;
				case sizeof(WORD):
625
626
627
628
					if (p->network_byte_order)
						*w = BE_SHORT(*w);
					else
						*w = LE_SHORT(*w);
629
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
630
631
					break;
				case sizeof(DWORD):
632
633
634
635
					if (p->network_byte_order)
						*l = BE_LONG(*l);
					else
						*l = LE_LONG(*l);
636
					JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
637
					break;
638
			}
639
640
641
		}
	}
	else {
642
		JS_RESUMEREQUEST(cx, rc);
643
644
645
646
647
648
649
650
    	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):
651
652
653
654
					if (p->network_byte_order)
						*w = BE_SHORT(*w);
					else
						*w = LE_SHORT(*w);
655
656
657
					v = INT_TO_JSVAL(*(w++));
					break;
				case sizeof(DWORD):
658
659
660
661
					if (p->network_byte_order)
						*l = BE_LONG(*l);
					else
						*l = LE_LONG(*l);
662
					v=UINT_TO_JSVAL(*(l++));
663
					break;
664
			}
deuce's avatar
deuce committed
665
        	if(!JS_SetElement(cx, array, i, &v)) {
666
				rc=JS_SUSPENDREQUEST(cx);
667
				goto end;
deuce's avatar
deuce committed
668
			}
669
		}
670
    	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
671
	}
672
673
674

end:
	free(buffer);
675
	JS_RESUMEREQUEST(cx, rc);
676
677
678
679
	return(JS_TRUE);
}

static JSBool
680
js_readall(JSContext *cx, uintN argc, jsval *arglist)
681
{
682
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
683
684
    jsint       len=0;
    JSObject*	array;
685
686
	private_t*	p;

687
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
688

689
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
690
		return(JS_FALSE);
691
	}
692

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

696
    array = JS_NewArrayObject(cx, 0, NULL);
697

698
    while(!feof(p->fp)) {
699
700
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
701
			break;
702
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
703
			break;
704
	}
705
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
706

707
708
    return(JS_TRUE);
}
709

710
711
712
713
714
715
716
717
718
719
720
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++) {
721
		if(*p=='.' && !f)
722
			f=TRUE;
723
		else if(!isdigit((uchar)*p))
724
725
			break;
	}
726
727
728
729
730
	if(*p==0) {
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
731
732
733
		return(val);
	}
	/* hexadecimal number? */
734
	if(!strncmp(value,"0x",2)) {
735
		for(p=value+2;*p;p++)
736
			if(!isxdigit((uchar)*p))
737
				break;
738
		if(*p==0) {
739
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,0));
740
741
742
743
744
745
746
747
748
749
750
751
752
			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
753
754
755
756
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
	jsval	rval;

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

763
static JSBool
764
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
765
{
766
767
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
768
	char*	section=ROOT_SECTION;
769
	char*	key;
770
	char**	list;
771
	char	buf[INI_MAX_VALUE_LEN];
772
773
	int32	i;
	jsval	val;
774
775
	jsval	dflt=argv[2];
	private_t*	p;
776
	JSObject*	array;
777
778
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
779
780
781
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
782
	char*		cstr=NULL;
deuce's avatar
deuce committed
783
	char*		cstr2;
784

785
786
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

787
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
788
789
790
		return(JS_FALSE);
	}

791
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
792
793
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
794
	if(JS_IsExceptionPending(cx)) {
795
796
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
deuce's avatar
deuce committed
797
		return JS_FALSE;
798
	}
799
800
801
802
803
804
	/*
	 * Although section can be NULL (ie: root), a NULL key will cause a
	 * segfault.
	 */
	if(key==NULL) {
		JS_ReportError(cx, "Invalid NULL key specified");
805
		FREE_AND_NULL(section);
806
807
		return JS_FALSE;
	}
808

809
	if(argc < 3 || dflt==JSVAL_VOID) {	/* unspecified default value */
810
		rc=JS_SUSPENDREQUEST(cx);
811
		cstr=iniReadString(p->fp,section,key,NULL,buf);
812
813
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
814
		JS_RESUMEREQUEST(cx, rc);
815
		JS_SET_RVAL(cx, arglist, get_value(cx, cstr));
816
817
818
		return(JS_TRUE);
	}

deuce's avatar
deuce committed
819
820
821
822
823
824
825
	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);
826
			rc=JS_SUSPENDREQUEST(cx);
827
			dbl=(double)iniReadDateTime(p->fp,section,key,tt);
deuce's avatar
deuce committed
828
			dbl *= 1000;
829
			JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
830
831
			date_obj = JS_NewDateObjectMsec(cx, dbl);
			if(date_obj!=NULL) {
deuce's avatar
deuce committed
832
				JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(date_obj));
deuce's avatar
deuce committed
833
			}
deuce's avatar
deuce committed
834
835
		}
		else {
836
		    array = JS_NewArrayObject(cx, 0, NULL);
837
			cstr=NULL;
838
			JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
839
			if(JS_IsExceptionPending(cx)) {
840
841
842
				FREE_AND_NULL(cstr);
				FREE_AND_NULL(section);
				FREE_AND_NULL(key);
843
844
				return JS_FALSE;
			}
845
			rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
846
			list=iniReadStringList(p->fp,section,key,",",cstr);
847
			FREE_AND_NULL(cstr);
848
			JS_RESUMEREQUEST(cx, rc);
849
850
851
852
853
			for(i=0;list && list[i];i++) {
				val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
				if(!JS_SetElement(cx, array, i, &val))
					break;
			}
854
			rc=JS_SUSPENDREQUEST(cx);
855
			iniFreeStringList(list);
856
			JS_RESUMEREQUEST(cx, rc);
857
			JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
deuce's avatar
deuce committed
858
859
860
861
862
863
864
865
866
		}
	}
	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)) {
867
		if(!JS_ValueToInt32(cx,dflt,&i)) {
868
869
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
deuce's avatar
deuce committed
870
			return(JS_FALSE);
871
		}
deuce's avatar
deuce committed
872
873
874
875
876
		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 {
877
		cstr=NULL;
878
		JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
879
		if(JS_IsExceptionPending(cx)) {
880
881
882
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
883
884
			return JS_FALSE;
		}
deuce's avatar
deuce committed
885
886
887
888
		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)));
889
		FREE_AND_NULL(cstr);
890
	}
891
892
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
893
894
895
896

	return(JS_TRUE);
}

897
static JSBool
898
js_iniSetValue_internal(JSContext *cx, JSObject *obj, uintN argc, jsval* argv, str_list_t* list)
899
{
rswindell's avatar
rswindell committed
900
	char*	section=ROOT_SECTION;
901
	char*	key=NULL;
902
903
904
905
	char*	result=NULL;
	int32	i;
	jsval	value=argv[2];
	private_t*	p;
906
	JSObject*	value_obj;
deuce's avatar
deuce committed
907
908
909
	jsrefcount	rc;
	char*		cstr;
	time_t		tt;
910

911
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
912
913
914
		return(JS_FALSE);
	}

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

918
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
919
920
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
921
	if(JS_IsExceptionPending(cx)) {
922
923
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
924
925
		return JS_FALSE;
	}
926

deuce's avatar
deuce committed
927
	if(value==JSVAL_VOID) { 	/* unspecified value */
928
		rc=JS_SUSPENDREQUEST(cx);
929
		result = iniSetString(list,section,key,"",&p->ini_style);
930
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
931
	}
deuce's avatar
deuce committed
932
	else if(JSVAL_IS_BOOLEAN(value)) {
933
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),&p->ini_style);
deuce's avatar
deuce committed
934
935
	}
	else if(JSVAL_IS_DOUBLE(value)) {
936
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),&p->ini_style);
deuce's avatar
deuce committed
<