Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

2343
LINES

< > BotCompany Repo | #1001110 // x26.java (JavaX)

JavaX source code [tags: use-pretranspiled] - run with: x30.jar

Libraryless. Click here for Pure Java version (4924L/37K/101K).

1  
!747
2  
!awt {
3  
!actionListener {
4  
5  
/**
6  
 JavaX runner version 26
7  
8  
 Changes to v25:
9  
 -Adding "[main done]" message
10  
11  
 */
12  
13  
m { p { throw new RuntimeException("placebo"); } }
14  
15  
class x26 implements Runnable {
16  
  static final String version = "JavaX 26";
17  
18  
  // If programs run longer than this, they might have their class files
19  
  // deleted.
20  
  static int tempFileRetentionTime = 24; // hours
21  
  
22  
  static boolean verbose = false, translate = false, list = false, virtualizeTranslators = true;
23  
  static String translateTo = null;
24  
  static boolean preferCached = false, noID = false, noPrefetch = false;
25  
  static boolean safeOnly = false, safeTranslate = false, javacOnly = false, logOn = true;
26  
  static boolean runMainInProcess = true, consoleOn = true, hasHelloMessage = false;
27  
  static List<String[]> mainTranslators = new ArrayList<String[]>();
28  
  private static Map<Long, String> memSnippetCache = new HashMap<Long, String>();
29  
  private static int processesStarted, compilations;
30  
31  
  // snippet ID -> md5
32  
  private static HashMap<Long, String> prefetched = new HashMap<Long, String>();
33  
  private static File virtCache;
34  
35  
  // doesn't work yet
36  
  private static Map<String, Class<?>> programCache = new HashMap<String, Class<?>>();
37  
  static boolean cacheTranslators = false;
38  
39  
  // this should work (caches transpiled translators)
40  
  private static HashMap<Long, Object[]> translationCache = new HashMap<Long, Object[]>();
41  
  static boolean cacheTranspiledTranslators = true;
42  
43  
  // which snippets are available pre-transpiled server-side?
44  
  private static Set<Long> hasTranspiledSet = new HashSet<Long>();
45  
  static boolean useServerTranspiled = true;
46  
47  
  static Object androidContext;
48  
  static boolean android = isAndroid();
49  
50  
  // Translators currently being translated (to detect recursions)
51  
  private static Set<Long> translating = new HashSet<Long>();
52  
53  
  static String lastOutput;
54  
  static String[] fullArgs;
55  
  private static Console console;
56  
57  
  public static void main(String[] args) {
58  
    try {
59  
      goMain(args);
60  
    } catch (Throwable e) {
61  
      e.printStackTrace();
62  
    }
63  
  }
64  
  
65  
  static void goMain(String[] args) throws Exception {
66  
    if (args.length != 0 && args[0].equals("-v")) verbose = true;
67  
    redirectSystemOutAndErr();
68  
69  
    if (consoleOn && console == null)
70  
      tryToOpenConsole(args);
71  
    
72  
    String autoReport = loadTextFile(new File(userHome(), ".javax/auto-report-to-chat").getPath(), "").trim();
73  
    //print("autoReport=" + autoReport);
74  
    if (!isChatServer(args) && autoReport.equals("1"))
75  
      autoReportToChat();
76  
77  
    if (!hasHelloMessage) {
78  
      hasHelloMessage = true;
79  
      //installHelloMessage(args.length == 0 ? "JavaX Start-Up VM" : "JavaX VM (" + smartJoin(args) + ")");
80  
      makeVMAndroid();
81  
    }
82  
    
83  
    File ioBaseDir = new File("."), inputDir = null, outputDir = null;
84  
    String src = null;
85  
    List<String> programArgs = new ArrayList<String>();
86  
    fullArgs = args;
87  
88  
    for (int i = 0; i < args.length; i++) {
89  
      String arg = args[i];
90  
91  
      if (arg.equals("-version")) {
92  
        showVersion();
93  
        return;
94  
      }
95  
96  
      if (arg.equals("-sysprop")) {
97  
        showSystemProperties();
98  
        return;
99  
      }
100  
101  
      if (arg.equals("-v") || arg.equals("-verbose"))
102  
        verbose = true;
103  
      else if (arg.equals("-finderror"))
104  
        verbose = true;
105  
      else if (arg.equals("-offline") || arg.equalsIgnoreCase("-prefercached"))
106  
        preferCached = true;
107  
      else if (arg.equals("-novirt"))
108  
        virtualizeTranslators = false;
109  
      else if (arg.equals("-safeonly"))
110  
        safeOnly = true;
111  
      else if (arg.equals("-safetranslate"))
112  
        safeTranslate = true;
113  
      else if (arg.equals("-noid"))
114  
        noID = true;
115  
      else if (arg.equals("-nocachetranspiled"))
116  
        cacheTranspiledTranslators = false;
117  
      else if (arg.equals("-javac"))
118  
        javacOnly = true;
119  
      else if (arg.equals("-localtranspile"))
120  
        useServerTranspiled = false;
121  
      else if (arg.equals("translate") && src == null)
122  
        translate = true;
123  
      else if (arg.equals("list") && src == null) {
124  
        list = true;
125  
        virtualizeTranslators = false; // so they are silenced
126  
      } else if (arg.equals("run") && src == null) {
127  
        // it's the default command anyway
128  
      } else if (arg.startsWith("input="))
129  
        inputDir = new File(arg.substring(6));
130  
      else if (arg.startsWith("output="))
131  
        outputDir = new File(arg.substring(7));
132  
      else if (arg.equals("with"))
133  
        mainTranslators.add(new String[] {args[++i], null});
134  
      else if (translate && arg.equals("to"))
135  
        translateTo = args[++i];
136  
      else if (src == null) {
137  
        //System.out.println("src=" + arg);
138  
        src = arg;
139  
      } else
140  
        programArgs.add(arg);
141  
    }
142  
143  
    cleanCache();
144  
145  
    if (useServerTranspiled)
146  
      noPrefetch = true;
147  
148  
    if (src == null) src = ".";
149  
150  
    // Might actually want to write to 2 disk caches (global/per program).
151  
    if (virtualizeTranslators && !preferCached)
152  
      virtCache = TempDirMaker_make();
153  
154  
    if (inputDir != null) {
155  
      ioBaseDir = TempDirMaker_make();
156  
      System.out.println("Taking input from: " + inputDir.getAbsolutePath());
157  
      System.out.println("Output is in: " + new File(ioBaseDir, "output").getAbsolutePath());
158  
      copyInput(inputDir, new File(ioBaseDir, "input"));
159  
    }
160  
    
161  
    if (logOn)
162  
      logStart(args);
163  
164  
    javaxmain(src, ioBaseDir, translate, list, programArgs.toArray(new String[programArgs.size()]));
165  
166  
    if (outputDir != null) {
167  
      copyInput(new File(ioBaseDir, "output"), outputDir);
168  
      System.out.println("Output copied to: " + outputDir.getAbsolutePath());
169  
    }
170  
171  
    if (verbose) {
172  
      // print stats
173  
      System.out.println("Processes started: " + processesStarted + ", compilations: " + compilations);
174  
    }
175  
  }
176  
177  
  public static void javaxmain(String src, File ioDir, boolean translate, boolean list,
178  
                               String[] args) throws Exception {
179  
    String programID = isSnippetID(src) ? "" + parseSnippetID(src) : null;
180  
    
181  
    if (programID != null)
182  
      System.err.println("JavaX TRANSLATE " + programID + " " + smartJoin(args));
183  
    
184  
    List<File> libraries = new ArrayList<File>();
185  
    File X = transpileMain(src, libraries);
186  
    if (X == null) {
187  
      showVersion();
188  
      
189  
      if (fullArgs != null) {
190  
        String[] nargs;
191  
        if (fullArgs.length == 0)
192  
          nargs = new String[] {"1000825"}; // swing-start
193  
        else {
194  
          // forward to search
195  
          nargs = new String[fullArgs.length+1];
196  
          nargs[0] = "636";
197  
          // nargs[1] = "search-runnables";
198  
          System.arraycopy(fullArgs, 0, nargs, 1, fullArgs.length);
199  
        }
200  
        main(nargs); // Hopefully we get no infinite recursion :)
201  
        return;
202  
      }
203  
      
204  
      System.out.println("No main.java found, exiting");
205  
      return;
206  
    }
207  
    
208  
    info.transpiledSrc = X;
209  
210  
    // list or run
211  
212  
    if (translate) {
213  
      File to = X;
214  
      if (translateTo != null) {
215  
        StringBuilder buf = new StringBuilder();
216  
        for (File f : libraries) buf.append(f.getName()+"\n");
217  
        if (new File(translateTo).isDirectory()) {
218  
          to = new File(translateTo, "main.java");
219  
          saveTextFile(new File(translateTo, "libraries.txt").getPath(), buf.toString());
220  
        } else {
221  
          to = new File(translateTo);
222  
          saveTextFile(new File(translateTo + "_libraries").getPath(), buf.toString());
223  
        }
224  
      }
225  
      if (to != X)
226  
        copy(new File(X, "main.java"), to);
227  
      System.out.println("Program translated to: " + to.getAbsolutePath());
228  
    } else if (list)
229  
      System.out.println(loadTextFile(new File(X, "main.java").getPath(), null));
230  
    else {
231  
      if (programID != null)
232  
        System.err.println("JavaX RUN " + programID + " " + smartJoin(args));
233  
      System.err.println(); // Make empty line before actual program starts
234  
      
235  
      javax2(X, ioDir, false, runMainInProcess, libraries, args, null, programID, info);
236  
      
237  
      System.out.println("[main done]");
238  
      
239  
      // cleanup reportToChat thread
240  
      if (reportToChat_q != null) {
241  
        if (customSystemOut != null)
242  
          Thread.sleep(1000); // delay to finish autoReportToChat. Yes it's hacky.
243  
        if (verbose) System.out.println("Closing reportToChat queue");
244  
        reportToChat_q.done();
245  
      }
246  
    }
247  
  }
248  
249  
  static File transpileMain(String src, List<File> libraries) throws Exception {
250  
    File srcDir;
251  
    boolean isTranspiled = false;
252  
    if (isSnippetID(src)) {
253  
      prefetch(src);
254  
      long id = parseSnippetID(src);
255  
      prefetched.remove(id); // hackfix to ensure transpiled main program is found.
256  
      srcDir = loadSnippetAsMainJava(src);
257  
      if (verbose)
258  
        System.err.println("hasTranspiledSet: " + hasTranspiledSet);
259  
      if (hasTranspiledSet.contains(id) && useServerTranspiled) {
260  
        //System.err.println("Trying pretranspiled main program: #" + id);
261  
        String transpiledSrc = getServerTranspiled("#" + id);
262  
        int i = transpiledSrc.indexOf('\n');
263  
        String libs = transpiledSrc.substring(0, Math.max(0, i));
264  
        transpiledSrc = transpiledSrc.substring(i+1);
265  
        if (!transpiledSrc.isEmpty()) {
266  
          srcDir = TempDirMaker_make();
267  
          saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
268  
          isTranspiled = true;
269  
          //translationCache.put(id, new Object[] {srcDir, libraries});
270  
271  
          Matcher m = Pattern.compile("\\d+").matcher(libs);
272  
          while (m.find()) {
273  
            String libid = m.group();
274  
            File libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(libid));
275  
            loadLibrary(libid, libraries, libraryFile);
276  
          }
277  
        }
278  
      }
279  
    } else {
280  
      srcDir = new File(src);
281  
282  
      // if the argument is a file, it is assumed to be main.java
283  
      if (srcDir.isFile()) {
284  
        srcDir = TempDirMaker_make();
285  
        copy(new File(src), new File(srcDir, "main.java"));
286  
      }
287  
288  
      if (!new File(srcDir, "main.java").exists())
289  
        return null;
290  
    }
291  
292  
    // translate
293  
294  
    File X = srcDir;
295  
296  
    if (!isTranspiled) {
297  
      X = topLevelTranslate(X, libraries);
298  
      System.err.println("Translated " + src);
299  
300  
      // save prefetch data
301  
      if (isSnippetID(src))
302  
        savePrefetchData(src);
303  
    }
304  
    return X;
305  
  }
306  
307  
  private static void prefetch(String mainSnippetID) throws IOException {
308  
    if (noPrefetch) return;
309  
310  
    long mainID = parseSnippetID(mainSnippetID);
311  
    String s = mainID + " " + loadTextFile(new File(userHome(), ".tinybrain/prefetch/" + mainID + ".txt").getPath(), "");
312  
    String[] ids = s.trim().split(" ");
313  
    if (ids.length > 1) {
314  
      String url = "http://tinybrain.de:8080/tb-int/prefetch.php?ids=" + URLEncoder.encode(s, "UTF-8");
315  
      String data = loadPage(new URL(url));
316  
      String[] split = data.split(" ");
317  
      if (split.length == ids.length)
318  
        for (int i = 0; i < ids.length; i++)
319  
          prefetched.put(parseSnippetID(ids[i]), split[i]);
320  
    }
321  
  }
322  
323  
  static String userHome() {
324  
    if (android)
325  
      return ((File) call(androidContext, "getFilesDir")).getAbsolutePath();
326  
    else
327  
      return System.getProperty("user.home");
328  
  }
329  
330  
  private static void savePrefetchData(String mainSnippetID) throws IOException {
331  
    List<String> ids = new ArrayList<String>();
332  
    long mainID = parseSnippetID(mainSnippetID);
333  
334  
    for (long id : memSnippetCache.keySet())
335  
      if (id != mainID)
336  
        ids.add(String.valueOf(id));
337  
338  
    saveTextFile(new File(userHome(),".tinybrain/prefetch/" + mainID + ".txt").getPath(), join(" ", ids));
339  
  }
340  
341  
  static File topLevelTranslate(File srcDir, List<File> libraries_out) throws Exception {
342  
    File X = srcDir;
343  
    X = applyTranslators(X, mainTranslators, libraries_out); // translators supplied on command line (unusual)
344  
345  
    // actual inner translation of the JavaX source
346  
    X = defaultTranslate(X, libraries_out);
347  
    return X;
348  
  }
349  
350  
  private static File defaultTranslate(File x, List<File> libraries_out) throws Exception {
351  
    x = luaPrintToJavaPrint(x);
352  
    x = repeatAutoTranslate(x, libraries_out);
353  
    return x;
354  
  }
355  
356  
  private static File repeatAutoTranslate(File x, List<File> libraries_out) throws Exception {
357  
    while (true) {
358  
      File y = autoTranslate(x, libraries_out);
359  
      if (y == x)
360  
        return x;
361  
      x = y;
362  
    }
363  
  }
364  
365  
  private static File autoTranslate(File x, List<File> libraries_out) throws Exception {
366  
    String main = loadTextFile(new File(x, "main.java").getPath(), null);
367  
    List<String> lines = toLines(main);
368  
    List<String[]> translators = findTranslators(lines);
369  
    if (translators.isEmpty())
370  
      return x;
371  
372  
    main = fromLines(lines);
373  
    File newDir = TempDirMaker_make();
374  
    saveTextFile(new File(newDir, "main.java").getPath(), main);
375  
    return applyTranslators(newDir, translators, libraries_out);
376  
  }
377  
378  
  private static List<String[]> findTranslators(List<String> lines) {
379  
    List<String[]> translators = new ArrayList<String[]>();
380  
    Pattern pattern = Pattern.compile("^!([0-9# \t]+)");
381  
    Pattern pArgs = Pattern.compile("^\\s*\\((.*)\\)");
382  
    for (ListIterator<String> iterator = lines.listIterator(); iterator.hasNext(); ) {
383  
      String line = iterator.next();
384  
      line = line.trim();
385  
      Matcher matcher = pattern.matcher(line);
386  
      if (matcher.find()) {
387  
        String[] t = matcher.group(1).split("[ \t]+");
388  
        String rest = line.substring(matcher.end());
389  
        String arg = null;
390  
        if (t.length == 1) {
391  
          Matcher mArgs = pArgs.matcher(rest);
392  
          if (mArgs.find())
393  
            arg = mArgs.group(1);
394  
        }
395  
        for (String transi : t)
396  
          translators.add(new String[]{transi, arg});
397  
        iterator.remove();
398  
      }
399  
    }
400  
    return translators;
401  
  }
402  
403  
  public static List<String> toLines(String s) {
404  
    List<String> lines = new ArrayList<String>();
405  
    int start = 0;
406  
    while (true) {
407  
      int i = toLines_nextLineBreak(s, start);
408  
      if (i < 0) {
409  
        if (s.length() > start) lines.add(s.substring(start));
410  
        break;
411  
      }
412  
413  
      lines.add(s.substring(start, i));
414  
      if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n')
415  
        i += 2;
416  
      else
417  
        ++i;
418  
419  
      start = i;
420  
    }
421  
    return lines;
422  
  }
423  
424  
  private static int toLines_nextLineBreak(String s, int start) {
425  
    for (int i = start; i < s.length(); i++) {
426  
      char c = s.charAt(i);
427  
      if (c == '\r' || c == '\n')
428  
        return i;
429  
    }
430  
    return -1;
431  
  }
432  
433  
  public static String fromLines(List<String> lines) {
434  
    StringBuilder buf = new StringBuilder();
435  
    for (String line : lines) {
436  
      buf.append(line).append('\n');
437  
    }
438  
    return buf.toString();
439  
  }
440  
441  
  private static File applyTranslators(File x, List<String[]> translators, List<File> libraries_out) throws Exception {
442  
    for (String[] translator : translators)
443  
      x = applyTranslator(x, translator[0], translator[1], libraries_out);
444  
    return x;
445  
  }
446  
447  
  // also takes a library
448  
  private static File applyTranslator(File x, String translator, String arg, List<File> libraries_out) throws Exception {
449  
    if (verbose)
450  
      System.out.println("Using translator " + translator + " on sources in " + x.getPath());
451  
452  
    File newDir = runTranslatorOnInput(translator, null, arg, x, !verbose, libraries_out);
453  
454  
    if (!new File(newDir, "main.java").exists()) {
455  
      throw new Exception("Translator " + translator + " did not generate main.java");
456  
      // TODO: show translator output
457  
    }
458  
    if (verbose)
459  
      System.out.println("Translated with " + translator + " from " + x.getPath() + " to " + newDir.getPath());
460  
    x = newDir;
461  
    return x;
462  
  }
463  
464  
  private static File luaPrintToJavaPrint(File x) throws IOException {
465  
    File newDir = TempDirMaker_make();
466  
    String code = loadTextFile(new File(x, "main.java").getPath(), null);
467  
    code = luaPrintToJavaPrint(code);
468  
    if (verbose)
469  
      System.out.println(code);
470  
    saveTextFile(new File(newDir, "main.java").getPath(), code);
471  
    return newDir;
472  
  }
473  
474  
  public static String luaPrintToJavaPrint(String code) {
475  
    return ("\n" + code).replaceAll(
476  
      "(\n\\s*)print (\".*\")",
477  
      "$1System.out.println($2);").substring(1);
478  
  }
479  
480  
  public static File loadSnippetAsMainJava(String snippetID) throws IOException {
481  
    checkProgramSafety(snippetID);
482  
    File srcDir = TempDirMaker_make();
483  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippet(snippetID));
484  
    return srcDir;
485  
  }
486  
487  
  public static File loadSnippetAsMainJavaVerified(String snippetID, String hash) throws IOException {
488  
    checkProgramSafety(snippetID);
489  
    File srcDir = TempDirMaker_make();
490  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippetVerified(snippetID, hash));
491  
    return srcDir;
492  
  }
