js_file.c 78.6 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
187
188
				if((p->fp=fdopen(file,fdomode)) == NULL) {
					JS_ReportWarning(cx, "fdopen(%s, %s) ERROR %d: %s", p->name, fdomode, errno, strerror(errno));
				}
189
190
			}
			free(fdomode);
191
192
		}
	}
193
	if(p->fp!=NULL) {
194
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
195
		dbprintf(FALSE, p, "opened: %s",p->name);
196
197
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
198
199
200
201
202
		else {
#ifdef _WIN32
			if(bufsize < 2)
				bufsize = 2;
#endif
203
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
204
		}
205
206
	} else if(file >= 0)
		close(file);
207
	JS_RESUMEREQUEST(cx, rc);
208
209
210
211

	return(JS_TRUE);
}

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

223
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
224

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

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

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

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

	return(JS_TRUE);
}
263
264

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

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

275
276
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

	dbprintf(FALSE, p, "closed");

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

	return(JS_TRUE);
}

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

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

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

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

413
414
415
416
	return(JS_TRUE);
}


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

432
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
433

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

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

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

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

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

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

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

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

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

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

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

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

508
509
510
511
	return(JS_TRUE);
}

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

523
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
524

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

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

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

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

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

	return(JS_TRUE);
}

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

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

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

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

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

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

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

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

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

670
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
671

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

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

679
    array = JS_NewArrayObject(cx, 0, NULL);
680

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

690
691
    return(JS_TRUE);
}
692

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

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

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

768
769
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

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

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

	return(JS_TRUE);
}

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

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

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

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

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