]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Updated command line
authorarved <arved@unknown>
Wed, 21 Feb 2001 01:08:08 +0000 (01:08 +0000)
committerarved <arved@unknown>
Wed, 21 Feb 2001 01:08:08 +0000 (01:08 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194079 13f79535-47bb-0310-9956-ffa450edef68

conf/config.xml
src/org/apache/fop/apps/AWTStarter.java [new file with mode: 0644]
src/org/apache/fop/apps/CommandLineOptions.java [new file with mode: 0644]
src/org/apache/fop/apps/CommandLineStarter.java [new file with mode: 0644]
src/org/apache/fop/apps/FOInputHandler.java [new file with mode: 0644]
src/org/apache/fop/apps/Fop.java [new file with mode: 0644]
src/org/apache/fop/apps/InputHandler.java [new file with mode: 0644]
src/org/apache/fop/apps/Options.java [new file with mode: 0644]
src/org/apache/fop/apps/PrintStarter.java [new file with mode: 0644]
src/org/apache/fop/apps/Starter.java [new file with mode: 0644]
src/org/apache/fop/apps/XSLTInputHandler.java [new file with mode: 0644]

index 051eb4a1caeac0c32f211ac8dfa854122b9122b3..794fbcca96f0cdef55e6019c7e6dfbc997c91620 100644 (file)
@@ -5,9 +5,33 @@
 <configuration>
   <entry>
     <key>version</key>
-    <value>FOP 0.16.0 DEV</value>
+    <value>FOP 0.17.0 DEV</value>
   </entry>
 
+  <!-- default values for commandline options -->
+  <!-- suppress all progress information, error message are still displayed -->
+  <entry>
+    <key>quiet</key>
+    <value>false</value>
+  </entry>
+<!-- sets debug mode on/off; debug mode hasm more progress 
+     information and a stacktrace in case of a fatal exception -->
+  <entry>
+    <key>debugMode</key>
+    <value>false</value>
+  </entry>
+  <!-- displays all configuration  settings and then exits -->
+  <entry>
+    <key>dumpConfiguration</key>
+    <value>false</value>
+  </entry>
+  <!--  -->
+  <entry>
+    <key>debugMode</key>
+    <value>false</value>
+  </entry>
+
+
   <!-- stream-filter-list provides the default filters that are applied to all
        stream objects within the PDF file. These are normally used for 
        compression -->
     <key>stream-filter-list</key>
     <list>
       <!-- provides compression using zlib flate (default is on)-->
-      <value>flate</value>
+      <!-- <value>flate</value> -->
       
       <!-- encodes binary data into printable ascii characters (default off)
            This provides about a 4:5 expansion of data size -->
-      <value>ascii-85</value>
+      <!--  <value>ascii-85</value> -->
 
       <!-- encodes binary data with hex representation (default off)
            This filter is not recommended as it doubles the data size -->
diff --git a/src/org/apache/fop/apps/AWTStarter.java b/src/org/apache/fop/apps/AWTStarter.java
new file mode 100644 (file)
index 0000000..061c391
--- /dev/null
@@ -0,0 +1,178 @@
+/* 
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the 
+ * LICENSE file included with these sources."
+ */
+
+package org.apache.fop.apps;
+/*
+  originally contributed by
+  Juergen Verwohlt: Juergen.Verwohlt@jCatalog.com,
+  Rainer Steinkuhle: Rainer.Steinkuhle@jCatalog.com,
+  Stanislav Gorkhover: Stanislav.Gorkhover@jCatalog.com
+
+ */
+import org.apache.fop.messaging.MessageHandler;
+import org.apache.fop.viewer.*;
+import org.apache.fop.render.awt.*;
+
+
+import javax.swing.UIManager;
+import java.awt.*;
+
+// SAX
+import org.xml.sax.XMLReader;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+
+
+// Java
+import java.io.FileReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.*;
+
+
+
+/**
+ * initialize AWT previewer
+ */
+
+public class AWTStarter extends CommandLineStarter {
+
+    PreviewDialog frame;
+    AWTRenderer renderer;
+    public static String TRANSLATION_PATH = "/org/apache/fop/viewer/resources/";
+
+    private Translator resource;
+
+    public AWTStarter (CommandLineOptions commandLineOptions) {
+        super(commandLineOptions);
+        init();
+    }
+
+    private void init () {
+        try {
+            UIManager.setLookAndFeel(
+              new javax.swing.plaf.metal.MetalLookAndFeel());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        String language = commandLineOptions.getLanguage();
+
+        if (language == null)
+            language = System.getProperty("user.language");
+
+        resource = getResourceBundle(TRANSLATION_PATH + "resources." +
+                                     language);
+
+        UserMessage.setTranslator(
+          getResourceBundle(TRANSLATION_PATH + "messages." +
+                            language));
+
+        resource.setMissingEmphasized(false);
+        renderer = new AWTRenderer(resource);
+        frame = createPreviewDialog(renderer, resource);
+        renderer.setProgressListener(frame);
+        renderer.setComponent(frame);
+        MessageHandler.setOutputMethod(MessageHandler.EVENT);
+        MessageHandler.addListener(frame);
+    }
+
+
+    public void run () {
+               Driver driver = new Driver();
+        if (errorDump) {
+            driver.setErrorDump(true);
+        }
+
+        //init parser
+        frame.progress(resource.getString("Init parser") + " ...");
+        XMLReader parser = inputHandler.getParser();
+
+        if (parser == null) {
+            MessageHandler.errorln("ERROR: Unable to create SAX parser");
+            System.exit(1);
+        }
+
+        setParserFeatures(parser);
+
+        try {
+            driver.setRenderer(renderer);
+
+            // init mappings: time
+            frame.progress(resource.getString("Init mappings") + " ...");
+
+            driver.addElementMapping("org.apache.fop.fo.StandardElementMapping");
+            driver.addElementMapping("org.apache.fop.svg.SVGElementMapping");
+            driver.addPropertyList("org.apache.fop.fo.StandardPropertyListMapping");
+            driver.addPropertyList("org.apache.fop.svg.SVGPropertyListMapping");
+
+            // build FO tree: time
+            frame.progress(resource.getString("Build FO tree") + " ...");
+            driver.buildFOTree(parser, inputHandler.getInputSource());
+
+            // layout FO tree: time
+            frame.progress(resource.getString("Layout FO tree") + " ...");
+            driver.format();
+
+            // render: time
+            frame.progress(resource.getString("Render") + " ...");
+            driver.render();
+
+            frame.progress(resource.getString("Show"));
+            frame.showPage();
+
+        } catch (Exception e) {
+            MessageHandler.errorln("FATAL ERROR: " + e.getMessage());
+            e.printStackTrace();
+            System.exit(1);
+        }
+
+    }
+
+    protected PreviewDialog createPreviewDialog(AWTRenderer renderer,
+            Translator res) {
+        PreviewDialog frame = new PreviewDialog(renderer, res);
+        frame.validate();
+
+        // center window
+        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+        Dimension frameSize = frame.getSize();
+        if (frameSize.height > screenSize.height)
+            frameSize.height = screenSize.height;
+        if (frameSize.width > screenSize.width)
+            frameSize.width = screenSize.width;
+        frame.setLocation((screenSize.width - frameSize.width) / 2,
+                          (screenSize.height - frameSize.height) / 2);
+        frame.setVisible(true);
+        return frame;
+    }
+
+
+
+    private SecureResourceBundle getResourceBundle(String path) {
+        InputStream in = null;
+
+        try {
+            URL url = getClass().getResource(path);
+            in = url.openStream();
+        } catch (Exception ex) {
+            MessageHandler.logln("Can't find URL to: <" + path + "> " +
+                                 ex.getMessage());
+        }
+        return new SecureResourceBundle(in);
+    }
+}
+
+
+
diff --git a/src/org/apache/fop/apps/CommandLineOptions.java b/src/org/apache/fop/apps/CommandLineOptions.java
new file mode 100644 (file)
index 0000000..b5575ca
--- /dev/null
@@ -0,0 +1,504 @@
+/* 
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the 
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.apps;
+
+//java
+import java.util.Vector;
+import java.io.File;
+
+// FOP
+import org.apache.fop.messaging.MessageHandler;
+import org.apache.fop.configuration.Configuration;
+import org.apache.fop.apps.FOPException;
+
+/**
+ *     Options parses the commandline arguments
+ */
+
+public class CommandLineOptions {
+
+    /* input / output not set */
+    private static final int NOT_SET = 0;
+    /* input: fo file  */
+    private static final int FO_INPUT = 1;
+    /* input: xml+xsl file  */
+    private static final int XSLT_INPUT = 2;
+    /* output: pdf file  */
+    private static final int PDF_OUTPUT = 1;
+    /* output: screen using swing  */
+    private static final int AWT_OUTPUT = 2;
+    /* output: mif file  */
+    private static final int MIF_OUTPUT = 3;
+    /* output: sent swing rendered file to printer  */
+    private static final int PRINT_OUTPUT = 4;
+
+    /* use debug mode*/
+    Boolean errorDump = null;
+    /* show configuration information */
+    Boolean dumpConfiguration = null;
+    /*suppress any progress information */
+    Boolean quiet = null;
+    /* name of user configuration file*/
+    File userConfigFile = null;
+    /* name of input fo file  */
+    File fofile = null;
+    /*  name of xsltfile (xslt transformation as input)*/
+    File xsltfile = null;
+    /*  name of xml file (xslt transformation as input)*/
+    File xmlfile = null;
+    /* name of output file  */
+    File outfile = null;
+    /* input mode */
+    int inputmode = NOT_SET;
+    /*output mode */
+    int outputmode = NOT_SET;
+    /* language for user information */
+    String language = null;
+
+    public CommandLineOptions (String [] args) {
+        parseOptions(args);
+        checkSettings ();
+        if (errorDump != null && errorDump.booleanValue()) {
+            debug();
+        }
+    }
+
+    /**
+      *  parses the commandline arguments
+      */
+    private void parseOptions (String args[]) {
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].equals("-d") || args[i].equals("--full-error-dump")) {
+                errorDump = new Boolean(true);
+            } else if (args[i].equals("-x") || args[i].equals("--dump-config")) {
+                dumpConfiguration =  new Boolean(true);
+            } else if (args[i].equals("-q") || args[i].equals("--quiet")) {
+                quiet =  new Boolean(true);
+            } else if (args[i].equals("-c")) {
+                if ((i + 1 == args.length) ||
+                        (args[i + 1].charAt(0) == '-')) {
+                    MessageHandler.errorln("ERROR: if you use '-c', you must specify the name of the configuration file");
+                    printUsage();
+                } else {
+                    userConfigFile = new File (args[i + 1]);
+                    i++;
+                }
+            } else if (args[i].equals("-l")) {
+                if ((i + 1 == args.length) ||
+                        (args[i + 1].charAt(0) == '-')) {
+                    MessageHandler.errorln("ERROR: if you use '-l', you must specify a language");
+                    printUsage();
+                } else {
+                    language = args[i + 1];
+                    i++;
+                }
+            } else if (args[i].equals("-fo")) {
+                inputmode = FO_INPUT;
+                if ((i + 1 == args.length) ||
+                        (args[i + 1].charAt(0) == '-')) {
+                    MessageHandler.errorln("ERROR: you must specify the fo file");
+                    printUsage();
+                } else {
+                    fofile = new File (args[i + 1]);
+                    i++;
+                }
+            } else if (args[i].equals("-xsl")) {
+                inputmode = XSLT_INPUT;
+                if ((i + 1 == args.length) ||
+                        (args[i + 1].charAt(0) == '-')) {
+                    MessageHandler.errorln("ERROR: you must specify the stylesheet file");
+                    printUsage();
+                } else {
+                    xsltfile = new File(args[i + 1]);
+                    i++;
+                }
+            } else if (args[i].equals("-xml")) {
+                inputmode = XSLT_INPUT;
+                if ((i + 1 == args.length) ||
+                        (args[i + 1].charAt(0) == '-')) {
+                    MessageHandler.errorln("ERROR: you must specify the input file");
+                    printUsage();
+                } else {
+                    xmlfile = new File(args[i + 1]);
+                    i++;
+                }
+            } else if (args[i].equals("-awt")) {
+                if (outputmode == NOT_SET) {
+                    outputmode = AWT_OUTPUT;
+                } else {
+                    MessageHandler.errorln("ERROR: you can only set one output method");
+                    printUsage();
+                }
+            } else if (args[i].equals("-pdf")) {
+                if (outputmode == NOT_SET) {
+                    outputmode = PDF_OUTPUT;
+                } else {
+                    MessageHandler.errorln("ERROR: you can only set one output method");
+                    printUsage();
+                }
+                if ((i + 1 == args.length) ||
+                        (args[i + 1].charAt(0) == '-')) {
+                    MessageHandler.errorln("ERROR: you must specify the pdf output file");
+                    printUsage();
+                } else {
+                    outfile = new File (args[i + 1]);
+                    i++;
+                }
+            } else if (args[i].equals("-mif")) {
+                if (outputmode == NOT_SET) {
+                    outputmode = MIF_OUTPUT;
+                } else {
+                    MessageHandler.errorln("ERROR: you can only set one output method");
+                    printUsage();
+                }
+                if ((i + 1 == args.length) ||
+                        (args[i + 1].charAt(0) == '-')) {
+                    MessageHandler.errorln("ERROR: you must specify the mif output file");
+                    printUsage();
+                } else {
+                    outfile = new File(args[i + 1]);
+                    i++;
+                }
+            } else if (args[i].equals("-print")) {
+                if (outputmode == NOT_SET) {
+                    outputmode = PRINT_OUTPUT;
+                } else {
+                    MessageHandler.errorln("ERROR: you can only set one output method");
+                    printUsage();
+                }
+                //show print help
+                if (i + 1 < args.length) {
+                    if (args[i + 1].equals("help")) {
+                        printUsagePrintOutput();
+                    }
+                }
+            }
+            else if (args[i].charAt(0) != '-') {
+                if (inputmode == NOT_SET) {
+                    inputmode = FO_INPUT;
+                    fofile = new File (args[i]);
+                } else if (outputmode == NOT_SET) {
+                    outputmode = PDF_OUTPUT;
+                    outfile = new File(args[i]);
+                } else {
+                    MessageHandler.errorln(
+                      "ERROR: Don't know what to do with " + args[i]);
+                    printUsage();
+                }
+            } else {
+                printUsage();
+            }
+        }
+    } //end parseOptions
+
+    /**
+     * checks whether all necessary information has been given in a consistent way
+     */
+    private void checkSettings () {
+        if (inputmode == NOT_SET) {
+            MessageHandler.errorln("ERROR: you have to specify an input file");
+            printUsage();
+        }
+
+        if (outputmode == NOT_SET) {
+            MessageHandler.errorln("ERROR: you have to specify an output mode");
+            printUsage();
+        }
+
+        if (inputmode == XSLT_INPUT) {
+            //check whether xml *and* xslt file have been set
+            if (xmlfile == null || xsltfile == null) {
+                MessageHandler.errorln(
+                  "ERROR: if you want to use an xml file transformed with an xslt file as input\n" +
+                  "       you must specify both files. \n" +
+                  "       Your input is \nxmlfile: " +
+                  xmlfile.getAbsolutePath() + "\nxsltfile: " +
+                  xsltfile.getAbsolutePath());
+                printUsage();
+            }
+            //warning if fofile has been set in xslt mode
+            if (fofile != null) {
+                MessageHandler.errorln(
+                  "ERROR: Can't use fo file in transformation!" +
+                  "       Your input is \nxmlfile: " +
+                  xmlfile.getAbsolutePath() + "\nxsltfile: " +
+                  xsltfile.getAbsolutePath() + "\nfofile: " +
+                  fofile.getAbsolutePath());
+            }
+            if (!xmlfile.exists()) {
+                MessageHandler.errorln("ERROR: xml file " +
+                                       xmlfile.getAbsolutePath() + " not found ");
+                System.exit(1);
+            }
+            if (!xsltfile.exists()) {
+                MessageHandler.errorln("ERROR: xsl file " +
+                                       xsltfile.getAbsolutePath() + " not found ");
+                System.exit(1);
+            }
+
+        } else if (inputmode == FO_INPUT) {
+            if (xmlfile != null || xsltfile != null) {
+                MessageHandler.logln("ERROR: fo input mode, but xmlfile or xslt file are set:");
+                MessageHandler.logln("xml file: " + xmlfile.toString());
+                MessageHandler.logln("xslt file: " + xsltfile.toString());
+            }
+            if (!fofile.exists()) {
+                MessageHandler.errorln("ERROR: fo file " +
+                                       fofile.getAbsolutePath() + " not found ");
+                System.exit(1);
+            }
+
+        }
+    }// end checkSettings
+
+
+    /**
+     *  returns the chosen renderer, throws FOPException
+     */
+    public String getRenderer () throws FOPException {
+        switch (outputmode) {
+            case NOT_SET:
+                throw new FOPException("Renderer has not been set!");
+            case PDF_OUTPUT:
+                return "org.apache.fop.render.pdf.PDFRenderer";
+            case AWT_OUTPUT:
+                return "org.apache.fop.render.awt.AWTRenderer";
+            case MIF_OUTPUT:
+                return "org.apache.fop.render.mif.MIFRenderer";
+            case PRINT_OUTPUT:
+                return "org.apache.fop.render.awt.PrintRenderer";
+            default:
+                throw new FOPException("Invalid Renderer setting!");
+        }
+    }
+
+    /**
+      *
+      **/
+    public InputHandler getInputHandler () {
+        switch (inputmode) {
+            case FO_INPUT:
+                return new FOInputHandler(fofile);
+            case XSLT_INPUT:
+                return new XSLTInputHandler(xmlfile,xsltfile);
+            default:
+                return new FOInputHandler(fofile);
+        }
+    }
+
+
+    public Starter getStarter() {
+        switch (outputmode) {
+            case PDF_OUTPUT:
+                return new CommandLineStarter(this);
+            case AWT_OUTPUT:
+                return new AWTStarter(this);
+            case MIF_OUTPUT:
+                return new CommandLineStarter(this);
+            case PRINT_OUTPUT:
+                return new PrintStarter(this);
+            default:
+                return new CommandLineStarter(this);
+        }
+    }
+
+    public int getInputMode() {
+        return inputmode;
+    }
+
+    public int getOutputMode() {
+        return outputmode;
+    }
+
+    public File getFOFile() {
+        return fofile;
+    }
+
+    public File getXMLFile() {
+        return xmlfile;
+    }
+
+    public File getXSLFile() {
+        return xsltfile;
+    }
+
+    public File getOutputFile() {
+        return outfile;
+    }
+
+    public File getUserConfigFile () {
+        return userConfigFile;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public Boolean isQuiet() {
+        return quiet;
+    }
+
+       public Boolean dumpConfiguration() {
+               return dumpConfiguration;
+       }
+
+    public Boolean isDebugMode() {
+        return errorDump;
+    }
+
+       
+    /**
+      * return either the fofile or the xmlfile
+      */
+    public File getInputFile() {
+        switch (inputmode) {
+            case FO_INPUT:
+                return fofile;
+            case XSLT_INPUT:
+                return xmlfile;
+            default:
+                return fofile;
+        }
+    }
+
+
+    /**
+      *         shows the commandline syntax including a summary of all available options and some examples
+      */
+    public static void printUsage() {
+        MessageHandler.logln(
+          "\nUSAGE\nFop [options] [-fo|-xml] infile [-xsl file] [-awt|-pdf|-mif|-print] <outfile>\n" +
+          " [OPTIONS]  \n" + "  -d          debug mode   \n" +
+          "  -x          dump configuration settings  \n" +
+          "  -q          quiet mode  \n" +
+          "  -c cfg.xml  use additional configuration file cfg.xml\n" +
+          "  -l lang     the language to use for user information \n\n" +
+          " [INPUT]  \n" +
+          "  infile            xsl:fo input file (the same as the next) \n" +
+          "  -fo  infile       xsl:fo input file  \n" +
+          "  -xml infile       xml input file, must be used together with -xsl \n" +
+          "  -xsl stylesheet   xslt stylesheet \n \n" +
+          " [OUTPUT] \n" +
+          "  outfile           input will be rendered as pdf file into outfile \n" +
+          "  -pdf outfile      input will be rendered as pdf file (outfile req'd) \n" +
+          "  -awt              input will be displayed on screen \n" +
+          "  -mif outfile      input will be rendered as mif file (outfile req'd)\n" +
+          "  -print            input file will be rendered and sent to the printer \n" +
+          "                    see options with \"-print help\" \n\n" +
+          " [Examples]\n" + "  Fop foo.fo foo.pdf \n" +
+          "  Fop -fo foo.fo -pdf foo.pdf (does the same as the previous line)\n" +
+          "  Fop -xsl foo.xsl -xml foo.xml -pdf foo.pdf\n" +
+          "  Fop foo.fo -mif foo.mif\n" +
+          "  Fop foo.fo -print or Fop -print foo.fo \n" + "  Fop foo.fo -awt ");
+        System.exit(1);
+    }
+
+    /**
+      *        shows the options for print output
+      */
+    public void printUsagePrintOutput() {
+        MessageHandler.errorln(
+          "USAGE: -print [-Dstart=i] [-Dend=i] [-Dcopies=i] [-Deven=true|false] " +
+          " org.apache.fop.apps.Fop (..) -print \n" +
+          "Example:\n" + "java -Dstart=1 -Dend=2 org.apache.Fop.apps.Fop infile.fo -print ");
+        System.exit(1);
+    }
+
+
+    /**
+      * debug mode. outputs all commandline settings
+      */
+    private void debug () {
+        System.out.print("Input mode: ");
+        switch (inputmode) {
+            case NOT_SET:
+                MessageHandler.logln("not set");
+                break;
+            case FO_INPUT:
+                MessageHandler.logln("FO ");
+                MessageHandler.logln("fo input file: " + fofile.toString());
+                break;
+            case XSLT_INPUT:
+                MessageHandler.logln("xslt transformation");
+                MessageHandler.logln("xml input file: " +
+                                     xmlfile.toString());
+                MessageHandler.logln("xslt stylesheet: " +
+                                     xsltfile.toString());
+                break;
+            default:
+                MessageHandler.logln("unknown input type");
+        }
+        System.out.print("Output mode: ");
+        switch (outputmode) {
+            case NOT_SET:
+                MessageHandler.logln("not set");
+                break;
+            case PDF_OUTPUT:
+                MessageHandler.logln("pdf");
+                MessageHandler.logln("output file: " + outfile.toString());
+                break;
+            case AWT_OUTPUT:
+                MessageHandler.logln("awt on screen");
+                if (outfile != null) {
+                    MessageHandler.logln("ERROR: awt mode, but outfile is set:");
+                    MessageHandler.logln("out file: " + outfile.toString());
+                }
+                break;
+            case MIF_OUTPUT:
+                MessageHandler.logln("mif");
+                MessageHandler.logln("output file: " + outfile.toString());
+                break;
+            case PRINT_OUTPUT:
+                MessageHandler.logln("print directly");
+                if (outfile != null) {
+                    MessageHandler.logln("ERROR: print mode, but outfile is set:");
+                    MessageHandler.logln("out file: " + outfile.toString());
+                }
+                break;
+            default:
+                MessageHandler.logln("unknown input type");
+        }
+
+
+        MessageHandler.logln("OPTIONS");
+        if (userConfigFile != null) {
+            MessageHandler.logln("user configuration file: " +
+                                 userConfigFile.toString());
+        } else {
+            MessageHandler.logln("no user configuration file is used [default]");
+        }
+        if (errorDump != null) {
+            MessageHandler.logln("debug mode on");
+        } else {
+            MessageHandler.logln("debug mode off [default]");
+        }
+        if (dumpConfiguration != null) {
+            MessageHandler.logln("dump configuration");
+        } else {
+            MessageHandler.logln("don't dump configuration [default]");
+        }
+        if (quiet != null) {
+            MessageHandler.logln("quiet mode on");
+        } else {
+            MessageHandler.logln("quiet mode off [default]");
+        }
+
+    }
+
+    //debug: create class and output all settings
+    public static void main (String args[]) {
+        /*
+         for (int i = 0; i < args.length; i++) {
+               MessageHandler.logln(">"+args[i]+"<");
+         }*/
+
+        CommandLineOptions options = new CommandLineOptions (args);
+        //options.debug();
+    }
+}
+
diff --git a/src/org/apache/fop/apps/CommandLineStarter.java b/src/org/apache/fop/apps/CommandLineStarter.java
new file mode 100644 (file)
index 0000000..fe8cdde
--- /dev/null
@@ -0,0 +1,68 @@
+package org.apache.fop.apps;
+
+// SAX
+import org.xml.sax.XMLReader;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+// Java
+import java.io.*;
+import java.net.URL;
+
+
+// FOP
+import org.apache.fop.messaging.MessageHandler;
+import org.apache.fop.configuration.Configuration;
+
+/**
+ *  super class for all classes which start Fop from the commandline
+ */
+
+public class CommandLineStarter extends Starter {
+       
+    CommandLineOptions commandLineOptions;
+       boolean errorDump;
+       
+    public CommandLineStarter (CommandLineOptions commandLineOptions) {
+        this.commandLineOptions = commandLineOptions;
+               options.setCommandLineOptions(commandLineOptions);
+               errorDump = Configuration.getBooleanValue("debugMode").booleanValue();
+               super.setInputHandler(commandLineOptions.getInputHandler());            
+    }
+       
+    public void run() {
+        String version = Version.getVersion();
+        MessageHandler.logln(version);
+
+        XMLReader parser = inputHandler.getParser();
+        setParserFeatures(parser,errorDump);
+
+               Driver driver = new Driver();
+        if (errorDump) {
+            driver.setErrorDump(true);
+        }
+                       
+        try {
+            driver.setRenderer(commandLineOptions.getRenderer(), "");
+            driver.addElementMapping("org.apache.fop.fo.StandardElementMapping");
+            driver.addElementMapping("org.apache.fop.svg.SVGElementMapping");
+            driver.addElementMapping("org.apache.fop.extensions.ExtensionElementMapping");
+            driver.addPropertyList("org.apache.fop.fo.StandardPropertyListMapping");
+            driver.addPropertyList("org.apache.fop.svg.SVGPropertyListMapping");
+            driver.addPropertyList("org.apache.fop.extensions.ExtensionPropertyListMapping");
+            driver.buildFOTree(parser,inputHandler.getInputSource());
+            driver.format();
+            driver.setOutputStream(new FileOutputStream(commandLineOptions.getOutputFile()));
+            driver.render();
+        } catch (Exception e) {
+            MessageHandler.errorln("FATAL ERROR: " + e.getMessage());
+            if (errorDump) {
+                e.printStackTrace();
+            }
+            System.exit(1);
+        }
+    }
+       
+}
+
diff --git a/src/org/apache/fop/apps/FOInputHandler.java b/src/org/apache/fop/apps/FOInputHandler.java
new file mode 100644 (file)
index 0000000..9a40a6a
--- /dev/null
@@ -0,0 +1,44 @@
+/* 
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the 
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.apps;
+
+// Imported SAX classes
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+//fop
+import org.apache.fop.messaging.MessageHandler;
+
+//java
+import java.io.File;
+
+/**
+ * Manages input if it is an xsl:fo file
+ */
+
+public class FOInputHandler extends InputHandler {
+
+       File fofile;
+    public FOInputHandler (File fofile) {
+               this.fofile = fofile;
+    }
+
+    public InputSource getInputSource () {
+        return super.fileInputSource(fofile);
+    }
+
+    public XMLReader getParser() {
+        XMLReader parser = super.createParser();
+        if (parser == null) {
+            MessageHandler.errorln("ERROR: Unable to create SAX parser");
+            System.exit(1);
+        }
+        return parser;
+    }
+}
+
diff --git a/src/org/apache/fop/apps/Fop.java b/src/org/apache/fop/apps/Fop.java
new file mode 100644 (file)
index 0000000..727fbba
--- /dev/null
@@ -0,0 +1,17 @@
+/* 
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the 
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.apps;
+
+public class Fop {
+    public static void main (String [] args) {
+        CommandLineOptions options = new CommandLineOptions (args);
+        Starter starter = options.getStarter();
+        starter.run();
+    }
+}
+
diff --git a/src/org/apache/fop/apps/InputHandler.java b/src/org/apache/fop/apps/InputHandler.java
new file mode 100644 (file)
index 0000000..133d866
--- /dev/null
@@ -0,0 +1,96 @@
+/* 
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the 
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.apps;
+
+// SAX
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+// Java
+import java.net.URL;
+import java.io.File;
+
+// FOP
+import org.apache.fop.messaging.MessageHandler;
+import org.apache.fop.configuration.Configuration;
+
+
+abstract public class InputHandler {
+
+
+    abstract public InputSource getInputSource();
+    abstract public XMLReader getParser();
+
+
+    /**
+       * create an InputSource from a File
+       *
+       * @param file the File
+       * @return the InputSource created
+       */
+    static public InputSource fileInputSource(File file) {
+        /* this code adapted from James Clark's in XT */
+        String path = file.getAbsolutePath();
+        String fSep = System.getProperty("file.separator");
+        if (fSep != null && fSep.length() == 1)
+            path = path.replace(fSep.charAt(0), '/');
+        if (path.length() > 0 && path.charAt(0) != '/')
+            path = '/' + path;
+        try {
+            return new InputSource(new URL("file", null, path).toString());
+        } catch (java.net.MalformedURLException e) {
+            throw new Error("unexpected MalformedURLException");
+        }
+    }
+
+    /**
+        * creates a SAX parser, using the value of org.xml.sax.parser
+        * defaulting to org.apache.xerces.parsers.SAXParser
+        *
+        * @return the created SAX parser
+        */
+    static XMLReader createParser() {
+               boolean debugMode = Configuration.getBooleanValue("debugMode").booleanValue();
+        String parserClassName = System.getProperty("org.xml.sax.parser");
+        if (parserClassName == null) {
+            parserClassName = "org.apache.xerces.parsers.SAXParser";
+        }
+        MessageHandler.logln("using SAX parser " + parserClassName);
+
+        try {
+            return (XMLReader) Class.forName(
+                     parserClassName).newInstance();
+        } catch (ClassNotFoundException e) {
+            MessageHandler.errorln("Could not find " + parserClassName);
+            if (debugMode) {
+                e.printStackTrace();
+            }
+        }
+        catch (InstantiationException e) {
+            MessageHandler.errorln("Could not instantiate " +
+                                   parserClassName);
+            if (debugMode) {
+                e.printStackTrace();
+            }
+        }
+        catch (IllegalAccessException e) {
+            MessageHandler.errorln("Could not access " + parserClassName);
+            if (debugMode) {
+                e.printStackTrace();
+            }
+        }
+        catch (ClassCastException e) {
+            MessageHandler.errorln(parserClassName + " is not a SAX driver");
+            if (debugMode) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+}
+
diff --git a/src/org/apache/fop/apps/Options.java b/src/org/apache/fop/apps/Options.java
new file mode 100644 (file)
index 0000000..893e7bf
--- /dev/null
@@ -0,0 +1,162 @@
+/* 
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the 
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.apps;
+
+//sax
+import org.xml.sax.InputSource;
+
+//java
+import java.io.File;
+import java.io.InputStream;
+
+//fop
+import org.apache.fop.messaging.MessageHandler;
+import org.apache.fop.configuration.Configuration;
+import org.apache.fop.configuration.ConfigurationReader;
+       
+/**
+ *     Options handles loading of configuration files and 
+ *  additional setting of commandline options
+ */
+
+public class Options {
+       boolean errorDump = false;
+       
+       public Options () {
+               this.loadStandardConfiguration();
+               initOptions ();
+       }
+       
+       public Options (File userConfigFile) {
+               this();
+               this.loadUserconfiguration(userConfigFile);
+       }
+
+       public Options (CommandLineOptions clOptions) {
+               this();
+               this.setCommandLineOptions(clOptions);
+       }
+
+       //initializing option settings  
+       void initOptions () {
+               if (Configuration.getBooleanValue("quiet").booleanValue()) {
+                       MessageHandler.setQuiet(true);          
+               }
+               if (Configuration.getBooleanValue("debugMode").booleanValue()) {
+                       errorDump = true;
+               }
+        if (Configuration.getBooleanValue("dumpConfiguration").booleanValue()) {               
+                       Configuration.put("dumpConfiguration","true");                  
+                       Configuration.dumpConfiguration();
+               }
+       }
+       
+       //setting clOptions
+    void setCommandLineOptions(CommandLineOptions clOptions) {
+               //load user configuration file,if there is one
+               File userConfigFile = clOptions.getUserConfigFile();
+        if (userConfigFile != null) {
+            this.loadUserconfiguration(userConfigFile);
+        }
+        
+        //debug mode
+               if (clOptions.isDebugMode() != null) {
+                       errorDump = clOptions.isDebugMode().booleanValue();
+                       Configuration.put("errorDump",new Boolean(errorDump));                  
+               } 
+               
+               //show configuration settings
+               boolean dumpConfiguration;
+               if (clOptions.dumpConfiguration() != null) {
+                       dumpConfiguration = clOptions.dumpConfiguration().booleanValue();
+               } else {
+                       dumpConfiguration = Configuration.getBooleanValue("dumpConfiguration").booleanValue();
+               }
+        if (dumpConfiguration) {               
+                       Configuration.put("dumpConfiguration","true");                  
+                       Configuration.dumpConfiguration();
+            System.exit(0);
+               }
+               
+               //quiet mode
+        if (clOptions.isQuiet() != null) {
+            MessageHandler.setQuiet(clOptions.isQuiet().booleanValue());
+               } 
+               
+               //set base directory
+        String baseDir = Configuration.getStringValue("baseDir");
+        if (baseDir == null) {
+            baseDir = new File(clOptions.getInputFile().getAbsolutePath()).getParent();
+            Configuration.put("baseDir",baseDir);
+        }
+        if (errorDump) {
+            MessageHandler.logln("base directory: " + baseDir);
+        }
+    }
+
+    /**
+        *  loads standard configuration file and a user file, if it has been specified
+        */
+    public void loadStandardConfiguration() {
+        String file = "config.xml";
+
+        // the entry /conf/config.xml refers to a directory conf which is a sibling of org
+        InputStream configfile =
+          ConfigurationReader.class.getResourceAsStream("/conf/"+
+                  file);
+        if (configfile == null) {
+            MessageHandler.errorln("Fatal error: can't find default configuration file");
+            System.exit(1);
+        }
+        if (errorDump) {
+            MessageHandler.logln("reading default configuration file");
+        }
+        ConfigurationReader reader =
+          new ConfigurationReader (new InputSource(configfile));
+        if (errorDump) {
+            reader.setDumpError(true);
+        }
+        try {
+            reader.start();
+        } catch (org.apache.fop.apps.FOPException error) {
+            MessageHandler.errorln("Fatal Error: Can't process default configuration file. \nProbably it is not well-formed.");
+            if (errorDump) {
+                reader.dumpError(error);
+            }
+            System.exit(1);
+        }
+    }
+
+    public void loadUserconfiguration(String userConfigFile) {
+        loadUserconfiguration(new File(userConfigFile));
+    }
+
+    public void loadUserconfiguration(File userConfigFile) {
+        //read user configuration file
+        if (userConfigFile != null) {
+            MessageHandler.logln("reading user configuration file");
+            ConfigurationReader reader = new ConfigurationReader (
+                                           InputHandler.fileInputSource(userConfigFile));
+            if (errorDump) {
+                reader.setDumpError(true);
+            }
+            try {
+                reader.start();
+            } catch (org.apache.fop.apps.FOPException error) {
+                MessageHandler.errorln(
+                  "Can't find user configuration file " +
+                  userConfigFile);
+                MessageHandler.errorln("using default values");
+                if (errorDump) {
+                    reader.dumpError(error);
+                }
+            }
+        }
+    }
+}
+
diff --git a/src/org/apache/fop/apps/PrintStarter.java b/src/org/apache/fop/apps/PrintStarter.java
new file mode 100644 (file)
index 0000000..e246335
--- /dev/null
@@ -0,0 +1,197 @@
+/* 
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the 
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.apps;
+
+/*
+  originally contributed by
+  Stanislav Gorkhover: stanislav.gorkhover@jcatalog.com
+  jCatalog Software AG
+ */
+
+
+import org.xml.sax.XMLReader;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import java.awt.Graphics;
+import java.awt.print.*;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.Vector;
+
+import org.apache.fop.render.awt.AWTRenderer;
+import org.apache.fop.layout.AreaTree;
+import org.apache.fop.layout.Page;
+import org.apache.fop.messaging.MessageHandler;
+
+
+/**
+ * This class prints a xsl-fo dokument without interaction.
+ * At the moment java has not the possibility to configure the printer and it's
+ * options without interaction (30.03.2000).
+ * This class allows to print a set of pages (from-to), even/odd pages and many copies.
+ * - Print from page xxx: property name - start, value int
+ * - Print to page xxx: property name - end, value int
+ * - Print even/odd pages: property name - even, value boolean
+ * - Print xxx copies: property name - copies, value int
+ *
+ */
+public class PrintStarter extends CommandLineStarter {
+
+    public PrintStarter (CommandLineOptions options) {
+        super(options);
+    }
+
+    public void run () {
+        Driver driver = new Driver();
+        if (errorDump) {
+            driver.setErrorDump(true);
+        }
+
+        String version = Version.getVersion();
+        MessageHandler.errorln(version);
+
+        XMLReader parser = inputHandler.getParser();
+        
+        setParserFeatures(parser,errorDump);
+
+        PrintRenderer renderer = new PrintRenderer();
+
+        try {
+            driver.setRenderer(renderer);
+            driver.addElementMapping("org.apache.fop.fo.StandardElementMapping");
+            driver.addElementMapping("org.apache.fop.svg.SVGElementMapping");
+            driver.addPropertyList("org.apache.fop.fo.StandardPropertyListMapping");
+            driver.addPropertyList("org.apache.fop.svg.SVGPropertyListMapping");
+            driver.buildFOTree(parser, inputHandler.getInputSource());
+            driver.format();
+            driver.render();
+        } catch (Exception e) {
+            MessageHandler.errorln("FATAL ERROR: " + e.getMessage());
+            if (errorDump) {
+                e.printStackTrace();
+            }
+
+            System.exit(1);
+        }
+
+        int copies = PrintRenderer.getIntProperty("copies", 1);
+        renderer.setCopies(copies);
+
+        PrinterJob pj = PrinterJob.getPrinterJob();
+        pj.setPageable(renderer);
+
+        pj.setCopies(copies);
+        try {
+            pj.print();
+        } catch (PrinterException pe) {
+            pe.printStackTrace();
+        }
+    }
+
+
+    static class PrintRenderer extends AWTRenderer {
+
+        static int EVEN_AND_ALL = 0;
+        static int EVEN = 1;
+        static int ODD = 2;
+
+        int startNumber;
+        int endNumber;
+        int mode = EVEN_AND_ALL;
+        int copies = 1;
+
+        PrintRenderer() {
+            super(null);
+
+            startNumber = getIntProperty("start", 1) - 1;
+            endNumber = getIntProperty("end", -1);
+
+            mode = EVEN_AND_ALL;
+            String str = System.getProperty("even");
+            if (str != null) {
+                try {
+                    mode = Boolean.valueOf(str).booleanValue() ? EVEN : ODD;
+                } catch (Exception e) {
+                }
+            }
+
+        }
+
+
+        static int getIntProperty(String name, int def) {
+            String propValue = System.getProperty(name);
+            if (propValue != null) {
+                try {
+                    return Integer.parseInt(propValue);
+                } catch (Exception e) {
+                    return def;
+                }
+            } else {
+                return def;
+            }
+        }
+
+        public void render(AreaTree areaTree,
+                           OutputStream stream) throws IOException {
+            tree = areaTree;
+            if (endNumber == -1) {
+                endNumber = tree.getPages().size();
+            }
+
+            Vector numbers = getInvalidPageNumbers();
+            for (int i = numbers.size() - 1; i > -1; i--)
+                tree.getPages().removeElementAt(
+                  Integer.parseInt((String) numbers.elementAt(i)));
+
+        }
+
+        public void renderPage(Page page) {
+            pageWidth = (int)((float) page.getWidth() / 1000f);
+            pageHeight = (int)((float) page.getHeight() / 1000f);
+            super.renderPage(page);
+        }
+
+
+        private Vector getInvalidPageNumbers() {
+
+            Vector vec = new Vector();
+            int max = tree.getPages().size();
+            boolean isValid;
+            for (int i = 0; i < max; i++) {
+                isValid = true;
+                if (i < startNumber || i > endNumber) {
+                    isValid = false;
+                } else if (mode != EVEN_AND_ALL) {
+                    if (mode == EVEN && ((i + 1) % 2 != 0))
+                        isValid = false;
+                    else if (mode == ODD && ((i + 1) % 2 != 1))
+                        isValid = false;
+                }
+
+                if (!isValid)
+                    vec.add(i + "");
+            }
+
+            return vec;
+        }
+
+        void setCopies(int val) {
+            copies = val;
+            Vector copie = tree.getPages();
+            for (int i = 1; i < copies; i++) {
+                tree.getPages().addAll(copie);
+            }
+
+        }
+
+    } // class PrintRenderer
+} // class PrintCommandLine
+
+
diff --git a/src/org/apache/fop/apps/Starter.java b/src/org/apache/fop/apps/Starter.java
new file mode 100644 (file)
index 0000000..3456aff
--- /dev/null
@@ -0,0 +1,61 @@
+/* 
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the 
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.apps;
+
+// SAX
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+
+// Java
+import java.io.*;
+import java.net.URL;
+
+// FOP
+import org.apache.fop.messaging.MessageHandler;
+
+
+/**
+ * 
+ * abstract super class 
+ * Creates a SAX Parser (defaulting to Xerces).
+ *
+ */
+public abstract class Starter {
+
+       Options options;
+       InputHandler inputHandler;
+       
+       public Starter() {
+               options = new Options ();               
+       }
+
+       public void setInputHandler(InputHandler inputHandler) {
+               this.inputHandler = inputHandler;
+       }
+
+       abstract public void run();
+
+       // setting the parser features  
+       public void setParserFeatures (XMLReader parser) {
+               setParserFeatures (parser,true);
+       }
+       
+
+    public void setParserFeatures (XMLReader parser,boolean errorDump) {
+        try {
+            parser.setFeature("http://xml.org/sax/features/namespace-prefixes",true);
+        } catch (SAXException e) {
+            MessageHandler.errorln("Error in setting up parser feature namespace-prefixes");
+            MessageHandler.errorln("You need a parser which supports SAX version 2");
+            if (errorDump) {
+                e.printStackTrace();
+            }
+            System.exit(1);
+        }
+    }
+}
diff --git a/src/org/apache/fop/apps/XSLTInputHandler.java b/src/org/apache/fop/apps/XSLTInputHandler.java
new file mode 100644 (file)
index 0000000..7e955e6
--- /dev/null
@@ -0,0 +1,111 @@
+/* 
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the 
+ * LICENSE file included with these sources."
+ */
+
+
+package org.apache.fop.apps;
+
+
+// Imported TraX classes
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
+
+// Imported SAX classes
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.XMLFilter;
+
+
+// Imported java.io classes
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+
+// FOP
+import org.apache.fop.messaging.MessageHandler;
+
+/**
+ * XSLTInputHandler basically takes an xmlfile and transforms it with an xsltfile
+ * and the resulting xsl:fo document is input for Fop.
+ */
+
+public class XSLTInputHandler extends InputHandler {
+
+       File xmlfile, xsltfile;
+
+    public XSLTInputHandler (File xmlfile, File xsltfile ) {
+        this.xmlfile = xmlfile;
+               this.xsltfile = xsltfile;
+    }
+
+    /**
+      *  overwrites the method of the super class to return the xmlfile
+      */
+    public InputSource getInputSource () {
+        return fileInputSource(xmlfile);
+    }
+
+    /**
+      *  overwrites this method of the super class and returns an XMLFilter instead of a
+      *  simple XMLReader which allows chaining of transformations
+      *
+      */
+    public XMLReader getParser() {
+        return this.getXMLFilter(xmlfile,xsltfile);
+    }
+
+    /**
+      * Creates from the transformer an instance of an XMLFilter which
+      * then can be used in a chain with the XMLReader passed to Driver. This way
+      * during the conversion of the xml file + xslt stylesheet the resulting
+      * data is fed into Fop. This should help to avoid memory problems
+      * @param xmlfile The xmlfile containing the text data
+      * @param xsltfile An xslt stylesheet
+      * @return XMLFilter an XMLFilter which can be chained together with other XMLReaders or XMLFilters
+      */
+    private XMLFilter getXMLFilter (File xmlfile, File xsltfile) {
+        try {
+            // Instantiate  a TransformerFactory.
+            TransformerFactory tFactory = TransformerFactory.newInstance();
+            // Determine whether the TransformerFactory supports The use uf SAXSource
+            // and SAXResult
+            if (tFactory.getFeature(SAXSource.FEATURE) &&
+                    tFactory.getFeature(SAXResult.FEATURE)) {
+                // Cast the TransformerFactory to SAXTransformerFactory.
+                SAXTransformerFactory saxTFactory =
+                  ((SAXTransformerFactory) tFactory);
+                // Create an XMLFilter for each stylesheet.
+                XMLFilter xmlfilter = saxTFactory.newXMLFilter(
+                                        new StreamSource(xsltfile));
+
+                // Create an XMLReader.
+                XMLReader parser = super.createParser();
+                if (parser == null) {
+                    MessageHandler.errorln("ERROR: Unable to create SAX parser");
+                    System.exit(1);
+                }
+
+                // xmlFilter1 uses the XMLReader as its reader.
+                xmlfilter.setParent(parser);
+                return xmlfilter;
+            } else {
+                MessageHandler.errorln(
+                  "Your parser doesn't support the features SAXSource and SAXResult." +
+                  "\nMake sure you are using a xsl parser which supports TrAX");
+                System.exit(1);
+                return null;
+            }
+        }
+        catch (Exception ex) {
+            MessageHandler.errorln(ex.toString());
+            return null;
+        }
+    }
+}
+