493  
494  
  @SuppressWarnings( "unchecked" )
495  
  /** returns output dir */
496  
  private static File runTranslatorOnInput(String snippetID, String hash, String arg, File input,
497  
                                           boolean silent,
498  
                                           List<File> libraries_out) throws Exception {
499  
    if (safeTranslate)
500  
      checkProgramSafetyImpl(snippetID);
501  
    long id = parseSnippetID(snippetID);
502  
503  
    // It's a library, not a translator.
504  
    File libraryFile = DiskSnippetCache_getLibrary(id);
505  
    if (verbose)
506  
      System.out.println("Library file for " + id + ": " + libraryFile);
507  
    if (libraryFile != null) {
508  
      loadLibrary(snippetID, libraries_out, libraryFile);
509  
      return input;
510  
    }
511  
512  
    String[] args = arg != null ? new String[]{arg} : new String[0];
513  
514  
    File srcDir = hash == null ? loadSnippetAsMainJava(snippetID)
515  
      : loadSnippetAsMainJavaVerified(snippetID, hash);
516  
    long mainJavaSize = new File(srcDir, "main.java").length();
517  
518  
    if (verbose)
519  
      System.out.println(snippetID + ": length = " + mainJavaSize);
520  
    if (mainJavaSize == 0) { // no text in snippet? assume it's a library
521  
      loadLibrary(snippetID, libraries_out, libraryFile);
522  
      return input;
523  
    }
524  
525  
    List<File> libraries = new ArrayList<File>();
526  
    Object[] cached = translationCache.get(id);
527  
    if (cached != null) {
528  
      //System.err.println("Taking translator " + snippetID + " from cache!");
529  
      srcDir = (File) cached[0];
530  
      libraries = (List<File>) cached[1];
531  
    } else if (hasTranspiledSet.contains(id) && useServerTranspiled) {
532  
      System.err.println("Trying pretranspiled translator: #" + snippetID);
533  
      String transpiledSrc = getServerTranspiled(snippetID);
534  
      transpiledSrc = transpiledSrc.substring(transpiledSrc.indexOf('\n')+1);
535  
      // TODO: check for libraries
536  
      if (!transpiledSrc.isEmpty()) {
537  
        srcDir = TempDirMaker_make();
538  
        saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
539  
        translationCache.put(id, cached = new Object[] {srcDir, libraries});
540  
      }
541  
    }
542  
543  
    File ioBaseDir = TempDirMaker_make();
544  
545  
    /*Class<?> mainClass = programCache.get("" + parseSnippetID(snippetID));
546  
    if (mainClass != null)
547  
      return runCached(ioBaseDir, input, args);*/
548  
    // Doesn't work yet because virtualized directories are hardcoded in translator...
549  
550  
    if (cached == null) {
551  
      System.err.println("Translating translator #" + id);
552  
      if (translating.contains(id))
553  
        throw new RuntimeException("Recursive translator reference chain including #" + id);
554  
      translating.add(id);
555  
      try {
556  
        srcDir = defaultTranslate(srcDir, libraries);
557  
      } finally {
558  
        translating.remove(id);
559  
      }
560  
      System.err.println("Translated translator #" + id);
561  
      translationCache.put(id, new Object[]{srcDir, libraries});
562  
    }
563  
564  
    boolean runInProcess = false;
565  
566  
    if (virtualizeTranslators) {
567  
      if (verbose) System.out.println("Virtualizing translator");
568  
569  
      // TODO: don't virtualize class _javax (as included in, say, #636)
570  
571  
      //srcDir = applyTranslator(srcDir, "#2000351"); // I/O-virtualize the translator
572  
      // that doesn't work because it recurses infinitely...
573  
574  
      // So we do it right here:
575  
      String s = loadTextFile(new File(srcDir, "main.java").getPath(), null);
576  
      s = s.replaceAll("new\\s+File\\(", "virtual.newFile(");
577  
      s = s.replaceAll("new\\s+FileInputStream\\(", "virtual.newFileInputStream(");
578  
      s = s.replaceAll("new\\s+FileOutputStream\\(", "virtual.newFileOutputStream(");
579  
      s += "\n\n" + loadSnippet("#2000355"); // load class virtual
580  
581  
      // change baseDir
582  
      s = s.replace("virtual_baseDir = \"\";",
583  
        "virtual_baseDir " + "= " + javaQuote(ioBaseDir.getAbsolutePath()) + ";"); // extra + is necessary for Dumb TinyBrain :)
584  
585  
      // forward snippet cache (virtualized one)
586  
      File dir = virtCache != null ? virtCache : DiskSnippetCache_dir;
587  
      s = s.replace("static File DiskSnippetCache_dir" + ";",
588  
        "static File DiskSnippetCache_dir " + "= new File(" + javaQuote(dir.getAbsolutePath()) + ");"); // extra + is necessary for Dumb TinyBrain :)
589  
      s = s.replace("static boolean preferCached = false;", "static boolean preferCached = true;");
590  
591  
      if (verbose) {
592  
        System.out.println("==BEGIN VIRTUALIZED TRANSLATOR==");
593  
        System.out.println(s);
594  
        System.out.println("==END VIRTUALIZED TRANSLATOR==");
595  
      }
596  
      srcDir = TempDirMaker_make();
597  
      saveTextFile(new File(srcDir, "main.java").getPath(), s);
598  
599  
      // TODO: silence translator also
600  
      runInProcess = true;
601  
    }
602  
603  
    return runJavaX(ioBaseDir, srcDir, input, silent, runInProcess, libraries,
604  
      args, cacheTranslators ? "" + id : null, "" + id);
605  
  }
