Warning: session_start(): open(/var/lib/php/sessions/sess_81cav37jbolee8h2g5iabn8epr, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
!7
set flag AllPublic.
set flag InCore.
should not include function cget.
do not include function has.
should not include class RemoteDB.
should not include class Concepts.
/**
JavaX runner version 30
Changes to v29:
-added integrated MultiPort
-useBossBot = false
-Beginning support for offline mode (transpiled programs only so far)
-faster console update (100ms)
-weakref
-made first program an injection
-manage multi-ports
-multitry for loadPage (partially implemented)
-list injections
-additional "get output" questions
-send line * to system.in
-multi-port 1 accessible directly through VM android
-getInjectionID (from main.class)
-allow programs without main method
-increase buffer size for PipedInputStream (console output/input)
-registerSourceCode + getSourceCodeForClass
-autoScroll
-retaining class files for 30 days (restart JavaX programs after 30 days!!)
-close confirmation for console (no running apps without console!)
-utf8 fixed in transpilations!
-maxConsoleChars
-pause button
-regular GC every 60s
-GC after main ran
-and more
TODO when making x31: change program ID in source
*/
m { p { throw new RuntimeException("placebo"); } }
interface StringFunc {
String get(String s);
}
/*interface DynamicMethods {
O _dynCall(S methodName, O[] args);
}*/
class x30 implements Runnable {
static final String version = "JavaX 30";
static final int subversion = 2;
static S dateChanged = "2018/05/23";
static final S javaxProgramID = "#1001638";
// If programs run longer than this, they might have their class files
// deleted. Should set to 30 for servers. Working on real solution.
static int tempFileRetentionTime = 2*24; // hours
static int maxConsoleChars = 1024*1024;
static int consoleUpdateDelay = 50; // ms
static int pipeDelay = 50;
static bool focusConsoleInputOnActivate = false;
sS donePrefix = "."; // "[Done] ";
static bool consoleGrabFocus;
static int consoleWidth = 550, consoleHeight = 200;
static int consoleXGap = 10, consoleYGap = 10;
static bool gcAfterMainDone = true, registerSourceCodes = false;
static bool verbose = false, translate = false, list = false, virtualizeTranslators = true;
static S translateTo = null;
static bool noID = false, noPrefetch = false, noAWT = false;
static bool safeOnly = false, safeTranslate = false, javacOnly = false, logOn = true, noCleanCache;
static volatile bool cleanCacheDone;
static bool runMainInProcess = true, consoleOn = true, hasHelloMessage = false;
static L mainTranslators = new ArrayList();
private static Map memSnippetCache = new HashMap();
private static int processesStarted, compilations;
// snippet ID -> md5
private static HashMap prefetched = new HashMap();
private static File virtCache;
// doesn't work yet
private static Map> programCache = new HashMap>();
static boolean cacheTranslators = false;
// this should work (caches transpiled translators)
private static HashMap translationCache = new HashMap();
static boolean cacheTranspiledTranslators = true;
// which snippets are available pre-transpiled server-side?
private static Set hasTranspiledSet = new HashSet();
static boolean useServerTranspiled = true;
static boolean useBossBot = false;
static Object androidContext;
static boolean android = isAndroid();
// We stick to 1.7 to support Android.
// Also, ecj doesn't seem to support 1.8?
static S javaTarget =
System.getProperty("java.version").startsWith("1.6.") ? "1.6"
: /*System.getProperty("java.version").startsWith("1.7.") ?*/ "1.7" /* : "1.8"*/;
// Translators currently being translated (to detect recursions)
private static Set translating = new HashSet();
static String lastOutput;
static String[] fullArgs;
private static Console console;
static String javaCompilerOutput;
static int systemOutPipeSize = 128*1024; // 128 K
static int systemErrPipeSize = 4*1024; // 4 K
static int systemInPipeSize = 4*1024; // 4 K
static S caseID;
static volatile bool hiddenVM;
static long vmStarted = now();
static long vmStarted_sysTime = sysNow();
sclass VMKeep {
S programMD5;
new HashMap vars; // var name -> structure
}
static new HashMap vmKeep;
static Lock vmKeep_lock = lock();
// store anything here
static Map generalMap = synchroHashMap();
public static void main(String[] args) {
try {
goMain(args);
} catch (Throwable e) {
printStackTrace(e);
}
}
// rewrite command line args if we're called from browser
// e.g. "javax:123"
static S[] rewriteArgsForURLHandler(S[] args) {
//print("Args: " + sfu(args));
if (l(args) == 1 && args[0].startsWith("javax:")) {
S a = args[0];
//print("Rewriting argument: " + a);
a = dropPrefix("javax:", a);
a = trim(dropPrefix("//", a));
a = dropSuffix("/", a);
ret asStringArray(splitAtSpace(a)); // TODO: handle quotes
}
ret args;
}
sbool inited;
svoid initMe {
if (inited) ret;
inited = true;
__javax = x30.class; // for hotwire
regularGC();
computerID(); // Generate!
}
static void goMain(String[] args) throws Exception {
// init Global Util's reference to me
setOpt(classForName("x30_pkg.x30_util"), "__javax", x30.class);
appendToMechQ_withDate("x30 start log on computer " + computerID(), quote(first(args)));
initMe();
args = rewriteArgsForURLHandler(args);
if (args.length != 0 && args[0].equals("-v")) verbose = true;
redirectSystemOutAndErr();
for (S arg : args)
if (arg.equals("-noawt"))
noAWT = true;
if (consoleOn && console == null && !noAWT)
tryToOpenConsole(args);
String autoReport = loadTextFile(new File(userHome(), ".javax/auto-report-to-chat").getPath(), "").trim();
//print("autoReport=" + autoReport);
if (!isChatServer(args) && autoReport.equals("1"))
autoReportToChat();
if (!hasHelloMessage) {
hasHelloMessage = true;
//installHelloMessage(args.length == 0 ? "JavaX Start-Up VM" : "JavaX VM (" + smartJoin(args) + ")");
makeVMAndroid();
}
File ioBaseDir = new File("."), inputDir = null, outputDir = null;
String src = null;
List programArgs = new ArrayList();
fullArgs = args;
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("-version")) {
showVersion();
System.exit(0);
}
if (arg.equals("-sysprop")) {
showSystemProperties();
return;
}
if (arg.equals("-v") || arg.equals("-verbose"))
verbose = true;
else if (arg.equals("-finderror"))
verbose = true;
else if (arg.equals("-offline") || arg.equalsIgnoreCase("-prefercached"))
preferCached = true;
else if (arg.equals("-novirt"))
virtualizeTranslators = false;
else if (arg.equals("-safeonly"))
safeOnly = true;
else if (arg.equals("-safetranslate"))
safeTranslate = true;
else if (arg.equals("-noawt"))
noAWT = true;
else if (arg.equals("-case"))
caseID = args[++i];
else if (arg.equals("-noid"))
noID = true;
else if (arg.equals("-nocachetranspiled"))
cacheTranspiledTranslators = false;
else if (arg.equals("-javac"))
javacOnly = true;
else if (arg.equals("-nocleancache"))
noCleanCache = true;
else if (arg.equals("-localtranspile"))
useServerTranspiled = false;
else if (arg.equals("translate") && src == null)
translate = true;
else if (arg.equals("eval") && src == null)
src = #1006008;
else if (arg.equals("list") && src == null) {
list = true;
virtualizeTranslators = false; // so they are silenced
} else if (arg.equals("run") && src == null) {
// it's the default command anyway
} else if (arg.startsWith("input="))
inputDir = new File(arg.substring(6));
else if (arg.startsWith("output="))
outputDir = new File(arg.substring(7));
else if (arg.equals("with"))
mainTranslators.add(new String[] {args[++i], null});
else if (translate && arg.equals("to"))
translateTo = args[++i];
else if (src == null) {
//System.out.println("src=" + arg);
src = arg;
} else
programArgs.add(arg);
}
if (!noCleanCache) thread "Clean Cache" { cleanCache(); }
if (useServerTranspiled)
noPrefetch = true;
if (src == null && fileExists("main.java")) {
src = ".";
print("WARNING: Runnning " + absolutePath("main.java") + " - this may not be what you want. Change to another directory to resume normal operation.");
}
// Might actually want to write to 2 disk caches (global/per program).
if (virtualizeTranslators && !preferCached)
virtCache = TempDirMaker_make();
if (inputDir != null) {
ioBaseDir = TempDirMaker_make();
System.out.println("Taking input from: " + inputDir.getAbsolutePath());
System.out.println("Output is in: " + new File(ioBaseDir, "output").getAbsolutePath());
copyInput(inputDir, new File(ioBaseDir, "input"));
}
if (logOn)
logStart(args);
javaxmain(src, ioBaseDir, translate, list, programArgs.toArray(new String[programArgs.size()]));
if (outputDir != null) {
copyInput(new File(ioBaseDir, "output"), outputDir);
System.out.println("Output copied to: " + outputDir.getAbsolutePath());
}
if (verbose) {
// print stats
print("Processes started: " + processesStarted + ", compilations: " + compilations);
print("Timers: " + l(_registeredTimers()));
}
}
public static void javaxmain(String src, File ioDir, boolean translate, boolean list,
String[] args) throws Exception {
String programID = isSnippetID(src) ? "" + parseSnippetID(src) : null;
if (programID != null)
System.out.println(trim("JavaX TRANSLATE " + programID + " " + smartJoin(args)) + " / " + vmPort());
List libraries = new ArrayList();
File x = transpileMain(src, libraries);
if (verbose)
print("After transpileMain: " + x);
if (x == null) {
showVersion();
// DEFAULT PROGRAM TO RUN
if (fullArgs != null) {
String[] nargs;
if (fullArgs.length == 0) {
nargs = new String[] {str(psI(javaxDefaultProgram()))};
loadPage_retries = 60*60; // try to get internet for an hour instead of a minute, lol
} else {
// forward to search
nargs = new String[fullArgs.length+1];
nargs[0] = str(psI(#636));
// nargs[1] = "search-runnables";
System.arraycopy(fullArgs, 0, nargs, 1, fullArgs.length);
}
if (console != null)
console.args = nargs;
main(nargs); // Hopefully we get no infinite recursion :)
return;
}
System.out.println("No main.java found, exiting");
return;
}
info.transpiledSrc = x;
// list or run
if (translate) {
File to = x;
if (translateTo != null) {
StringBuilder buf = new StringBuilder();
for (File f : libraries) buf.append(f.getName()+"\n");
if (new File(translateTo).isDirectory()) {
to = new File(translateTo, "main.java");
saveTextFile(new File(translateTo, "libraries.txt").getPath(), buf.toString());
} else {
to = new File(translateTo);
saveTextFile(new File(translateTo + "_libraries").getPath(), buf.toString());
}
}
if (to != x)
copy(new File(x, "main.java"), to);
System.out.println("Program translated to: " + to.getAbsolutePath());
} else if (list)
System.out.println(loadTextFile(new File(x, "main.java").getPath(), null));
else {
if (programID != null)
System.out.println("JavaX RUN " + programID + " " + smartJoin(args));
System.out.println(); // Make empty line before actual program starts
PaA paa = javax2(x, ioDir, false, runMainInProcess, libraries, args, null, programID, info);
final bool error = paa != null && paa.exception != null;
if (error || !isTrue(getOpt(paa.mainClass, 'mainDoneQuietly_on)))
System.out.println(error ? "[main done with error]" : "[main done]");
if (console != null) awt {
if (eq(console.frame.getTitle(), console.title + " [Output]") && autoVMExit_visibleObjects() <= 1)
console.frame.setTitle((error ? "[Error] " : donePrefix) + console.title);
}
// cleanup reportToChat thread
if (reportToChat_q != null) {
if (customSystemOut != null)
Thread.sleep(1000); // delay to finish autoReportToChat. Yes it's hacky.
if (verbose) System.out.println("Closing reportToChat queue");
reportToChat_q.done();
}
if (gcAfterMainDone) gc();
}
}
static File transpileMain(String src, List libraries) throws Exception {
File srcDir = null;
boolean isTranspiled = false;
if (isSnippetID(src)) {
S transpiledSrc = useBossBot ? getTranspilationFromBossBot(parseSnippetID(src)) : null;
if (transpiledSrc != null) {
int i = transpiledSrc.indexOf('\n');
String libs = transpiledSrc.substring(0, Math.max(0, i));
transpiledSrc = transpiledSrc.substring(i+1);
if (!transpiledSrc.isEmpty()) {
srcDir = TempDirMaker_make();
saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
isTranspiled = true;
Matcher m = Pattern.compile("\\d+").matcher(libs);
while (m.find()) {
String libid = m.group();
File libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(libid));
loadLib(libid, libraries, libraryFile);
}
}
}
if (srcDir == null) {
prefetch(src);
long id = parseSnippetID(src);
prefetched.remove(id); // hackfix to ensure transpiled main program is found.
bool offline = isOfflineMode();
srcDir = offline ? null : loadSnippetAsMainJava(src);
if (verbose)
System.err.println("hasTranspiledSet: " + hasTranspiledSet);
if (hasTranspiledSet.contains(id) && useServerTranspiled || offline) {
//System.err.println("Trying pretranspiled main program: #" + id);
transpiledSrc = getServerTranspiled2("#" + id);
int i = transpiledSrc.indexOf('\n');
String libs = transpiledSrc.substring(0, Math.max(0, i));
transpiledSrc = transpiledSrc.substring(i+1);
if (!transpiledSrc.isEmpty()) {
srcDir = TempDirMaker_make();
saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
isTranspiled = true;
//translationCache.put(id, new Object[] {srcDir, libraries});
Matcher m = Pattern.compile("\\d+").matcher(libs);
while (m.find()) {
String libid = m.group();
File libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(libid));
loadLib(libid, libraries, libraryFile);
}
}
}
}
} else {
if (src == null) null;
srcDir = new File(src);
// if the argument is a file, it is assumed to be main.java
if (srcDir.isFile()) {
srcDir = TempDirMaker_make();
copy(new File(src), new File(srcDir, "main.java"));
}
if (!new File(srcDir, "main.java").exists())
return null;
}
// translate
File x = srcDir;
if (!isTranspiled) {
temp tempSetThreadLocal(transpilingSnippetID, isSnippetID(src) ? fsI(src) : null);
x = topLevelTranslate(x, libraries);
System.err.println("Translated " + src);
// save prefetch data
if (isSnippetID(src))
savePrefetchData(src);
}
return x;
}
static new ThreadLocal transpilingSnippetID;
private static void prefetch(String mainSnippetID) throws IOException {
if (noPrefetch) return;
long mainID = parseSnippetID(mainSnippetID);
String s = mainID + " " + loadTextFile(javaxCachesDir("prefetch/" + mainID + ".txt").getPath(), "");
String[] ids = s.trim().split(" ");
if (ids.length > 1) {
String url = tb_mainServer() + "/tb-int/prefetch.php?ids=" + URLEncoder.encode(s, "UTF-8") + standardCredentials();
String data = loadPage(new URL(url));
String[] split = data.split(" ");
if (split.length == ids.length)
for (int i = 0; i < ids.length; i++)
prefetched.put(parseSnippetID(ids[i]), split[i]);
}
}
static String userHome() {
if (android)
return ((File) call(androidContext, "getFilesDir")).getAbsolutePath();
else
return System.getProperty("user.home");
}
private static void savePrefetchData(String mainSnippetID) throws IOException {
List ids = new ArrayList();
long mainID = parseSnippetID(mainSnippetID);
for (long id : memSnippetCache.keySet())
if (id != mainID)
ids.add(String.valueOf(id));
saveTextFile(javaxCachesDir("prefetch/" + mainID + ".txt").getPath(), join(" ", ids));
}
static File topLevelTranslate(File srcDir, List libraries_out) throws Exception {
File x = srcDir;
x = applyTranslators(x, mainTranslators, libraries_out); // translators supplied on command line (unusual)
// actual inner translation of the JavaX source
x = defaultTranslate(x, libraries_out);
return x;
}
private static File defaultTranslate(File x, List libraries_out) throws Exception {
x = luaPrintToJavaPrint(x);
x = repeatAutoTranslate(x, libraries_out);
return x;
}
private static File repeatAutoTranslate(File x, List libraries_out) throws Exception {
List postTranslators = new ArrayList;
while (true) {
String main = loadTextFile(new File(x, "main.java").getPath(), null);
List lines = toLines(main);
List t = findPostTranslators(lines);
postTranslators.addAll(t);
if (!t.isEmpty()) {
main = fromLines(lines);
x = TempDirMaker_make();
saveTextFile(new File(x, "main.java").getPath(), main);
}
File y = autoTranslate(x, libraries_out);
if (y == x)
break;
x = y;
}
x = applyTranslators(x, postTranslators, libraries_out);
return x;
}
private static File autoTranslate(File x, List libraries_out) throws Exception {
String main = loadTextFile(new File(x, "main.java").getPath(), null);
L translators = new L;
main = findTranslators2x(main, translators);
if (verbose) print("autoTranslate: Translators=" + sfu(translators));
if (translators.isEmpty())
return x;
//main = fromLines(lines);
File newDir = TempDirMaker_make();
saveTextFile(new File(newDir, "main.java").getPath(), main);
return applyTranslators(newDir, translators, libraries_out);
}
static S findTranslators2x(S src, L translatorsOut) {
L tok = javaTok(src);
int i;
while ((i = jfind(tok, "!(")) >= 0) {
int j = indexOf(tok, ")", i);
translatorsOut.add(new S[] {tok.get(i+2), join(subList(tok, i+4, j+1))});
clearTokens(tok, i, j+1);
}
while ((i = jfind(tok, "!")) >= 0) {
translatorsOut.add(new S[] {tok.get(i+2), null});
clearTokens(tok, i, i+3);
}
ret join(tok);
}
static List findPostTranslators(List lines) {
List translators = new ArrayList();
Pattern pattern = Pattern.compile("^!post\\s*([0-9# \t]+)");
Pattern pArgs = Pattern.compile("^\\s*\\((.*)\\)");
for (ListIterator iterator = lines.listIterator(); iterator.hasNext(); ) {
String line = iterator.next();
line = line.trim();
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
String[] t = matcher.group(1).split("[ \t]+");
String rest = line.substring(matcher.end());
String arg = null;
if (t.length == 1) {
Matcher mArgs = pArgs.matcher(rest);
if (mArgs.find())
arg = mArgs.group(1);
}
for (String transi : t)
translators.add(new String[]{transi, arg});
iterator.remove();
}
}
return translators;
}
private static File applyTranslators(File x, List translators, List libraries_out) throws Exception {
for (String[] translator : translators)
x = applyTranslator(x, translator[0], translator[1], libraries_out);
return x;
}
// also takes a library
private static File applyTranslator(File x, String translator, String arg, List libraries_out) throws Exception {
if (verbose)
System.out.println("Using translator " + translator + " on sources in " + x.getPath());
File newDir = runTranslatorOnInput(translator, null, arg, x, !verbose, libraries_out);
if (!new File(newDir, "main.java").exists()) {
throw new Exception("Translator " + translator + " did not generate main.java");
// TODO: show translator output
}
if (verbose)
System.out.println("Translated with " + translator + " from " + x.getPath() + " to " + newDir.getPath());
x = newDir;
return x;
}
private static File luaPrintToJavaPrint(File x) throws IOException {
File newDir = TempDirMaker_make();
String code = loadTextFile(new File(x, "main.java").getPath(), null);
code = luaPrintToJavaPrint(code);
saveTextFile(new File(newDir, "main.java").getPath(), code);
return newDir;
}
public static String luaPrintToJavaPrint(String code) {
return ("\n" + code).replaceAll(
"(\n\\s*)print (\".*\")",
"$1System.out.println($2);").substring(1);
}
public static File loadSnippetAsMainJava(String snippetID) throws IOException {
checkProgramSafety(snippetID);
File srcDir = TempDirMaker_make();
saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippet_code(parseSnippetID(snippetID)));
return srcDir;
}
public static File loadSnippetAsMainJavaVerified(String snippetID, String hash) throws IOException {
checkProgramSafety(snippetID);
File srcDir = TempDirMaker_make();
saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippetVerified(snippetID, hash));
return srcDir;
}
@SuppressWarnings( "unchecked" )
/** returns output dir */
private static File runTranslatorOnInput(String snippetID, String hash, String arg, File input,
boolean silent,
List libraries_out) throws Exception {
if (safeTranslate)
checkProgramSafetyImpl(snippetID);
long id = parseSnippetID(snippetID);
// It's a library, not a translator.
File libraryFile = DiskSnippetCache_getLibrary(id);
if (verbose)
System.out.println("Library file for " + id + ": " + libraryFile);
if (libraryFile != null) {
loadLib(snippetID, libraries_out, libraryFile);
return input;
}
String[] args = arg != null ? new String[]{arg} : new String[0];
File srcDir = hash == null ? loadSnippetAsMainJava(snippetID)
: loadSnippetAsMainJavaVerified(snippetID, hash);
long mainJavaSize = new File(srcDir, "main.java").length();
if (verbose)
System.out.println(snippetID + ": length = " + mainJavaSize);
if (mainJavaSize == 0) { // no text in snippet? assume it's a library
loadLib(snippetID, libraries_out, libraryFile);
return input;
}
List libraries = new ArrayList();
Object[] cached = translationCache.get(id);
if (cached != null) {
//System.err.println("Taking translator " + snippetID + " from cache!");
srcDir = (File) cached[0];
libraries = (List) cached[1];
} else if (hasTranspiledSet.contains(id) && useServerTranspiled) {
print("Trying pretranspiled translator: #" + snippetID);
S transpiledSrc = getServerTranspiled2(snippetID);
int i = transpiledSrc.indexOf('\n');
S libs = takeFirst(i, transpiledSrc);
transpiledSrc = transpiledSrc.substring(i+1);
print("libs=" + libs);
libraries.addAll(javax_librariesToFiles(libs));
if (!transpiledSrc.isEmpty()) {
srcDir = TempDirMaker_make();
saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
translationCache.put(id, cached = new Object[] {srcDir, libraries});
}
}
File ioBaseDir = TempDirMaker_make();
/*Class> mainClass = programCache.get("" + parseSnippetID(snippetID));
if (mainClass != null)
return runCached(ioBaseDir, input, args);*/
// Doesn't work yet because virtualized directories are hardcoded in translator...
if (cached == null) {
System.err.println("Translating translator #" + id);
if (translating.contains(id))
throw new RuntimeException("Recursive translator reference chain: " + structure(translating));
translating.add(id);
try {
srcDir = defaultTranslate(srcDir, libraries);
} finally {
translating.remove(id);
}
System.err.println("Translated translator #" + id);
translationCache.put(id, new Object[]{srcDir, libraries});
}
boolean runInProcess = false;
if (virtualizeTranslators) {
if (verbose) System.out.println("Virtualizing translator");
// TODO: don't virtualize class _javax (as included in, say, #636)
//srcDir = applyTranslator(srcDir, "#2000351"); // I/O-virtualize the translator
// that doesn't work because it recurses infinitely...
// So we do it right here:
String s = loadTextFile(new File(srcDir, "main.java").getPath(), null);
s = s.replaceAll("new\\s+File\\(", "virtual.newFile(");
s = s.replaceAll("new\\s+FileInputStream\\(", "virtual.newFileInputStream(");
s = s.replaceAll("new\\s+FileOutputStream\\(", "virtual.newFileOutputStream(");
s += "\n\n" + loadSnippet("#1004414"); // load class virtual
// forward snippet cache (virtualized one)
File dir = virtCache != null ? virtCache : DiskSnippetCache_dir;
s = s.replace("static File DiskSnippetCache_dir" + ";",
"static File DiskSnippetCache_dir " + "= new File(" + javaQuote(dir.getAbsolutePath()) + ");"); // extra + is necessary for Dumb TinyBrain :)
s = s.replace("static boolean preferCached = false;", "static boolean preferCached = true;");
/*if (verbose) {
System.out.println("==BEGIN VIRTUALIZED TRANSLATOR==");
System.out.println(s);
System.out.println("==END VIRTUALIZED TRANSLATOR==");
}*/
srcDir = TempDirMaker_make();
saveTextFile(new File(srcDir, "main.java").getPath(), s);
// TODO: silence translator also
runInProcess = true;
}
return runJavaX(ioBaseDir, srcDir, input, silent, runInProcess, libraries,
args, cacheTranslators ? "" + id : null, "" + id);
}
static void checkProgramSafety(String snippetID) throws IOException {
if (!safeOnly) return;
checkProgramSafetyImpl(snippetID);
}
static void checkProgramSafetyImpl(String snippetID) throws IOException {
URL url = new URL(tb_mainServer() + "/tb-int/is-javax-safe.php?id=" + parseSnippetID(snippetID) + standardCredentials());
String text = loadPage(url);
if (!text.startsWith("{\"safe\":\"1\"}"))
throw new RuntimeException("Program not safe: #" + parseSnippetID(snippetID));
}
static void loadLib(String snippetID, List libraries_out, File libraryFile) throws IOException {
if (verbose)
System.out.println("Assuming " + snippetID + " is a library.");
if (libraryFile == null) {
byte[] data = loadDataSnippetImpl(snippetID);
DiskSnippetCache_putLibrary(parseSnippetID(snippetID), data);
libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(snippetID));
}
if (!libraries_out.contains(libraryFile))
libraries_out.add(libraryFile);
}
/** returns output dir */
private static File runJavaX(File ioBaseDir, File originalSrcDir, File originalInput,
boolean silent, boolean runInProcess,
List libraries, String[] args, String cacheAs,
String programID) throws Exception {
File srcDir = new File(ioBaseDir, "src");
File inputDir = new File(ioBaseDir, "input");
File outputDir = new File(ioBaseDir, "output");
copyInput(originalSrcDir, srcDir);
copyInput(originalInput, inputDir);
javax2(srcDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs, programID, null);
return outputDir;
}
private static void copyInput(File src, File dst) throws IOException {
copyDirectory(src, dst);
}
public static boolean hasFile(File inputDir, String name) {
return new File(inputDir, name).exists();
}
public static void copyDirectory(File src, File dst) throws IOException {
if (verbose) System.out.println("Copying " + src.getAbsolutePath() + " to " + dst.getAbsolutePath());
dst.mkdirs();
File[] files = src.listFiles();
if (files == null) return;
for (File file : files) {
File dst1 = new File(dst, file.getName());
if (file.isDirectory())
copyDirectory(file, dst1);
else {
if (verbose) System.out.println("Copying " + file.getAbsolutePath() + " to " + dst1.getAbsolutePath());
copy(file, dst1);
}
}
}
/** Quickly copy a file without a progress bar or any other fancy GUI... :) */
public static void copy(File src, File dest) throws IOException {
FileInputStream inputStream = newFileInputStream(src);
FileOutputStream outputStream = newFileOutputStream(dest);
try {
copy(inputStream, outputStream);
inputStream.close();
} finally {
outputStream.close();
}
}
private static FileInputStream newFileInputStream(File f) throws FileNotFoundException {
/*if (androidContext != null)
return (FileInputStream) call(androidContext,
"openFileInput", f.getPath());
else*/
return new // line break for Dumb TinyBrain :)
FileInputStream(f);
}
public static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buf = new byte[65536];
while (true) {
int n = in.read(buf);
if (n <= 0) return;
out.write(buf, 0, n);
}
}
public static String loadSnippetVerified(String snippetID, String hash) throws IOException {
String text = loadSnippet(snippetID);
String realHash = getHash(text.getBytes("UTF-8"));
if (!realHash.equals(hash)) {
String msg;
if (hash.isEmpty())
msg = "Here's your hash for " + snippetID + ", please put in your program: " + realHash;
else
msg = "Hash mismatch for " + snippetID + ": " + realHash + " (new) vs " + hash + " - has tinybrain.de been hacked??";
throw new RuntimeException(msg);
}
return text;
}
public static String getHash(byte[] data) {
return bytesToHex(getFullFingerprint(data));
}
public static byte[] getFullFingerprint(byte[] data) {
try {
return MessageDigest.getInstance("MD5").digest(data);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static long parseSnippetID(String snippetID) {
return Long.parseLong(shortenSnippetID(snippetID));
}
private static String shortenSnippetID(String snippetID) {
if (snippetID.startsWith("#"))
snippetID = snippetID.substring(1);
String httpBlaBla = "http://tinybrain.de/";
if (snippetID.startsWith(httpBlaBla))
snippetID = snippetID.substring(httpBlaBla.length());
return snippetID;
}
static String getTranspilationFromBossBot(long snippetID) {
return boss(format3("get transpilation for *", snippetID));
}
// This is DIFFERENT from the std library loadSnippet
// (this is only for code!)
public static String loadSnippet_code(long snippetID) throws IOException {
String text = getSnippetFromBossBot(snippetID);
if (text != null) return text;
if (snippetID >= 1400000 && snippetID < 1500000) ret ""; // binary snippets
text = memSnippetCache.get(snippetID);
if (text != null) {
if (verbose)
System.out.println("Getting " + snippetID + " from mem cache");
return text;
}
initSnippetCache();
text = DiskSnippetCache_get(snippetID);
if (preferCached && text != null) {
if (verbose)
System.out.println("Getting " + snippetID + " from disk cache (preferCached)");
return text;
}
String md5 = text != null ? md5(text) : "-";
if (text != null) {
String hash = prefetched.get(snippetID);
if (hash != null) {
if (md5.equals(hash)) {
memSnippetCache.put(snippetID, text);
if (verbose)
System.out.println("Getting " + snippetID + " from prefetched");
return text;
} else
prefetched.remove(snippetID); // (maybe this is not necessary)
}
}
try {
String theURL = tb_mainServer() + "/getraw.php?id=" + snippetID + "&getmd5=1&utf8=1&usetranspiled=1" + standardCredentials();
if (text != null) {
//System.err.println("MD5: " + md5);
theURL += "&md5=" + md5;
}
URL url = new URL(theURL);
String page = loadPage(url);
// parse & drop transpilation flag available line
int i = page.indexOf('\n');
boolean hasTranspiled = page.substring(0, i).trim().equals("1");
if (hasTranspiled)
hasTranspiledSet.add(snippetID);
else
hasTranspiledSet.remove(snippetID);
page = page.substring(i+1);
if (page.startsWith("==*#*==")) {
// same, keep text
//System.err.println("Snippet unchanged, keeping.");
} else {
// drop md5 line
i = page.indexOf('\n');
String hash = page.substring(0, i).trim();
text = page.substring(i+1);
String myHash = md5(text);
if (myHash.equals(hash)) {
//System.err.println("Hash match: " + hash);
} else
System.err.println("Hash mismatch");
}
} catch (Exception e) {
printStackTrace(e);
throw new IOException("Snippet #" + snippetID + " not found or not public");
}
memSnippetCache.put(snippetID, text);
try {
initSnippetCache();
DiskSnippetCache_put(snippetID, text);
} catch (IOException e) {
System.err.println("Minor warning: Couldn't save snippet to cache (" + DiskSnippetCache_getDir() + ")");
}
return text;
}
/** runs a transpiled set of sources */
public static PaA javax2(File srcDir, File ioBaseDir, boolean silent, boolean runInProcess,
List libraries, String[] args, String cacheAs,
String programID, Info info) throws Exception {
if (android) {
// TODO: no translator virtualization? huh?
javax2android(srcDir, args, programID);
null;
} else {
File jarFile = null, classesDir = null;
bool jarOK = false;
S javacOutput = "";
if (useDummyMainClasses()) {
//print("Trying to rename " + srcDir + ", " + programID);
if (isSnippetID(programID))
renameMainJava(srcDir, programID);
}
if (isSnippetID(programID)) {
S md5 = md5(struct(libraries) + "\n"
+ loadTextFile(new File(srcDir, "main.java"))
+ loadTextFile(new File(srcDir, dummyMainClassName(programID) + ".java")));
S psi = str(parseSnippetID(programID));
jarFile = new File(getCacheProgramDir("#1001638"), psi + "-" + md5 + ".jar");
jarOK = jarFile.length() >= 50;
if (jarOK)
classesDir = jarFile;
}
if (!jarOK) {
classesDir = TempDirMaker_make();
loading "Compiling Java" {
javacOutput = compileJava(srcDir, libraries, classesDir);
}
}
// save jar
if (!jarOK && isSnippetID(programID)) pcall {
dir2zip_recurse_verbose = false;
dir2jar(classesDir, jarFile);
}
// run
if (verbose) System.out.println("Running program (" + srcDir.getAbsolutePath()
+ ") on io dir " + ioBaseDir.getAbsolutePath() + (runInProcess ? "[in-process]" : "") + "\n");
ret runProgram(javacOutput, classesDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs, programID, info);
}
}
static Class> loadx2android(File srcDir, String programID) throws Exception {
// TODO: optimize if it's a loaded snippet anyway
URL url = new URL(tb_mainServer() + "/dexcompile.php");
URLConnection conn = url.openConnection();
String postData = "src=" + URLEncoder.encode(loadTextFile(new File(srcDir, "main.java").getPath(), null), "UTF-8") + standardCredentials();
byte[] dexData = doPostBinary(postData, conn);
if (!isDex(dexData))
throw new RuntimeException("Dex generation error: " + dexData.length + " bytes - " + new String(dexData, "UTF-8"));
System.out.println("Dex loaded: " + dexData.length + "b");
File dexDir = TempDirMaker_make();
File dexFile = new File(dexDir, System.currentTimeMillis() + ".dex");
File dexOutputDir = TempDirMaker_make();
System.out.println("Saving dex to: " + dexDir.getAbsolutePath());
try {
saveBinaryFile(dexFile.getPath(), dexData);
} catch (Throwable e) {
System.out.println("Whoa!");
throw new RuntimeException(e);
}
System.out.println("Getting parent class loader.");
ClassLoader parentClassLoader =
//ClassLoader.getSystemClassLoader(); // does not find support jar
//getClass().getClassLoader(); // Let's try this...
x30.class.getClassLoader().getParent(); // XXX !
//System.out.println("Making DexClassLoader.");
//DexClassLoader classLoader = new DexClassLoader(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
// parentClassLoader);
Class dcl = Class.forName("dalvik.system.DexClassLoader");
Object classLoader = dcl.getConstructors()[0].newInstance(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
parentClassLoader);
//System.out.println("Loading main class.");
//Class> theClass = classLoader.loadClass(mainClassName);
Class> theClass = (Class>) call(classLoader, "loadClass", "main");
//System.out.println("Main class loaded.");
try {
set(theClass, "androidContext", androidContext);
} catch (Throwable e) {}
setVars(theClass, programID);
addInstance(programID, theClass);
return theClass;
}
static void addInstance(S programID, Class mainClass) {
programID = "" + parseSnippetID(programID);
instances.put(programID, new WeakReference(mainClass));
}
static Class getInstance(S programID) {
programID = "" + parseSnippetID(programID);
L> l = instances.get(programID);
for (WeakReference c : l) {
Class theClass = c.get();
// TODO: shorten the list
if (theClass != null)
return theClass;
}
return null;
}
static MultiMap> instances = new MultiMap>();
!include #1007192 // autoVMExit (core version)
static void javax2android(File srcDir, String[] args, String programID) throws Exception {
Class> theClass = loadx2android(srcDir, programID);
Method main = null;
try {
main = findStaticMethod(theClass, "main", new Object[]{androidContext});
} catch (RuntimeException e) {
}
//System.out.println("main method for " + androidContext + " of " + theClass + ": " + main);
if (main != null) {
// old style main program that returns a View
// TODO: maybe allow programs without main method, although it doesn't seem to make sense here really (Android main program)
System.out.println("Calling main (old-style)");
Object view = main.invoke(null, androidContext);
System.out.println("Calling setContentView with " + view);
call(Class.forName("main"), "setContentViewInUIThread", view);
//call(androidContext, "setContentView", view);
System.out.println("Done.");
} else {
System.out.println("New-style main method running.\n\n====\n");
runMainMethod(args, theClass);
}
}
static byte[] DEX_FILE_MAGIC = { 0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00 };
static boolean isDex(byte[] dexData) {
if (dexData.length < DEX_FILE_MAGIC.length) return false;
for (int i = 0; i < DEX_FILE_MAGIC.length; i++)
if (dexData[i] != DEX_FILE_MAGIC[i])
return false;
return true;
}
static String compileJava(File srcDir, List libraries, File classesDir) throws IOException {
javaCompilerOutput = null;
++compilations;
// collect sources
List sources = new ArrayList();
if (verbose) System.out.println("Scanning for sources in " + srcDir.getPath());
scanForSources(srcDir, sources, true);
if (sources.isEmpty())
throw new IOException("No sources found");
// compile
File optionsFile = File.createTempFile("javax", "");
try {
if (verbose) System.out.println("Compiling " + sources.size() + " source(s) to " + classesDir.getPath());
if (verbose) System.out.println("Libraries: " + libraries);
String options = "-d " + bashQuote(classesDir.getPath());
writeOptions(sources, libraries, optionsFile, options);
classesDir.mkdirs();
return invokeJavaCompiler(optionsFile);
} finally {
optionsFile.delete();
}
}
private static PaA runProgram(String javacOutput, File classesDir, File ioBaseDir,
boolean silent, boolean runInProcess,
List libraries, String[] args, String cacheAs,
String programID, Info info) throws Exception {
// print javac output if compile failed and it hasn't been printed yet
if (info != null) {
info.programID = programID;
info.programArgs = args;
}
boolean didNotCompile = !didCompile(classesDir);
if (verbose || didNotCompile)
System.out.println(javacOutput);
if (didNotCompile)
null;
if (runInProcess
|| (ioBaseDir.getAbsolutePath().equals(new File(".").getAbsolutePath()) && !silent)) {
ret runProgramQuick(classesDir, libraries, args, cacheAs, programID, info, ioBaseDir);
}
boolean echoOK = false;
// TODO: add libraries to class path
String bashCmd = "(cd " + bashQuote(ioBaseDir.getAbsolutePath()) + " && (java -cp "
+ bashQuote(classesDir.getAbsolutePath()) + " main" + (echoOK ? "; echo ok" : "") + "))";
if (verbose) System.out.println(bashCmd);
String output = backtick(bashCmd);
lastOutput = output;
if (verbose || !silent)
System.out.println(output);
null;
}
// classesDir can also be a .jar
static boolean didCompile(File classesDir) {
return classesDir.length() >= 50 || hasFile(classesDir, "main.class");
}
private static PaA runProgramQuick(File classesDir, List libraries,
String[] args, String cacheAs,
String programID, Info info,
File ioBaseDir) throws Exception {
// make class loader
JavaXClassLoader classLoader = new JavaXClassLoader(programID, concatLists(ll(classesDir), libraries));
// load JavaX main class
Class> mainClass = classLoader.loadClass("main");
S src = null;
if (info != null && info.transpiledSrc != null)
src = loadTextFile(findMainJavaInDir(info.transpiledSrc));
if (info == null) {
//print("no info");
} else {
//print("info.transpiledSrc = " + info.transpiledSrc);
info.mainClass = mainClass;
if (hasFieldNamed(mainClass, "myJavaSource_code")) {
//print("src = " + l(src));
set(mainClass, "myJavaSource_code", src);
}
if (registerSourceCodes && info.transpiledSrc != null)
registerSourceCode(mainClass, src);
}
if (cacheAs != null)
programCache.put(cacheAs, mainClass);
// record injection
final PaA paa = new PaA(programID, args);
paa.injectionID = randomID(8);
paa.mainClass = mainClass;
if (src != null) paa.srcMD5 = md5(src);
addInjection(paa);
// set case
if (caseID != null)
setOpt(mainClass, 'caseID_caseID, caseID);
// change baseDir
try {
//print("Changing base dir to " + ioBaseDir.getAbsolutePath());
Class virtual = mainClass.getClassLoader().loadClass("virtual");
set(virtual, "virtual_baseDir", ioBaseDir.getAbsolutePath());
} catch (Throwable e) { /* whatever */ }
setVars(mainClass, programID);
addInstance(programID, mainClass);
paaRun(paa);
ret paa;
}
static void paaRun(PaA paa) {
moveThisThreadToChild(paa.mainClass);
paa.mainThread = new WeakReference(currentThread());
paa.exception = null;
try {
runMainMethod(paa.arguments, paa.mainClass);
} catch (Throwable e) {
paa.exception = e;
printStackTrace2(e);
//throw e;
} finally {
paa.mainDone = true;
synchronized(x30.class) {}
}
}
static void setVars(Class> theClass, String programID) {
try {
set(theClass, "programID", formatSnippetIDOpt(programID));
} catch (Throwable e) {}
try {
set(theClass, "__javax", x30.class);
} catch (Throwable e) {}
callOnLoadMethods(theClass);
}
static void runMainMethod(String[] args, Class> mainClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
callMain(mainClass, args);
}
static String invokeJavaCompiler(File optionsFile) throws IOException {
long time = now();
String output;
if (hasEcj() && !javacOnly)
output = invokeEcj(optionsFile);
else
output = invokeJavac(optionsFile);
if (verbose) System.out.println(output);
done(time, "Java compile");
return output;
}
private static boolean hasEcj() {
try {
Class.forName("org.eclipse.jdt.internal.compiler.batch.Main");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
// TODO: fix UTF-8 here too
private static String invokeJavac(File optionsFile) throws IOException {
String output;
output = backtick("javac " + bashQuote("@" + optionsFile.getPath()));
javaCompilerOutput = output;
if (backtick_exitValue != 0) {
System.out.println(output);
throw new RuntimeException("javac returned errors.");
}
return output;
}
// throws ClassNotFoundException if ecj is not in classpath
static String invokeEcj(File optionsFile) {
if (vmPort() != 5000) pcall-short {
ret invokeEcjInFirstVM(optionsFile);
}
try {
StringWriter writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
// add more eclipse options in the line below
String[] args = {
"-source", javaTarget,
"-target", javaTarget,
"-nowarn",
"-encoding", "UTF-8",
"@" + optionsFile.getPath()
};
if (verbose)
print("ECJ options: " + structure(args));
Class ecjClass = Class.forName("org.eclipse.jdt.internal.compiler.batch.Main");
Object main = newInstance(ecjClass, printWriter, printWriter, false);
call(main, "compile", new Object[]{args});
int errors = (Integer) get(main, "globalErrorsCount");
String output = cleanJavaCompilerOutput(writer.toString());
javaCompilerOutput = output;
if (errors != 0) {
System.out.println(output);
throw new RuntimeException("Java compiler returned errors.");
}
return output;
} catch (Exception e) {
throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
}
}
static Object newInstance(Class c, Object... args) { try {
Constructor m = findConstructor(c, args);
m.setAccessible(true);
return m.newInstance(args);
} catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
static Constructor findConstructor(Class c, Object... args) {
for (Constructor m : c.getDeclaredConstructors()) {
if (!checkArgs(m.getParameterTypes(), args, false))
continue;
return m;
}
throw new RuntimeException("Constructor with " + args.length + " matching parameter(s) not found in " + c.getName());
}
static boolean checkArgs(Class[] types, Object[] args, boolean debug) {
if (types.length != args.length) {
if (debug)
System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
return false;
}
for (int i = 0; i < types.length; i++)
if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
if (debug)
System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
return false;
}
return true;
}
private static void writeOptions(List sources, List libraries,
File optionsFile, String moreOptions) throws IOException {
FileWriter writer = new FileWriter(optionsFile);
for (File source : sources)
writer.write(bashQuote(source.getPath()) + " ");
if (!libraries.isEmpty()) {
List cp = new ArrayList();
for (File lib : libraries)
cp.add(lib.getAbsolutePath());
writer.write("-cp " + bashQuote(join(File.pathSeparator, cp)) + " ");
}
writer.write(moreOptions);
writer.close();
}
static void scanForSources(File source, List sources, boolean topLevel) {
if (source.isFile() && source.getName().endsWith(".java"))
sources.add(source);
else if (source.isDirectory() && !isSkippedDirectoryName(source.getName(), topLevel)) {
File[] files = source.listFiles();
for (File file : files)
scanForSources(file, sources, false);
}
}
private static boolean isSkippedDirectoryName(String name, boolean topLevel) {
if (topLevel) return false; // input or output ok as highest directory (intentionally specified by user, not just found by a directory scan in which case we probably don't want it. it's more like heuristics actually.)
return name.equalsIgnoreCase("input") || name.equalsIgnoreCase("output");
}
public final static String charsetForTextFiles = "UTF8";
static long TempDirMaker_lastValue;
public static File TempDirMaker_make() {
File dir = javaxTempDir("" + TempDirMaker_newValue());
dir.mkdirs();
chmod_aPlusRX(dir);
return dir;
}
private static long TempDirMaker_newValue() {
long value;
do
value = System.currentTimeMillis();
while (value == TempDirMaker_lastValue);
TempDirMaker_lastValue = value;
return value;
}
!include #1000810 // join
static String computerID;
public static String getComputerID() throws IOException {
if (noID) return null;
if (computerID == null) {
File file = computerIDFile();
computerID = loadTextFile(file.getPath());
if (computerID == null) {
// legacy load
computerID = loadTextFile(userDir(".tinybrain/computer-id"));
if (computerID == null)
computerID = makeRandomID(12);
saveTextFile(file.getPath(), computerID);
}
if (verbose)
System.out.println("Local computer ID: " + computerID);
}
return computerID;
}
static void cleanCache() {
try {
pcall {
S s = trim(loadTextFile(getProgramFile("#1001638", "temp-file-retention-time")));
if (nempty(s))
tempFileRetentionTime = parseInt(s);
}
cleanJavaXCache(tempFileRetentionTime, verbose);
} finally {
cleanCacheDone = true;
}
}
static void showSystemProperties() {
System.out.println("System properties:\n");
for (Map.Entry