/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU Public License (the "GPL"), in which case the * provisions of the GPL are applicable instead of those above. * If you wish to allow use of your version of this file only * under the terms of the GPL and not to allow others to use your * version of this file under the NPL, indicate your decision by * deleting the provisions above and replace them with the notice * and other provisions required by the GPL. If you do not delete * the provisions above, a recipient may use your version of this * file under either the NPL or the GPL. */ /* Copyright © 1998 Netscape Communications Corporation, All Rights Reserved.*/ /* JavaScript Shell: jssh. Provides capabilities for calling commans, */ /* loading libraries, etc. in JavaScript. For a full list of features, see /* README.html */ #include #include #include #include "jsapi.h" /* The API itself */ #include "jsatom.h" #ifdef HAS_FILE_SUPPORT /* File object */ # include "jsfile.h" #endif #ifdef LIVECONNECT /* link w/LiveConnect DLL */ # include "jsjava.h" #endif #ifdef PERLCONNECT /* link w/PerlConnect DLL */ # include "jsperl.h" #endif #define STACK_CHUNK_SIZE 8192 /* Platform-dependent stuff */ #ifdef XP_PC # define ENVIRON _environ # define PUTENV _putenv # define POPEN _popen # define PCLOSE _pclose # define PLATFORM "PC" #elif XP_UNIX # define ENVIRON environ # define PUTENV putenv # define POPEN popen # define PCLOSE pclose # define PLATFORM "UNIX" #elif XP_BEOS # define ENVIRON environ # define PUTENV putenv # define POPEN popen # define PCLOSE pclose # define PLATFORM "BeOS" #else # error "Platform not supported." #endif /* globals */ JSRuntime *rt; JSContext *cx; JSObject *globalObject, *systemObject, *envObject; /* forward-definitions */ static JSBool Process(JSContext*, JSObject*, char*, jsval *rval); static JSBool environment_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); /* global class */ JSClass globalClass = { "Global", 0, JS_PropertyStub, JS_PropertyStub,JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub }; /* system class */ JSClass systemClass = { "System", 0, JS_PropertyStub, JS_PropertyStub,JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub }; /* environment class */ JSClass envClass = { "Environment", 0, JS_PropertyStub, environment_setProperty, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub }; /* object loaded via use() get a separate namespace of this type */ JSClass libraryClass = { "Library", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub }; /****************************** global methods ******************************/ /* load JS files in argv and execute them */ static JSBool call(JSContext *cx, JSObject *obj, int argc, jsval *argv, jsval* rval){ int i; char *ch; JSBool result = JS_TRUE; FILE *file; static char* processFile(FILE*); for(i=0;ilength; i++) { jschar *prop; JSString *str; JS_IdToValue(cx, ida->vector[i], &v); str = JS_ValueToString(cx, v); prop = JS_GetStringChars(str); JS_GetUCProperty(cx, scriptObject, prop, JS_GetStringLength(str), &v); /* add v if it's a function */ if(JS_TypeOfValue(cx, v) == JSTYPE_FUNCTION){ char const *name = JS_GetFunctionName(JS_ValueToFunction(cx, v)); JS_DefineProperty(cx, scriptObject, name, v, NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT); } } /* save script as private data for the object */ if(!JS_SetPrivate(cx, scriptObject, (void*)script)){ return JS_FALSE; } JS_DefineFunction(cx, scriptObject, "eval", evalScript, 0, 0); } return JS_TRUE; } /********************** Define system methods **************************/ /* a replacement for System.out.write */ static JSBool system_print(JSContext *cx, JSObject *obj, int argc, jsval *argv, jsval* rval){ int i; JSString *str; for(i=0;ifilename, report->lineno, message); } /* add properties to Env */ static void readEnvironment(JSContext *cx, JSObject *env){ char **currEnvString; char currEnvName [256]; char currEnvValue[1024]; /* this must be big enough */ JSString *str; JSBool ok; for(currEnvString = ENVIRON; *currEnvString!=NULL; currEnvString++){ char *equal = strchr(*currEnvString, '='); strncpy(currEnvName, *currEnvString, equal-*currEnvString); currEnvName[equal-*currEnvString] = 0; /* append null char at the end */ equal++; strncpy(currEnvValue, equal, *currEnvString+strlen(*currEnvString)-equal+1); str=JS_NewStringCopyZ(cx, equal/*, *currEnvString+strlen(*currEnvString)-equal*/); if(!str) { JS_ReportError(cx, "Error in readEnvironment, str==NULL"); return; } /* add a new property to env object */ ok = JS_DefineProperty(cx, env, currEnvName, STRING_TO_JSVAL(str), JS_PropertyStub, environment_setProperty, JSPROP_ENUMERATE|JSPROP_PERMANENT); if(!ok) { JS_ReportError(cx, "Error in readEnvironment, can't define a property"); return; } } } /* formatted output of the environment */ static JSBool env_toString(JSContext *cx, JSObject *obj, int argc, jsval *argv, jsval* rval){ char **currEnvString; char currEnvName [256]; char currEnvValue[1024]; /* this must be big enough */ char *result; int len=0; result = JS_malloc(cx, 1); strcpy(result, ""); for(currEnvString = ENVIRON; *currEnvString!=NULL; currEnvString++){ char *equal = strchr(*currEnvString, '='), *p; char line[1024]; strncpy(currEnvName, *currEnvString, equal-*currEnvString); currEnvName[equal-*currEnvString] = 0; /* append null char at the end */ equal++; strncpy(currEnvValue, equal, *currEnvString+strlen(*currEnvString)-equal+1); sprintf(line, "%25s = %s\n", currEnvName, currEnvValue); len+=strlen(line)+1; p = (char*)JS_realloc(cx, result, len*sizeof(char)); if(!p) { JS_ReportOutOfMemory(cx); return JS_FALSE; } strcpy(p, result); result=p; strcat(result, line); } //JS_free(cx, result); *rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, result)); return JS_TRUE; } /*************************************************************************/ /* methods available */ JSFunctionSpec globalMethods[] = { {"call", call, 0, 0}, {"use", use, 0, 0}, { NULL, NULL, 0, 0} }; JSFunctionSpec systemMethods[] = { {"print", system_print, 0, 0}, {"version", system_version, 0, 0}, {"system", system_system, 0, 0}, {"gc", system_gc, 0, 0}, {"pipe", system_pipe, 0, 0}, {"script", system_script, 0, 0}, //{"help", system_help, 0, 0}, {"exit", system_exit, 0, 0}, { NULL, NULL, 0, 0} }; JSFunctionSpec envMethods[] = { {"toString", env_toString, 0}, { NULL, NULL,0 } }; /* Read a file. Return it as a char pointer that should be deallocated. Ignore #-comments. */ static char* processFile(FILE *file){ char *buf, *bufEnd, *bufUpto, ch; int bufLen, len; /* read the file into memory */ bufLen = 4096; buf = malloc(bufLen); /* allocate character buffer */ bufEnd = buf+bufLen; /* end of the buffer */ bufUpto = buf; /* current buffer pointer */ ch=fgetc(file); /* ignore first line starting with # */ if(ch=='#') while((ch=fgetc(file))!=EOF) { if(ch=='\n') break;} else ungetc(ch,file); while((len=fread(bufUpto, sizeof(char), bufEnd-bufUpto, file))>0){ bufUpto+=len; if(bufUpto>=bufEnd) { /* expand the buffer if needed */ bufLen+=bufLen; bufEnd=buf+bufLen; buf=realloc(buf,bufLen); } } *bufUpto = '\0'; //puts(buf); return buf; } /* Read JavaScript source from file or stdin if !filename Evaluate it. */ static JSBool Process(JSContext *cx, JSObject *obj, char *filename, jsval *rval){ FILE *file; char *ch; /* Process the input */ if(filename){ file = fopen(filename, "r"); if(file==NULL){ JS_ReportError(cx, "Can't open %s\n", filename); return JS_FALSE; } ch = processFile(file); JS_EvaluateScript(cx, obj, ch, strlen(ch), "jssh", 0, rval); free(ch); fclose(file); }else{ /* process input line-by-line */ char line[256]; int currLine = 0; JSString *str; do{ printf("js> "); gets(line); *rval = JSVAL_VOID; JS_EvaluateScript(cx, globalObject, line, strlen(line), "jss", ++currLine, rval); if(!JSVAL_IS_VOID(*rval)){ str=JS_ValueToString(cx, *rval); if(!str){ JS_ReportError(cx, "Can't convert to string"); } printf("%s\n", JS_GetStringBytes(str)); } }while(1); /* need to type 'exit' to exit */ } } static int usage(){ fprintf(stderr, "%s", JS_GetImplementationVersion()); fputs("usage: js [ [scriptfile] [scriptarg...] | - ]", stderr); return 2; } /* This is taken from JSShell. */ static int ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc){ int i; char *filename; jsval *vector; jsval *p; JSObject *argsObj; jsval rval; JSBool ok; /* prompt */ if(argc<2 || !strcmp(argv[1], "-")) filename = NULL; else if(argc==2) filename = argv[1]; else return usage(); vector = JS_malloc(cx, (argc-1)* sizeof(jsval)); p = vector; if(!p){ JS_ReportError(cx, "Error in ProcessArgs, p==NULL!"); } for(i=1;i