606  
607  
  private static String getServerTranspiled(String snippetID) throws IOException {
608  
    long id = parseSnippetID(snippetID);
609  
    URL url = new URL("http://tinybrain.de:8080/tb-int/get-transpiled.php?raw=1&withlibs=1&id=" + id);
610  
    return loadPage(url);
611  
  }
612  
613  
  static void checkProgramSafety(String snippetID) throws IOException {
614  
    if (!safeOnly) return;
615  
    checkProgramSafetyImpl(snippetID);
616  
  }
617  
618  
  static void checkProgramSafetyImpl(String snippetID) throws IOException {
619  
    URL url = new URL("http://tinybrain.de:8080/tb-int/is-javax-safe.php?id=" + parseSnippetID(snippetID));
620  
    String text = loadPage(url);
621  
    if (!text.startsWith("{\"safe\":\"1\"}"))
622  
      throw new RuntimeException("Program not safe: #" + parseSnippetID(snippetID));
623  
  }
624  
625  
  static void loadLibrary(String snippetID, List<File> libraries_out, File libraryFile) throws IOException {
626  
    if (verbose)
627  
      System.out.println("Assuming " + snippetID + " is a library.");
628  
629  
    if (libraryFile == null) {
630  
      byte[] data = loadDataSnippetImpl(snippetID);
631  
      DiskSnippetCache_putLibrary(parseSnippetID(snippetID), data);
632  
      libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(snippetID));
633  
    }
634  
635  
    if (!libraries_out.contains(libraryFile))
636  
      libraries_out.add(libraryFile);
637  
  }
638  
639  
  private static byte[] loadDataSnippetImpl(String snippetID) throws IOException {
640  
    byte[] data;
641  
    try {
642  
      URL url = new URL("http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_"
643  
        + parseSnippetID(snippetID) + "&contentType=application/binary");
644  
      System.err.println("Loading library: " + url);
645  
      data = loadBinaryPage(url.openConnection());
646  
      if (verbose)
647  
        System.err.println("Bytes loaded: " + data.length);
648  
    } catch (FileNotFoundException e) {
649  
      throw new IOException("Binary snippet #" + snippetID + " not found or not public");
650  
    }
651  
    return data;
652  
  }
653  
654  
  /** returns output dir */
655  
  private static File runJavaX(File ioBaseDir, File originalSrcDir, File originalInput,
656  
                               boolean silent, boolean runInProcess,
657  
                               List<File> libraries, String[] args, String cacheAs,
658  
                               String programID) throws Exception {
659  
    File srcDir = new File(ioBaseDir, "src");
660  
    File inputDir = new File(ioBaseDir, "input");
661  
    File outputDir = new File(ioBaseDir, "output");
662  
    copyInput(originalSrcDir, srcDir);
663  
    copyInput(originalInput, inputDir);
664  
    javax2(srcDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs, programID, null);
665  
    return outputDir;
666  
  }
667  
668  
  private static void copyInput(File src, File dst) throws IOException {
669  
    copyDirectory(src, dst);
670  
  }
671  
672  
  public static boolean hasFile(File inputDir, String name) {
673  
    return new File(inputDir, name).exists();
674  
  }
675  
676  
  public static void copyDirectory(File src, File dst) throws IOException {
677  
    if (verbose) System.out.println("Copying " + src.getAbsolutePath() + " to " + dst.getAbsolutePath());
678  
    dst.mkdirs();
679  
    File[] files = src.listFiles();
680  
    if (files == null) return;
681  
    for (File file : files) {
682  
      File dst1 = new File(dst, file.getName());
683  
      if (file.isDirectory())
684  
        copyDirectory(file, dst1);
685  
      else {
686  
        if (verbose) System.out.println("Copying " + file.getAbsolutePath() + " to " + dst1.getAbsolutePath());
687  
        copy(file, dst1);
688  
      }
689  
    }
690  
  }
691  
692  
  /** Quickly copy a file without a progress bar or any other fancy GUI... :) */
693  
  public static void copy(File src, File dest) throws IOException {
694  
    FileInputStream inputStream = newFileInputStream(src);
695  
    FileOutputStream outputStream = newFileOutputStream(dest);
696  
    try {
697  
      copy(inputStream, outputStream);
698  
      inputStream.close();
699  
    } finally {
700  
      outputStream.close();
701  
    }
702  
  }
703  
704  
  static Object call(Object o, String method, Object... args) {
705  
    try {
706  
      Method m = call_findMethod(o, method, args, false);
707  
      m.setAccessible(true);
708  
      return m.invoke(o, args);
709  
    } catch (Exception e) {
710  
      throw new RuntimeException(e);
711  
    }
712  
  }
713  
714  
  static Object call(Class c, String method, Object... args) {
715  
    try {
716  
      Method m = call_findStaticMethod(c, method, args, false);
717  
      m.setAccessible(true);
718  
      return m.invoke(null, args);
719  
    } catch (Exception e) {
720  
      throw new RuntimeException(e);
721  
    }
722  
  }
723  
724  
  static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) {
725  
    while (c != null) {
726  
      for (Method m : c.getDeclaredMethods()) {
727  
        if (debug)
728  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
729  
        if (!m.getName().equals(method)) {
730  
          if (debug) System.out.println("Method name mismatch: " + method);
731  
          continue;
732  
        }
733  
734  
        if ((m.getModifiers() & Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug))
735  
          continue;
736  
737  
        return m;
738  
      }
739  
      c = c.getSuperclass();
740  
    }
741  
    throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + c.getName());
742  
  }
743  
744  
  static Method call_findMethod(Object o, String method, Object[] args, boolean debug) {
745  
    Class c = o.getClass();
746  
    while (c != null) {
747  
      for (Method m : c.getDeclaredMethods()) {
748  
        if (debug)
749  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
750  
        if (m.getName().equals(method) && call_checkArgs(m, args, debug))
751  
          return m;
752  
      }
753  
      c = c.getSuperclass();
754  
    }
755  
    throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName());
756  
  }
757  
758  
  private static boolean call_checkArgs(Method m, Object[] args, boolean debug) {
759  
    Class<?>[] types = m.getParameterTypes();
760  
    if (types.length != args.length) {
761  
      if (debug)
762  
        System.out.println("checkArgs: Bad parameter length: " + args.length + " vs " + types.length);
763  
      return false;
764  
    }
765  
    for (int i = 0; i < types.length; i++)
766  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
767  
        if (debug)
768  
          System.out.println("checkArgs: Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
769  
        return false;
770  
      }
771  
    return true;
772  
  }
773  
774  
  private static FileInputStream newFileInputStream(File f) throws FileNotFoundException {
775  
    /*if (androidContext != null)
776  
      return (FileInputStream) call(androidContext,
777  
        "openFileInput", f.getPath());
778  
    else*/
779  
    return new // line break for Dumb TinyBrain :)
780  
    FileInputStream(f);
781  
  }
782  
783  
  private static FileOutputStream newFileOutputStream(File f) throws FileNotFoundException {
784  
    /*if (androidContext != null)
785  
      return (FileOutputStream) call(androidContext,
786  
        "openFileOutput", f.getPath(), 0);
787  
    else*/
788  
    return new // line break for Dumb TinyBrain :)
789  
    FileOutputStream(f);
790  
  }
791  
792  
  public static void copy(InputStream in, OutputStream out) throws IOException {
793  
    byte[] buf = new byte[65536];
794  
    while (true) {
795  
      int n = in.read(buf);
796  
      if (n <= 0) return;
797  
      out.write(buf, 0, n);
798  
    }
799  
  }
800  
801  
  /** writes safely (to temp file, then rename) */
802  
  public static void saveTextFile(String fileName, String contents) throws IOException {
803  
    File file = new File(fileName);
804  
    File parentFile = file.getParentFile();
805  
    if (parentFile != null)
806  
      parentFile.mkdirs();
807  
    String tempFileName = fileName + "_temp";
808  
    FileOutputStream fileOutputStream = newFileOutputStream(new File(tempFileName));
809  
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, charsetForTextFiles);
810  
    PrintWriter printWriter = new PrintWriter(outputStreamWriter);
811  
    printWriter.print(contents);
812  
    printWriter.close();
813  
    if (file.exists() && !file.delete())
814  
      throw new IOException("Can't delete " + fileName);
815  
816  
    if (!new File(tempFileName).renameTo(file))
817  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
818  
  }
819  
820  
  /** writes safely (to temp file, then rename) */
821  
  public static void saveBinaryFile(String fileName, byte[] contents) throws IOException {
822  
    File file = new File(fileName);
823  
    File parentFile = file.getParentFile();
824  
    if (parentFile != null)
825  
      parentFile.mkdirs();
826  
    String tempFileName = fileName + "_temp";
827  
    FileOutputStream fileOutputStream = newFileOutputStream(new File(tempFileName));
828  
    fileOutputStream.write(contents);
829  
    fileOutputStream.close();
830  
    if (file.exists() && !file.delete())
831  
      throw new IOException("Can't delete " + fileName);
832  
833  
    if (!new File(tempFileName).renameTo(file))
834  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
835  
  }
836  
837  
  !include #1001049 // loadTextFile
838  
  
839  
  static File DiskSnippetCache_dir;
840  
841  
  public static void initDiskSnippetCache(File dir) {
842  
    DiskSnippetCache_dir = dir;
843  
    dir.mkdirs();
844  
  }
845  
846  
  // Data files are immutable, use centralized cache
847  
  public static synchronized File DiskSnippetCache_getLibrary(long snippetID) throws IOException {
848  
    File file = new File(getGlobalCache(), "data_" + snippetID + ".jar");
849  
    if (verbose)
850  
      System.out.println("Checking data cache: " + file.getPath());
851  
    return file.exists() ? file : null;
852  
  }
853  
854  
  public static synchronized String DiskSnippetCache_get(long snippetID) throws IOException {
855  
    return loadTextFile(DiskSnippetCache_getFile(snippetID).getPath(), null);
856  
  }
857  
858  
  private static File DiskSnippetCache_getFile(long snippetID) {
859  
    return new File(DiskSnippetCache_dir, "" + snippetID);
860  
  }
861  
862  
  public static synchronized void DiskSnippetCache_put(long snippetID, String snippet) throws IOException {
863  
    saveTextFile(DiskSnippetCache_getFile(snippetID).getPath(), snippet);
864  
  }
