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

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

48
49
#ifdef JAVASCRIPT

50
#include "js_request.h"
51

52
53
typedef struct
{
54
	FILE*	fp;
55
56
	char	name[MAX_PATH+1];
	char	mode[4];
57
	uchar	etx;
58
59
	BOOL	external;	/* externally created, don't close */
	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

} private_t;

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

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

85
	lprintf(LOG_DEBUG,"%04u File %s%s",p->fp ? fileno(p->fp) : 0,error ? "ERROR: ":"",sbuf);
86
87
}

88
89
90
91
92
93
94
/* 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;
95
96
	else
		flags|=O_TEXT;
97

98
99
100
	if(strchr(mode,'x'))
		flags|=O_EXCL;

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

/* File Object Methods */

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
	JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
145

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

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

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

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

			if(fdomode && e) {
180
181
				/* Remove deprecated (never-worked, non-standard) 'e'xclusive mode char (and warn): */
				for(e=strchr(fdomode, 'e'); e ; e=strchr(e, 'e')) {
182
					JS_ReportWarning(cx, "Deprecated file open mode: 'e'");
183
184
185
186
					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'))
187
188
189
190
191
					memmove(e, e+1, strlen(e));
				if((p->fp=fdopen(file,fdomode))==NULL)
					close(file);
			}
			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
228
229
230

	if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) {
		JS_ReportError(cx,getprivate_failure,WHERE);
		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

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

	dbprintf(FALSE, p, "closed");

291
	p->fp=NULL;
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
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
362
363
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;
}

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
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);
398
	if(len<0)
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
		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);
414

415
416
417
418
	return(JS_TRUE);
}


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

434
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
435

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

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

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

458
	if((buf=malloc(len+1))==NULL)
459
460
		return(JS_TRUE);

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

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

473
474
475
	if(p->rot13)
		rot13(buf);

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

499
	str = JS_NewStringCopyN(cx, buf, len);
500
	free(buf);
501

502
503
504
	if(str==NULL)
		return(JS_FALSE);

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

507
	rc=JS_SUSPENDREQUEST(cx);
508
	dbprintf(FALSE, p, "read %u bytes",len);
509
	JS_RESUMEREQUEST(cx, rc);
510

511
512
513
514
	return(JS_TRUE);
}

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

526
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
527

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

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

536
537
538
539
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return(JS_FALSE);
	}
540

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

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

	return(JS_TRUE);
}

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

585
	JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
586

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

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

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

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

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

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

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

675
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
676

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

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

685
    array = JS_NewArrayObject(cx, 0, NULL);
686

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

696
697
    return(JS_TRUE);
}
698

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

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

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

774
775
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

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

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

	return(JS_TRUE);
}

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

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

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

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

deuce's avatar
deuce committed
918
	if(value==JSVAL_VOID) { 	/* unspecified value */
919
		rc=JS_SUSPENDREQUEST(cx);
920
		result = iniSetString(list,section,key,"",&p->ini_style);
921
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
922
	}
deuce's avatar
deuce committed
923
	else if(JSVAL_IS_BOOLEAN(value)) {
924
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),&p->ini_style);
deuce's avatar
deuce committed
925
926
	}
	else if(JSVAL_IS_DOUBLE(value)) {
927
		result = iniSetFloat(list,section,key,JSVAL_TO_DOUBLE(value),&p->ini_style);
deuce's avatar
deuce committed
928
929
	}
	else if(JSVAL_IS_NUMBER(value)) {
930
		if(!JS_ValueToInt32(cx,value,&i)) {
931
932
			FREE_AND_NULL(section);
			FREE_AND_NULL(key);
933
934
			return JS_FALSE;
		}
deuce's avatar
deuce committed
935
		rc=JS_SUSPENDREQUEST(cx);
936
		result = iniSetInteger(list,section,key,i,&p->ini_style);
deuce's avatar
deuce committed
937
		JS_RESUMEREQUEST(cx, rc);
938
	} else if(JSVAL_IS_OBJECT(value)
deuce's avatar
deuce committed
939
940
941
942
			&& (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);
943
		result = iniSetDateTime(list,section,key,/* include_time */TRUE, tt, &p->ini_style);