js_file.c 80.1 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
		return(JS_FALSE);
	}

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

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

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

383
	if(argc && !JSVAL_NULL_OR_VOID(argv[0])) {
384
385
386
387
388
389
390
391
392
393
394
395
		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
	dbprintf(FALSE, p, "read %u raw bytes",len);
397
	if(len<0)
398
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));

	return(JS_TRUE);
}


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

429
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
430

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

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

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

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

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

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

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

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

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

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

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

502
503
504
505
	return(JS_TRUE);
}

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

517
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
518

519
	if((p=(private_t*)js_GetClassPrivate(cx, obj, &js_file_class))==NULL) {
520
		return(JS_FALSE);
521
	}
522
523
524

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

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

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

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

	return(JS_TRUE);
}

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

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

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

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

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

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

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

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

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

680
	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
681

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

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

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

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

700
701
    return(JS_TRUE);
}
702

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

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

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

778
779
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

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

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

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

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

	return(JS_TRUE);
}

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

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

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

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

deuce's avatar
deuce committed
920
	if(value==JSVAL_VOID) { 	/* unspecified value */
921
		rc=JS_SUSPENDREQUEST(cx);
922
		result = iniSetString(list,section,key,"",&p->ini_style);
923
		JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
924
	}
deuce's avatar
deuce committed
925
	else if(JSVAL_IS_BOOLEAN(value)) {
926
		result = iniSetBool(list,section,key,JSVAL_TO_BOOLEAN(value),&p->ini_style);
deuce's avatar
deuce committed
927
928
	}
	else if(JSVAL_IS_DOUBLE(val