Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

jsexec.c 35.2 KB
Newer Older
rswindell's avatar
rswindell committed
1
/* Execute a Synchronet JavaScript module from the command-line */
2

Rob Swindell's avatar
Rob Swindell committed
3
/* $Id: jsexec.c,v 1.217 2020/08/17 00:48:28 rswindell Exp $ */
rswindell's avatar
rswindell committed
4
// vi: tabstop=4
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
 *																			*
 * 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.	*
 ****************************************************************************/

rswindell's avatar
rswindell committed
37
#ifndef JAVASCRIPT
38
#define JAVASCRIPT
rswindell's avatar
rswindell committed
39
#endif
40

deuce's avatar
deuce committed
41
#ifdef __unix__
42
#define _WITH_GETLINE
deuce's avatar
deuce committed
43
#include <signal.h>
deuce's avatar
deuce committed
44
#include <termios.h>
deuce's avatar
deuce committed
45 46
#endif

47
#include "sbbs.h"
48
#include "ciolib.h"
49
#include "ini_file.h"
50
#include "js_rtpool.h"
51
#include "js_request.h"
52
#include "jsdebug.h"
53

54
#define DEFAULT_LOG_LEVEL	LOG_INFO
55
#define DEFAULT_ERR_LOG_LVL	LOG_WARNING
56

57 58 59 60 61 62
static const char*	strJavaScriptMaxBytes		="JavaScriptMaxBytes";
static const char*	strJavaScriptContextStack	="JavaScriptContextStack";
static const char*	strJavaScriptTimeLimit		="JavaScriptTimeLimit";
static const char*	strJavaScriptGcInterval		="JavaScriptGcInterval";
static const char*	strJavaScriptYieldInterval	="JavaScriptYieldInterval";

63
js_startup_t	startup;
64 65 66
JSRuntime*	js_runtime;
JSContext*	js_cx;
JSObject*	js_glob;
67
js_callback_t	cb;
68
scfg_t		scfg;
69
char*		text[TOTAL_TEXT];
70
ulong		js_max_bytes=JAVASCRIPT_MAX_BYTES;
71
ulong		js_cx_stack=JAVASCRIPT_CONTEXT_STACK;
rswindell's avatar
rswindell committed
72 73
FILE*		confp;
FILE*		errfp;
74
FILE*		nulfp;
75
FILE*		statfp;
76
char		revision[16];
77
char		compiler[32];
78 79
char*		host_name=NULL;
char		host_name_buf[128];
80
char*		load_path_list=JAVASCRIPT_LOAD_PATH;
81
BOOL		pause_on_exit=FALSE;
rswindell's avatar
rswindell committed
82
BOOL		pause_on_error=FALSE;
83
BOOL		terminated=FALSE;
84
BOOL		recycled;
85
int			log_level=DEFAULT_LOG_LEVEL;
86
int  		err_level=DEFAULT_ERR_LOG_LVL;
87
long		umask_val = -1;
88
pthread_mutex_t output_mutex;
89 90
#if defined(__unix__)
BOOL		daemonize=FALSE;
91
struct termios	orig_term;
92
#endif
93
char		orig_cwd[MAX_PATH+1];
deuce's avatar
deuce committed
94
BOOL		debugger=FALSE;
95 96 97 98 99 100
#ifndef PROG_NAME
#define PROG_NAME "JSexec"
#endif
#ifndef PROG_NAME_LC
#define PROG_NAME_LC "jsexec"
#endif
101

102 103
void banner(FILE* fp)
{
104
	fprintf(fp,"\n" PROG_NAME " v%s%c-%s (rev %s)%s - "
105 106 107 108
		"Execute Synchronet JavaScript Module\n"
		,VERSION,REVISION
		,PLATFORM_DESC
		,revision
109 110 111 112 113
#ifdef _DEBUG
		," Debug"
#else
		,""
#endif
114
		);
115 116 117

	fprintf(fp, "Compiled %s %s with %s\n"
		,__DATE__, __TIME__, compiler);
118
}
119

