1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - Calixte DENIZET
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15 
16 package org.scilab.modules.helptools.scilab;
17 
18 import java.io.BufferedReader;
19 import java.io.InputStreamReader;
20 import java.io.IOException;
21 import java.io.Reader;
22 import java.io.OutputStreamWriter;
23 import java.io.Writer;
24 import java.net.Socket;
25 import java.net.ServerSocket;
26 import java.nio.charset.Charset;
27 import java.util.HashMap;
28 import java.util.Map;
29 import java.util.Stack;
30 
31 /**
32  * Server to colorize Scilab code.
33  * The string passed to the server must be terminated with an EOF or a null char "\0".
34  */
35 public final class ScilabCodeServer {
36 
37     private static final int DEFAULTMAXHANDLERS = 5;
38 
39     private Stack<HTMLWithStyleScilabCodeHandler> stack = new Stack<HTMLWithStyleScilabCodeHandler>();
40     private String prim;
41     private String macro;
42     private int maxHandler;
43 
44     /**
45      * Main method
46      * @param args the command line arguments
47      */
main(String[] args)48     public static void main(String[] args) {
49         Map<String, String> map = parseCommandLine(args);
50         if (map.containsKey("help")) {
51             System.out.println("Usage scicodeserver [OPTION]...");
52             System.out.println("Create a multi-thread server to colorize Scilab code");
53             System.out.println("");
54             System.out.println("-port          An integer giving the port where to listen to");
55             System.out.println("-sciprim       A file containing the list of the Scilab primitives");
56             System.out.println("-scimacro      A file containing the list of the Scilab macros");
57             System.out.println("-maxhandlers   An integer giving the maximum of Scilab code handlers");
58             System.out.println("               which must be kept in memory (5 by default)");
59             System.out.println("");
60             System.out.println("Report bugs on: <http://bugzilla.scilab.org>");
61             System.out.println("Project page: <http://forge.scilab.org/index.php/p/scidoc>");
62             return;
63         }
64 
65         if (!map.containsKey("port")) {
66             System.err.println("No port");
67             System.err.println("Use the option -help");
68             return;
69         }
70 
71         int max = DEFAULTMAXHANDLERS;
72         if (map.containsKey("maxhandlers")) {
73             try {
74                 max = Integer.parseInt(map.get("maxhandlers"));
75             } catch (Exception e) {
76                 System.err.println("The option -maxhandlers expects a positive integer");
77                 return;
78             }
79         }
80 
81         int port = 0;
82         if (map.containsKey("port")) {
83             try {
84                 port = Integer.parseInt(map.get("port"));
85             } catch (Exception e) {
86                 System.err.println("The option -port expects a positive integer");
87                 return;
88             }
89         }
90 
91         ScilabCodeServer scs = new ScilabCodeServer(map.get("sciprim"), map.get("scimacro"), max);
92         try {
93             ServerSocket server = new ServerSocket(port);
94             while (true) {
95                 new ScilabCodeThread(server.accept(), scs);
96             }
97         } catch (IOException e) {
98             e.printStackTrace();
99         }
100     }
101 
102     /**
103      * Private constructor
104      * @param primFile the filename containing the list of the scilab built-in commands
105      * @param macroFile the filename containing the list of the scilab macros
106      * @param maxHandler the maximum handlers which must be cached
107      */
ScilabCodeServer(String primFile, String macroFile, int maxHandler)108     private ScilabCodeServer(String primFile, String macroFile, int maxHandler) {
109         this.prim = primFile;
110         this.macro = macroFile;
111         this.maxHandler = maxHandler;
112     }
113 
114     /**
115      * Get an handler. The stack is synchronized.
116      * @return an handler
117      */
getHandler()118     private HTMLWithStyleScilabCodeHandler getHandler() {
119         synchronized (stack) {
120             if (stack.isEmpty()) {
121                 return new HTMLWithStyleScilabCodeHandler(prim, macro);
122             }
123             return stack.pop();
124         }
125     }
126 
127     /**
128      * Push an handler in the stack to cach it. The stack is synchronized.
129      * @param h the handler
130      */
pushHandler(HTMLWithStyleScilabCodeHandler h)131     private void pushHandler(HTMLWithStyleScilabCodeHandler h) {
132         synchronized (stack) {
133             if (stack.size() < maxHandler) {
134                 stack.push(h);
135             }
136         }
137     }
138 
139     /**
140      * @param in the input
141      * @param out the output
142      * @throws IOException
143      */
convert(Reader in, Writer out)144     private void convert(Reader in, Writer out) throws IOException {
145         HTMLWithStyleScilabCodeHandler handler = getHandler();
146         handler.convert(in, out);
147         pushHandler(handler);
148     }
149 
150     /**
151      * Parse the command line
152      * @param args the arguments
153      * @return the options with their argument in a map
154      */
parseCommandLine(String[] args)155     private static Map<String, String> parseCommandLine(String[] args) {
156         String option = null;
157         boolean in = false;
158         Map<String, String> map = new HashMap<String, String>();
159         for (int i = 0; i < args.length; i++) {
160             if (args[i].length() >= 2 && args[i].charAt(0) == '-') {
161                 if (option != null) {
162                     map.put(option, "");
163                 }
164                 if (args[i].charAt(1) == '-') {
165                     option = args[i].substring(2);
166                 } else {
167                     option = args[i].substring(1);
168                 }
169             } else {
170                 if (option != null) {
171                     map.put(option, args[i]);
172                     option = null;
173                 } else if (!in) {
174                     map.put("input", args[i]);
175                     in = true;
176                 } else {
177                     System.err.println("Not an argument " + args[i]);
178                     return null;
179                 }
180             }
181         }
182         if (option != null) {
183             map.put(option, "");
184         }
185 
186         return map;
187     }
188 
189     /**
190      * Inner class
191      */
192     private static class ScilabCodeThread implements Runnable {
193 
194         private Reader in;
195         private Writer out;
196         private Socket sock;
197         private ScilabCodeServer scs;
198 
199         /**
200          * Default constructor
201          * @param sock the socket where to read and write
202          * @param scs the server
203          */
ScilabCodeThread(Socket sock, ScilabCodeServer scs)204         ScilabCodeThread(Socket sock, ScilabCodeServer scs) {
205             this.sock = sock;
206             this.scs = scs;
207             try {
208                 in = new BufferedReader(new InputStreamReader(sock.getInputStream(), Charset.forName("UTF-8")));
209                 out = new OutputStreamWriter(sock.getOutputStream(), Charset.forName("UTF-8"));
210             } catch (IOException e) {
211                 e.printStackTrace();
212             }
213             new Thread(this).start();
214         }
215 
run()216         public void run() {
217             try {
218                 scs.convert(in, out);
219                 out.flush();
220                 out.close();
221                 in.close();
222                 sock.close();
223             } catch (IOException e) {
224                 e.printStackTrace();
225             }
226         }
227     }
228 }
229