content: /*
   * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * The Universal Permissive License (UPL), Version 1.0
   *
   * Subject to the condition set forth below, permission is hereby granted to any
   * person obtaining a copy of this software, associated documentation and/or
   * data (collectively the "Software"), free of charge and under any and all
   * copyright rights in the Software, and any and all patent rights owned or
   * freely licensable by each licensor hereunder covering either (i) the
   * unmodified Software as contributed to or provided by such licensor, or (ii)
   * the Larger Works (as defined below), to deal in both
   *
   * (a) the Software, and
   *
   * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
   * one is included with the Software each a "Larger Work" to which the Software
   * is contributed by such licensors),
   *
   * without restriction, including without limitation the rights to copy, create
   * derivative works of, display, perform, and distribute the Software and make,
   * use, sell, offer for sale, import, export, have made, and have sold the
   * Software and the Larger Work(s), and to sublicense the foregoing rights on
   * either these or other terms.
   *
   * This license is subject to the following condition:
   *
   * The above copyright notice and either this complete permission notice or at a
   * minimum a reference to the UPL must be included in all copies or substantial
   * portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
   */
  package org.graalphp.launcher;
  
  import org.graalvm.polyglot.Context;
  import org.graalvm.polyglot.PolyglotException;
  import org.graalvm.polyglot.Source;
  import org.graalvm.polyglot.Value;
  
  import java.io.Console;
  import java.io.File;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.PrintStream;
  import java.util.HashMap;
  import java.util.Map;
  
  public final class GraalPhpMain {
  
      private static final String PHP = "php";
      private static final String REPL = "repl";
      private static final String VERSION = "version";
  
      /**
       * The main entry point.
       */
      public static void main(String[] args) throws IOException {
          Source source;
          Map<String, String> options = new HashMap<>();
          String file = null;
          for (String arg : args) {
              if (parseOption(options, arg)) {
                  continue;
              } else {
                  if (file == null) {
                      file = arg;
                  }
              }
          }
          if (options.containsKey(VERSION)) {
              // version generated with src/main/java-templates
              System.out.println(LauncherVersion.getCuratedVersion());
              System.exit(0);
          }
          if (options.containsKey(REPL)) {
              options.remove(REPL);
              System.exit(executeRepl(options));
          }
  
          if (file == null) {
              source = Source.newBuilder(PHP, new InputStreamReader(System.in), "<stdin>").build();
          } else {
              source = Source.newBuilder(PHP, new File(file)).build();
          }
          System.exit(executeSource(source, System.in, System.out, options));
      }
  
      private static String phpTags(String src) {
          return "<?php " + src + " ?>";
      }
  
      private static int executeRepl(Map<String, String> options) {
          Context context;
          PrintStream err = System.err;
          try {
              context = Context.newBuilder(PHP).in(System.in).out(System.out).options(options).build();
          } catch (IllegalArgumentException e) {
              err.println(e.getMessage());
              return 1;
          }
  
          Console console = System.console();
          while (true) {
              String line = console.readLine();
              if (line == null) {
                  break;
              }
              try {
                  Source source = Source.newBuilder(PHP, phpTags(line), "<console>").build();
                  executeSource(source, System.in, System.out, options);
  
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
          context.close();
          return 0;
      }
  
      private static int executeSource(Source source,
                                       InputStream in,
                                       PrintStream out,
                                       Map<String, String> options) {
          Context context;
          PrintStream err = System.err;
          try {
              context = Context.newBuilder(PHP).in(in).out(out).options(options).build();
          } catch (IllegalArgumentException e) {
              err.println(e.getMessage());
              return 1;
          }
          // out.println("== running on " + context.getEngine());
  
          try {
              Value result = context.eval(source);
              // out.println(result.toString());
              return 0;
          } catch (PolyglotException ex) {
              if (ex.isInternalError()) {
                  // for internal errors we print the full stack trace
                  ex.printStackTrace();
              } else {
                  err.println(ex.getMessage());
              }
              return 1;
          } finally {
              context.close();
          }
      }
  
      private static boolean parseOption(Map<String, String> options, String arg) {
          if (arg.length() <= 2 || !arg.startsWith("--")) {
              return false;
          }
          int eqIdx = arg.indexOf('=');
          String key;
          String value;
          if (eqIdx < 0) {
              key = arg.substring(2);
              value = null;
          } else {
              key = arg.substring(2, eqIdx);
              value = arg.substring(eqIdx + 1);
          }
  
          if (value == null) {
              value = "true";
          }
          int index = key.indexOf('.');
          String group = key;
          if (index >= 0) {
              group = group.substring(0, index);
          }
          options.put(key, value);
          return true;
      }
  
  }
  