rswindell's avatar
rswindell committed
120 121
void usage(FILE* fp)
{
122 123
	banner(fp);

124
	fprintf(fp,"\nusage: " PROG_NAME_LC " [-opts] [path]module[.js] [args]\n"
rswindell's avatar
rswindell committed
125
		"\navailable opts:\n\n"
126
#ifdef JSDOOR
127
		"    -c<ctrl_dir>   specify path to CTRL directory\n"
128
#else
129
		"    -c<ctrl_dir>   specify path to Synchronet CTRL directory\n"
130
#endif
131
		"    -C             do not change the current working directory (to CTRL dir)\n"
132
#if defined(__unix__)
133
		"    -d             run in background (daemonize)\n"
134
#endif
135 136 137 138 139
		"    -m<bytes>      set maximum heap size (default=%u bytes)\n"
		"    -s<bytes>      set context stack size (default=%u bytes)\n"
		"    -t<limit>      set time limit (default=%u, 0=unlimited)\n"
		"    -y<interval>   set yield interval (default=%u, 0=never)\n"
		"    -g<interval>   set garbage collection interval (default=%u, 0=never)\n"
140
#ifdef JSDOOR
141
		"    -h[hostname]   use local or specified host name\n"
142
#else
143
		"    -h[hostname]   use local or specified host name (instead of SCFG value)\n"
144
#endif
145 146 147 148 149 150
		"    -u<mask>       set file creation permissions mask (in octal)\n"
		"    -L<level>      set log level (default=%u)\n"
		"    -E<level>      set error log level threshold (default=%u)\n"
		"    -i<path_list>  set load() comma-sep search path list (default=\"%s\")\n"
		"    -f             use non-buffered stream for console messages\n"
		"    -a             append instead of overwriting message output files\n"
151 152
		"    -A             send all message to stdout\n"
		"    -A<filename>   send all message to file instead of stdout/stderr\n"
153 154
		"    -e<filename>   send error messages to file in addition to stderr\n"
		"    -o<filename>   send console messages to file instead of stdout\n"
155 156
		"    -S<filename>   send status messages to file instead of stderr\n"
		"    -S             send status messages to stdout\n"
157 158 159 160 161 162 163 164
		"    -n             send status messages to %s instead of stderr\n"
		"    -q             send console messages to %s instead of stdout\n"
		"    -v             display version details and exit\n"
		"    -x             disable auto-termination on local abort signal\n"
		"    -l             loop until intentionally terminated\n"
		"    -p             wait for keypress (pause) on exit\n"
		"    -!             wait for keypress (pause) on error\n"
		"    -D             debugs the script\n"
rswindell's avatar
rswindell committed
165 166
		,JAVASCRIPT_MAX_BYTES
		,JAVASCRIPT_CONTEXT_STACK
167
		,JAVASCRIPT_TIME_LIMIT
168 169
		,JAVASCRIPT_YIELD_INTERVAL
		,JAVASCRIPT_GC_INTERVAL
170
		,DEFAULT_LOG_LEVEL
171
		,DEFAULT_ERR_LOG_LVL
172
		,load_path_list
173
		,_PATH_DEVNULL
174
		,_PATH_DEVNULL
rswindell's avatar
rswindell committed
175 176
		);
}
177

178 179 180 181 182 183 184 185 186
static void
cooked_tty(void)
{
	if (isatty(fileno(stdin))) {
#ifdef __unix__
		tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
#elif defined _WIN32
		SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_ECHO_INPUT
		    | ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT
187
		    | ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE);
188
#else
189
		#warning "Can't cook the tty on this platform"
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
#endif
	}
}

