001    /*
002     * LAPIS lightweight structured text processing system
003     *
004     * Copyright (C) 1998-2002 Carnegie Mellon University,
005     * Copyright (C) 2003 Massachusetts Institute of Technology.
006     * All rights reserved.
007     *
008     * This library is free software; you can redistribute it
009     * and/or modify it under the terms of the GNU General
010     * Public License as published by the Free Software
011     * Foundation, version 2.
012     *
013     * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/
014     */
015    
016    package lapis.tcl;
017    
018    import java.io.*;
019    import java.util.*;
020    import lapisx.util.Str;
021    
022    public abstract class Optimizer {
023        public static lapisx.util.Debug debug = lapisx.util.Debug.QUIET; 
024    
025        /**
026          * Optimize a Tcl script by commenting out any URL command
027          * that is immediately followed by another URL command
028          */
029        public static String optimizeDeadURLs (String script) {
030            StreamTokenizer in = new StreamTokenizer (new StringReader (script));
031            in.resetSyntax ();
032            in.wordChars (Character.MIN_VALUE, Character.MAX_VALUE);
033            in.whitespaceChars ('\r', '\r');
034            in.whitespaceChars ('\n', '\n');
035    
036            StringWriter sout = new StringWriter ();
037            PrintWriter out = new PrintWriter (sout);
038    
039            String last = null;  // last command, including surrounding whitespace
040            boolean lastWasURL = false; // last command was a URL
041    
042            try {
043                while (in.nextToken () != StreamTokenizer.TT_EOF) {
044                    if (in.ttype == StreamTokenizer.TT_WORD) {
045                        String cmd = trim (in.sval);
046    
047                        if (cmd.length () == 0) {
048                            if (last != null)
049                                last = last + in.sval + "\n";
050                            else
051                                last = in.sval + "\n";
052                        } else {
053                            if (isURL (cmd)) {
054                                if (lastWasURL) 
055                                    // comment out last command
056                                    last = "# " + last;
057                                lastWasURL = true;
058                            } else {
059                                lastWasURL = false;
060                            }
061    
062                            // print previous command
063                            if (last != null)
064                                out.print (last);
065                            last = in.sval + "\n";
066                        }
067                    }
068                }
069    
070                if (last != null)
071                    out.print (last);
072    
073                out.close ();
074                return sout.toString ();
075            } catch (IOException e) {
076                debug.report (e);
077                return script;
078            }
079        }
080    
081    
082        /**
083          * Optimize a Tcl script by converting a form submission
084          * (URL, enter, enter, ..., submit) into a webquery command.
085          */
086        public static String optimizeFormSubmits (String script) {
087            StreamTokenizer in = new StreamTokenizer (new StringReader (script));
088            in.resetSyntax ();
089            in.wordChars (Character.MIN_VALUE, Character.MAX_VALUE);
090            in.whitespaceChars ('\r', '\r');
091            in.whitespaceChars ('\n', '\n');
092    
093            StringWriter sout = new StringWriter ();
094            PrintWriter out = new PrintWriter (sout);
095    
096            String formSubmission = null;  
097            // current form submission, or null if not currently
098            // reading a form submission
099    
100            String hrefForm = null;
101            // URL of form
102            Vector params = new Vector ();
103            // parameters of Enter commands: name, value, name, value, ...
104    
105            try {
106                while (in.nextToken () != StreamTokenizer.TT_EOF) {
107                    if (in.ttype == StreamTokenizer.TT_WORD) {
108                        String cmd = trim (in.sval);
109                        String line = in.sval + "\n";
110    
111                        if (formSubmission == null) {
112                            if (isURL (cmd)) {
113                                formSubmission = line;
114                                hrefForm = cmd;
115                                params.removeAllElements ();
116                            }
117                            else
118                                out.print (line);
119                        } else {
120                            if (isURL (cmd)) {
121                                // Jumped to a new URL before form submission 
122                                // was complete. Print out partial form
123                                // submission and reset for new form.
124                                out.print (formSubmission);
125                                formSubmission = line;
126                                hrefForm = cmd;
127                                params.removeAllElements ();
128                            } else if (isCommand (cmd, "enter")) {
129                                if (getEnterParameters (cmd, params)) 
130                                    // Continuing form submission
131                                    formSubmission += in.sval + "\n";
132                                else {
133                                    // Can't handle this form submission
134                                    System.err.println ("Can't handle enter command: " + cmd);
135                                    out.print (formSubmission);
136                                    out.print (line);
137                                    formSubmission = null;
138                                }
139                            } else if (isCommand (cmd, "submit")) {
140                                    out.print (formSubmission);
141                                    out.print (line);
142                                    formSubmission = null;
143                                
144    //                             try {
145    //                                 FormURL formURL = Submit.submit 
146    //                                     (new Arguments ().getFactory ().make (hrefForm),
147                                         
148    
149    //                                     new lapis.tools.Submit ()
150    //                                     .invoke (new Arguments ()
151    //                                              .add ("href", hrefForm));
152                                
153    //                             out.print ("webquery");
154    //                             out.print (" -" + formURL.getMethod ().toLowerCase ());
155    //                             out.print (" " + formURL.getAction ());
156                                
157    //                             Hashtable defaults = formURL.getQueryHash ();
158                                
159    //                             // Print enter'ed params first
160    //                             for (int i = 0, n = params.size (); 
161    //                                  i < n; ++i) {
162    //                                 Object obj = params.elementAt (i);
163    //                                 out.print (" " + obj);
164    //                                 if (i % 2 == 0)
165    //                                     // it's a parameter name; delete it from
166    //                                     // list of defaults
167    //                                     defaults.remove (obj);
168    //                             }
169    
170    //                             // Now print defaults 
171    //                             for (Enumeration e = defaults.keys (); 
172    //                                  e.hasMoreElements (); ) {
173    //                                 Object key = e.nextElement ();
174    //                                 out.print (" " + key + " " + defaults.get(key));
175    //                             }
176    
177    //                             // finish command and return to start state
178    //                             out.println ();
179    //                             formSubmission = null;
180    //                             } catch (Exception e) {
181    //                                 // forget trying to optimize this submission
182    //                                 e.printStackTrace ();
183    //                                 out.print (formSubmission);
184    //                                 formSubmission = null;
185    //                             }
186                            } else {
187                                // Unfinished form submission, can't be optimized
188                                out.print (formSubmission);
189                                formSubmission = null;
190                            }
191                        }
192                    }
193                }
194    
195                if (formSubmission != null)
196                    out.print (formSubmission);
197    
198                out.close ();
199                return sout.toString ();
200            } catch (IOException e) {
201                debug.report (e);
202                return script;
203            }
204        }
205    
206    
207    
208        /**
209          * Deletes trailing comment (#...) and leading and trailing whitespace
210          * from a string.
211          */
212        static String trim (String line) {
213            int comment = line.lastIndexOf ('#');
214            if (comment >= 0)
215                line = line.substring (0, comment);
216            return line.trim ();
217        }
218    
219        /**
220          * Tests whether command is a URL.
221          */
222        static boolean isURL (String cmd) {
223            return cmd.startsWith ("http:")
224                || cmd.startsWith ("ftp:")
225                || cmd.startsWith ("file:")
226                || cmd.startsWith ("systemresource:");
227        }
228    
229        static boolean isCommand (String cmd, String cmdName) {
230            return cmd.startsWith (cmdName)
231                && (cmd.length() == cmdName.length() 
232                    || Character.isWhitespace (cmd.charAt (cmdName.length())));
233        }
234    
235        static boolean getEnterParameters (String cmd, Vector params) {
236            String args = Str.after (cmd, " ").trim ();
237    
238            String fieldArg = Str.before (args, " ").trim ();
239            if (!fieldArg.toLowerCase ().startsWith ("Field.") 
240                || fieldArg.indexOf (" ") != -1)
241                // this enter command uses a pattern more complicated than
242                // Field.foo -- we can't handle it
243                return false;
244            String fieldName = fieldArg.substring (6);
245            
246            String valueArg = Str.after (args, " ").trim ();
247    
248            params.addElement (fieldName);
249            params.addElement (valueArg);
250            return true;
251        }
252    
253    }
254