js_file.c 78.5 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
39
#include "md5.h"
#include "base64.h"
40
#include "uucode.h"
41
#include "yenc.h"
42
#include "ini_file.h"
43

44
45
46
47
#if !defined(__unix__)
	#include <conio.h>		/* for kbhit() */
#endif

48
49
#ifdef JAVASCRIPT

50
#include "js_request.h"
51

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

} 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);
79
80
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
81
    va_end(argptr);
82

83
	lprintf(LOG_DEBUG,"%04u File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
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
	if(strchr(mode,'x'))
		flags|=O_EXCL;

99
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
	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);
}
126
127
128

/* File Object Methods */

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

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

147
148
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

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

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

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

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

	return(JS_TRUE);
}

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

221
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
222

223
224
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
225
226
227
		return(JS_FALSE);
	}

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

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

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

	return(JS_TRUE);
}
261
262

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

269
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
270
		return(JS_FALSE);
271
	}
272

273
274
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

	dbprintf(FALSE, p, "closed");

288
	p->fp=NULL;
289
	JS_RESUMEREQUEST(cx, rc);
290
291
292
293

	return(JS_TRUE);
}

294
295
296
297
298
299
300
301
302
303
304
305
306
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

307
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
308
309
310
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
		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;
}

360
361
362
363
364
365
366
367
368
369
370
371
372
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);

373
374
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
		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);
394
	if(len<0)
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
		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);
410

411
412
413
414
	return(JS_TRUE);
}


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

430
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
431

432
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
433
		return(JS_FALSE);
434
	}
435

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

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

453
	if((buf=malloc(len+1))==NULL)
454
455
		return(JS_TRUE);

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

	if(p->etx) {
		cp=strchr(buf,p->etx);
464
		if(cp) *cp=0;
465
		len=strlen(buf);
466
467
	}

468
469
470
	if(p->rot13)
		rot13(buf);

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

494
	str = JS_NewStringCopyN(cx, buf, len);
495
	free(buf);
496

497
498
499
	if(str==NULL)
		return(JS_FALSE);

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

502
	rc=JS_SUSPENDREQUEST(cx);
503
	dbprintf(FALSE, p, "read %u bytes",len);
504
	JS_RESUMEREQUEST(cx, rc);
505

506
507
508
509
	return(JS_TRUE);
}

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

521
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
522

523
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
524
		return(JS_FALSE);
525
	}
526
527
528

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

530
531
532
533
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
534

535
	if((buf=malloc(len + 1))==NULL)
deuce's avatar
deuce committed
536
		return(JS_FALSE);
537

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

	return(JS_TRUE);
}

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

579
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
580

581
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
582
		return(JS_FALSE);
583
	}
584
585
586
587

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

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

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

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

end:
	free(buffer);
656
	JS_RESUMEREQUEST(cx, rc);
657
658
659
660
	return(JS_TRUE);
}

static JSBool
661
js_readall(JSContext *cx, uintN argc, jsval *arglist)
662
{
663
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
664
665
    jsint       len=0;
    JSObject*	array;
666
667
	private_t*	p;

668
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
669

670
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
671
		return(JS_FALSE);
672
	}
673

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

677
    array = JS_NewArrayObject(cx, 0, NULL);
678

679
    while(!feof(p->fp)) {
680
681
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
682
			break;
683
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
684
			break;
685
	}
686
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
687

688
689
    return(JS_TRUE);
}
690

691
692
693
694
695
696
697
698
699
700
701
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++) {
702
		if(*p=='.' && !f)
703
			f=TRUE;
704
		else if(!isdigit((uchar)*p))
705
706
			break;
	}
707
708
709
710
711
	if(*p==0) {
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
712
713
714
		return(val);
	}
	/* hexadecimal number? */
715
	if(!strncmp(value,"0x",2)) {
716
		for(p=value+2;*p;p++)
717
			if(!isxdigit((uchar)*p))
718
				break;
719
		if(*p==0) {
720
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,0));
721
722
723
724
725
726
727
728
729
730
731
732
733
			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
734
735
736
737
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
	jsval	rval;

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

744
static JSBool
745
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
746
{
747
748
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
749
	char*	section=ROOT_SECTION;
750
	char*	key;
751
	char**	list;
752
	char	buf[INI_MAX_VALUE_LEN];
753
754
	int32	i;
	jsval	val;
755
756
	jsval	dflt=argv[2];
	private_t*	p;
757
	JSObject*	array;
758
759
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
760
761
762
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
763
	char*		cstr=NULL;
deuce's avatar
deuce committed
764
	char*		cstr2;
765

766
767
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

768
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
769
770
771
		return(JS_FALSE);
	}

772
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
773
774
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
775
	if(JS_IsExceptionPending(cx)) {
776
777
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
deuce's avatar
deuce committed
778
		return JS_FALSE;
779
	}