#ifdef __unix__
static void raw_input(struct termios *t)
{
#ifdef JSDOOR
	t->c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
	t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
#else
	t->c_iflag &= ~(IMAXBEL|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
	t->c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
#endif
}
#endif

static void
raw_tty(void)
{
	if (isatty(fileno(stdin))) {
#ifdef __unix__
		struct termios term = orig_term;

		raw_input(&term);
		tcsetattr(fileno(stdin), TCSANOW, &term);
#elif defined _WIN32
deuce's avatar
deuce committed
217 218
		SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), 0);
#else
219
		#warning "Can't set the tty as raw on this platform"
220 221 222 223
#endif
	}
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
int mfprintf(FILE* fp, char *fmt, ...)
{
	va_list argptr;
	char sbuf[1024];
	int ret=0;

    va_start(argptr,fmt);
    ret=vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
	sbuf[sizeof(sbuf)-1]=0;
    va_end(argptr);

	/* Mutex-protect stdout/stderr */
	pthread_mutex_lock(&output_mutex);

	ret = fprintf(fp, "%s\n", sbuf);

	pthread_mutex_unlock(&output_mutex);
    return(ret);
}

244
/* Log printf */
245
int lprintf(int level, const char *fmt, ...)
246 247 248
{
	va_list argptr;
	char sbuf[1024];
deuce's avatar
deuce committed
249
	int ret=0;
250

251
	if(level > log_level)
252 253 254
		return(0);

    va_start(argptr,fmt);
255
    ret=vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
256 257
	sbuf[sizeof(sbuf)-1]=0;
    va_end(argptr);
258 259
#if defined(__unix__)
	if(daemonize) {
260
		syslog(level,"%s",sbuf);
261 262 263
		return(ret);
	}
#endif
264 265 266 267

	/* Mutex-protect stdout/stderr */
	pthread_mutex_lock(&output_mutex);

268
	if(level<=err_level) {
269
		ret=fprintf(errfp,"%s\n",sbuf);
270
		if(errfp!=stderr)
271 272
			ret=fprintf(statfp,"%s\n",sbuf);
	}
273 274
	if(level>err_level)
		ret=fprintf(statfp,"%s\n",sbuf);
275 276

	pthread_mutex_unlock(&output_mutex);
277 278 279
    return(ret);
}

280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
#if defined(__unix__) && defined(NEEDS_DAEMON)
/****************************************************************************/
/* Daemonizes the process                                                   */
/****************************************************************************/
int
daemon(int nochdir, int noclose)
{
    int fd;

    switch (fork()) {
    case -1:
        return (-1);
    case 0:
        break;
    default:
        _exit(0);
    }

    if (setsid() == -1)
        return (-1);

    if (!nochdir)
        (void)chdir("/");

    if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
        (void)dup2(fd, STDIN_FILENO);
        (void)dup2(fd, STDOUT_FILENO);
        (void)dup2(fd, STDERR_FILENO);
        if (fd > 2)
            (void)close(fd);
    }
    return (0);
}
#endif

315
#if defined(_WINSOCKAPI_)
316 317

WSADATA WSAData;
318
#define SOCKLIB_DESC WSAData.szDescription
319 320 321 322 323 324 325
static BOOL WSAInitialized=FALSE;

static BOOL winsock_startup(void)
{
	int		status;             /* Status Code */

    if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
326
/*		fprintf(statfp,"%s %s\n",WSAData.szDescription, WSAData.szSystemStatus); */
327 328 329 330
		WSAInitialized=TRUE;
		return(TRUE);
	}

331
    lprintf(LOG_CRIT,"!WinSock startup ERROR %d", status);
332 333 334 335 336
	return(FALSE);
}

#else /* No WINSOCK */

337 338
#define winsock_startup()	(TRUE)
#define SOCKLIB_DESC NULL
339 340 341

#endif

342
static int do_bail(int code)
343
{
344
#if defined(_WINSOCKAPI_)
345
	if(WSAInitialized && WSACleanup()!=0) 
346
		lprintf(LOG_ERR,"!WSACleanup ERROR %d",ERROR_VALUE);
347 348
#endif

349
	cooked_tty();
rswindell's avatar
rswindell committed
350
	if(pause_on_exit || (code && pause_on_error)) {
351
		fprintf(statfp,"\nHit enter to continue...");
352 353
		getchar();
	}
354 355 356

	if(code)
		fprintf(statfp,"\nReturning error code: %d\n",code);
357 358 359 360 361 362
	return(code);
}

