xref: /aosp_15_r20/external/libpcap/testprogs/visopts.py (revision 8b26181f966a6af5cf6981a6f474313de533bb28)
1*8b26181fSAndroid Build Coastguard Worker#!/usr/bin/env python
2*8b26181fSAndroid Build Coastguard Worker
3*8b26181fSAndroid Build Coastguard Worker"""
4*8b26181fSAndroid Build Coastguard WorkerThis program parses the output from pcap_compile() to visualize the CFG after
5*8b26181fSAndroid Build Coastguard Workereach optimize phase.
6*8b26181fSAndroid Build Coastguard Worker
7*8b26181fSAndroid Build Coastguard WorkerUsage guide:
8*8b26181fSAndroid Build Coastguard Worker1. Enable optimizer debugging code when configure libpcap,
9*8b26181fSAndroid Build Coastguard Worker   and build libpcap & the test programs
10*8b26181fSAndroid Build Coastguard Worker       ./configure --enable-optimizer-dbg
11*8b26181fSAndroid Build Coastguard Worker       make
12*8b26181fSAndroid Build Coastguard Worker       make testprogs
13*8b26181fSAndroid Build Coastguard Worker2. Run filtertest to compile BPF expression and produce the CFG as a
14*8b26181fSAndroid Build Coastguard Worker   DOT graph, save to output a.txt
15*8b26181fSAndroid Build Coastguard Worker       testprogs/filtertest -g EN10MB host 192.168.1.1 > a.txt
16*8b26181fSAndroid Build Coastguard Worker3. Send a.txt to this program's standard input
17*8b26181fSAndroid Build Coastguard Worker       cat a.txt | testprogs/visopts.py
18*8b26181fSAndroid Build Coastguard Worker   (Graphviz must be installed)
19*8b26181fSAndroid Build Coastguard Worker4. Step 2&3 can be merged:
20*8b26181fSAndroid Build Coastguard Worker       testprogs/filtertest -g EN10MB host 192.168.1.1 | testprogs/visopts.py
21*8b26181fSAndroid Build Coastguard Worker5. The standard output is something like this:
22*8b26181fSAndroid Build Coastguard Worker       generated files under directory: /tmp/visopts-W9ekBw
23*8b26181fSAndroid Build Coastguard Worker         the directory will be removed when this programs finished.
24*8b26181fSAndroid Build Coastguard Worker       open this link: http://localhost:39062/expr1.html
25*8b26181fSAndroid Build Coastguard Worker6. Open the URL at the 3rd line in a browser.
26*8b26181fSAndroid Build Coastguard Worker
27*8b26181fSAndroid Build Coastguard WorkerNote:
28*8b26181fSAndroid Build Coastguard Worker1. The CFG is translated to SVG images, expr1.html embeds them as external
29*8b26181fSAndroid Build Coastguard Worker   documents. If you open expr1.html as local file using file:// protocol, some
30*8b26181fSAndroid Build Coastguard Worker   browsers will deny such requests so the web page will not work properly.
31*8b26181fSAndroid Build Coastguard Worker   For Chrome, you can run it using the following command to avoid this:
32*8b26181fSAndroid Build Coastguard Worker       chromium --disable-web-security
33*8b26181fSAndroid Build Coastguard Worker   That's why this program starts a localhost HTTP server.
34*8b26181fSAndroid Build Coastguard Worker2. expr1.html uses jQuery from https://ajax.googleapis.com, so it needs Internet
35*8b26181fSAndroid Build Coastguard Worker   access to work.
36*8b26181fSAndroid Build Coastguard Worker"""
37*8b26181fSAndroid Build Coastguard Worker
38*8b26181fSAndroid Build Coastguard Workerimport sys, os
39*8b26181fSAndroid Build Coastguard Workerimport string
40*8b26181fSAndroid Build Coastguard Workerimport subprocess
41*8b26181fSAndroid Build Coastguard Workerimport json
42*8b26181fSAndroid Build Coastguard Worker
43*8b26181fSAndroid Build Coastguard Workerhtml_template = string.Template("""
44*8b26181fSAndroid Build Coastguard Worker<html>
45*8b26181fSAndroid Build Coastguard Worker  <head>
46*8b26181fSAndroid Build Coastguard Worker    <title>BPF compiler optimization phases for $expr </title>
47*8b26181fSAndroid Build Coastguard Worker    <style type="text/css">
48*8b26181fSAndroid Build Coastguard Worker      .hc {
49*8b26181fSAndroid Build Coastguard Worker         /* half width container */
50*8b26181fSAndroid Build Coastguard Worker         display: inline-block;
51*8b26181fSAndroid Build Coastguard Worker         float: left;
52*8b26181fSAndroid Build Coastguard Worker         width: 50%;
53*8b26181fSAndroid Build Coastguard Worker      }
54*8b26181fSAndroid Build Coastguard Worker    </style>
55*8b26181fSAndroid Build Coastguard Worker
56*8b26181fSAndroid Build Coastguard Worker    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"/></script>
57*8b26181fSAndroid Build Coastguard Worker    <!--script type="text/javascript" src="./jquery.min.js"/></script-->
58*8b26181fSAndroid Build Coastguard Worker    <script type="text/javascript">
59*8b26181fSAndroid Build Coastguard Worker      var expr = '$expr';
60*8b26181fSAndroid Build Coastguard Worker      var exprid = 1;
61*8b26181fSAndroid Build Coastguard Worker      var gcount = $gcount;
62*8b26181fSAndroid Build Coastguard Worker      var logs = JSON.parse('$logs');
63*8b26181fSAndroid Build Coastguard Worker      logs[gcount] = "";
64*8b26181fSAndroid Build Coastguard Worker
65*8b26181fSAndroid Build Coastguard Worker      var leftsvg = null;
66*8b26181fSAndroid Build Coastguard Worker      var rightsvg = null;
67*8b26181fSAndroid Build Coastguard Worker
68*8b26181fSAndroid Build Coastguard Worker      function gurl(index) {
69*8b26181fSAndroid Build Coastguard Worker         index += 1;
70*8b26181fSAndroid Build Coastguard Worker         if (index < 10)
71*8b26181fSAndroid Build Coastguard Worker           s = "00" + index;
72*8b26181fSAndroid Build Coastguard Worker         else if (index < 100)
73*8b26181fSAndroid Build Coastguard Worker           s = "0" + index;
74*8b26181fSAndroid Build Coastguard Worker         else
75*8b26181fSAndroid Build Coastguard Worker           s = "" + index;
76*8b26181fSAndroid Build Coastguard Worker         return "./expr" + exprid + "_g" + s + ".svg"
77*8b26181fSAndroid Build Coastguard Worker      }
78*8b26181fSAndroid Build Coastguard Worker
79*8b26181fSAndroid Build Coastguard Worker      function annotate_svgs() {
80*8b26181fSAndroid Build Coastguard Worker         if (!leftsvg || !rightsvg) return;
81*8b26181fSAndroid Build Coastguard Worker
82*8b26181fSAndroid Build Coastguard Worker         $$.each([$$(leftsvg), $$(rightsvg)], function() {
83*8b26181fSAndroid Build Coastguard Worker           $$(this).find("[id|='block'][opacity]").each(function() {
84*8b26181fSAndroid Build Coastguard Worker             $$(this).removeAttr('opacity');
85*8b26181fSAndroid Build Coastguard Worker            });
86*8b26181fSAndroid Build Coastguard Worker          });
87*8b26181fSAndroid Build Coastguard Worker
88*8b26181fSAndroid Build Coastguard Worker         $$(leftsvg).find("[id|='block']").each(function() {
89*8b26181fSAndroid Build Coastguard Worker           var has = $$(rightsvg).find("#" + this.id).length != 0;
90*8b26181fSAndroid Build Coastguard Worker           if (!has) $$(this).attr("opacity", "0.4");
91*8b26181fSAndroid Build Coastguard Worker           else {
92*8b26181fSAndroid Build Coastguard Worker             $$(this).click(function() {
93*8b26181fSAndroid Build Coastguard Worker                var target = $$(rightsvg).find("#" + this.id);
94*8b26181fSAndroid Build Coastguard Worker                var offset = $$("#rightsvgc").offset().top + target.position().top;
95*8b26181fSAndroid Build Coastguard Worker                window.scrollTo(0, offset);
96*8b26181fSAndroid Build Coastguard Worker                target.focus();
97*8b26181fSAndroid Build Coastguard Worker             });
98*8b26181fSAndroid Build Coastguard Worker           }
99*8b26181fSAndroid Build Coastguard Worker          });
100*8b26181fSAndroid Build Coastguard Worker         $$(rightsvg).find("[id|='block']").each(function() {
101*8b26181fSAndroid Build Coastguard Worker           var has = $$(leftsvg).find("#" + this.id).length != 0;
102*8b26181fSAndroid Build Coastguard Worker           if (!has) $$(this).attr("opacity", "0.4");
103*8b26181fSAndroid Build Coastguard Worker           else {
104*8b26181fSAndroid Build Coastguard Worker             $$(this).click(function() {
105*8b26181fSAndroid Build Coastguard Worker                var target = $$(leftsvg).find("#" + this.id);
106*8b26181fSAndroid Build Coastguard Worker                var offset = $$("#leftsvgc").offset().top + target.position().top;
107*8b26181fSAndroid Build Coastguard Worker                window.scrollTo(0, offset);
108*8b26181fSAndroid Build Coastguard Worker                target.focus();
109*8b26181fSAndroid Build Coastguard Worker             });
110*8b26181fSAndroid Build Coastguard Worker           }
111*8b26181fSAndroid Build Coastguard Worker          });
112*8b26181fSAndroid Build Coastguard Worker      }
113*8b26181fSAndroid Build Coastguard Worker
114*8b26181fSAndroid Build Coastguard Worker      function init_svgroot(svg) {
115*8b26181fSAndroid Build Coastguard Worker         svg.setAttribute("width", "100%");
116*8b26181fSAndroid Build Coastguard Worker         svg.setAttribute("height", "100%");
117*8b26181fSAndroid Build Coastguard Worker      }
118*8b26181fSAndroid Build Coastguard Worker      function wait_leftsvg() {
119*8b26181fSAndroid Build Coastguard Worker         if (leftsvg) return;
120*8b26181fSAndroid Build Coastguard Worker         var doc = document.getElementById("leftsvgc").getSVGDocument();
121*8b26181fSAndroid Build Coastguard Worker         if (doc == null) {
122*8b26181fSAndroid Build Coastguard Worker            setTimeout(wait_leftsvg, 500);
123*8b26181fSAndroid Build Coastguard Worker            return;
124*8b26181fSAndroid Build Coastguard Worker         }
125*8b26181fSAndroid Build Coastguard Worker         leftsvg = doc.documentElement;
126*8b26181fSAndroid Build Coastguard Worker         //console.log(leftsvg);
127*8b26181fSAndroid Build Coastguard Worker         // initialize it
128*8b26181fSAndroid Build Coastguard Worker         init_svgroot(leftsvg);
129*8b26181fSAndroid Build Coastguard Worker         annotate_svgs();
130*8b26181fSAndroid Build Coastguard Worker      }
131*8b26181fSAndroid Build Coastguard Worker      function wait_rightsvg() {
132*8b26181fSAndroid Build Coastguard Worker         if (rightsvg) return;
133*8b26181fSAndroid Build Coastguard Worker         var doc = document.getElementById("rightsvgc").getSVGDocument();
134*8b26181fSAndroid Build Coastguard Worker         if (doc == null) {
135*8b26181fSAndroid Build Coastguard Worker            setTimeout(wait_rightsvg, 500);
136*8b26181fSAndroid Build Coastguard Worker            return;
137*8b26181fSAndroid Build Coastguard Worker         }
138*8b26181fSAndroid Build Coastguard Worker         rightsvg = doc.documentElement;
139*8b26181fSAndroid Build Coastguard Worker         //console.log(rightsvg);
140*8b26181fSAndroid Build Coastguard Worker         // initialize it
141*8b26181fSAndroid Build Coastguard Worker         init_svgroot(rightsvg);
142*8b26181fSAndroid Build Coastguard Worker         annotate_svgs();
143*8b26181fSAndroid Build Coastguard Worker      }
144*8b26181fSAndroid Build Coastguard Worker      function load_left(index) {
145*8b26181fSAndroid Build Coastguard Worker        var url = gurl(index);
146*8b26181fSAndroid Build Coastguard Worker        var frag = "<embed id='leftsvgc'  type='image/svg+xml' pluginspage='https://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
147*8b26181fSAndroid Build Coastguard Worker        $$("#lsvg").html(frag);
148*8b26181fSAndroid Build Coastguard Worker        $$("#lcomment").html(logs[index]);
149*8b26181fSAndroid Build Coastguard Worker        $$("#lsvglink").attr("href", url);
150*8b26181fSAndroid Build Coastguard Worker        leftsvg = null;
151*8b26181fSAndroid Build Coastguard Worker        wait_leftsvg();
152*8b26181fSAndroid Build Coastguard Worker      }
153*8b26181fSAndroid Build Coastguard Worker      function load_right(index) {
154*8b26181fSAndroid Build Coastguard Worker        var url = gurl(index);
155*8b26181fSAndroid Build Coastguard Worker        var frag = "<embed id='rightsvgc' type='image/svg+xml' pluginspage='https://www.adobe.com/svg/viewer/install/' src='" + url + "'/>";
156*8b26181fSAndroid Build Coastguard Worker        $$("#rsvg").html(frag);
157*8b26181fSAndroid Build Coastguard Worker        $$("#rcomment").html(logs[index]);
158*8b26181fSAndroid Build Coastguard Worker        $$("#rsvglink").attr("href", url);
159*8b26181fSAndroid Build Coastguard Worker        rightsvg = null;
160*8b26181fSAndroid Build Coastguard Worker        wait_rightsvg();
161*8b26181fSAndroid Build Coastguard Worker      }
162*8b26181fSAndroid Build Coastguard Worker
163*8b26181fSAndroid Build Coastguard Worker      $$(document).ready(function() {
164*8b26181fSAndroid Build Coastguard Worker        for (var i = 0; i < gcount; i++) {
165*8b26181fSAndroid Build Coastguard Worker          var opt = "<option value='" + i + "'>loop" + i + " -- " + logs[i] + "</option>";
166*8b26181fSAndroid Build Coastguard Worker          $$("#lselect").append(opt);
167*8b26181fSAndroid Build Coastguard Worker          $$("#rselect").append(opt);
168*8b26181fSAndroid Build Coastguard Worker        }
169*8b26181fSAndroid Build Coastguard Worker        var on_selected = function() {
170*8b26181fSAndroid Build Coastguard Worker          var index = parseInt($$(this).children("option:selected").val());
171*8b26181fSAndroid Build Coastguard Worker          if (this.id == "lselect")
172*8b26181fSAndroid Build Coastguard Worker             load_left(index);
173*8b26181fSAndroid Build Coastguard Worker          else
174*8b26181fSAndroid Build Coastguard Worker             load_right(index);
175*8b26181fSAndroid Build Coastguard Worker        }
176*8b26181fSAndroid Build Coastguard Worker        $$("#lselect").change(on_selected);
177*8b26181fSAndroid Build Coastguard Worker        $$("#rselect").change(on_selected);
178*8b26181fSAndroid Build Coastguard Worker
179*8b26181fSAndroid Build Coastguard Worker        $$("#backward").click(function() {
180*8b26181fSAndroid Build Coastguard Worker          var index = parseInt($$("#lselect option:selected").val());
181*8b26181fSAndroid Build Coastguard Worker          if (index <= 0) return;
182*8b26181fSAndroid Build Coastguard Worker          $$("#lselect").val(index - 1).change();
183*8b26181fSAndroid Build Coastguard Worker          $$("#rselect").val(index).change();
184*8b26181fSAndroid Build Coastguard Worker        });
185*8b26181fSAndroid Build Coastguard Worker        $$("#forward").click(function() {
186*8b26181fSAndroid Build Coastguard Worker          var index = parseInt($$("#rselect option:selected").val());
187*8b26181fSAndroid Build Coastguard Worker          if (index >= gcount - 1) return;
188*8b26181fSAndroid Build Coastguard Worker          $$("#lselect").val(index).change();
189*8b26181fSAndroid Build Coastguard Worker          $$("#rselect").val(index + 1).change();
190*8b26181fSAndroid Build Coastguard Worker        });
191*8b26181fSAndroid Build Coastguard Worker
192*8b26181fSAndroid Build Coastguard Worker        if (gcount >= 1) $$("#lselect").val(0).change();
193*8b26181fSAndroid Build Coastguard Worker        if (gcount >= 2) $$("#rselect").val(1).change();
194*8b26181fSAndroid Build Coastguard Worker      });
195*8b26181fSAndroid Build Coastguard Worker    </script>
196*8b26181fSAndroid Build Coastguard Worker  </head>
197*8b26181fSAndroid Build Coastguard Worker  <body style="width: 96%">
198*8b26181fSAndroid Build Coastguard Worker    <div>
199*8b26181fSAndroid Build Coastguard Worker      <h1>$expr</h1>
200*8b26181fSAndroid Build Coastguard Worker      <div style="text-align: center;">
201*8b26181fSAndroid Build Coastguard Worker        <button id="backward" type="button">&lt;&lt;</button>
202*8b26181fSAndroid Build Coastguard Worker          &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
203*8b26181fSAndroid Build Coastguard Worker        <button id="forward" type="button">&gt;&gt;</button>
204*8b26181fSAndroid Build Coastguard Worker      </div>
205*8b26181fSAndroid Build Coastguard Worker    </div>
206*8b26181fSAndroid Build Coastguard Worker    <br/>
207*8b26181fSAndroid Build Coastguard Worker    <div style="clear: both;">
208*8b26181fSAndroid Build Coastguard Worker       <div class="hc lc">
209*8b26181fSAndroid Build Coastguard Worker        <select id="lselect"></select>
210*8b26181fSAndroid Build Coastguard Worker        <a id="lsvglink" target="_blank">open this svg in browser</a>
211*8b26181fSAndroid Build Coastguard Worker        <p id="lcomment"></p>
212*8b26181fSAndroid Build Coastguard Worker       </div>
213*8b26181fSAndroid Build Coastguard Worker       <div class="hc rc">
214*8b26181fSAndroid Build Coastguard Worker        <select id="rselect"></select>
215*8b26181fSAndroid Build Coastguard Worker        <a id="rsvglink" target="_blank">open this svg in browser</a>
216*8b26181fSAndroid Build Coastguard Worker        <p id="rcomment"></p>
217*8b26181fSAndroid Build Coastguard Worker       </div>
218*8b26181fSAndroid Build Coastguard Worker    </div>
219*8b26181fSAndroid Build Coastguard Worker    <br/>
220*8b26181fSAndroid Build Coastguard Worker    <div style="clear: both;">
221*8b26181fSAndroid Build Coastguard Worker       <div id="lsvg"  class="hc lc"></div>
222*8b26181fSAndroid Build Coastguard Worker       <div id="rsvg" class="hc rc"></div>
223*8b26181fSAndroid Build Coastguard Worker    </div>
224*8b26181fSAndroid Build Coastguard Worker  </body>
225*8b26181fSAndroid Build Coastguard Worker</html>
226*8b26181fSAndroid Build Coastguard Worker""")
227*8b26181fSAndroid Build Coastguard Worker
228*8b26181fSAndroid Build Coastguard Workerdef write_html(expr, gcount, logs):
229*8b26181fSAndroid Build Coastguard Worker    logs = map(lambda s: s.strip().replace("\n", "<br/>"), logs)
230*8b26181fSAndroid Build Coastguard Worker
231*8b26181fSAndroid Build Coastguard Worker    global html_template
232*8b26181fSAndroid Build Coastguard Worker    html = html_template.safe_substitute(expr=expr.encode("string-escape"), gcount=gcount, logs=json.dumps(logs).encode("string-escape"))
233*8b26181fSAndroid Build Coastguard Worker    with file("expr1.html", "wt") as f:
234*8b26181fSAndroid Build Coastguard Worker        f.write(html)
235*8b26181fSAndroid Build Coastguard Worker
236*8b26181fSAndroid Build Coastguard Workerdef render_on_html(infile):
237*8b26181fSAndroid Build Coastguard Worker    expr = None
238*8b26181fSAndroid Build Coastguard Worker    gid = 1
239*8b26181fSAndroid Build Coastguard Worker    log = ""
240*8b26181fSAndroid Build Coastguard Worker    dot = ""
241*8b26181fSAndroid Build Coastguard Worker    indot = 0
242*8b26181fSAndroid Build Coastguard Worker    logs = []
243*8b26181fSAndroid Build Coastguard Worker
244*8b26181fSAndroid Build Coastguard Worker    for line in infile:
245*8b26181fSAndroid Build Coastguard Worker        if line.startswith("machine codes for filter:"):
246*8b26181fSAndroid Build Coastguard Worker            expr = line[len("machine codes for filter:"):].strip()
247*8b26181fSAndroid Build Coastguard Worker            break
248*8b26181fSAndroid Build Coastguard Worker        elif line.startswith("digraph BPF {"):
249*8b26181fSAndroid Build Coastguard Worker            indot = 1
250*8b26181fSAndroid Build Coastguard Worker            dot = line
251*8b26181fSAndroid Build Coastguard Worker        elif indot:
252*8b26181fSAndroid Build Coastguard Worker            dot += line
253*8b26181fSAndroid Build Coastguard Worker            if line.startswith("}"):
254*8b26181fSAndroid Build Coastguard Worker                indot = 2
255*8b26181fSAndroid Build Coastguard Worker        else:
256*8b26181fSAndroid Build Coastguard Worker            log += line
257*8b26181fSAndroid Build Coastguard Worker
258*8b26181fSAndroid Build Coastguard Worker        if indot == 2:
259*8b26181fSAndroid Build Coastguard Worker            try:
260*8b26181fSAndroid Build Coastguard Worker                p = subprocess.Popen(['dot', '-Tsvg'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
261*8b26181fSAndroid Build Coastguard Worker            except OSError as ose:
262*8b26181fSAndroid Build Coastguard Worker                print "Failed to run 'dot':", ose
263*8b26181fSAndroid Build Coastguard Worker                print "(Is Graphviz installed?)"
264*8b26181fSAndroid Build Coastguard Worker                exit(1)
265*8b26181fSAndroid Build Coastguard Worker
266*8b26181fSAndroid Build Coastguard Worker            svg = p.communicate(dot)[0]
267*8b26181fSAndroid Build Coastguard Worker            with file("expr1_g%03d.svg" % (gid), "wt") as f:
268*8b26181fSAndroid Build Coastguard Worker                f.write(svg)
269*8b26181fSAndroid Build Coastguard Worker
270*8b26181fSAndroid Build Coastguard Worker            logs.append(log)
271*8b26181fSAndroid Build Coastguard Worker            gid += 1
272*8b26181fSAndroid Build Coastguard Worker            log = ""
273*8b26181fSAndroid Build Coastguard Worker            dot = ""
274*8b26181fSAndroid Build Coastguard Worker            indot = 0
275*8b26181fSAndroid Build Coastguard Worker
276*8b26181fSAndroid Build Coastguard Worker    if indot != 0:
277*8b26181fSAndroid Build Coastguard Worker        #unterminated dot graph for expression
278*8b26181fSAndroid Build Coastguard Worker        return False
279*8b26181fSAndroid Build Coastguard Worker    if expr is None:
280*8b26181fSAndroid Build Coastguard Worker        # BPF parser encounter error(s)
281*8b26181fSAndroid Build Coastguard Worker        return False
282*8b26181fSAndroid Build Coastguard Worker    write_html(expr, gid - 1, logs)
283*8b26181fSAndroid Build Coastguard Worker    return True
284*8b26181fSAndroid Build Coastguard Worker
285*8b26181fSAndroid Build Coastguard Workerdef run_httpd():
286*8b26181fSAndroid Build Coastguard Worker    import SimpleHTTPServer
287*8b26181fSAndroid Build Coastguard Worker    import SocketServer
288*8b26181fSAndroid Build Coastguard Worker
289*8b26181fSAndroid Build Coastguard Worker    class MySocketServer(SocketServer.TCPServer):
290*8b26181fSAndroid Build Coastguard Worker        allow_reuse_address = True
291*8b26181fSAndroid Build Coastguard Worker    Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
292*8b26181fSAndroid Build Coastguard Worker    httpd = MySocketServer(("localhost", 0), Handler)
293*8b26181fSAndroid Build Coastguard Worker    print "open this link: http://localhost:%d/expr1.html" % (httpd.server_address[1])
294*8b26181fSAndroid Build Coastguard Worker    try:
295*8b26181fSAndroid Build Coastguard Worker        httpd.serve_forever()
296*8b26181fSAndroid Build Coastguard Worker    except KeyboardInterrupt as e:
297*8b26181fSAndroid Build Coastguard Worker        pass
298*8b26181fSAndroid Build Coastguard Worker
299*8b26181fSAndroid Build Coastguard Workerdef main():
300*8b26181fSAndroid Build Coastguard Worker    import tempfile
301*8b26181fSAndroid Build Coastguard Worker    import atexit
302*8b26181fSAndroid Build Coastguard Worker    import shutil
303*8b26181fSAndroid Build Coastguard Worker    os.chdir(tempfile.mkdtemp(prefix="visopts-"))
304*8b26181fSAndroid Build Coastguard Worker    atexit.register(shutil.rmtree, os.getcwd())
305*8b26181fSAndroid Build Coastguard Worker    print "generated files under directory: %s" % os.getcwd()
306*8b26181fSAndroid Build Coastguard Worker    print "  the directory will be removed when this program has finished."
307*8b26181fSAndroid Build Coastguard Worker
308*8b26181fSAndroid Build Coastguard Worker    if not render_on_html(sys.stdin):
309*8b26181fSAndroid Build Coastguard Worker        return 1
310*8b26181fSAndroid Build Coastguard Worker    run_httpd()
311*8b26181fSAndroid Build Coastguard Worker    return 0
312*8b26181fSAndroid Build Coastguard Worker
313*8b26181fSAndroid Build Coastguard Workerif __name__ == "__main__":
314*8b26181fSAndroid Build Coastguard Worker    if '-h' in sys.argv or '--help' in sys.argv:
315*8b26181fSAndroid Build Coastguard Worker        print __doc__
316*8b26181fSAndroid Build Coastguard Worker        exit(0)
317*8b26181fSAndroid Build Coastguard Worker    exit(main())
318