865  
866  
  public static synchronized void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException {
867  
    saveBinaryFile(new File(getGlobalCache(), "data_" + snippetID).getPath() + ".jar", data);
868  
  }
869  
870  
  public static File DiskSnippetCache_getDir() {
871  
    return DiskSnippetCache_dir;
872  
  }
873  
874  
  public static void initSnippetCache() {
875  
    if (DiskSnippetCache_dir == null)
876  
      initDiskSnippetCache(getGlobalCache());
877  
  }
878  
879  
  private static File getGlobalCache() {
880  
    File file = new File(userHome(), ".tinybrain/snippet-cache");
881  
    file.mkdirs();
882  
    return file;
883  
  }
884  
885  
  public static String loadSnippetVerified(String snippetID, String hash) throws IOException {
886  
    String text = loadSnippet(snippetID);
887  
    String realHash = getHash(text.getBytes("UTF-8"));
888  
    if (!realHash.equals(hash)) {
889  
      String msg;
890  
      if (hash.isEmpty())
891  
        msg = "Here's your hash for " + snippetID + ", please put in your program: " + realHash;
892  
      else
893  
        msg = "Hash mismatch for " + snippetID + ": " + realHash + " (new) vs " + hash + " - has tinybrain.de been hacked??";
894  
      throw new RuntimeException(msg);
895  
    }
896  
    return text;
897  
  }
898  
899  
  public static String getHash(byte[] data) {
900  
    return bytesToHex(getFullFingerprint(data));
901  
  }
902  
903  
  public static byte[] getFullFingerprint(byte[] data) {
904  
    try {
905  
      return MessageDigest.getInstance("MD5").digest(data);
906  
    } catch (NoSuchAlgorithmException e) {
907  
      throw new RuntimeException(e);
908  
    }
909  
  }
910  
911  
  public static String bytesToHex(byte[] bytes) {
912  
    return bytesToHex(bytes, 0, bytes.length);
913  
  }
914  
915  
  public static String bytesToHex(byte[] bytes, int ofs, int len) {
916  
    StringBuilder stringBuilder = new StringBuilder(len*2);
917  
    for (int i = 0; i < len; i++) {
918  
      String s = "0" + Integer.toHexString(bytes[ofs+i]);
919  
      stringBuilder.append(s.substring(s.length()-2, s.length()));
920  
    }
921  
    return stringBuilder.toString();
922  
  }
923  
924  
  public static String loadSnippet(String snippetID) throws IOException {
925  
    return loadSnippet(parseSnippetID(snippetID));
926  
  }
927  
928  
  public static long parseSnippetID(String snippetID) {
929  
    return Long.parseLong(shortenSnippetID(snippetID));
930  
  }
931  
932  
  private static String shortenSnippetID(String snippetID) {
933  
    if (snippetID.startsWith("#"))
934  
      snippetID = snippetID.substring(1);
935  
    String httpBlaBla = "http://tinybrain.de/";
936  
    if (snippetID.startsWith(httpBlaBla))
937  
      snippetID = snippetID.substring(httpBlaBla.length());
938  
    return snippetID;
939  
  }
940  
941  
  public static boolean isSnippetID(String snippetID) {
942  
    snippetID = shortenSnippetID(snippetID);
943  
    return isInteger(snippetID) && Long.parseLong(snippetID) != 0;
944  
  }
945  
946  
  public static boolean isInteger(String s) {
947  
    return Pattern.matches("\\-?\\d+", s);
948  
  }
949  
950  
  public static String loadSnippet(long snippetID) throws IOException {
951  
    String text = memSnippetCache.get(snippetID);
952  
    if (text != null) {
953  
      if (verbose)
954  
        System.out.println("Getting " + snippetID + " from mem cache");
955  
      return text;
956  
    }
957  
958  
    initSnippetCache();
959  
    text = DiskSnippetCache_get(snippetID);
960  
    if (preferCached && text != null) {
961  
      if (verbose)
962  
        System.out.println("Getting " + snippetID + " from disk cache (preferCached)");
963  
      return text;
964  
    }
965  
966  
    String md5 = text != null ? md5(text) : "-";
967  
    if (text != null) {
968  
      String hash = prefetched.get(snippetID);
969  
      if (hash != null) {
970  
        if (md5.equals(hash)) {
971  
          memSnippetCache.put(snippetID, text);
972  
          if (verbose)
973  
            System.out.println("Getting " + snippetID + " from prefetched");
974  
          return text;
975  
        } else
976  
          prefetched.remove(snippetID); // (maybe this is not necessary)
977  
      }
978  
    }
979  
980  
    try {
981  
      /*URL url = new URL("http://tinybrain.de:8080/getraw.php?id=" + snippetID);
982  
      text = loadPage(url);*/
983  
      String theURL = "http://tinybrain.de:8080/getraw.php?id=" + snippetID + "&getmd5=1&utf8=1&usetranspiled=1";
984  
      if (text != null) {
985  
        //System.err.println("MD5: " + md5);
986  
        theURL += "&md5=" + md5;
987  
      }
988  
      URL url = new URL(theURL);
989  
      String page = loadPage(url);
990  
991  
      // parse & drop transpilation flag available line
992  
      int i = page.indexOf('\n');
993  
      boolean hasTranspiled = page.substring(0, i).trim().equals("1");
994  
      if (hasTranspiled)
995  
        hasTranspiledSet.add(snippetID);
996  
      else
997  
        hasTranspiledSet.remove(snippetID);
998  
      page = page.substring(i+1);
999  
1000  
      if (page.startsWith("==*#*==")) {
1001  
        // same, keep text
1002  
        //System.err.println("Snippet unchanged, keeping.");
1003  
      } else {
1004  
        // drop md5 line
1005  
        i = page.indexOf('\n');
1006  
        String hash = page.substring(0, i).trim();
1007  
        text = page.substring(i+1);
1008  
1009  
        String myHash = md5(text);
1010  
        if (myHash.equals(hash)) {
1011  
          //System.err.println("Hash match: " + hash);
1012  
        } else
1013  
          System.err.println("Hash mismatch");
1014  
      }
1015  
    } catch (FileNotFoundException e) {
1016  
      e.printStackTrace();
1017  
      throw new IOException("Snippet #" + snippetID + " not found or not public");
1018  
    }
1019  
1020  
    memSnippetCache.put(snippetID, text);
1021  
1022  
    try {
1023  
      initSnippetCache();
1024  
      DiskSnippetCache_put(snippetID, text);
1025  
    } catch (IOException e) {
1026  
      System.err.println("Minor warning: Couldn't save snippet to cache ("  + DiskSnippetCache_getDir() + ")");
1027  
    }
1028  
1029  
    return text;
1030  
  }
1031  
1032  
  private static String md5(String text) {
1033  
    try {
1034  
      return bytesToHex(md5impl(text.getBytes("UTF-8"))); // maybe different than the way PHP does it...
1035  
    } catch (UnsupportedEncodingException e) {
1036  
      throw new RuntimeException(e);
1037  
    }
1038  
  }
1039  
1040  
  public static byte[] md5impl(byte[] data) {
1041  
    try {
1042  
      return MessageDigest.getInstance("MD5").digest(data);
1043  
    } catch (NoSuchAlgorithmException e) {
1044  
      throw new RuntimeException(e);
1045  
    }
1046  
  }
1047  
1048  
  private static String loadPage(URL url) throws IOException {
1049  
    System.err.println("Loading: " + url.toExternalForm());
1050  
    URLConnection con = url.openConnection();
1051  
    return loadPage(con, url);
1052  
  }
1053  
1054  
  public static String loadPage(URLConnection con, URL url) throws IOException {
1055  
    setHeaders(con);
1056  
    String contentType = con.getContentType();
1057  
    if (contentType == null)
1058  
      throw new IOException("Page could not be read: " + url);
1059  
    //Log.info("Content-Type: " + contentType);
1060  
    String charset = guessCharset(contentType);
1061  
    //System.err.println("Charset: " + charset);
1062  
    Reader r = new InputStreamReader(con.getInputStream(), charset);
1063  
    StringBuilder buf = new StringBuilder();
1064  
    while (true) {
1065  
      int ch = r.read();
1066  
      if (ch < 0)
1067  
        break;
1068  
      //Log.info("Chars read: " + buf.length());
1069  
      buf.append((char) ch);
1070  
    }
1071  
    return buf.toString();
1072  
  }
1073  
1074  
  public static byte[] loadBinaryPage(URLConnection con) throws IOException {
1075  
    setHeaders(con);
1076  
    return loadBinaryPage_noHeaders(con);
1077  
  }
1078  
1079  
  private static byte[] loadBinaryPage_noHeaders(URLConnection con) throws IOException {
1080  
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
1081  
    InputStream inputStream = con.getInputStream();
1082  
    while (true) {
1083  
      int ch = inputStream.read();
1084  
      if (ch < 0)
1085  
        break;
1086  
      buf.write(ch);
1087  
    }
1088  
    inputStream.close();
1089  
    return buf.toByteArray();
1090  
  }
1091  
1092  
  private static void setHeaders(URLConnection con) throws IOException {
1093  
    String computerID = getComputerID();
1094  
    if (computerID != null)
1095  
      con.setRequestProperty("X-ComputerID", computerID);
1096  
  }
1097  
1098  
  public static String guessCharset(String contentType) {
1099  
    Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*");
1100  
    Matcher m = p.matcher(contentType);
1101  
    /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */
1102  
    return m.matches() ? m.group(1) : "ISO-8859-1";
1103  
  }
1104  
1105  
  /** runs a transpiled set of sources */
1106  
  public static void javax2(File srcDir, File ioBaseDir, boolean silent, boolean runInProcess,
1107  
                            List<File> libraries, String[] args, String cacheAs,
1108  
                            String programID, Info info) throws Exception {
1109  
    if (android)
1110  
      javax2android(srcDir, args, programID);
1111  
    else {
1112  
      File classesDir = TempDirMaker_make();
1113  
      String javacOutput = compileJava(srcDir, libraries, classesDir);
1114  
1115  
      // run
1116  
1117  
      if (verbose) System.out.println("Running program (" + srcDir.getAbsolutePath()
1118  
        + ") on io dir " + ioBaseDir.getAbsolutePath() + (runInProcess ? "[in-process]" : "") + "\n");
1119  
      runProgram(javacOutput, classesDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs, programID, info);
1120  
    }
1121  
  }
1122  
1123  
  static Class<?> loadx2android(File srcDir, String programID) throws Exception {
1124  
    // TODO: optimize if it's a loaded snippet anyway
1125  
    URL url = new URL("http://tinybrain.de:8080/dexcompile.php");
1126  
    URLConnection conn = url.openConnection();
1127  
    String postData = "src=" + URLEncoder.encode(loadTextFile(new File(srcDir, "main.java").getPath(), null), "UTF-8");
1128  
    byte[] dexData = doPostBinary(postData, conn);
1129  
    if (!isDex(dexData))
1130  
      throw new RuntimeException("Dex generation error: " + dexData.length + " bytes - " + new String(dexData, "UTF-8"));
1131  
    System.out.println("Dex loaded: " + dexData.length + "b");
1132  
1133  
    File dexDir = TempDirMaker_make();
1134  
    File dexFile = new File(dexDir, System.currentTimeMillis() + ".dex");
1135  
    File dexOutputDir = TempDirMaker_make();
1136  
1137  
    System.out.println("Saving dex to: " + dexDir.getAbsolutePath());
1138  
    try {
1139  
      saveBinaryFile(dexFile.getPath(), dexData);
1140  
    } catch (Throwable e) {
1141  
      System.out.println("Whoa!");
1142  
      throw new RuntimeException(e);
1143  
    }
1144  
1145  
    System.out.println("Getting parent class loader.");
1146  
    ClassLoader parentClassLoader =
1147  
      //ClassLoader.getSystemClassLoader(); // does not find support jar
1148  
      //getClass().getClassLoader(); // Let's try this...
1149  
      x26.class.getClassLoader().getParent(); // XXX !
1150  
1151  
    //System.out.println("Making DexClassLoader.");
1152  
    //DexClassLoader classLoader = new DexClassLoader(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
1153  
    //  parentClassLoader);
1154  
    Class dcl = Class.forName("dalvik.system.DexClassLoader");
1155  
    Object classLoader = dcl.getConstructors()[0].newInstance(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
1156  
      parentClassLoader);
1157  
1158  
    //System.out.println("Loading main class.");
1159  
    //Class<?> theClass = classLoader.loadClass(mainClassName);
1160  
    Class<?> theClass = (Class<?>) call(classLoader, "loadClass", "main");
1161  
1162  
    //System.out.println("Main class loaded.");
1163  
    try {
1164  
      set(theClass, "androidContext", androidContext);
1165  
    } catch (Throwable e) {}
1166  
1167  
    setVars(theClass, programID);
1168  
1169  
    return theClass;
1170  
  }