void bail(int code)
{
	exit(do_bail(code));
363 364
}

365
static JSBool
366
js_log(JSContext *cx, uintN argc, jsval *arglist)
367
{
368
	jsval *argv=JS_ARGV(cx, arglist);
369 370
    uintN		i=0;
	int32		level=LOG_INFO;
371
    JSString*	str=NULL;
deuce's avatar
deuce committed
372
	jsrefcount	rc;
deuce's avatar
deuce committed
373 374
	char		*logstr=NULL;
	size_t		logstr_sz=0;
375

376 377
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

378 379 380 381
	if(argc > 1 && JSVAL_IS_NUMBER(argv[i])) {
		if(!JS_ValueToInt32(cx,argv[i++],&level))
			return JS_FALSE;
	}
382

383 384 385
	for(; i<argc; i++) {
		if((str=JS_ValueToString(cx, argv[i]))==NULL)
			return(JS_FALSE);
deuce's avatar
deuce committed
386
		JSSTRING_TO_RASTRING(cx, str, logstr, &logstr_sz, NULL);
deuce's avatar
deuce committed
387 388
		if(logstr==NULL)
			return(JS_FALSE);
389
		rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
390
		lprintf(level,"%s",logstr);
391
		JS_RESUMEREQUEST(cx, rc);
392
		FREE_AND_NULL(logstr);
393 394
	}

395
	if(str==NULL)
396
		JS_SET_RVAL(cx, arglist, JSVAL_VOID);
397
	else
398
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
399

400 401 402
    return(JS_TRUE);
}

403
static JSBool
404
js_read(JSContext *cx, uintN argc, jsval *arglist)
405
{
406
	jsval *argv=JS_ARGV(cx, arglist);
407 408 409
	char*	buf;
	int		rd;
	int32	len=128;
deuce's avatar
deuce committed
410
	jsrefcount	rc;
411

412 413
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

414 415 416 417
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return JS_FALSE;
	}
deuce's avatar
deuce committed
418
	if((buf=malloc(len))==NULL)
419 420
		return(JS_TRUE);

421
	rc=JS_SUSPENDREQUEST(cx);
422
	rd=fread(buf,sizeof(char),len,stdin);
423
	JS_RESUMEREQUEST(cx, rc);
424 425

	if(rd>=0)
426
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyN(cx,buf,rd)));
deuce's avatar
deuce committed
427
	free(buf);
428 429 430 431 432

    return(JS_TRUE);
}

static JSBool
433
js_readln(JSContext *cx, uintN argc, jsval *arglist)
434
{
435
	jsval *argv=JS_ARGV(cx, arglist);
436 437 438
	char*	buf;
	char*	p;
	int32	len=128;
deuce's avatar
deuce committed
439
	jsrefcount	rc;
440

441 442
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

443 444 445 446
	if(argc) {
		if(!JS_ValueToInt32(cx,argv[0],&len))
			return JS_FALSE;
	}
deuce's avatar
deuce committed
447
	if((buf=malloc(len+1))==NULL)
448 449
		return(JS_TRUE);

450
	rc=JS_SUSPENDREQUEST(cx);
451
	cooked_tty();
452
	p=fgets(buf,len+1,stdin);
453
	raw_tty();
454
	JS_RESUMEREQUEST(cx, rc);
455 456

	if(p!=NULL)
457
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx,truncnl(p))));
deuce's avatar
deuce committed
458
	free(buf);
459 460 461 462 463

    return(JS_TRUE);
}


