js_file.c 79.4 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
#include "xpendian.h"
39
40
#include "md5.h"
#include "base64.h"
41
#include "uucode.h"
42
#include "yenc.h"
43
#include "ini_file.h"
44

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

49
50
#ifdef JAVASCRIPT

51
#include "js_request.h"
52

53
54
typedef struct
{
55
	FILE*	fp;
56
57
	char	name[MAX_PATH+1];
	char	mode[4];
58
	uchar	etx;
59
	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,"%04d File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
84
85
}

86
87
88
89
90
91
92
/* Converts fopen() style 'mode' string into open() style 'flags' integer */
static int fopenflags(char *mode)
{
	int flags=0;

	if(strchr(mode,'b'))
		flags|=O_BINARY;
93
94
	else
		flags|=O_TEXT;
95

96
97
98
	if(strchr(mode,'x'))
		flags|=O_EXCL;

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
	if(strchr(mode,'w')) {
		flags|=O_CREAT|O_TRUNC;
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_WRONLY;
		return(flags);
	}

	if(strchr(mode,'a')) {
		flags|=O_CREAT|O_APPEND;
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_WRONLY;
		return(flags);
	}

	if(strchr(mode,'r')) {
		if(strchr(mode,'+'))
			flags|=O_RDWR;
		else
			flags|=O_RDONLY;
	}

	return(flags);
}
126
127
128

/* File Object Methods */

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

143
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
144
		return(JS_FALSE);
145
	}
146

147
148
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

149
	if(p->fp!=NULL)
150
		return(JS_TRUE);
151

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

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

			if(fdomode && e) {
178
179
				/* Remove deprecated (never-worked, non-standard) 'e'xclusive mode char (and warn): */
				for(e=strchr(fdomode, 'e'); e ; e=strchr(e, 'e')) {
180
					JS_ReportWarning(cx, "Deprecated file open mode: 'e'");
181
182
183
184
					memmove(e, e+1, strlen(e));
				}
				/* Remove (C11 standard) 'x'clusive mode char to avoid MSVC assertion: */
				for(e=strchr(fdomode, 'x'); e ; e=strchr(e, 'x'))
185
					memmove(e, e+1, strlen(e));
186
187
188
				if((p->fp=fdopen(file,fdomode)) == NULL) {
					JS_ReportWarning(cx, "fdopen(%s, %s) ERROR %d: %s", p->name, fdomode, errno, strerror(errno));
				}
189
190
			}
			free(fdomode);
191
192
		}
	}
193
	if(p->fp!=NULL) {
194
		JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
195
		dbprintf(FALSE, p, "opened: %s",p->name);
196
197
		if(!bufsize)
			setvbuf(p->fp,NULL,_IONBF,0);	/* no buffering */
198
199
200
201
202
		else {
#ifdef _WIN32
			if(bufsize < 2)
				bufsize = 2;
#endif
203
			setvbuf(p->fp,NULL,_IOFBF,bufsize);
204
		}
205
206
	} else if(file >= 0)
		close(file);
207
	JS_RESUMEREQUEST(cx, rc);
208
209
210
211

	return(JS_TRUE);
}

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

223
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
224

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

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

233
	SAFECOPY(p->mode,"r+");	/* default mode */
234
235
236
237
238
239
	for(i=0;i<argc;i++) {
		if(JSVAL_IS_STRING(argv[i])) {	/* mode */
			if((str = JS_ValueToString(cx, argv[i]))==NULL) {
				JS_ReportError(cx,"Invalid mode specified: %s",str);
				return(JS_TRUE);
			}
240
			JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
241
242
243
244
245
246
247
		}
		else if(JSVAL_IS_NUMBER(argv[i])) {	/* bufsize */
			if(!JS_ValueToInt32(cx,argv[i],&bufsize))
				return(JS_FALSE);
		}
	}

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

	return(JS_TRUE);
}
263
264

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

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

275
276
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

288
	p->fp=NULL;
289
290
	dbprintf(FALSE, p, "closed: %s", p->name);

291
	JS_RESUMEREQUEST(cx, rc);
292
293
294
295

	return(JS_TRUE);
}

296
297
298
299
300
301
302
303
304
305
306
307
308
static JSBool
js_raw_pollin(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	private_t*	p;
	jsrefcount	rc;
	int32		timeout = -1;
#ifdef __unix__
	fd_set		rd;
	struct	timeval tv = {0, 0};
#endif

309
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
		return(JS_FALSE);
	}

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

	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&timeout))
			return(JS_FALSE);
	}

	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(FALSE));
	rc=JS_SUSPENDREQUEST(cx);