1171  
1172  
  static void javax2android(File srcDir, String[] args, String programID) throws Exception {
1173  
    Class<?> theClass = loadx2android(srcDir, programID);
1174  
1175  
    Method main = null;
1176  
    try {
1177  
      main = call_findStaticMethod(theClass, "main", new Object[]{androidContext}, false);
1178  
    } catch (RuntimeException e) {
1179  
    }
1180  
1181  
    //System.out.println("main method for " + androidContext + " of " + theClass + ": " + main);
1182  
1183  
    if (main != null) {
1184  
      // old style main program that returns a View
1185  
      System.out.println("Calling main (old-style)");
1186  
      Object view = main.invoke(null, androidContext);
1187  
      System.out.println("Calling setContentView with " + view);
1188  
      call(Class.forName("main"), "setContentViewInUIThread", view);
1189  
      //call(androidContext, "setContentView", view);
1190  
      System.out.println("Done.");
1191  
    } else {
1192  
      System.out.println("New-style main method running.\n\n====\n");
1193  
      runMainMethod(args, theClass);
1194  
    }
1195  
  }
1196  
1197  
  static byte[] DEX_FILE_MAGIC = { 0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00 };
1198  
1199  
  static boolean isDex(byte[] dexData) {
1200  
    if (dexData.length < DEX_FILE_MAGIC.length) return false;
1201  
    for (int i = 0; i < DEX_FILE_MAGIC.length; i++)
1202  
      if (dexData[i] != DEX_FILE_MAGIC[i])
1203  
        return false;
1204  
    return true;
1205  
  }
1206  
1207  
  static byte[] doPostBinary(String urlParameters, URLConnection conn) throws IOException {
1208  
    // connect and do POST
1209  
    setHeaders(conn);
1210  
    conn.setDoOutput(true);
1211  
1212  
    OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
1213  
    writer.write(urlParameters);
1214  
    writer.flush();
1215  
1216  
    byte[] contents = loadBinaryPage_noHeaders(conn);
1217  
    writer.close();
1218  
    return contents;
1219  
  }
1220  
1221  
  static String compileJava(File srcDir, List<File> libraries, File classesDir) throws IOException {
1222  
    ++compilations;
1223  
1224  
    // collect sources
1225  
1226  
    List<File> sources = new ArrayList<File>();
1227  
    if (verbose) System.out.println("Scanning for sources in " + srcDir.getPath());
1228  
    scanForSources(srcDir, sources, true);
1229  
    if (sources.isEmpty())
1230  
      throw new IOException("No sources found");
1231  
1232  
    // compile
1233  
1234  
    File optionsFile = File.createTempFile("javax", "");
1235  
    if (verbose) System.out.println("Compiling " + sources.size() + " source(s) to " + classesDir.getPath());
1236  
    if (verbose) System.out.println("Libraries: " + libraries);
1237  
    String options = "-d " + bashQuote(classesDir.getPath());
1238  
    writeOptions(sources, libraries, optionsFile, options);
1239  
    classesDir.mkdirs();
1240  
    return invokeJavaCompiler(optionsFile);
1241  
  }
1242  
1243  
  private static void runProgram(String javacOutput, File classesDir, File ioBaseDir,
1244  
                                 boolean silent, boolean runInProcess,
1245  
                                 List<File> libraries, String[] args, String cacheAs,
1246  
                                 String programID, Info info) throws Exception {
1247  
    // print javac output if compile failed and it hasn't been printed yet
1248  
    if (info != null) {
1249  
      info.programID = programID;
1250  
      info.programArgs = args;
1251  
    }
1252  
    boolean didNotCompile = !didCompile(classesDir);
1253  
    if (verbose || didNotCompile)
1254  
      System.out.println(javacOutput);
1255  
    if (didNotCompile)
1256  
      return;
1257  
1258  
    if (runInProcess
1259  
      || (ioBaseDir.getAbsolutePath().equals(new File(".").getAbsolutePath()) && !silent)) {
1260  
      runProgramQuick(classesDir, libraries, args, cacheAs, programID, info);
1261  
      return;
1262  
    }
1263  
1264  
    boolean echoOK = false;
1265  
    // TODO: add libraries to class path
1266  
    String bashCmd = "(cd " + bashQuote(ioBaseDir.getAbsolutePath()) + " && (java -cp "
1267  
      + bashQuote(classesDir.getAbsolutePath()) + " main" + (echoOK ? "; echo ok" : "") + "))";
1268  
    if (verbose) System.out.println(bashCmd);
1269  
    String output = backtick(bashCmd);
1270  
    lastOutput = output;
1271  
    if (verbose || !silent)
1272  
      System.out.println(output);
1273  
  }
1274  
1275  
  static boolean didCompile(File classesDir) {
1276  
    return hasFile(classesDir, "main.class");
1277  
  }
1278  
1279  
  private static void runProgramQuick(File classesDir, List<File> libraries,
1280  
                                      String[] args, String cacheAs,
1281  
                                      String programID, Info info) throws Exception {
1282  
    // collect urls
1283  
    URL[] urls = new URL[libraries.size()+1];
1284  
    urls[0] = classesDir.toURI().toURL();
1285  
    for (int i = 0; i < libraries.size(); i++)
1286  
      urls[i+1] = libraries.get(i).toURI().toURL();
1287  
1288  
    // make class loader
1289  
    URLClassLoader classLoader = new URLClassLoader(urls);
1290  
1291  
    // load JavaX main class
1292  
    Class<?> mainClass = classLoader.loadClass("main");
1293  
    
1294  
    if (info != null)
1295  
      info.mainClass = mainClass;
1296  
1297  
    if (cacheAs != null)
1298  
      programCache.put(cacheAs, mainClass);
1299  
1300  
    setVars(mainClass, programID);
1301  
    runMainMethod(args, mainClass);
1302  
  }
1303  
1304  
  static void setVars(Class<?> theClass, String programID) {
1305  
    try {
1306  
      set(theClass, "programID", programID);
1307  
    } catch (Throwable e) {}
1308  
1309  
    try {
1310  
      set(theClass, "__javax", x26.class);
1311  
    } catch (Throwable e) {}
1312  
  }
1313  
1314  
1315  
  static void runMainMethod(Object args, Class<?> mainClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
1316  
    Method main = mainClass.getMethod("main", String[].class);
1317  
    main.invoke(null, args);
1318  
  }
1319  
1320  
  private static String invokeJavaCompiler(File optionsFile) throws IOException {
1321  
    String output;
1322  
    if (hasEcj() && !javacOnly)
1323  
      output = invokeEcj(optionsFile);
1324  
    else
1325  
      output = invokeJavac(optionsFile);
1326  
    if (verbose) System.out.println(output);
1327  
    return output;
1328  
  }
1329  
1330  
  private static boolean hasEcj() {
1331  
    try {
1332  
      Class.forName("org.eclipse.jdt.internal.compiler.batch.Main");
1333  
      return true;
1334  
    } catch (ClassNotFoundException e) {
1335  
      return false;
1336  
    }
1337  
  }
1338  
1339  
  private static String invokeJavac(File optionsFile) throws IOException {
1340  
    String output;
1341  
    output = backtick("javac " + bashQuote("@" + optionsFile.getPath()));
1342  
    if (exitValue != 0) {
1343  
      System.out.println(output);
1344  
      throw new RuntimeException("javac returned errors.");
1345  
    }
1346  
    return output;
1347  
  }
1348  
1349  
  // throws ClassNotFoundException if ecj is not in classpath
1350  
  static String invokeEcj(File optionsFile) {
1351  
    try {
1352  
      StringWriter writer = new StringWriter();
1353  
      PrintWriter printWriter = new PrintWriter(writer);
1354  
1355  
      // add more eclipse options in the line below
1356  
1357  
      String[] args = {"@" + optionsFile.getPath(),
1358  
        "-source", "1.7",
1359  
        "-nowarn"
1360  
      };
1361  
1362  
      Class ecjClass = Class.forName("org.eclipse.jdt.internal.compiler.batch.Main");
1363  
      Object main = newInstance(ecjClass, printWriter, printWriter, false);
1364  
      call(main, "compile", new Object[]{args});
1365  
      int errors = (Integer) get(main, "globalErrorsCount");
1366  
1367  
      String output = writer.toString();
1368  
      if (errors != 0) {
1369  
        System.out.println(output);
1370  
        throw new RuntimeException("Java compiler returned errors.");
1371  
      }
1372  
      return output;
1373  
    } catch (Exception e) {
1374  
      throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
1375  
    }
1376  
  }
1377  
1378  
  static Object get(Object o, String field) {
1379  
    try {
1380  
      Field f = findField(o.getClass(), field);
1381  
      f.setAccessible(true);
1382  
      return f.get(o);
1383  
    } catch (Exception e) {
1384  
      throw new RuntimeException(e);
1385  
    }
1386  
  }
1387  
1388  
  static Object newInstance(Class c, Object... args) { try {
1389  
    Constructor m = findConstructor(c, args);
1390  
    m.setAccessible(true);
1391  
    return m.newInstance(args);
1392  
  } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
1393  
1394  
  static Constructor findConstructor(Class c, Object... args) {
1395  
    for (Constructor m : c.getDeclaredConstructors()) {
1396  
      if (!checkArgs(m.getParameterTypes(), args, verbose))
1397  
        continue;
1398  
      return m;
1399  
    }
1400  
    throw new RuntimeException("Constructor with " + args.length + " matching parameter(s) not found in " + c.getName());
1401  
  }
1402  
1403  
  static boolean checkArgs(Class[] types, Object[] args, boolean debug) {
1404  
    if (types.length != args.length) {
1405  
      if (debug)
1406  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
1407  
      return false;
1408  
    }
1409  
    for (int i = 0; i < types.length; i++)
1410  
      if (!(args[i] == null || isInstanceX(types[i], args[i]))) {
1411  
        if (debug)
1412  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
1413  
        return false;
1414  
      }
1415  
    return true;
1416  
  }
1417  
1418  
  // extended to handle primitive types
1419  
  private static boolean isInstanceX(Class type, Object arg) {
1420  
    if (type == boolean.class) return arg instanceof Boolean;
1421  
    if (type == int.class) return arg instanceof Integer;
1422  
    if (type == long.class) return arg instanceof Long;
1423  
    if (type == float.class) return arg instanceof Float;
1424  
    if (type == short.class) return arg instanceof Short;
1425  
    if (type == char.class) return arg instanceof Character;
1426  
    if (type == byte.class) return arg instanceof Byte;
1427  
    return type.isInstance(arg);
1428  
  }
1429  
1430  
  private static void writeOptions(List<File> sources, List<File> libraries,
1431  
                                   File optionsFile, String moreOptions) throws IOException {
1432  
    FileWriter writer = new FileWriter(optionsFile);
1433  
    for (File source : sources)
1434  
      writer.write(bashQuote(source.getPath()) + " ");
1435  
    if (!libraries.isEmpty()) {
1436  
      List<String> cp = new ArrayList<String>();
1437  
      for (File lib : libraries)
1438  
        cp.add(lib.getAbsolutePath());
1439  
      writer.write("-cp " + bashQuote(join(File.pathSeparator, cp)) + " ");
1440  
    }
1441  
    writer.write(moreOptions);
1442  
    writer.close();
1443  
  }
1444  
1445  
  static void scanForSources(File source, List<File> sources, boolean topLevel) {
1446  
    if (source.isFile() && source.getName().endsWith(".java"))
1447  
      sources.add(source);
1448  
    else if (source.isDirectory() && !isSkippedDirectoryName(source.getName(), topLevel)) {
1449  
      File[] files = source.listFiles();
1450  
      for (File file : files)
1451  
        scanForSources(file, sources, false);
1452  
    }
1453  
  }
1454  
1455  
  private static boolean isSkippedDirectoryName(String name, boolean topLevel) {
1456  
    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.)
1457  
    return name.equalsIgnoreCase("input") || name.equalsIgnoreCase("output");
1458  
  }
