js_file.c 75 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
93
/* 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;
94
95
	else
		flags|=O_TEXT;
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

	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;
	}

122
123
124
	if(strchr(mode,'e'))
		flags|=O_EXCL;

125
126
	return(flags);
}
127
128
129
130

/* File Object Methods */

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
136
	BOOL		shareable=FALSE;
	int			file;
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
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
144

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

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

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

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

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

	return(JS_TRUE);
}

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

216
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
217
218
219
220
221
222
223
224
225

	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);

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

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

	return(JS_TRUE);
}
256
257

static JSBool
258
js_close(JSContext *cx, uintN argc, jsval *arglist)
259
{
260
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
261
	private_t*	p;
deuce's avatar
deuce committed
262
	jsrefcount	rc;
263

deuce's avatar
deuce committed
264
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
265
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
266
		JS_ReportError(cx,getprivate_failure,WHERE);
267
		return(JS_FALSE);
268
	}
269
270
271
272

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

273
	rc=JS_SUSPENDREQUEST(cx);
274
275
276
277
278
279
#ifdef __unix__
	if(p->pipe)
		pclose(p->fp);
	else
#endif
		fclose(p->fp);
280
281
282
283

	dbprintf(FALSE, p, "closed");

	p->fp=NULL; 
284
	JS_RESUMEREQUEST(cx, rc);
285
286
287
288

	return(JS_TRUE);
}

289
290
291
292
293
294
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
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;
}

356
357
358
359
360
361
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
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);
}


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

426
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
427

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

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

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

450
	if((buf=malloc(len+1))==NULL)
451
452
		return(JS_TRUE);

453
	rc=JS_SUSPENDREQUEST(cx);
454
455
456
457
458
459
460
461
	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; 
462
		len=strlen(buf);
463
464
	}

465
466
467
	if(p->rot13)
		rot13(buf);

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

491
	str = JS_NewStringCopyN(cx, buf, len);
492
	free(buf);
493

494
495
496
	if(str==NULL)
		return(JS_FALSE);

497
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
498

499
	rc=JS_SUSPENDREQUEST(cx);
500
	dbprintf(FALSE, p, "read %u bytes",len);
501
	JS_RESUMEREQUEST(cx, rc);
502
503
504
505
506
		
	return(JS_TRUE);
}

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

518
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
519

520
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
521
		JS_ReportError(cx,getprivate_failure,WHERE);
522
		return(JS_FALSE);
523
	}
524
525
526

	if(p->fp==NULL)
		return(JS_TRUE);
527
	
528
529
530
531
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
532

deuce's avatar
deuce committed
533
534
	if((buf=malloc(len))==NULL)
		return(JS_FALSE);
535

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

	return(JS_TRUE);
}

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

577
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
578

579
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
580
		JS_ReportError(cx,getprivate_failure,WHERE);
581
		return(JS_FALSE);
582
	}
583
584
585
586

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

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

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

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

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

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

667
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
668

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

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

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

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

688
689
    return(JS_TRUE);
}
690

691
692
693
694
695
696
697
698
699
700
701
static jsval get_value(JSContext *cx, char* value)
{
	char*	p;
	BOOL	f=FALSE;
	jsval	val;

	if(value==NULL || *value==0)
		return(JSVAL_VOID);

	/* integer or float? */
	for(p=value;*p;p++) {
702
		if(*p=='.' && !f)
703
			f=TRUE;
704
		else if(!isdigit((uchar)*p))
705
706
			break;
	}
707
708
709
710
711
	if(*p==0) {
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
712
713
714
715
716
		return(val);
	}
	/* hexadecimal number? */
	if(!strncmp(value,"0x",2)) {	
		for(p=value+2;*p;p++)
717
			if(!isxdigit((uchar)*p))
718
719
				break;
		if(*p==0) {	
720
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,0));
721
722
723
724
725
726
727
728
729
730
731
732
733
			return(val);
		}
	}
	/* Boolean? */
	if(!stricmp(value,"true"))
		return(JSVAL_TRUE);
	if(!stricmp(value,"false"))
		return(JSVAL_FALSE);

	/* String */
	return(STRING_TO_JSVAL(JS_NewStringCopyZ(cx,value)));
}

deuce's avatar
deuce committed
734
735
736
737
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
	jsval	rval;

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

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

766
767
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

768
769
770
771
772
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		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
894
895
896
897

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		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,"",NULL);
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),NULL);
deuce's avatar
deuce committed
917
918
	}
	else if(JSVAL_IS_DOUBLE(value)) {
919
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),NULL);
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,NULL);
deuce's avatar
deuce committed
929
930
931
932
933
934
		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);
935
		result = iniSetDateTime(list,section,key,/* include_time */TRUE, tt,NULL);
deuce's avatar
deuce committed
936
937
		JS_RESUMEREQUEST(cx, rc);
	} else {
938
		cstr=NULL;
939
		JSVALUE_TO_MSTRING(cx, value, cstr, NULL);
940
		if(JS_IsExceptionPending(cx)) {
941
942
943
			FREE_AND_NULL(cstr);
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
944
945
			return JS_FALSE;
		}
deuce's avatar
deuce committed
946
		rc=JS_SUSPENDREQUEST(cx);
947
948
		result = iniSetString(list,section,key, cstr,NULL);
		FREE_AND_NULL(cstr);
deuce's avatar
deuce committed
949
		JS_RESUMEREQUEST(cx, rc);
950
	}
951
952
	FREE_AND_NULL(section);
	FREE_AND_NULL(key);
953

954
	return(result != NULL);
955
956
}

deuce's avatar
deuce committed
957
958
959
960
961
static JSBool
js_iniSetValue(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
	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,getprivate_failure,WHERE);
		return(JS_FALSE);
	}

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

	rc=JS_SUSPENDREQUEST(cx);
	if((list=iniReadFile(p->fp)) != NULL) {
		if(js_iniSetValue_internal(cx, obj, argc, argv, &list))
			rval = BOOLEAN_TO_JSVAL(iniWriteFile(p->fp,list));
	}
	strListFree(&list);
	JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
982
983

	JS_SET_RVAL(cx, arglist, rval);
984
	return JS_TRUE;
deuce's avatar
deuce committed
985
986
}

987
static JSBool