js_file.c 76.9 KB
Newer Older
1
/* Synchronet JavaScript "File" Object */
2
// vi: tabstop=4
3

4
/* $Id: js_file.c,v 1.196 2020/04/17 05:37:14 rswindell Exp $ */
5
6
7
8
9

/****************************************************************************
 * @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
#include <stdbool.h>
45

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

50
51
#ifdef JAVASCRIPT

52
#include "js_request.h"
53

54
55
typedef struct
{
56
	FILE*	fp;
57
58
	char	name[MAX_PATH+1];
	char	mode[4];
59
	uchar	etx;
60
	BOOL	debug;
61
	BOOL	rot13;
62
	BOOL	yencoded;
63
	BOOL	uuencoded;
64
65
	BOOL	b64encoded;
	BOOL	network_byte_order;
66
	BOOL	pipe;		/* Opened with popen() use pclose() to close */
67
	ini_style_t ini_style;
68
69
70
71
72
73
74
75
76
77
78
79

} 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);
80
81
    vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
82
    va_end(argptr);
83

84
	lprintf(LOG_DEBUG,"%04d File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
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
	if(strchr(mode,'x'))
		flags|=O_EXCL;

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
126
	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);
}
127
128
129

/* File Object Methods */

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

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

148
149
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);

150
	if(p->fp!=NULL)
151
		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
			char *fdomode=strdup(p->mode);
			char *e=fdomode;

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

	return(JS_TRUE);
}

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

224
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
225

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

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

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

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

	return(JS_TRUE);
}
264
265

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

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

276
277
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

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

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

	return(JS_TRUE);
}

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

310
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
311
312
313
314
315
316
		return(JS_FALSE);
	}

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

317
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
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
362
		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;
}

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

376
377
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
		
378
379
380
381
382
383
		return(JS_FALSE);
	}

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

384
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
385
386
387
388
389
390
391
392
393
394
395
396
		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);
397
	dbprintf(FALSE, p, "read %u raw bytes",len);
398
	if(len<0)
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
		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));

	return(JS_TRUE);
}


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

430
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
431

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

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

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

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

456
	rc=JS_SUSPENDREQUEST(cx);
457
	len = fread(buf,1,len,p->fp);
458
	dbprintf(FALSE, p, "read %u bytes",len);
459
	if(len<0)
460
461
462
463
464
		len=0;
	buf[len]=0;

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

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

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

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

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

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

503
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_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
521
		return(JS_FALSE);
522
	}
523
524
525

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

527
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
528
529
530
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
531

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

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

	return(JS_TRUE);
}

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

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

578
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
579
		return(JS_FALSE);
580
	}
581
582
583
584

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

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

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

	buffer=malloc(size*count);
	if(buffer==NULL) {
		dbprintf(TRUE, p, "malloc failure of %u bytes", size*count);
605
		JS_RESUMEREQUEST(cx, rc);
606
607
608
609
610
611
612
613
614
615
		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):
616
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
617
618
					break;
				case sizeof(WORD):
619
620
621
622
					if (p->network_byte_order)
						*w = BE_SHORT(*w);
					else
						*w = LE_SHORT(*w);
623
					JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
624
625
					break;
				case sizeof(DWORD):
626
627
628
629
					if (p->network_byte_order)
						*l = BE_LONG(*l);
					else
						*l = LE_LONG(*l);
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
    	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):
645
646
647
648
					if (p->network_byte_order)
						*w = BE_SHORT(*w);
					else
						*w = LE_SHORT(*w);
649
650
651
					v = INT_TO_JSVAL(*(w++));
					break;
				case sizeof(DWORD):
652
653
654
655
					if (p->network_byte_order)
						*l = BE_LONG(*l);
					else
						*l = LE_LONG(*l);
656
					v=UINT_TO_JSVAL(*(l++));
657
					break;
658
			}
deuce's avatar
deuce committed
659
        	if(!JS_SetElement(cx, array, i, &v)) {
660
				rc=JS_SUSPENDREQUEST(cx);
661
				goto end;
deuce's avatar
deuce committed
662
			}
663
		}
664
    	JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
665
	}
666
667
668

end:
	free(buffer);
669
	JS_RESUMEREQUEST(cx, rc);
670
671
672
673
	return(JS_TRUE);
}

static JSBool
674
js_readall(JSContext *cx, uintN argc, jsval *arglist)
675
{
676
	JSObject *obj=JS_THIS_OBJECT(cx, arglist);
677
678
    jsint       len=0;
    JSObject*	array;
679
680
	private_t*	p;

681
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
682

683
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
684
		return(JS_FALSE);
685
	}
686

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

690
    array = JS_NewArrayObject(cx, 0, NULL);
691

692
    while(!feof(p->fp)) {
693
694
		js_readln(cx, argc, arglist);
		if(JS_RVAL(cx, arglist)==JSVAL_NULL)
695
			break;
696
        if(!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
697
			break;
698
	}
699
    JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
700

701
702
    return(JS_TRUE);
}
703

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

deuce's avatar
deuce committed
751
	if(!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
deuce's avatar
deuce committed
752
		return ((double)time(NULL))*1000;
deuce's avatar
deuce committed
753
	}
deuce's avatar
deuce committed
754
755
756
	return JSVAL_TO_DOUBLE(rval);
}

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

779
780
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

781
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
782
783
784
		return(JS_FALSE);
	}

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

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

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

	return(JS_TRUE);
}

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

905
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
906
907
908
		return(JS_FALSE);
	}

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

912
	if(argc && argv[0]!=JSVAL_VOID && argv[0]!=JSVAL_NULL)
913
914
		JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
	JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
915
	if(JS_IsExceptionPending(cx)) {
916
917
		FREE_AND_NULL(section);
		FREE_AND_NULL(key);
918
919
		return JS_FALSE;
	}
920

deuce's avatar
deuce committed
921
	if(value==JSVAL_VOID) { 	/* unspecified value */
922
		rc=JS_SUSPENDREQUEST(cx);
923
		result = iniSetString(list,section,key,"",&p->ini_style);
924
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
925
	}
deuce's avatar
deuce committed