464
static JSBool
465
js_write(JSContext *cx, uintN argc, jsval *arglist)
466
{
467
	jsval *argv=JS_ARGV(cx, arglist);
468
    uintN		i;
469
    JSString*	str=NULL;
deuce's avatar
deuce committed
470
	jsrefcount	rc;
deuce's avatar
deuce committed
471 472
	char		*line=NULL;
	size_t		line_sz=0;
473

474 475
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

476
    for (i = 0; i < argc; i++) {
477
		if((str=JS_ValueToString(cx, argv[i]))==NULL)
478
		    return(JS_FALSE);
deuce's avatar
deuce committed
479
		JSSTRING_TO_RASTRING(cx, str, line, &line_sz, NULL);
deuce's avatar
deuce committed
480 481
		if(line==NULL)
			return(JS_FALSE);
482
		rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
483
		fprintf(confp,"%s",line);
484
		FREE_AND_NULL(line);
485
		JS_RESUMEREQUEST(cx, rc);
486 487
	}

488
	if(str==NULL)
489
		JS_SET_RVAL(cx, arglist, JSVAL_VOID);
490
	else
491
		JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
492 493 494 495
    return(JS_TRUE);
}

static JSBool
496
js_writeln(JSContext *cx, uintN argc, jsval *arglist)
497
{
deuce's avatar
deuce committed
498 499
	jsrefcount	rc;

500 501
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

deuce's avatar
deuce committed
502
	if(!js_write(cx,argc,arglist))
503 504
		return(JS_FALSE);

505
	rc=JS_SUSPENDREQUEST(cx);
506
	fprintf(confp,"\n");
507
	JS_RESUMEREQUEST(cx, rc);
508 509 510 511
    return(JS_TRUE);
}

static JSBool
512
jse_printf(JSContext *cx, uintN argc, jsval *arglist)
513
{
514
	jsval *argv=JS_ARGV(cx, arglist);
515
	char* p;
deuce's avatar
deuce committed
516
	jsrefcount	rc;
517

518 519
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

520 521
	if((p = js_sprintf(cx, 0, argc, argv))==NULL) {
		JS_ReportError(cx,"js_sprintf failed");
522 523 524
		return(JS_FALSE);
	}

525
	rc=JS_SUSPENDREQUEST(cx);
526
	fprintf(confp,"%s",p);
527
	JS_RESUMEREQUEST(cx, rc);
528

529
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, p)));
530

531
	js_sprintf_free(p);
532 533 534 535 536

    return(JS_TRUE);
}

static JSBool
537
js_alert(JSContext *cx, uintN argc, jsval *arglist)
538
{
539
	jsval *argv=JS_ARGV(cx, arglist);
deuce's avatar
deuce committed
540
	jsrefcount	rc;
deuce's avatar
deuce committed
541
	char		*line;
542

543 544
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

deuce's avatar
deuce committed
545
	JSVALUE_TO_MSTRING(cx, argv[0], line, NULL);
deuce's avatar
deuce committed
546
	if(line==NULL)
547 548
	    return(JS_FALSE);

549
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
550
	fprintf(confp,"!%s\n",line);
deuce's avatar
deuce committed
551
	free(line);
552
	JS_RESUMEREQUEST(cx, rc);
553

554
	JS_SET_RVAL(cx, arglist, argv[0]);
555

556 557 558 559
    return(JS_TRUE);
}

static JSBool
560
js_confirm(JSContext *cx, uintN argc, jsval *arglist)
561
{
562
	jsval *argv=JS_ARGV(cx, arglist);
563
    JSString *	str;
564
	char	 *	cstr = NULL;
565
	char     *	p;
deuce's avatar
deuce committed
566
	jsrefcount	rc;
567
	char		instr[81]="y";
568

569 570
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

571 572 573
	if((str=JS_ValueToString(cx, argv[0]))==NULL)
	    return(JS_FALSE);

deuce's avatar
deuce committed
574
	JSSTRING_TO_MSTRING(cx, str, cstr, NULL);
575
	HANDLE_PENDING(cx, cstr);
deuce's avatar
deuce committed
576 577
	if(cstr==NULL)
		return JS_TRUE;
578
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
579 580
	printf("%s (Y/n)? ", cstr);
	free(cstr);
581
	cooked_tty();
582
	fgets(instr,sizeof(instr),stdin);
583
	raw_tty();
584
	JS_RESUMEREQUEST(cx, rc);
585

586 587
	p=instr;
	SKIP_WHITESPACE(p);
588
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(tolower(*p)!='n'));
589 590 591 592
	return(JS_TRUE);
}