1459  
1460  
  static int exitValue;
1461  
  public static String backtick(String cmd) throws IOException {
1462  
    ++processesStarted;
1463  
    File outFile = File.createTempFile("_backtick", "");
1464  
    File scriptFile = File.createTempFile("_backtick", isWindows() ? ".bat" : "");
1465  
1466  
    String command = cmd + " >" + bashQuote(outFile.getPath()) + " 2>&1";
1467  
    //Log.info("[Backtick] " + command);
1468  
    try {
1469  
      saveTextFile(scriptFile.getPath(), command);
1470  
      String[] command2;
1471  
      if (isWindows())
1472  
        command2 = new String[] { scriptFile.getPath() };
1473  
      else
1474  
        command2 = new String[] { "/bin/bash", scriptFile.getPath() };
1475  
      Process process = Runtime.getRuntime().exec(command2);
1476  
      try {
1477  
        process.waitFor();
1478  
      } catch (InterruptedException e) {
1479  
        throw new RuntimeException(e);
1480  
      }
1481  
      exitValue = process.exitValue();
1482  
      if (verbose)
1483  
        System.out.println("Process return code: " + exitValue);
1484  
      return loadTextFile(outFile.getPath(), "");
1485  
    } finally {
1486  
      scriptFile.delete();
1487  
    }
1488  
  }
1489  
1490  
  /** possibly improvable */
1491  
  public static String javaQuote(String text) {
1492  
    return bashQuote(text);
1493  
  }
1494  
1495  
  /** possibly improvable */
1496  
  public static String bashQuote(String text) {
1497  
    if (text == null) return null;
1498  
    return "\"" + text
1499  
      .replace("\\", "\\\\")
1500  
      .replace("\"", "\\\"")
1501  
      .replace("\n", "\\n")
1502  
      .replace("\r", "\\r") + "\"";
1503  
  }
1504  
1505  
  public final static String charsetForTextFiles = "UTF8";
1506  
1507  
  static long TempDirMaker_lastValue;
1508  
1509  
  public static File TempDirMaker_make() {
1510  
    File dir = new File(userHome(), ".javax/" + TempDirMaker_newValue());
1511  
    dir.mkdirs();
1512  
    return dir;
1513  
  }
1514  
1515  
  private static long TempDirMaker_newValue() {
1516  
    long value;
1517  
    do
1518  
      value = System.currentTimeMillis();
1519  
    while (value == TempDirMaker_lastValue);
1520  
    TempDirMaker_lastValue = value;
1521  
    return value;
1522  
  }
1523  
1524  
  !include #1000810 // join
1525  
  
1526  
  public static boolean isWindows() {
1527  
    return System.getProperty("os.name").contains("Windows");
1528  
  }
1529  
1530  
  public static String makeRandomID(int length) {
1531  
    Random random = new Random();
1532  
    char[] id = new char[length];
1533  
    for (int i = 0; i< id.length; i++)
1534  
      id[i] = (char) ((int) 'a' + random.nextInt(26));
1535  
    return new String(id);
1536  
  }
1537  
1538  
  static String computerID;
1539  
  public static String getComputerID() throws IOException {
1540  
    if (noID) return null;
1541  
    if (computerID == null) {
1542  
      File file = new File(userHome(), ".tinybrain/computer-id");
1543  
      computerID = loadTextFile(file.getPath(), null);
1544  
      if (computerID == null) {
1545  
        computerID = makeRandomID(12);
1546  
        saveTextFile(file.getPath(), computerID);
1547  
      }
1548  
      if (verbose)
1549  
        System.out.println("Local computer ID: " + computerID);
1550  
    }
1551  
    return computerID;
1552  
  }
1553  
1554  
  static int fileDeletions;
1555  
1556  
  static void cleanCache() {
1557  
    try {
1558  
      if (verbose)
1559  
        System.out.println("Cleaning cache");
1560  
      fileDeletions = 0;
1561  
      File javax = new File(userHome(), ".javax");
1562  
      long now = System.currentTimeMillis();
1563  
      File[] files = javax.listFiles();
1564  
      if (files != null) for (File dir : files) {
1565  
        if (dir.isDirectory() && Pattern.compile("\\d+").matcher(dir.getName()).matches()) {
1566  
          long time = Long.parseLong(dir.getName());
1567  
          long seconds = (now - time) / 1000;
1568  
          long minutes = seconds / 60;
1569  
          long hours = minutes / 60;
1570  
          if (hours >= tempFileRetentionTime) {
1571  
            //System.out.println("Can delete " + dir.getAbsolutePath() + ", age: " + hours + " h");
1572  
            removeDir(dir);
1573  
          }
1574  
        }
1575  
      }
1576  
      if (verbose && fileDeletions != 0)
1577  
        System.out.println("Cleaned cache. File deletions: " + fileDeletions);
1578  
    } catch (Throwable e) {
1579  
      e.printStackTrace();
1580  
    }
1581  
  }
1582  
1583  
  static void removeDir(File dir) {
1584  
    if (dir.getAbsolutePath().indexOf(".javax") < 0)  // security check!
1585  
      return;
1586  
    for (File f : dir.listFiles()) {
1587  
      if (f.isDirectory())
1588  
        removeDir(f);
1589  
      else {
1590  
        if (verbose)
1591  
          System.out.println("Deleting " + f.getAbsolutePath());
1592  
        f.delete();
1593  
        ++fileDeletions;
1594  
      }
1595  
    }
1596  
    dir.delete();
1597  
  }
1598  
1599  
  static void showSystemProperties() {
1600  
    System.out.println("System properties:\n");
1601  
    for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
1602  
      System.out.println("  " + entry.getKey() + " = " + entry.getValue());
1603  
    }
1604  
    System.out.println();
1605  
  }
1606  
1607  
  static void showVersion() {
1608  
    //showSystemProperties();
1609  
    boolean eclipseFound = hasEcj();
1610  
    //String platform = System.getProperty("java.vendor") + " " + System.getProperty("java.runtime.name") + " " + System.getProperty("java.version");
1611  
    String platform = System.getProperty("java.vm.name") + " " + System.getProperty("java.version");
1612  
    String os = System.getProperty("os.name"), arch = System.getProperty("os.arch");
1613  
    System.out.println("This is " + version + ".");
1614  
    System.out.println("[Details: " +
1615  
      (eclipseFound ? "Eclipse compiler (good)" : "javac (not so good)")
1616  
      + ", " + platform + ", " + arch + ", " + os + "]");
1617  
  }
1618  
1619  
  static boolean isAndroid() {
1620  
    return System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0;
1621  
  }
1622  
1623  
  static void set(Class c, String field, Object value) {
1624  
    try {
1625  
      Field f = findStaticField(c, field);
1626  
      f.setAccessible(true);
1627  
      f.set(null, value);
1628  
    } catch (Exception e) {
1629  
      throw new RuntimeException(e);
1630  
    }
1631  
  }
1632  
1633  
  static Field findStaticField(Class<?> c, String field) {
1634  
    for (Field f : c.getDeclaredFields())
1635  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
1636  
        return f;
1637  
    throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
1638  
  }
1639  
1640  
  static Field findField(Class<?> c, String field) {
1641  
    for (Field f : c.getDeclaredFields())
1642  
      if (f.getName().equals(field))
1643  
        return f;
1644  
    throw new RuntimeException("Field '" + field + "' not found in " + c.getName());
1645  
  }
1646  
  
1647  
  static String smartJoin(String[] args) {
1648  
    String[] a2 = new String[args.length];
1649  
    for (int i = 0; i < args.length; i++) {
1650  
      a2[i] = Pattern.compile("\\w+").matcher(args[i]).matches() ? args[i] : quote(args[i]);
1651  
    }
1652  
    return join(" ", a2);
1653  
  }
1654  
  
1655  
  static void logStart(String[] args) throws IOException {
1656  
    String line = smartJoin(args);
1657  
    appendToLog(new File(userHome(), ".javax/log.txt").getPath(), line);
1658  
  }
1659  
  
1660  
  static String quote(String s) {
1661  
    if (s == null) return "null";
1662  
    return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\"";
1663  
  }
1664  
  
1665  
  static void appendToLog(String path, String line) throws IOException {
1666  
    appendToFile(path, "\n" + line + "\n");
1667  
  }
1668  
  
1669  
  static void appendToFile(String path, String s) throws IOException {
1670  
    new File(path).getParentFile().mkdirs();
1671  
    Writer writer = new BufferedWriter(new OutputStreamWriter(
1672  
      new FileOutputStream(path, true), "UTF-8"));
1673  
    writer.write(s);
1674  
    writer.close();
1675  
  }
1676  
1677  
  !include #1000943
1678  
1679  
  static PrintStream oldOut, oldErr;
1680  
  static Thread reader, reader2;
1681  
  static boolean quit; // always false now
1682  
  static PipedInputStream pin=new PipedInputStream();
1683  
  static PipedInputStream pin2=new PipedInputStream();
1684  
  static PipedInputStream pin3=new PipedInputStream();
