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

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
9
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
10
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
 *																			*
 * 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"
37
38
#include "md5.h"
#include "base64.h"
39
#include "uucode.h"
40
#include "yenc.h"
41
#include "ini_file.h"
42

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

47
48
#ifdef JAVASCRIPT

49
#include "js_request.h"
50

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

} private_t;

68
static const char* getprivate_failure = "line %d %s %s JS_GetPrivate failed";
69
70
71
72
73
74
75
76
77
78

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
82
    va_end(argptr);
	
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
129

/* File Object Methods */

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

142
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
143

144
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
145
		JS_ReportError(cx,getprivate_failure,WHERE);
146
		return(JS_FALSE);
147
	}
148
149
150

	if(p->fp!=NULL)  
		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
226
227
228
229
230
231

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

	if(p->fp!=NULL)  
		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

deuce's avatar
deuce committed
270
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
271
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
272
		JS_ReportError(cx,getprivate_failure,WHERE);
273
		return(JS_FALSE);
274
	}
275
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
289

	dbprintf(FALSE, p, "closed");

	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
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
360
361
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

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

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		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);
	if(len<0) 
		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);
		
	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_GetPrivate(cx,obj))==NULL) {
435
		JS_ReportError(cx,getprivate_failure,WHERE);
436
		return(JS_FALSE);
437
	}
438

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

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

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

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

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

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

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

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

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

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

505
	rc=JS_SUSPENDREQUEST(cx);
506
	dbprintf(FALSE, p, "read %u bytes",len);
507
	JS_RESUMEREQUEST(cx, rc);
508
509
510
511
512
		
	return(JS_TRUE);
}

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

524
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
525

526
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
527
		JS_ReportError(cx,getprivate_failure,WHERE);
528
		return(JS_FALSE);
529
	}
530
531
532

	if(p->fp==NULL)
		return(JS_TRUE);
533
	
534
535
536
537
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
538

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

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

	return(JS_TRUE);
}

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

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

585
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
586
		JS_ReportError(cx,getprivate_failure,WHERE);
587
		return(JS_FALSE);
588
	}
589
590
591
592

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

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

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

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

end:
	free(buffer);
661
	JS_RESUMEREQUEST(cx, rc);
662
663
664
665
	return(JS_TRUE);
}

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

673
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
674

675
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
676
		JS_ReportError(cx,getprivate_failure,WHERE);
677
		return(JS_FALSE);
678
	}
679

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

683
    array = JS_NewArrayObject(cx, 0, NULL);
684

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

694
695
    return(JS_TRUE);
}
696

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

deuce's avatar
deuce committed
744
	if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
deuce's avatar
deuce committed
745
		return ((double)time(NULL))*1000;
deuce's avatar
deuce committed
746
	}
deuce's avatar
deuce committed
747
748
749
	return JSVAL_TO_DOUBLE(rval);
}

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

772
773
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

774
775
776
777
778
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

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

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

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

	return(JS_TRUE);
}

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

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

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

907
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
908
909
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
910
	if(JS_IsExceptionPending(cx)) {
911
912
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
913
914
		return JS_FALSE;
	}
915

deuce's avatar
deuce committed
916
	if(value==JSVAL_VOID) { 	/* unspecified value */
917
		rc=JS_SUSPENDREQUEST(cx);
918
		result = iniSetString(list,section,key,"",NULL);
919
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
920
	}
deuce's avatar
deuce committed
921
	else if(JSVAL_IS_BOOLEAN(value)) {
922
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),NULL);
deuce's avatar
deuce committed
923
924
	}
	else if(JSVAL_IS_DOUBLE(value)) {
925
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),NULL);
deuce's avatar
deuce committed
926
927
	}
	else if(JSVAL_IS_NUMBER(value)) {
928
		if(!JS_ValueToInt32(cx,value,&i)) {
929
930
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
931
932
			return JS_FALSE;
		}
deuce's avatar
deuce committed
933
		rc=JS_SUSPENDREQUEST(cx);
934
		result = iniSetInteger(list,section,key,i,NULL);
deuce's avatar
deuce committed
935
936
937
938
939
940
		JS_RESUMEREQUEST(cx, rc);
	} else if(JSVAL_IS_OBJECT(value) 
			&& (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);
941
		result = iniSetDateTime(list,section,key,/* include_time */TRUE, tt,NULL);
deuce's avatar
deuce committed
942
943
		JS_RESUMEREQUEST(cx, rc);
	} else {
944
		cstr=NULL;
945
		JSVALUE_TO_MSTRING(cx, value, cstr, NULL);
946
		if(JS_IsExceptionPending(cx)) {
947
948
949
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
950
951
			return JS_FALSE;
		}
deuce's avatar
deuce committed
952
		rc=JS_SUSPENDREQUEST(cx);
953
954
		result = iniSetString(list,section,key, cstr,NULL);
		FREE_AND_NULL(cstr);
deuce's avatar
deuce committed
955
		JS_RESUMEREQUEST(cx, rc);
956
	}
957
958
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
959

960
	return(result != NULL);
961
962
}

deuce's avatar
deuce committed
963
964
965
966
967
static JSBool
js_iniSetValue(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
	jsval	rval=JSVAL_FALSE;
	private_t*	p;
	str_list_t	list;
	jsrefcount	rc;

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx