js_file.c 75.1 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
	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
	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
	} else if(file >= 0)
		close(file);
201
	JS_RESUMEREQUEST(cx, rc);
202
203
204
205

	return(JS_TRUE);
}

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

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

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

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

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

	return(JS_TRUE);
}
257
258

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

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

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

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

	dbprintf(FALSE, p, "closed");

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

	return(JS_TRUE);
}

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

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


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

427
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
428

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

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

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

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

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

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

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

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

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

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

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

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

519
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
520

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

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

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

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

	return(JS_TRUE);
}

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

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

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

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

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

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

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

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

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

668
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
669

670
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
671
		JS_ReportError(cx,getprivate_failure,WHERE);
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
716
717
		return(val);
	}
	/* hexadecimal number? */
	if(!strncmp(value,"0x",2)) {	
		for(p=value+2;*p;p++)
718
			if(!isxdigit((uchar)*p))
719
720
				break;
		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
770
771
772
773
	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		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
895
896
897
898

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

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

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

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

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

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

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