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

	return(JS_TRUE);
}

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

222
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
223

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

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

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

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

	return(JS_TRUE);
}
262
263

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

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

274
275
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

	dbprintf(FALSE, p, "closed");

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

	return(JS_TRUE);
}

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

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

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

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

412
413
414
415
	return(JS_TRUE);
}


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

431
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
432

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

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

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

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

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

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

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

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

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

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

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

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

507
508
509
510
	return(JS_TRUE);
}

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

522
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
523

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

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

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

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

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

	return(JS_TRUE);
}

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

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

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

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

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

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

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

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

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

669
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
670

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

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

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

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

689
690
    return(JS_TRUE);
}
691

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

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

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

767
768
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

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

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

	return(JS_TRUE);
}

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

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

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

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

deuce's avatar
deuce committed
909
	if(value==JSVAL_VOID) { 	/* unspecified value */
910
		rc=JS_SUSPENDREQUEST(cx);
911
		result = iniSetString(list,section,key,"",&p->ini_style);
912
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
913
	}
deuce's avatar
deuce committed
914
	else if(JSVAL_IS_BOOLEAN(value)) {
915
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),&p->ini_style);
deuce's avatar
deuce committed
916
917
	}
	else if(JSVAL_IS_DOUBLE(value)) {
918
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),&p->ini_style);
deuce's avatar
deuce committed
919
920
	}
	else if(JSVAL_IS_NUMBER(value)) {
921
		if(!JS_ValueToInt32(cx,value,&i)) {
922
923
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
924
925
			return JS_FALSE;
		}
deuce's avatar
deuce committed
926
		rc=JS_SUSPENDREQUEST(cx);
927
		result = iniSetInteger(list,section,key,i,&p->ini_style);
deuce's avatar
deuce committed
928
		JS_RESUMEREQUEST(cx, rc);
929
	} else if(JSVAL_IS_OBJECT(value)
deuce's avatar
deuce committed
930
931
932
933
			&& (value_obj = JSVAL_TO_OBJECT(value))!=NULL
			&& (strcmp("Date",JS_GetClass(cx, value_obj)->name)==0)) {
		tt=(time_t)(js_DateGetMsecSinceEpoch(cx,value_obj)/1000.0);
		rc=JS_SUSPENDREQUEST(cx);
934
		result = iniSetDateTime(list,section,key