#ifdef __unix__
	if (timeout >= 0) {
		tv.tv_sec = timeout / 1000;
		tv.tv_usec = (timeout%1000)*1000;
	}
	FD_ZERO(&rd);
	FD_SET(fileno(p->fp), &rd);
	if (select(fileno(p->fp)+1, &rd, NULL, NULL, timeout < 0 ? NULL : &tv) == 1)
		JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
#else
	while(timeout) {
		if (isatty(fileno(p->fp))) {
			if (kbhit()) {
				JS_RESUMEREQUEST(cx, rc);
				JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
				rc=JS_SUSPENDREQUEST(cx);
				break;
			}
			SLEEP(1);
			if (timeout > 0)
				timeout--;
		}
		else {
			if (!eof(fileno(p->fp))) {
				JS_RESUMEREQUEST(cx, rc);
				JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
				rc=JS_SUSPENDREQUEST(cx);
				break;
			}
			SLEEP(1);
			if (timeout > 0)
				timeout--;
		}
	}
#endif
	JS_RESUMEREQUEST(cx, rc);
	return JS_TRUE;
}

362
363
364
365
366
367
368
369
370
371
372
373
374
static JSBool
js_raw_read(JSContext *cx, uintN argc, jsval *arglist)
{
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
	char*		buf;
	int32		len;
	JSString*	str;
	private_t*	p;
	jsrefcount	rc;

	JS_SET_RVAL(cx, arglist, JSVAL_NULL);

375
376
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
		return(JS_FALSE);
	}

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

	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	} else
		len = 1;
	if(len<0)
		len=1;

	if((buf=malloc(len))==NULL)
		return(JS_TRUE);

	rc=JS_SUSPENDREQUEST(cx);
	len = read(fileno(p->fp),buf,len);
396
	if(len<0)
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
		len=0;

	JS_RESUMEREQUEST(cx, rc);

	str = JS_NewStringCopyN(cx, buf, len);
	free(buf);

	if(str==NULL)
		return(JS_FALSE);

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

	rc=JS_SUSPENDREQUEST(cx);
	dbprintf(FALSE, p, "read %u raw bytes",len);
	JS_RESUMEREQUEST(cx, rc);
412

413
414
415
416
	return(JS_TRUE);
}


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

432
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
433

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

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

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

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

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

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

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

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

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

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

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

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

508
509
510
511
	return(JS_TRUE);
}

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

523
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
524

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

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

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

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

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

	return(JS_TRUE);
}

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

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

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

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

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

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

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
610
		JS_RESUMEREQUEST(cx, rc);
611
612
613
614
615
616
617
618
619
620
		return(JS_FALSE);
	}
	b=buffer;
	w=buffer;
	l=buffer;
	retlen=fread(buffer, size, count, p->fp);
	if(count==1) {
		if(retlen==1) {
			switch(size) {
				case sizeof(BYTE):
621
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
622
623
					break;
				case sizeof(WORD):
624
625
626
627
					if (p->network_byte_order)
						*w = BE_SHORT(*w);
					else
						*w = LE_SHORT(*w);
628
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
629
630
					break;
				case sizeof(DWORD):
631
632
633
634
					if (p->network_byte_order)
						*l = BE_LONG(*l);
					else
						*l = LE_LONG(*l);
635
					JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
636
					break;
637
			}
638
639
640
		}
	}
	else {
641
		JS_RESUMEREQUEST(cx, rc);
642
643
644
645
646
647
648
649
    	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):
650
651
652
653
					if (p->network_byte_order)
						*w = BE_SHORT(*w);
					else
						*w = LE_SHORT(*w);
654
655
656
					v = INT_TO_JSVAL(*(w++));
					break;
				case sizeof(DWORD):
657
658
659
660
					if (p->network_byte_order)
						*l = BE_LONG(*l);
					else
						*l = LE_LONG(*l);
661
					v=UINT_TO_JSVAL(*(l++));
662
					break;
663
			}
deuce's avatar
deuce committed
664
        	if(!JS_SetElement(cx, array, i, &v)) {
665
				rc=JS_SUSPENDREQUEST(cx);
666
				goto end;
deuce's avatar
deuce committed
667
			}
668
		}
669
    	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
670
	}
671
672
673

end:
	free(buffer);
674
	JS_RESUMEREQUEST(cx, rc);
675
676
677
678
	return(JS_TRUE);
}

static JSBool
679
js_readall(JSContext *cx, uintN argc, jsval *arglist)
680
{
681
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
682
683
    jsint       len=0;
    JSObject*	array;
684
685
	private_t*	p;

686
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
687

688
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
689
		return(JS_FALSE);
690
	}
