js_file.c 78.2 KB
Newer Older
1
2
3
4
5
6
/* Synchronet JavaScript "File" Object */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *																			*
 * 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										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"
23
#include "xpendian.h"
24
25
#include "md5.h"
#include "base64.h"
26
#include "uucode.h"
27
#include "yenc.h"
28
#include "ini_file.h"
29
#include <stdbool.h>
30

31
32
33
34
#if !defined(__unix__)
	#include <conio.h>		/* for kbhit() */
#endif

35
36
#ifdef JAVASCRIPT

37
#include "js_request.h"
38

39
40
typedef struct
{
41
	FILE*	fp;
42
43
	char	name[MAX_PATH+1];
	char	mode[4];
44
	uchar	etx;
45
	BOOL	debug;
46
	BOOL	rot13;
47
	BOOL	yencoded;
48
	BOOL	uuencoded;
49
50
	BOOL	b64encoded;
	BOOL	network_byte_order;
51
	BOOL	pipe;		/* Opened with popen() use pclose() to close */
52
	ini_style_t ini_style;
53
54
55
56
57
58
59
60
61
62
63
64

} 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);
65
66
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
67
    va_end(argptr);
68

69
	lprintf(LOG_DEBUG,"%04d File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
70
71
}

72
73
74
75
76
77
78
/* 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;
79
80
	else
		flags|=O_TEXT;
81

82
83
84
	if(strchr(mode,'x'))
		flags|=O_EXCL;

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
	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);
}
112
113
114

/* File Object Methods */

115
extern JSClass js_file_class;
116
static JSBool
117
js_open(JSContext *cx, uintN argc, jsval *arglist)
118
{
119
120
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
121
	BOOL		shareable=FALSE;
122
	int			file = -1;
123
	uintN		i;
124
	jsint		bufsize=2*1024;
125
126
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
127
	jsrefcount	rc;
128

129
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
130
		return(JS_FALSE);
131
	}
132

133
134
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

135
	if(p->fp!=NULL)
136
		return(JS_TRUE);
137

138
	SAFECOPY(p->mode,"w+");		/* default mode */
139
140
141
	for(i=0;i<argc;i++) {
		if(JSVAL_IS_STRING(argv[i])) {	/* mode */
			if((str = JS_ValueToString(cx, argv[i]))==NULL) {
142
143
				JS_ReportError(cx,"Invalid mode specified: %s",str);
				return(JS_TRUE);
144
			}
145
146
147
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
		}
		else if(JSVAL_IS_BOOLEAN(argv[i]))	/* shareable */
148
			shareable=JSVAL_TO_BOOLEAN(argv[i]);
149
150
151
152
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
153
154
	}

155
	rc=JS_SUSPENDREQUEST(cx);
156
157
158
159
	if(shareable)
		p->fp=fopen(p->name,p->mode);
	else {
		if((file=nopen(p->name,fopenflags(p->mode)))!=-1) {
160
161
162
163
			char *fdomode=strdup(p->mode);
			char *e=fdomode;

			if(fdomode && e) {
164
165
				/* Remove deprecated (never-worked, non-standard) 'e'xclusive mode char (and warn): */
				for(e=strchr(fdomode, 'e'); e ; e=strchr(e, 'e')) {
166
					JS_ReportWarning(cx, "Deprecated file open mode: 'e'");
167
168
169
170
					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'))
171
					memmove(e, e+1, strlen(e));
172
173
174
				if((p->fp=fdopen(file,fdomode)) == NULL) {
					JS_ReportWarning(cx, "fdopen(%s, %s) ERROR %d: %s", p->name, fdomode, errno, strerror(errno));
				}
175
176
			}
			free(fdomode);
177
178
		}
	}
179
	if(p->fp!=NULL) {
180
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
181
		dbprintf(FALSE, p, "opened: %s",p->name);
182
183
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
184
185
186
187
188
		else {
#ifdef _WIN32
			if(bufsize < 2)
				bufsize = 2;
#endif
189
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
190
		}
191
192
	} else if(file >= 0)
		close(file);
193
	JS_RESUMEREQUEST(cx, rc);
194
195
196
197

	return(JS_TRUE);
}

198
static JSBool
199
js_popen(JSContext *cx, uintN argc, jsval *arglist)
200
{
201
202
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
203
204
205
206
	uintN		i;
	jsint		bufsize=2*1024;
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
207
	jsrefcount	rc;
208

209
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
210

211
212
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
213
214
215
		return(JS_FALSE);
	}

216
	if(p->fp!=NULL)
217
218
		return(JS_TRUE);

219
	SAFECOPY(p->mode,"r+");	/* default mode */
220
221
222
223
224
225
	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);
			}
226
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
227
228
229
230
231
232
233
		}
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
	}

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

	return(JS_TRUE);
}
249
250