static JSBool
593
js_deny(JSContext *cx, uintN argc, jsval *arglist)
594
{
595
	jsval *argv=JS_ARGV(cx, arglist);
596
    JSString *	str;
597
	char	 *	cstr = NULL;
598 599 600 601
	char     *	p;
	jsrefcount	rc;
	char		instr[81];

602 603
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

604 605 606
	if((str=JS_ValueToString(cx, argv[0]))==NULL)
	    return(JS_FALSE);

deuce's avatar
deuce committed
607
	JSSTRING_TO_MSTRING(cx, str, cstr, NULL);
608
	HANDLE_PENDING(cx, cstr);
deuce's avatar
deuce committed
609 610
	if(cstr==NULL)
		return JS_TRUE;
611
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
612 613
	printf("%s (N/y)? ", cstr);
	free(cstr);
614
	cooked_tty();
615
	fgets(instr,sizeof(instr),stdin);
616
	raw_tty();
617 618 619 620
	JS_RESUMEREQUEST(cx, rc);

	p=instr;
	SKIP_WHITESPACE(p);
621
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(tolower(*p)!='y'));
622 623 624 625
	return(JS_TRUE);
}

static JSBool
626
js_prompt(JSContext *cx, uintN argc, jsval *arglist)
627
{
628
	jsval *argv=JS_ARGV(cx, arglist);
629
	char		instr[256];
630
    JSString *	str;
deuce's avatar
deuce committed
631
	jsrefcount	rc;
632
	char		*prstr = NULL;
633

634 635
	JS_SET_RVAL(cx, arglist, JSVAL_VOID);

636
	if(argc>0 && !JSVAL_IS_VOID(argv[0])) {
deuce's avatar
deuce committed
637
		JSVALUE_TO_MSTRING(cx, argv[0], prstr, NULL);
638
		HANDLE_PENDING(cx, prstr);
639
		if(prstr==NULL)
640
			return(JS_FALSE);
641
		rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
642
		fprintf(confp,"%s: ",prstr);
deuce's avatar
deuce committed
643
		free(prstr);
644
		JS_RESUMEREQUEST(cx, rc);
645
	}
646 647

	if(argc>1) {
deuce's avatar
deuce committed
648
		JSVALUE_TO_STRBUF(cx, argv[1], instr, sizeof(instr), NULL);
649
		HANDLE_PENDING(cx, NULL);
650 651 652
	} else
		instr[0]=0;

653
	rc=JS_SUSPENDREQUEST(cx);
654
	cooked_tty();
655
	if(!fgets(instr,sizeof(instr),stdin)) {
656
		raw_tty();
657
		JS_RESUMEREQUEST(cx, rc);
658
		return(JS_TRUE);
659
	}
660
	raw_tty();
661
	JS_RESUMEREQUEST(cx, rc);
662

663
	if((str=JS_NewStringCopyZ(cx, truncnl(instr)))==NULL)
664 665
	    return(JS_FALSE);

666
	JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
667 668 669
    return(JS_TRUE);
}

rswindell's avatar
rswindell committed
670
static JSBool
671
js_chdir(JSContext *cx, uintN argc, jsval *arglist)
rswindell's avatar
rswindell committed
672
{
673
	jsval *argv=JS_ARGV(cx, arglist);
674
	char*		p = NULL;
deuce's avatar
deuce committed
675
	jsrefcount	rc;
deuce's avatar
deuce committed
676
	BOOL		ret;
rswindell's avatar
rswindell committed
677

deuce's avatar
deuce committed
678
	JSVALUE_TO_MSTRING(cx, argv[0], p, NULL);
679
	HANDLE_PENDING(cx, p);
deuce's avatar
deuce committed
680
	if(p==NULL) {
681
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
rswindell's avatar
rswindell committed
682 683 684
		return(JS_TRUE);
	}

685
	rc=JS_SUSPENDREQUEST(cx);
deuce's avatar
deuce committed
686 687
	ret=chdir(p)==0;
	free(p);
688
	JS_RESUMEREQUEST(cx, rc);
deuce's avatar
deuce committed
689
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(ret));
rswindell's avatar
rswindell committed
690 691 692
	return(JS_TRUE);
}