1685  
1686  
  static class Console extends WindowAdapter implements WindowListener, ActionListener {
1687  
    JFrame frame;
1688  
    JTextArea textArea;
1689  
    JTextField tfInput;
1690  
    StringBuffer buf = new StringBuffer();
1691  
    JButton buttonclear, buttonkill, buttonrestart, buttonduplicate, buttonstacktrace;
1692  
    String[] args;
1693  
1694  
    final DelayedUpdate du = new DelayedUpdate(new Runnable() {
1695  
      public void run() { try {
1696  
1697  
        textArea.append(buf.substring(textArea.getText().length()));
1698  
1699  
      } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
1700  
1701  
    public Console(final String[] args) ctex {
1702  
      this.args = args;
1703  
      // create all components and add them
1704  
      frame=new JFrame(args.length == 0 ? "JavaX Starter Output" : "JavaX Output - " + join(" ", args));
1705  
1706  
		/*Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
1707  
		Dimension frameSize=new Dimension((int)(screenSize.width/2),(int)(screenSize.height/2));
1708  
		int x=(int)(frameSize.width/2);
1709  
		int y=(int)(frameSize.height/2);
1710  
		frame.setBounds(x,y,frameSize.width,frameSize.height);*/
1711  
1712  
      // put in right-bottom corner
1713  
      Rectangle r = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
1714  
      int w = 550, h = 200;
1715  
      frame.setBounds(r.x+r.width-w, r.y+r.height-h, w, h);
1716  
1717  
      textArea=new JTextArea();
1718  
      textArea.setEditable(false);
1719  
      buttonclear = new JButton("clear");
1720  
      buttonkill = new JButton("kill");
1721  
      buttonrestart = new JButton("restart");
1722  
      buttonduplicate = new JButton("duplicate");
1723  
      buttonstacktrace = new JButton("status");
1724  
      buttonstacktrace.setToolTipText("Show threads & stack traces.");
1725  
1726  
      JPanel buttons = new JPanel(new GridLayout(1, 5));
1727  
      buttons.add(buttonclear);
1728  
      buttons.add(buttonkill);
1729  
      buttons.add(buttonrestart);
1730  
      buttons.add(buttonduplicate);
1731  
      buttons.add(buttonstacktrace);
1732  
1733  
      final PipedOutputStream pout3=new PipedOutputStream(pin3);
1734  
      tfInput = new JTextField();
1735  
      tfInput.addActionListener(actionListener {
1736  
        S line = tfInput.getText();
1737  
        try {
1738  
          pout3.write((line + "\n").getBytes("UTF-8"));
1739  
          pout3.flush();
1740  
        } catch (Exception e) {}
1741  
        tfInput.setText("");
1742  
      });
1743  
      
1744  
      JPanel panel = new JPanel(new BorderLayout());
1745  
      panel.add(new JScrollPane(textArea), BorderLayout.CENTER);
1746  
      panel.add(tfInput, BorderLayout.SOUTH);
1747  
      
1748  
      frame.addWindowListener(new WindowAdapter() {
1749  
        public void windowActivated(WindowEvent e) {
1750  
          tfInput.requestFocus();
1751  
        }
1752  
      });
1753  
      
1754  
      frame.getContentPane().setLayout(new BorderLayout());
1755  
      frame.getContentPane().add(panel, BorderLayout.CENTER);
1756  
      frame.getContentPane().add(buttons, BorderLayout.SOUTH);
1757  
      frame.setVisible(true);
1758  
      
1759  
      //frame.addWindowListener(this); // disabled for now
1760  
      buttonclear.addActionListener(this);
1761  
      buttonkill.addActionListener(this);
1762  
      buttonrestart.addActionListener(this);
1763  
      buttonduplicate.addActionListener(this);
1764  
      buttonstacktrace.addActionListener(this);
1765  
1766  
      quit=false; // signals the Threads that they should exit
1767  
      
1768  
      if (args.length != 0) {
1769  
        print("Starting title updater");
1770  
        new Thread("Console Title Updater :)") {
1771  
          public void run() {
1772  
            if (args.length != 0) {
1773  
              print("Getting title for " + args[0]);
1774  
              String title = getSnippetTitle(args[0]);
1775  
              print("Title: " + title);
1776  
              if (title != null && title.length() != 0)
1777  
                frame.setTitle(title + " [Output]");
1778  
            }
1779  
          }
1780  
        }.start();
1781  
      }
1782  
      
1783  
      System.setIn(pin3);
1784  
      
1785  
    }
1786  
1787  
    public synchronized void windowClosed(WindowEvent evt)
1788  
    {
1789  
      console = null;
1790  
      /*quit=true;
1791  
      this.notifyAll(); // stop all threads
1792  
      try { reader.join(1000);pin.close();   } catch (Exception e){}
1793  
      try { reader2.join(1000);pin2.close(); } catch (Exception e){}
1794  
      System.exit(0);*/
1795  
    }
1796  
1797  
    public synchronized void windowClosing(WindowEvent evt)
1798  
    {
1799  
      frame.setVisible(false); // default behaviour of JFrame
1800  
      frame.dispose();
1801  
    }
1802  
1803  
    public synchronized void actionPerformed(ActionEvent evt) {
1804  
      if (evt.getSource() == buttonkill) {
1805  
        print("Console: Kill button pressed!");
1806  
        // TODO: give threads time to finish, e.g. reportToChat?
1807  
        System.exit(0);
1808  
      } else if (evt.getSource() == buttonrestart) {
1809  
        print("Console: Restart button pressed.");
1810  
        nohupJavax(smartJoin(args));
1811  
        System.exit(0);
1812  
      } else if (evt.getSource() == buttonduplicate) {
1813  
        print("Console: Duplicate button pressed.");
1814  
        nohupJavax(smartJoin(args));
1815  
      } else if (evt.getSource() == buttonstacktrace) {
1816  
        listUserThreadsWithStackTraces();
1817  
      } else {
1818  
        textArea.setText("");
1819  
        buf = new StringBuffer();
1820  
      }
1821  
    }
1822  
1823  
    public void appendText(String s, boolean outNotErr) {
1824  
      if (verbose) oldOut.println("Console appendText " + outNotErr + " " + quote(s));
1825  
      buf.append(s);
1826  
      du.trigger();
1827  
    }
1828  
  } // Console
1829  
1830  
	static void tryToOpenConsole(String[] args) {
1831  
	  try {
1832  
	    console = new Console(args);
1833  
	  } catch (HeadlessException e) {
1834  
	    // ok, we're headless.
1835  
	  } catch (Throwable e) {
1836  
	    // some other error in console - continue without it
1837  
	    e.printStackTrace();
1838  
	  }
1839  
	}
1840  
1841  
  //// END CONSOLE STUFF
1842  
1843  
  static long now_virtualTime;
1844  
  static long now() {
1845  
    return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis();
1846  
  }
1847  
1848  
  static void print(Object o) {
1849  
    System.out.println(o);
1850  
  }
1851  
1852  
  public synchronized void run()
1853  
  {
1854  
    try
1855  
    {
1856  
      while (Thread.currentThread()==reader)
1857  
      {
1858  
        try { this.wait(100);}catch(InterruptedException ie) {}
1859  
        if (pin.available()!=0)
1860  
        {
1861  
          String input=readLine(pin);
1862  
          if (verbose) oldOut.println("reader: " + quote(input));
1863  
          appendText(input, true);
1864  
        }
1865  
        if (quit) return;
1866  
      }
1867  
1868  
      while (Thread.currentThread()==reader2)
1869  
      {
1870  
        try { this.wait(100);}catch(InterruptedException ie) {}
1871  
        if (pin2.available()!=0)
1872  
        {
1873  
          String input=readLine(pin2);
1874  
          if (verbose) oldOut.println("reader2: " + quote(input));
1875  
          appendText(input, false);
1876  
        }
1877  
        if (quit) return;
1878  
      }
1879  
    } catch (Exception e)
1880  
    {
1881  
      appendText("\nConsole reports an Internal error.", false);
1882  
      appendText("The error is: "+e, false);
1883  
    }
1884  
  }
1885  
1886  
  static void redirectSystemOutAndErr() {
1887  
    if (reader != null) return; // did this already
1888  
1889  
    x26 _this = new x26();
1890  
    
1891  
    if (verbose) System.out.println("Redirecting System.out");
1892  
    try
1893  
    {
1894  
      PipedOutputStream pout=new PipedOutputStream(pin);
1895  
      oldOut = System.out;
1896  
      TeeOutputStream tee = new TeeOutputStream(oldOut, pout);
1897  
      System.setOut(new PrintStream(tee,true));
1898  
    }
1899  
    catch (Exception io)
1900  
    {
1901  
      System.err.println("Couldn't redirect STDOUT - " + io.getMessage());
1902  
    }
1903  
1904  
    if (verbose) System.out.println("Redirecting System.err");
1905  
    try
1906  
    {
1907  
      PipedOutputStream pout2=new PipedOutputStream(pin2);
1908  
      oldErr = System.err;
1909  
      TeeOutputStream tee = new TeeOutputStream(oldErr, pout2);
1910  
      System.setErr(new PrintStream(tee,true));
1911  
    }
1912  
    catch (Exception io)
1913  
    {
1914  
      System.err.println("Couldn't redirect STDERR - " + io.getMessage());
1915  
    }
1916  
1917  
    if (verbose) System.out.println("Redirects done. Starting readers");
1918  
    
1919  
    // Starting two seperate threads to read from the PipedInputStreams
1920  
    //
1921  
    reader=new Thread(_this, "StdOut Piper");
1922  
    reader.setDaemon(true);
1923  
    reader.start();
1924  
    //
1925  
    reader2 = new Thread(_this, "StdErr Piper");
1926  
    reader2.setDaemon(true);
1927  
    reader2.start();
1928  
  }
1929  
1930  
  static Appendable customSystemOut;
1931  
1932  
  static void appendText(String s, boolean outNotErr) {
1933  
    // We do this with a TeeOutputStream now (safer).
1934  
    // (outNotErr ? oldOut : oldErr).print(s);
1935  
    
1936  
    if (console != null)
1937  
      console.appendText(s, outNotErr);
1938  
    if (customSystemOut != null)
1939  
      try {
1940  
        customSystemOut.append(s);
1941  
      } catch (IOException e) {
1942  
        e.printStackTrace();
1943  
      }
1944  
  }
1945  
1946  
  static String readLine(PipedInputStream in) throws IOException
1947  
  {
1948  
    String input="";
1949  
    do
1950  
    {
1951  
      int available=in.available();
1952  
      if (available==0) break;
1953  
      byte b[]=new byte[available];
1954  
      in.read(b);
1955  
      input=input+new String(b,0,b.length);
1956  
    }while( !input.endsWith("\n") &&  !input.endsWith("\r\n") && !quit);
1957  
    return input;
1958  
  }
1959  
1960  
  static void nohupJavax(String javaxargs) {
1961  
    try {
1962  
      File xfile = new File(userHome(), ".javax/x26.jar");
1963  
      if (!xfile.isFile()) {
1964  
        String url = "http://tinybrain.de/x26.jar";
1965  
        byte[] data = loadBinaryPage(new URL(url).openConnection());
1966  
        if (data.length < 1000000)
1967  
          throw new RuntimeException("Could not load " + url);
1968  
        saveBinaryFile(xfile.getPath(), data);
1969  
      }
1970  
      String jarPath = xfile.getPath();
1971  
      nohup("java -jar " + (isWindows() ? winQuote(jarPath) : bashQuote(jarPath)) + " " + javaxargs);
1972  
    } catch (Exception e) { throw new RuntimeException(e); }
1973  
  }
1974  
1975  
  /** possibly improvable */
1976  
  public static String winQuote(String text) {
1977  
    if (text == null) return null;
1978  
    return "\"" + text
1979  
      .replace("\\", "\\\\")
1980  
      .replace("\"", "\\\"")
1981  
      .replace("\n", "\\n")
1982  
      .replace("\r", "\\r") + "\"";
1983  
  }
1984  
1985  
  public static File nohup(String cmd) throws IOException {
1986  
    File outFile = File.createTempFile("nohup_" + nohup_sanitize(cmd), ".out");
1987  
    nohup(cmd, outFile, false);
1988  
    return outFile;
1989  
  }
1990  
1991  
  static String nohup_sanitize(String s) {
1992  
    return s.replaceAll("[^a-zA-Z0-9\\-_]", "");
1993  
  }
1994  
1995  
  /** outFile takes stdout and stderr. */
1996  
  public static void nohup(String cmd, File outFile, boolean append) throws IOException {
1997  
    String command = nohup_makeNohupCommand(cmd, outFile, append);
1998  
1999  
    File scriptFile = File.createTempFile("_realnohup", isWindows() ? ".bat" : "");
2000  
    System.out.println("[Nohup] " + command);
2001  
    try {
2002  
      //System.out.println("[RealNohup] Script file: " + scriptFile.getPath());
2003  
      saveTextFile(scriptFile.getPath(), command);
2004  
      String[] command2;
2005  
      if (isWindows())
2006  
        command2 = new String[] {"cmd", "/c", "start", "/b", scriptFile.getPath() };
2007  
      else
2008  
        command2 = new String[] {"/bin/bash", scriptFile.getPath() };
2009  
2010  
      Process process = Runtime.getRuntime().exec(command2);
2011  
      try {
2012  
        process.waitFor();
2013  
      } catch (InterruptedException e) {
2014  
        throw new RuntimeException(e);
2015  
      }
2016  
      int value = process.exitValue();
2017  
      //System.out.println("exit value: " + value);
2018  
    } finally {
2019  
      if (!isWindows())
2020  
        scriptFile.delete();
2021  
    }
2022  
  }
2023  
2024  
  public static String nohup_makeNohupCommand(String cmd, File outFile, boolean append) {
2025  
    mkdirsForFile(outFile);
2026  
2027  
    String command;
2028  
    if (isWindows())
2029  
      command = cmd + (append ? " >>" : " >") + winQuote(outFile.getPath()) + " 2>&1";
2030  
    else
2031  
      command = "nohup " + cmd + (append ? " >>" : " >") + bashQuote(outFile.getPath()) + " 2>&1 &";
2032  
    return command;
2033  
  }
2034  
2035  
  public static void mkdirsForFile(File file) {
2036  
    File dir = file.getParentFile();
2037  
    if (dir != null) // is null if file is in current dir
2038  
      dir.mkdirs();
2039  
  }
2040  
 
2041  
  static void autoReportToChat() {
2042  
    if (customSystemOut == null) {
2043  
      print("Auto-reporting to chat.");
2044  
      customSystemOut = new Appendable() {
2045  
        LineBuf buf = new LineBuf();
2046  
        
2047  
        // only using this one
2048  
        public Appendable append(CharSequence cs) {
2049  
          buf.append(cs.toString());
2050  
          while (true) {
2051  
            String s = buf.nextLine();
2052  
            if (s == null) break;
2053  
            reportToChat(s, true);
2054  
          }
2055  
          return this;
2056  
        }
2057  
    
2058  
        public Appendable append(char c) { return this; }
2059  
        public Appendable append(CharSequence s, int start, int end) { return this; }
2060  
      };
2061  
     }
2062  
  }
2063  
  
2064  
  static class Q {
2065  
    LinkedBlockingQueue<Runnable> q = new LinkedBlockingQueue<Runnable>();
2066  
    
2067  
    static class Done extends RuntimeException {}
2068  
    
2069  
    Q() {}
2070  
    
2071  
    Q(String name, boolean startThread) {
2072  
      if (startThread)
2073  
        new Thread(name) {
2074  
          public void run() {
2075  
            Q.this.run();
2076  
          }
2077  
        }.start();
2078  
    }
2079  
    
2080  
    Iterable<Runnable> master() {
2081  
      return new Iterable<Runnable>() {
2082  
        public Iterator<Runnable> iterator() {
2083  
          return new Iterator<Runnable>() {
2084  
            Runnable x;
2085  
            
2086  
            public boolean hasNext() { try {
2087  
   
2088  
              //debug("hasNext");
2089  
              while (x == null)
2090  
                x = q.poll(1, TimeUnit.DAYS);
2091  
              //debug("hasNext true");
2092  
              return true;
2093  
            
2094  
  } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}
2095  
            
2096  
            public Runnable next() {
2097  
              //debug("next");
2098  
              hasNext();
2099  
              Runnable _x = x;
2100  
              x = null;
2101  
              //debug("next " + structure(x));
2102  
              return _x;
2103  
            }
2104  
            
2105  
            public void remove() {
2106  
            }
2107  
          };
2108  
        }
2109  
      };
2110  
    }
2111  
    
2112  
    void add(Runnable r) {
2113  
      q.add(r);
2114  
    }
2115  
    
2116  
    void run() {
2117  
      for (Runnable r : master()) {
2118  
        try {
2119  
          r.run();
2120  
        } catch (Done e) {
2121  
          return; // break signal
2122  
        } catch (Throwable e) {
2123  
          e.printStackTrace();
2124  
        }
2125  
      }
2126  
    }
2127  
    
2128  
    void done() {
2129  
      add(new Runnable() {
2130  
        public void run() {
2131  
          throw new Done();
2132  
        }
2133  
      });
2134  
    }
2135  
  } // class Q
2136  
2137  
static void reportToChat(final String s, boolean silent) {
2138  
    if (s == null || s.length() == 0) return;
2139  
    if (!silent)
2140  
      print("reportToChat: " + quote(s));
2141  
    reportToChat_getChatThread().add(new Runnable() {
2142  
    public void run() { try {
2143  
        startChatServerIfNotUp();
2144  
        waitForChatServer();
2145  
        chatSend(s);
2146  
    } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}});
2147  
   }
2148  
  
2149  
  static Q reportToChat_q;
2150  
  
2151  
  static Q reportToChat_getChatThread() {
2152  
    if (reportToChat_q == null)
2153  
      reportToChat_q = new Q("reportToChat", true);
2154  
    return reportToChat_q;
2155  
  }
2156  
  
2157  
  static void startChatServerIfNotUp() {
2158  
    if (portIsBound(9751)) {
2159  
      //print("Chat seems to be up.");
2160  
    } else {
2161  
      nohupJavax("1000867");
2162  
      print("Chat server should be coming up any minute now.");
2163  
    }
2164  
  }
2165  
  
2166  
  static void waitForChatServer() {
2167  
    if (!portIsBound(9751)) {
2168  
      //System.out.print("Waiting for chat server... ");
2169  
      do {
2170  
        sleep(1000);
2171  
      } while (!portIsBound(9751));
2172  
      //print("OK.");
2173  
    }
2174  
  }
2175  
2176  
  static boolean portIsBound(int port) {
2177  
    try {
2178  
      ServerSocket s = new ServerSocket(port);
2179  
      s.close();
2180  
      return false;
2181  
    } catch (IOException e) {
2182  
      return true;
2183  
    }
2184  
  }
2185  
  
2186  
  static class LineBuf {
2187  
    StringBuffer buf = new StringBuffer();
2188  
    
2189  
    void append(String s) {
2190  
      buf.append(s);
2191  
    }
2192  
    
2193  
    String nextLine() {
2194  
      int i = buf.indexOf("\n");
2195  
      if (i >= 0) {
2196  
        String s = buf.substring(0, i > 0 && buf.charAt(i-1) == '\r' ? i-1 : i);
2197  
        buf.delete(0, i+1);
2198  
        return s;
2199  
      }
2200  
      return null;
2201  
    }
2202  
  } // LineBuf
2203  
2204  
  static void sleep(long ms) {
2205  
    try {
2206  
      Thread.sleep(ms);
2207  
    } catch (Exception e) { throw new RuntimeException(e); }
2208  
  }
2209  
2210  
  !include #1000937 // chatSend
2211  
2212  
  static class TeeOutputStream extends OutputStream {
2213  
    
2214  
    protected OutputStream out, branch;
2215  
2216  
    public TeeOutputStream( OutputStream out, OutputStream branch ) {
2217  
      this.out = out;
2218  
      this.branch = branch;
2219  
    }
2220  
2221  
    @Override
2222  
    public synchronized void write(byte[] b) throws IOException {
2223  
      write(b, 0, b.length);
2224  
    }
2225  
2226  
    @Override
2227  
    public synchronized void write(byte[] b, int off, int len) throws IOException {
2228  
      //if (verbose) oldOut.println("Tee write " + new String(b, "UTF-8"));
2229  
      out.write(b, off, len);
2230  
      this.branch.write(b, off, len);
2231  
    }
2232  
2233  
    @Override
2234  
    public synchronized void write(int b) throws IOException {
2235  
      write(new byte[] {(byte) b});
2236  
    }
2237  
2238  
    /**
2239  
     * Flushes both streams.
2240  
     * @throws IOException if an I/O error occurs
2241  
     */
2242  
    @Override
2243  
    public void flush() throws IOException {
2244  
      out.flush();
2245  
      this.branch.flush();
2246  
    }
2247  
2248  
    /**
2249  
     * Closes both streams.
2250  
     * @throws IOException if an I/O error occurs
2251  
     */
2252  
    @Override
2253  
    public void close() throws IOException {
2254  
      out.close();
2255  
      this.branch.close();
2256  
    }
2257  
  }
2258  
  
2259  
  static boolean isChatServer(String[] args) {
2260  
    for (int i = 0; i < args.length; i++)
2261  
      if (isSnippetID(args[i]))
2262  
        return parseSnippetID(args[i]) == 1000867;
2263  
    return false;
2264  
  }
2265  
  
2266  
  static String getSnippetTitle(String id) {
2267  
    try {
2268  
      return loadPage(new URL("http://tinybrain.de:8080/tb-int/getfield.php?id=" + parseSnippetID(id) + "&field=title"));
2269  
    } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }
2270  
  }
2271  
  
2272  
  static void listUserThreadsWithStackTraces() {
2273  
    print("");
2274  
    Map<Thread, StackTraceElement[]> threadMap = Thread.getAllStackTraces();
2275  
    int n = 0;
2276  
    for (Thread t : threadMap.keySet()) {
2277  
      ThreadGroup g = t.getThreadGroup();
2278  
      if (g != null && g.getName().equals("system")) continue;
2279  
      ++n;
2280  
      print(t);
2281  
      for (StackTraceElement e : threadMap.get(t)) {
2282  
        print("  " + e);
2283  
      }
2284  
      print("");
2285  
    }
2286  
    print(n + " user threads.");
2287  
  }
2288  
  
2289  
  static void killMyself() {
2290  
    print("Killing myself. (insert overall feeling here)");
2291  
    System.exit(0);
2292  
  }
2293  
  
2294  
  static void makeVMAndroid() {
2295  
    makeAndroidNoConsole("This is a JavaX VM.", stringfunc { answer(s) });
2296  
  }
2297  
  
2298  
  static class Info {
2299  
    S programID;
2300  
    S[] programArgs;
2301  
    File transpiledSrc;
2302  
    Class mainClass;
2303  
  }
2304  
  
2305  
  static new Info info;
2306  
  
2307  
  static synchronized S answer(S s) {
2308  
    new Matches m;
2309  
    
2310  
    if (match3("kill!", s)) {
2311  
      killMyself();
2312  
      return "ok";
2313  
    }
2314  
    if (match3("What is your process ID?", s) || match3("what is your pid?", s))
2315  
      return getPID();
2316  
    if (match3("what is your program id?", s))
2317  
      return info.programID;
2318  
    if (match3("what are your program arguments?", s))
2319  
      return structure(info.programArgs);
2320  
    if (match3("get fields of main class", s))
2321  
      return structure(listFields(info.mainClass));
2322  
    if (match3("get field * of main class", s, m))
2323  
      return structure(get(info.mainClass, m.m[0]));
2324  
    if (match3("invoke function * of main class", s, m))
2325  
      return structure(call(info.mainClass, m.m[0]));
2326  
    if (match3("set field * of main class to *", s, m)) {
2327  
      set(info.mainClass, m.m[0], unstructure(m.m[1]));
2328  
      return "ok";
2329  
    }
2330  
    if (match3("how much memory are you consuming", s))
2331  
      return "Java heap size: " + (Runtime.getRuntime().totalMemory()+1024*1024-1)/1024/1024 + " MB";
2332  
    if (match3("how much memory is used after GC?", s)) {
2333  
      System.gc();
2334  
      return "Java heap used: " + (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()+1024*1024-1)/1024/1024 + " MB";
2335  
    }
2336  
    if (match3("how much memory is used?", s))
2337  
      return "Java heap used: " + (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()+1024*1024-1)/1024/1024 + " MB";
2338  
    return null;
2339  
  }
2340  
  
2341  
  !include #1001103 // makeAndroid / makeAndroidNoConsole
2342  
  !include #1001074 // readLine
2343  
}

Author comment

Began life as a copy of #750

download  show line numbers  debug dex  old transpilations   

Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1001110
Snippet name: x26.java (JavaX)
Eternal ID of this version: #1001110/1
Text MD5: b0ca1255e8e0936f96b4b2ee363838ec
Transpilation MD5: 29e05fbb42ba17564c9a2150b09811ea
Author: stefan
Category: javax
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2015-09-22 21:40:15
Source code size: 81593 bytes / 2343 lines
Pitched / IR pitched: No / Yes
Views / Downloads: 713 / 644
Referenced in: [show references]