691

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

695
    array = JS_NewArrayObject(cx, 0, NULL);
696

697
    while(!feof(p->fp)) {
698
699
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
700
			break;
701
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
702
			break;
703
	}
704
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
705

706
707
    return(JS_TRUE);
}
708

709
710
711
712
713
714
715
716
717
718
719
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++) {
720
		if(*p=='.' && !f)
721
			f=TRUE;
722
		else if(!isdigit((uchar)*p))
723
724
			break;
	}
725
726
727
728
729
	if(*p==0) {
		if(f)
			val=DOUBLE_TO_JSVAL(atof(value));
		else
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,10));
730
731
732
		return(val);
	}
	/* hexadecimal number? */
733
	if(!strncmp(value,"0x",2)) {
734
		for(p=value+2;*p;p++)
735
			if(!isxdigit((uchar)*p))
736
				break;
737
		if(*p==0) {
738
			val=DOUBLE_TO_JSVAL((double)strtoul(value,NULL,0));
739
740
741
742
743
744
745
746
747
748
749
750
751
			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
752
753
754
755
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
	jsval	rval;

deuce's avatar
deuce committed
756
	if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
deuce's avatar
deuce committed
757
		return ((double)time(NULL))*1000;
deuce's avatar
deuce committed
758
	}
deuce's avatar
deuce committed
759
760
761
	return JSVAL_TO_DOUBLE(rval);
}

762
static JSBool
763
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
764
{
765
766
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
	jsval *argv=JS_ARGV(cx, arglist);
rswindell's avatar
rswindell committed
767
	char*	section=ROOT_SECTION;
768
	char*	key;
769
	char**	list;
770
	char	buf[INI_MAX_VALUE_LEN];
771
772
	int32	i;
	jsval	val;
773
774
	jsval	dflt=argv[2];
	private_t*	p;
775
	JSObject*	array;
776
777
	JSObject*	dflt_obj;
	JSObject*	date_obj;
deuce's avatar
deuce committed
778
779
780
	jsrefcount	rc;
	double		dbl;
	time_t		tt;
781
	char*		cstr=NULL;
deuce's avatar
deuce committed
782
	char*		cstr2;
783

784
785
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

786
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
787
788
789
		return(JS_FALSE);
	}

790
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
791
792
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
793
	if(JS_IsExceptionPending(cx)) {
794
795
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
deuce's avatar
deuce committed
796
		return JS_FALSE;
797
	}
798
799
800
801
802
803
	/*
	 * Although section can be NULL (ie: root), a NULL key will cause a
	 * segfault.
	 */
	if(key==NULL) {
		JS_ReportError(cx, "Invalid NULL key specified");
804
		FREE_AND_NULL(section);
805
806
		return JS_FALSE;
	}
807

808
	if(argc < 3 || dflt==JSVAL_VOID) {	/* unspecified default value */
809
		rc=JS_SUSPENDREQUEST(cx);
810
		cstr=iniReadString(p->fp,section,key,NULL,buf);
811
812
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
813
		JS_RESUMEREQUEST(cx, rc);
814
		JS_SET_RVAL(cx, arglist, get_value(cx, cstr));
815
816
817
		return(JS_TRUE);
	}

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

	return(JS_TRUE);
}

896
static JSBool
897
js_iniSetValue_internal(JSContext *cx, JSObject *obj, uintN argc, jsval* argv, str_list_t* list)
898
{
rswindell's avatar
rswindell committed
899
	char*	section=ROOT_SECTION;
900
	char*	key=NULL;
901
902
903
904
	char*	result=NULL;
	int32	i;
	jsval	value=argv[2];
	private_t*	p;
905
	JSObject*	value_obj;
deuce's avatar
deuce committed
906
907
908
	jsrefcount	rc;
	char*		cstr;
	time_t		tt;
909

910
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
911
912
913
		return(JS_FALSE);
	}

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

917
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
918
919
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
920
	if(JS_IsExceptionPending(cx)) {
921
922
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
923
924
		return JS_FALSE;
	}
925

deuce's avatar
deuce committed
926
	if(value==JSVAL_VOID) { 	/* unspecified value */
927
		rc=JS_SUSPENDREQUEST(cx);
928
		result = iniSetString(list,section,key,"",&p->ini_style);
929
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
930
	}
deuce's avatar
deuce committed
931
	else if(JSVAL_IS_BOOLEAN(value)) {
932
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),&p->ini_style);
deuce's avatar
deuce committed
933
934
	}
	else if(JSVAL_IS_DOUBLE(value)) {
935
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),&p->ini_style);