static JSBool
251
js_close(JSContext *cx, uintN argc, jsval *arglist)
252
{
253
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
254
	private_t*	p;
deuce's avatar
deuce committed
255
	jsrefcount	rc;
256

257
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
258
		return(JS_FALSE);
259
	}
260

261
262
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

274
	p->fp=NULL;
275
276
	dbprintf(FALSE, p, "closed: %s", p->name);

277
	JS_RESUMEREQUEST(cx, rc);
278
279
280
281

	return(JS_TRUE);
}

282
283
284
285
286
287
288
289
290
291
292
293
294
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

295
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
296
297
298
299
300
301
		return(JS_FALSE);
	}

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

302
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
303
304
305
306
307
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
		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;
}

348
349
350
351
352
353
354
355
356
357
358
359
360
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);

361
362
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
363
364
365
366
367
368
		return(JS_FALSE);
	}

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

369
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
370
371
372
373
374
375
376
377
378
379
380
381
		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);
382
	dbprintf(FALSE, p, "read %u raw bytes",len);
383
	if(len<0)
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
		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));

	return(JS_TRUE);
}


400
static JSBool
401
js_read(JSContext *cx, uintN argc, jsval *arglist)
402
{
403
404
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
405
	char*		cp;
406
	char*		buf;
407
	char*		uubuf;
408
409
	int32		len;
	int32		offset;
410
	int32		uulen;
411
412
	JSString*	str;
	private_t*	p;
deuce's avatar
deuce committed
413
	jsrefcount	rc;
414

415
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
416

417
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
418
		return(JS_FALSE);
419
	}
420

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

424
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
425
426
427
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else {
428
		rc=JS_SUSPENDREQUEST(cx);
429
430
		len=(long)filelength(fileno(p->fp));
		offset=(long)ftell(p->fp);
431
432
		if(offset>0)
			len-=offset;
433
		JS_RESUMEREQUEST(cx, rc);
434
435
436
	}
	if(len<0)
		len=512;
437

438
	if((buf=malloc(len+1))==NULL)
439
440
		return(JS_TRUE);

441
	rc=JS_SUSPENDREQUEST(cx);
442
	len = fread(buf,1,len,p->fp);
443
	dbprintf(FALSE, p, "read %u bytes",len);
444
	if(len<0)
445
446
447
448
449
		len=0;
	buf[len]=0;

	if(p->etx) {
		cp=strchr(buf,p->etx);
450
		if(cp) *cp=0;
451
		len=strlen(buf);
452
453
	}

454
455
456
	if(p->rot13)
		rot13(buf);

457
	if(p->uuencoded || p->b64encoded || p->yencoded) {
458
		uulen=len*2;
deuce's avatar
deuce committed
459
		if((uubuf=malloc(uulen))==NULL) {
460
			free(buf);
461
			JS_RESUMEREQUEST(cx, rc);
462
			return(JS_TRUE);
463
		}
464
465
		if(p->uuencoded)
			uulen=uuencode(uubuf,uulen,buf,len);
466
467
		else if(p->yencoded)
			uulen=yencode(uubuf,uulen,buf,len);
468
469
		else
			uulen=b64_encode(uubuf,uulen,buf,len);
470
		if(uulen>=0) {
471
			free(buf);
472
			buf=uubuf;
473
			len=uulen;
deuce's avatar
deuce committed
474
		}
475
476
		else
			free(uubuf);
477
	}
478
	JS_RESUMEREQUEST(cx, rc);
479

480
	str = JS_NewStringCopyN(cx, buf, len);
481
	free(buf);
482

483
484
485
	if(str==NULL)
		return(JS_FALSE);

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

488
489
490
491
	return(JS_TRUE);
}

static JSBool
492
js_readln(JSContext *cx, uintN argc, jsval *arglist)
493
{
494
495
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
496
497
	char*		cp;
	char*		buf;
498
	int32		len=512;
499
	JSString*	js_str;
500
	private_t*	p;
deuce's avatar
deuce committed
501
	jsrefcount	rc;
502

503
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
504

505
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
506
		return(JS_FALSE);
507
	}
508
509
510

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

512
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
513
514
515
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
516

517
	if((buf=malloc(len + 1))==NULL)
deuce's avatar
deuce committed
518
		return(JS_FALSE);
519

520
	rc=JS_SUSPENDREQUEST(cx);
521
	if(fgets(buf,len + 1,p->fp)!=NULL) {
522
523
524
525
		len=strlen(buf);
		while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n'))
			len--;
		buf[len]=0;
526
527
		if(p->etx) {
			cp=strchr(buf,p->etx);
528
			if(cp) *cp=0;
529
		}
530
531
		if(p->rot13)
			rot13(buf);
532
		JS_RESUMEREQUEST(cx, rc);
533
		if((js_str=JS_NewStringCopyZ(cx,buf))!=NULL)	/* exception here Feb-12-2005 */
534
			JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
535
536
	} else {
		JS_RESUMEREQUEST(cx, rc);
537
	}
deuce's avatar
deuce committed
538
	free(buf);
