blob: c3d9c7d3fc6a19a5a192a685a804934e6ca79191 [file] [log] [blame]
Guido van Rossumadb3a9d1997-05-21 07:24:50 +00001#! /depot/sundry/plat/bin/python1.4
2
Guido van Rossumd7bfa801997-05-21 21:31:39 +00003"""Interactive FAQ project.
4
5XXX TO DO
6
Guido van Rossum74427e51997-05-21 23:43:39 +00007- generic error handler
8- should have files containing section headers
Guido van Rossumf701bf11997-05-21 22:25:56 +00009- customize rcs command pathnames
10- recognize urls and email addresses and turn them into <A> tags
Guido van Rossumd7bfa801997-05-21 21:31:39 +000011- use cookies to keep Name/email the same
12- explanation of editing somewhere
13- various embellishments, GIFs, crosslinks, hints, etc.
14- create new sections
15- rearrange entries
16- delete entries
Guido van Rossumd7bfa801997-05-21 21:31:39 +000017- send email on changes
18- optional staging of entries until reviewed?
Guido van Rossumd7bfa801997-05-21 21:31:39 +000019- freeze entries
20- username/password for editors
21- Change references to other Q's and whole sections
22- Browse should display menu of 7 sections & let you pick
23 (or frontpage should have the option to browse a section or all)
24- support adding annotations, too
25
26"""
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000027
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000028NAMEPAT = "faq??.???.htp"
Guido van Rossumd7bfa801997-05-21 21:31:39 +000029NAMEREG = "^faq\([0-9][0-9]\)\.\([0-9][0-9][0-9]\)\.htp$"
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000030
31class FAQServer:
32
33 def __init__(self):
34 pass
35
36 def main(self):
37 self.form = cgi.FieldStorage()
38 req = self.req or 'frontpage'
39 try:
40 method = getattr(self, 'do_%s' % req)
41 except AttributeError:
42 print "Unrecognized request type", req
43 else:
44 method()
Guido van Rossum74427e51997-05-21 23:43:39 +000045 self.epilogue()
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000046
Guido van Rossum3c3354c1997-05-21 16:52:18 +000047 KEYS = ['req', 'query', 'name', 'text', 'commit', 'title',
Guido van Rossum74427e51997-05-21 23:43:39 +000048 'author', 'email', 'log', 'section', 'number', 'add',
49 'version']
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000050
51 def __getattr__(self, key):
52 if key not in self.KEYS:
53 raise AttributeError
Guido van Rossum3c3354c1997-05-21 16:52:18 +000054 try:
Guido van Rossumf701bf11997-05-21 22:25:56 +000055 value = self.form[key].value
56 setattr(self, key, value)
57 return value
Guido van Rossum3c3354c1997-05-21 16:52:18 +000058 except KeyError:
59 return ''
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000060
61 def do_frontpage(self):
Guido van Rossum74427e51997-05-21 23:43:39 +000062 self.prologue("Python FAQ (alpha) Front Page")
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000063 print """
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000064 <UL>
Guido van Rossumd7bfa801997-05-21 21:31:39 +000065 <LI><A HREF="faq.py?req=index">FAQ index</A>
66 <LI><A HREF="faq.py?req=all">The whole FAQ</A>
Guido van Rossum3c3354c1997-05-21 16:52:18 +000067 <LI><A HREF="faq.py?req=roulette">FAQ roulette</A>
Guido van Rossumd7bfa801997-05-21 21:31:39 +000068 <LI><A HREF="faq.py?req=recent">Recently changed FAQ entries</A>
69 <LI><A HREF="faq.py?req=add">Add a new FAQ entry</A>
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000070 </UL>
71
Guido van Rossumd7bfa801997-05-21 21:31:39 +000072 <H2>Search the FAQ</H2>
73
Guido van Rossumadb3a9d1997-05-21 07:24:50 +000074 <FORM ACTION="faq.py?req=query">
75 <INPUT TYPE=text NAME=query>
76 <INPUT TYPE=submit VALUE="Search">
77 <INPUT TYPE=hidden NAME=req VALUE=query>
78 </FORM>
79
80 Disclaimer: these pages are intended to be edited by anyone.
81 Please exercise discretion when editing, don't be rude, etc.
82 """
83
Guido van Rossumd7bfa801997-05-21 21:31:39 +000084 def do_index(self):
Guido van Rossum74427e51997-05-21 23:43:39 +000085 self.prologue("Python FAQ Index")
Guido van Rossumd7bfa801997-05-21 21:31:39 +000086 names = os.listdir(os.curdir)
87 names.sort()
88 section = None
89 for name in names:
90 headers, text = self.read(name)
91 if headers:
92 title = headers['title']
93 i = string.find(title, '.')
94 nsec = title[:i]
95 if nsec != section:
96 if section:
97 print """
98 <P>
99 <LI><A HREF="faq.py?req=add&amp;section=%s"
100 >Add new entry</A> (at this point)
101 </UL>
102 """ % section
103 section = nsec
104 print "<H2>Section %s</H2>" % section
105 print "<UL>"
106 print '<LI><A HREF="faq.py?req=show&name=%s">%s</A>' % (
107 name, cgi.escape(title))
108 if section:
109 print """
110 <P>
111 <LI><A HREF="faq.py?req=add&amp;section=%s">Add new entry</A>
112 (at this point)
113 </UL>
114 """ % section
115 else:
116 print "No FAQ entries?!?!"
117
118 def do_show(self):
119 name = self.name
120 headers, text = self.read(name)
121 if not headers:
122 print "Invalid file name", name
123 return
124 self.show(name, headers['title'], text, 1)
125
126 def do_all(self):
Guido van Rossum74427e51997-05-21 23:43:39 +0000127 self.prologue("The Whole Python FAQ")
128 print "<HR>"
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000129 names = os.listdir(os.curdir)
130 names.sort()
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000131 section = None
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000132 for name in names:
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000133 headers, text = self.read(name)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000134 if headers:
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000135 title = headers['title']
136 i = string.find(title, '.')
137 nsec = title[:i]
138 if nsec != section:
139 section = nsec
140 print "<H1>Section %s</H1>" % section
141 print "<HR>"
142 self.show(name, title, text, 1)
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000143 if not section:
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000144 print "No FAQ entries?!?!"
145
146 def do_roulette(self):
147 import whrandom
Guido van Rossum74427e51997-05-21 23:43:39 +0000148 self.prologue("Python FAQ Roulette")
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000149 print """
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000150 Please check the correctness of the entry below.
151 If you find any problems, please edit the entry.
152 <P>
153 <HR>
154 """
155 names = os.listdir(os.curdir)
156 while names:
157 name = whrandom.choice(names)
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000158 headers, text = self.read(name)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000159 if headers:
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000160 self.show(name, headers['title'], text, 1)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000161 print '<P><A HREF="faq.py?req=roulette">Show another one</A>'
162 break
163 else:
164 names.remove(name)
165 else:
166 print "No FAQ entries?!?!"
167
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000168 def do_recent(self):
169 import fnmatch, stat
170 names = os.listdir(os.curdir)
171 now = time.time()
172 list = []
173 for name in names:
174 if not fnmatch.fnmatch(name, NAMEPAT):
175 continue
176 try:
177 st = os.stat(name)
178 except os.error:
179 continue
180 tuple = (st[stat.ST_MTIME], name)
181 list.append(tuple)
182 list.sort()
183 list.reverse()
Guido van Rossum74427e51997-05-21 23:43:39 +0000184 self.prologue("Python FAQ, Most Recently Modified First")
185 print "<HR>"
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000186 n = 0
187 for (mtime, name) in list:
188 headers, text = self.read(name)
189 if headers:
190 self.show(name, headers['title'], text, 1)
191 n = n+1
192 if not n:
193 print "No FAQ entries?!?!"
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000194
195 def do_query(self):
196 import regex
Guido van Rossum74427e51997-05-21 23:43:39 +0000197 self.prologue("Python FAQ Query Results")
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000198 query = self.query
199 if not query:
200 print "No query string"
201 return
202 p = regex.compile(query, regex.casefold)
203 names = os.listdir(os.curdir)
204 names.sort()
205 print "<HR>"
206 n = 0
207 for name in names:
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000208 headers, text = self.read(name)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000209 if headers:
210 title = headers['title']
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000211 if p.search(title) >= 0 or p.search(text) >= 0:
212 self.show(name, title, text, 1)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000213 n = n+1
214 if not n:
215 print "No hits."
216
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000217 def do_add(self):
218 section = self.section
219 if not section:
Guido van Rossum74427e51997-05-21 23:43:39 +0000220 self.prologue("How to add a new FAQ entry")
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000221 print """
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000222 Go to the <A HREF="faq.py?req=index">FAQ index</A>
223 and click on the "Add new entry" link at the end
224 of the section to which you want to add the entry.
225 """
226 return
227 try:
228 nsec = string.atoi(section)
229 except ValueError:
230 print "Bad section number", nsec
231 names = os.listdir(os.curdir)
232 max = 0
233 import regex
234 prog = regex.compile(NAMEREG)
235 for name in names:
236 if prog.match(name) >= 0:
237 s1, s2 = prog.group(1, 2)
238 n1, n2 = string.atoi(s1), string.atoi(s2)
239 if n1 == nsec:
240 if n2 > max:
241 max = n2
242 if not max:
243 print "Can't add new sections yet."
244 return
245 num = max+1
246 name = "faq%02d.%03d.htp" % (nsec, num)
247 self.name = name
248 self.add = "yes"
249 self.number = str(num)
250 self.do_edit()
251
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000252 def do_edit(self):
253 name = self.name
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000254 headers, text = self.read(name)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000255 if not headers:
256 print "Invalid file name", name
257 return
Guido van Rossum74427e51997-05-21 23:43:39 +0000258 self.prologue("Python FAQ Edit Form")
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000259 title = headers['title']
Guido van Rossum74427e51997-05-21 23:43:39 +0000260 version = self.getversion(name)
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000261 print "<FORM METHOD=POST ACTION=faq.py>"
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000262 self.showedit(name, title, text)
263 if self.add:
264 print """
265 <INPUT TYPE=hidden NAME=add VALUE=%s>
266 <INPUT TYPE=hidden NAME=section VALUE=%s>
267 <INPUT TYPE=hidden NAME=number VALUE=%s>
268 """ % (self.add, self.section, self.number)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000269 print """
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000270 <INPUT TYPE=submit VALUE="Review Edit">
271 <INPUT TYPE=hidden NAME=req VALUE=review>
272 <INPUT TYPE=hidden NAME=name VALUE=%s>
Guido van Rossum74427e51997-05-21 23:43:39 +0000273 <INPUT TYPE=hidden NAME=version VALUE=%s>
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000274 </FORM>
275 <HR>
Guido van Rossum74427e51997-05-21 23:43:39 +0000276 """ % (name, version)
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000277 self.show(name, title, text)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000278
279 def do_review(self):
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000280 if self.commit:
281 self.checkin()
282 return
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000283 name = self.name
284 text = self.text
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000285 title = self.title
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000286 headers, oldtext = self.read(name)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000287 if not headers:
288 print "Invalid file name", name
289 return
Guido van Rossum74427e51997-05-21 23:43:39 +0000290 self.prologue("Python FAQ Review Form")
291 print "<HR>"
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000292 self.show(name, title, text)
293 print "<FORM METHOD=POST ACTION=faq.py>"
294 if self.log and self.author and '@' in self.email:
295 print """
296 <INPUT TYPE=submit NAME=commit VALUE="Commit">
297 Click this button to commit the change.
298 <P>
299 <HR>
300 <P>
301 """
302 else:
303 print """
304 To commit this change, please enter your name,
305 email and a log message in the form below.
306 <P>
307 <HR>
308 <P>
309 """
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000310 self.showedit(name, title, text)
311 if self.add:
312 print """
313 <INPUT TYPE=hidden NAME=add VALUE=%s>
314 <INPUT TYPE=hidden NAME=section VALUE=%s>
315 <INPUT TYPE=hidden NAME=number VALUE=%s>
316 """ % (self.add, self.section, self.number)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000317 print """
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000318 <BR>
319 <INPUT TYPE=submit VALUE="Review Edit">
320 <INPUT TYPE=hidden NAME=req VALUE=review>
321 <INPUT TYPE=hidden NAME=name VALUE=%s>
Guido van Rossum74427e51997-05-21 23:43:39 +0000322 <INPUT TYPE=hidden NAME=version VALUE=%s>
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000323 </FORM>
324 <HR>
Guido van Rossum74427e51997-05-21 23:43:39 +0000325 """ % (name, self.version)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000326
Guido van Rossumf701bf11997-05-21 22:25:56 +0000327 def do_info(self):
328 name = self.name
329 headers, text = self.read(name)
330 if not headers:
331 print "Invalid file name", name
332 return
333 print '<PRE>'
334 sys.stdout.flush()
335 os.system("/depot/gnu/plat/bin/rlog -r %s </dev/null 2>&1" % self.name)
336 print '</PRE>'
337 print '<A HREF="faq.py?req=rlog&name=%s">View full rcs log</A>' % name
338
339 def do_rlog(self):
340 name = self.name
341 headers, text = self.read(name)
342 if not headers:
343 print "Invalid file name", name
344 return
345 print '<PRE>'
346 sys.stdout.flush()
347 os.system("/depot/gnu/plat/bin/rlog %s </dev/null 2>&1" % self.name)
348 print '</PRE>'
349
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000350 def checkin(self):
351 import regsub, time, tempfile
352 name = self.name
353
354 headers, oldtext = self.read(name)
355 if not headers:
356 print "Invalid file name", name
357 return
Guido van Rossum74427e51997-05-21 23:43:39 +0000358 version = self.version
359 curversion = self.getversion(name)
360 if version != curversion:
361 print "Version conflict."
362 print "You edited version %s but current version is %s." % (
363 version, curversion)
364 print '<A HREF="faq.py?req=show&name=%s">Reload.</A>' % name
365 return
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000366 text = self.text
367 title = self.title
368 author = self.author
369 email = self.email
370 log = self.log
371 text = regsub.gsub("\r\n", "\n", text)
372 log = regsub.gsub("\r\n", "\n", log)
373 author = string.join(string.split(author))
374 email = string.join(string.split(email))
375 title = string.join(string.split(title))
376 oldtitle = headers['title']
377 oldtitle = string.join(string.split(oldtitle))
378 text = string.strip(text)
379 oldtext = string.strip(oldtext)
380 if text == oldtext and title == oldtitle:
381 print "No changes."
382 # XXX Should exit more ceremoniously
383 return
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000384 # Check that the FAQ entry number didn't change
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000385 if string.split(title)[:1] != string.split(oldtitle)[:1]:
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000386 print "Don't change the FAQ entry number please."
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000387 # XXX Should exit more ceremoniously
388 return
389 remhost = os.environ["REMOTE_HOST"]
390 remaddr = os.environ["REMOTE_ADDR"]
391 try:
392 os.unlink(name + "~")
393 except os.error:
394 pass
395 try:
396 os.rename(name, name + "~")
397 except os.error:
398 pass
399 try:
400 os.unlink(name)
401 except os.error:
402 pass
403 try:
404 f = open(name, "w")
405 except IOError, msg:
406 print "Can't open", name, "for writing:", cgi.escape(str(msg))
407 # XXX Should exit more ceremoniously
408 return
409 now = time.ctime(time.time())
410 f.write("Title: %s\n" % title)
411 f.write("Last-Changed-Date: %s\n" % now)
412 f.write("Last-Changed-Author: %s\n" % author)
413 f.write("Last-Changed-Email: %s\n" % email)
414 f.write("Last-Changed-Remote-Host: %s\n" % remhost)
415 f.write("Last-Changed-Remote-Address: %s\n" % remaddr)
416 keys = headers.keys()
417 keys.sort()
418 keys.remove('title')
419 for key in keys:
420 if key[:13] != 'last-changed-':
421 f.write("%s: %s\n" % (string.capwords(key, '-'),
422 headers[key]))
423 f.write("\n")
424 f.write(text)
425 f.write("\n")
426 f.close()
427
428 tfn = tempfile.mktemp()
429 f = open(tfn, "w")
430 f.write("Last-Changed-Date: %s\n" % now)
431 f.write("Last-Changed-Author: %s\n" % author)
432 f.write("Last-Changed-Email: %s\n" % email)
433 f.write("Last-Changed-Remote-Host: %s\n" % remhost)
434 f.write("Last-Changed-Remote-Address: %s\n" % remaddr)
435 f.write("\n")
436 f.write(log)
437 f.write("\n")
438 f.close()
439
440 p = os.popen("""
441 /depot/gnu/plat/bin/rcs -l %s </dev/null 2>&1
442 /depot/gnu/plat/bin/ci -u %s <%s 2>&1
443 rm -f %s
444 """ % (name, name, tfn, tfn))
445 output = p.read()
446 sts = p.close()
447 if not sts:
Guido van Rossum74427e51997-05-21 23:43:39 +0000448 self.prologue("Python FAQ Entry Edited")
449 print "<HR>"
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000450 self.show(name, title, text, 1)
451 if output:
452 print "<PRE>%s</PRE>" % cgi.escape(output)
453 else:
454 print """
455 <H1>Python FAQ Entry Commit Failed</H1>
456 Exit status 0x%04x
457 """ % sts
458 if output:
459 print "<PRE>%s</PRE>" % cgi.escape(output)
460
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000461 def showedit(self, name, title, text):
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000462 print """
463 Title: <INPUT TYPE=text SIZE=70 NAME=title VALUE="%s"<BR>
464 <TEXTAREA COLS=80 ROWS=20 NAME=text>""" % title
465 print cgi.escape(string.strip(text))
466 print """</TEXTAREA>
467 <BR>
468 Please provide the following information for logging purposes:
469 <BR>
470 <CODE>Name : </CODE><INPUT TYPE=text SIZE=70 NAME=author VALUE="%s"<BR>
471 <CODE>Email: </CODE><INPUT TYPE=text SIZE=70 NAME=email VALUE="%s"<BR>
472 Log message (reason for the change):<BR>
473 <TEXTAREA COLS=80 ROWS=5 NAME=log>\n%s\n</TEXTAREA>
474 """ % (self.author, self.email, self.log)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000475
476 def showheaders(self, headers):
477 print "<UL>"
478 keys = map(string.lower, headers.keys())
479 keys.sort()
480 for key in keys:
481 print "<LI><B>%s:</B> %s" % (string.capwords(key, '-'),
482 headers[key] or '')
483 print "</UL>"
484
485 def read(self, name):
486 import fnmatch, rfc822
487 if not fnmatch.fnmatch(name, NAMEPAT):
488 return None, None
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000489 if self.add:
490 try:
491 fname = "faq%02d.%03d.htp" % (string.atoi(self.section),
492 string.atoi(self.number))
493 except ValueError:
494 return None, None
495 if fname != name:
496 return None, None
497 headers = {'title': "%s.%s. " % (self.section, self.number)}
498 text = ""
499 return headers, text
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000500 f = open(name)
501 headers = rfc822.Message(f)
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000502 text = f.read()
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000503 f.close()
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000504 return headers, text
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000505
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000506 def show(self, name, title, text, edit=0):
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000507 # XXX Should put <A> tags around recognizable URLs
508 # XXX Should also turn "see section N" into hyperlinks
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000509 print "<H2>%s</H2>" % cgi.escape(title)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000510 pre = 0
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000511 for line in string.split(text, '\n'):
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000512 if not string.strip(line):
513 if pre:
514 print '</PRE>'
515 pre = 0
516 else:
517 print '<P>'
518 else:
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000519 if line == string.lstrip(line): # I.e., no leading whitespace
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000520 if pre:
521 print '</PRE>'
522 pre = 0
523 else:
524 if not pre:
525 print '<PRE>'
526 pre = 1
Guido van Rossumd7bfa801997-05-21 21:31:39 +0000527 print cgi.escape(line)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000528 if pre:
529 print '</PRE>'
530 pre = 0
531 print '<P>'
532 if edit:
Guido van Rossumf701bf11997-05-21 22:25:56 +0000533 print """
534 <A HREF="faq.py?req=edit&name=%s">Edit this entry</A> /
535 <A HREF="faq.py?req=info&name=%s" TARGET=_blank>Log info</A>
536 """ % (name, name)
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000537 print '<P>'
538 print "<HR>"
539
Guido van Rossum74427e51997-05-21 23:43:39 +0000540 def getversion(self, name):
541 p = os.popen("/depot/gnu/plat/bin/rlog -h %s </dev/null 2>&1" % name)
542 head = ""
543 while 1:
544 line = p.readline()
545 if not line:
546 break
547 if line[:5] == 'head:':
548 head = string.strip(line[5:])
549 p.close()
550 return head
551
552 def prologue(self, title):
553 title = cgi.escape(title)
554 print '''\
555 <HTML>
556 <HEAD>
557 <TITLE>%s</TITLE>
558 </HEAD>
559 <BODY BACKGROUND="http://www.python.org/pics/RedShort.gif"
560 BGCOLOR="#FFFFFF"
561 TEXT="#000000"
562 LINK="#AA0000"
563 VLINK="#906A6A">
564 <H1>%s</H1>
565 ''' % (title, title)
566
567 def epilogue(self):
568 print '''
569 <P>
570 <HR>
571 <A HREF="mailto:guido@python.org">GvR</A>
572 </BODY>
573 </HTML>
574 '''
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000575
576print "Content-type: text/html\n"
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000577dt = 0
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000578try:
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000579 import time
580 t1 = time.time()
Guido van Rossum74427e51997-05-21 23:43:39 +0000581 import cgi, string, os, sys
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000582 x = FAQServer()
583 x.main()
Guido van Rossum3c3354c1997-05-21 16:52:18 +0000584 t2 = time.time()
585 dt = t2-t1
Guido van Rossumadb3a9d1997-05-21 07:24:50 +0000586except:
587 print "<HR>Sorry, an error occurred"
588 cgi.print_exception()
Guido van Rossum74427e51997-05-21 23:43:39 +0000589print "<P>(running time = %s seconds)" % str(round(dt, 3))