693
static JSBool
694
js_putenv(JSContext *cx, uintN argc, jsval *arglist)
695
{
696
	jsval *argv=JS_ARGV(cx, arglist);
697
	char*		p=NULL;
deuce's avatar
deuce committed
698 699
	BOOL		ret;
	jsrefcount	rc;
700

deuce's avatar
deuce committed
701 702
	if(argc) {
		JSVALUE_TO_MSTRING(cx, argv[0], p, NULL);
703
		HANDLE_PENDING(cx, p);
deuce's avatar
deuce committed
704
	}
deuce's avatar
deuce committed
705
	if(p==NULL) {
706
		JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
707 708 709
		return(JS_TRUE);
	}

deuce's avatar
deuce committed
710 711 712 713 714
	rc=JS_SUSPENDREQUEST(cx);
	ret=putenv(strdup(p))==0;
	free(p);
	JS_RESUMEREQUEST(cx, rc);
	JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(ret));
715 716 717
	return(JS_TRUE);
}

718
static jsSyncMethodSpec js_global_functions[] = {
719
	{"log",				js_log,				1},
720
	{"read",			js_read,            1},
deuce's avatar
deuce committed
721 722 723 724
	{"readln",			js_readln,			0,	JSTYPE_STRING,	JSDOCSTR("[count]")
	,JSDOCSTR("read a single line, up to count characters, from input stream")
	,311
	},
725
    {"write",           js_write,           0},
726 727
    {"writeln",         js_writeln,         0},
    {"print",           js_writeln,         0},
728
    {"printf",          jse_printf,          1},	
729 730 731
	{"alert",			js_alert,			1},
	{"prompt",			js_prompt,			1},
	{"confirm",			js_confirm,			1},
732
	{"deny",			js_deny,			1},
rswindell's avatar
rswindell committed
733
	{"chdir",			js_chdir,			1},
734
	{"putenv",			js_putenv,			1},
735 736 737 738 739 740 741 742 743
    {0}
};

static void
js_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
{
	char	line[64];
	char	file[MAX_PATH+1];
	const char*	warning;
deuce's avatar
deuce committed
744
	jsrefcount	rc;
745
	int		log_level;
746

747
	rc=JS_SUSPENDREQUEST(cx);
748
	if(report==NULL) {
749
		lprintf(LOG_ERR,"!JavaScript: %s", message);
750
		JS_RESUMEREQUEST(cx, rc);
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
		return;
    }

	if(report->filename)
		sprintf(file," %s",report->filename);
	else
		file[0]=0;

	if(report->lineno)
		sprintf(line," line %d",report->lineno);
	else
		line[0]=0;

	if(JSREPORT_IS_WARNING(report->flags)) {
		if(JSREPORT_IS_STRICT(report->flags))
			warning="strict warning";
		else
			warning="warning";
769 770 771
		log_level=LOG_WARNING;
	} else {
		log_level=LOG_ERR;
772
		warning="";
773
	}
774

775
	lprintf(log_level,"!JavaScript %s%s%s: %s",warning,file,line,message);
776
	JS_RESUMEREQUEST(cx, rc);
777 778
}

779 780 781 782 783 784
static JSBool
js_OperationCallback(JSContext *cx)
{
	JSBool	ret;

	JS_SetOperationCallback(cx, NULL);
785
	ret=js_CommonOperationCallback(cx, &cb);
786 787 788
	JS_SetOperationCallback(cx, js_OperationCallback);
	return ret;
}
789

rswindell's avatar
rswindell committed