539
540
541
542
543

	return(JS_TRUE);
}

static JSBool
544
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
545
{
546
547
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
548
549
550
	BYTE		*b;
	WORD		*w;
	DWORD		*l;
551
	int32		size=sizeof(DWORD);
552
	private_t*	p;
553
	int32		count=1;
554
555
	size_t		retlen;
	void		*buffer=NULL;
rswindell's avatar
rswindell committed
556
	size_t		i;
557
558
    JSObject*	array;
    jsval       v;
deuce's avatar
deuce committed
559
	jsrefcount	rc;
560

561
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
562

563
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
564
		return(JS_FALSE);
565
	}
566
567
568
569

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

570
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
571
		if(!JS_ValueToInt32(cx,argv[0],&size))
572
			return(JS_FALSE);
573
		if(argc>1 && !JSVAL_NULL_OR_VOID(argv[1])) {
574
			if(!JS_ValueToInt32(cx,argv[1],&count))
575
576
				return(JS_FALSE);
		}
577
	}
578

579
	rc=JS_SUSPENDREQUEST(cx);
580
581
582
	if(size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD)) {
		/* unknown size */
		dbprintf(TRUE, p, "unsupported binary read size: %d",size);
583
		JS_RESUMEREQUEST(cx, rc);
584
585
586
587
588
589
		return(JS_TRUE);
	}

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

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

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

666
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
667

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

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

675
    array = JS_NewArrayObject(cx, 0, NULL);
676

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

686
687
    return(JS_TRUE);
}
688

689
static jsval get_value(JSContext *cx, char* value, bool blanks)
690
691
692
693
694
{
	char*	p;
	BOOL	f=FALSE;
	jsval	val;

695
	if(value==NULL || (*value==0 && !blanks))
696
697
698
699
		return(JSVAL_VOID);

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

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

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

764
765
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

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

deuce's avatar
deuce committed
800
801
	if(JSVAL_IS_BOOLEAN(dflt)) {
		JS_SET_RVAL(cx,arglist,BOOLEAN_TO_JSVAL(
802
			iniGetBool(ini,section,key,JSVAL_TO_BOOLEAN(dflt))));
deuce's avatar
deuce committed
803
804
805
806
	}
	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)iniGetDateTime(ini,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
				strListFree(&ini);
825
826
				return JS_FALSE;
			}
827
			rc=JS_SUSPENDREQUEST(cx);
828
			list=iniGetStringList(ini,section,key,",",cstr);
829
			FREE_AND_NULL(cstr);
830
			JS_RESUMEREQUEST(cx, rc);
831
832
833
834
835
			for(i=0;list && list[i];i++) {
				val=STRING_TO_JSVAL(JS_NewStringCopyZ(cx,list[i]));
				if(!JS_SetElement(cx, array, i, &val))
					break;
			}
836
			rc=JS_SUSPENDREQUEST(cx);
837
			iniFreeStringList(list);
838
			JS_RESUMEREQUEST(cx, rc);
839
			JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
deuce's avatar
deuce committed
840
841
842
843
		}
	}
	else if(JSVAL_IS_DOUBLE(dflt)) {
		rc=JS_SUSPENDREQUEST(cx);
844
		dbl=iniGetFloat(ini,section,key,JSVAL_TO_DOUBLE(dflt));
deuce's avatar
deuce committed
845
846
847
848
		JS_RESUMEREQUEST(cx, rc);
		JS_SET_RVAL(cx, arglist,DOUBLE_TO_JSVAL(dbl));
	}
	else if(JSVAL_IS_NUMBER(dflt)) {
849
		if(!JS_ValueToInt32(cx,dflt,&i)) {
850
851
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
852
			strListFree(&ini);
deuce's avatar
deuce committed
853
			return(JS_FALSE);
854
		}
deuce's avatar
deuce committed
855
		rc=JS_SUSPENDREQUEST(cx);
856
		i=iniGetInteger(ini,section,key,i);
deuce's avatar
deuce committed
857
858
859
		JS_RESUMEREQUEST(cx, rc);
		JS_SET_RVAL(cx, arglist,INT_TO_JSVAL(i));
	} else {
860
		cstr=NULL;
861
		JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
862
		if(JS_IsExceptionPending(cx)) {
863
864
865
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
866
			strListFree(&ini);
867
868
			return JS_FALSE;
		}
deuce's avatar
deuce committed
869
		rc=JS_SUSPENDREQUEST(cx);
870
		cstr2=iniGetString(ini,section,key,cstr,buf);
deuce's avatar
deuce committed
871
872
		JS_RESUMEREQUEST(cx, rc);
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, cstr2)));
873
		FREE_AND_NULL(cstr);
874
	}
875
876
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
877
	strListFree(&ini);
878
879
880
881

	return(JS_TRUE);
}

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

896
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
897
898
899
		return(JS_FALSE);
	}

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

903
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
904
905
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);