780
781
782
783
784
785
	/*
	 * Although section can be NULL (ie: root), a NULL key will cause a
	 * segfault.
	 */
	if(key==NULL) {
		JS_ReportError(cx, "Invalid NULL key specified");
786
		FREE_AND_NULL(section);
787
788
		return JS_FALSE;
	}
789

790
	if(argc < 3 || dflt==JSVAL_VOID) {	/* unspecified default value */
791
		rc=JS_SUSPENDREQUEST(cx);
792
		cstr=iniReadString(p->fp,section,key,NULL,buf);
793
794
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
795
		JS_RESUMEREQUEST(cx, rc);
796
		JS_SET_RVAL(cx, arglist, get_value(cx, cstr));
797
798
799
		return(JS_TRUE);
	}

deuce's avatar
deuce committed
800
801
802
803
804
805
806
	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);
807
			rc=JS_SUSPENDREQUEST(cx);
808
			dbl=(double)iniReadDateTime(p->fp,section,key,tt);
deuce's avatar
deuce committed
809
			dbl *= 1000;
810
			JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
811
812
			date_obj = JS_NewDateObjectMsec(cx, dbl);
			if(date_obj!=NULL) {
deuce's avatar
deuce committed
813
				JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(date_obj));
deuce's avatar
deuce committed
814
			}
deuce's avatar
deuce committed
815
816
		}
		else {
817
		    array = JS_NewArrayObject(cx, 0, NULL);
818
			cstr=NULL;
819
			JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
820
			if(JS_IsExceptionPending(cx)) {
821
822
823
				FREE_AND_NULL(cstr);
				FREE_AND_NULL(section);
				FREE_AND_NULL(key);
824
825
				return JS_FALSE;
			}
826
			rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
827
			list=iniReadStringList(p->fp,section,key,",",cstr);
828
			FREE_AND_NULL(cstr);
829
			JS_RESUMEREQUEST(cx, rc);
830
831
832
833
834
			for(i=0;list && list[i];i++) {
				val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
				if(!JS_SetElement(cx, array, i, &val))
					break;
			}
835
			rc=JS_SUSPENDREQUEST(cx);
836
			iniFreeStringList(list);
837
			JS_RESUMEREQUEST(cx, rc);
838
			JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
deuce's avatar
deuce committed
839
840
841
842
843
844
845
846
847
		}
	}
	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)) {
848
		if(!JS_ValueToInt32(cx,dflt,&i)) {
849
850
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
deuce's avatar
deuce committed
851
			return(JS_FALSE);
852
		}
deuce's avatar
deuce committed
853
854
855
856
857
		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 {
858
		cstr=NULL;
859
		JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
860
		if(JS_IsExceptionPending(cx)) {
861
862
863
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
864
865
			return JS_FALSE;
		}
deuce's avatar
deuce committed
866
867
868
869
		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)));
870
		FREE_AND_NULL(cstr);
871
	}
872
873
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
874
875
876
877

	return(JS_TRUE);
}

878
static JSBool
879
js_iniSetValue_internal(JSContext *cx, JSObject *obj, uintN argc, jsval* argv, str_list_t* list)
880
{
rswindell's avatar
rswindell committed
881
	char*	section=ROOT_SECTION;
882
	char*	key=NULL;
883
884
885
886
	char*	result=NULL;
	int32	i;
	jsval	value=argv[2];
	private_t*	p;
887
	JSObject*	value_obj;
deuce's avatar
deuce committed
888
889
890
	jsrefcount	rc;
	char*		cstr;
	time_t		tt;
891

892
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
893
894
895
		return(JS_FALSE);
	}

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

899
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
900
901
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
902
	if(JS_IsExceptionPending(cx)) {
903
904
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
905
906
		return JS_FALSE;
	}
907

deuce's avatar
deuce committed
908
	if(value==JSVAL_VOID) { 	/* unspecified value */
909
		rc=JS_SUSPENDREQUEST(cx);
910
		result = iniSetString(list,section,key,"",&p->ini_style);
911
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
912
	}
deuce's avatar
deuce committed
913
	else if(JSVAL_IS_BOOLEAN(value)) {
914
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),&p->ini_style);
deuce's avatar
deuce committed
915
916
	}
	else if(JSVAL_IS_DOUBLE(value)) {
917
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),&p->ini_style);
deuce's avatar
deuce committed
918
919
	}
	else if(JSVAL_IS_NUMBER(value)) {
920
		if(!JS_ValueToInt32(cx,value,&i)) {
921
922
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
923
924
			return JS_FALSE;
		}
deuce's avatar
deuce committed
925
		rc=JS_SUSPENDREQUEST(cx);
926
		result = iniSetInteger(list,section,key,i,&p->ini_style);
deuce's avatar
deuce committed
927
		JS_RESUMEREQUEST(cx, rc);
928
	} else if(JSVAL_IS_OBJECT(value)
deuce's avatar
deuce committed