1
2import re, time
3
4class Node:
5	def __init__(self, name):
6		self.name = name
7		self.body = ""
8		self.index = ""
9		self.indexname = ""
10		self.tag = ""
11		self.nodes = []
12	def Sorted(self):
13		names = []
14		for n in self.nodes:
15			names += [n.name]
16		names.sort()
17		new_list = []
18		for name in names:
19			for n in self.nodes:
20				if n.name == name:
21					new_list += [n]
22					break
23		self.nodes = new_list
24		return self
25
26# tags
27group_tag = "@GROUP"
28function_tag = "@FUNCTION"
29option_tag = "@OPTION"
30body_tag = "@BODY"
31tags = [function_tag, option_tag, body_tag]
32end_tag = "@END"
33
34class DocInfo:
35	def __init__(self):
36		self.name = ""
37		self.copyright = ""
38		self.logo = ""
39
40class Output:
41	def __init__(self, filename, docinfo):
42		self.filename = filename
43		self.docinfo = docinfo
44
45	def output_name(self):
46		return self.filename
47
48	def render_node_index(self, cur):
49		if len(cur.index):
50			print >>self.file, self.index_node_begin(cur)
51		for node in cur.nodes:
52			self.render_node_index(node)
53		if len(cur.index):
54			print >>self.file, self.index_node_end(cur)
55	def render_node(self, cur):
56		if len(cur.index):
57			print >>self.file, self.format_header(cur)
58			print >>self.file, self.format_body(cur)
59		for node in cur.nodes:
60			self.render_node(node)
61
62	def index_nodes(self, cur, index=""):
63		for i in xrange(0, len(cur.nodes)):
64			if len(index):
65				cur.nodes[i].index = index + "." + str(i+1)
66			else:
67				cur.nodes[i].index = str(i+1)
68
69			cur.nodes[i].indexname = cur.nodes[i].name
70			if cur.nodes[i].tag == function_tag:
71				cur.nodes[i].indexname = cur.nodes[i].indexname.split("(")[0].strip()
72			self.index_nodes(cur.nodes[i], cur.nodes[i].index)
73
74	def render(self, rootnode):
75		self.index_nodes(rootnode)
76		print >>self.file, self.render_begin()
77
78		print >>self.file, self.index_begin()
79		self.render_node_index(rootnode)
80		print >>self.file, self.index_end()
81
82		self.render_node(rootnode)
83		print >>self.file, self.render_end()
84
85class HTMLOutput(Output):
86	def render_begin(self):
87		img = ""
88		if len(self.docinfo.logo):
89			img = '<img src="%s"/>'%self.docinfo.logo
90
91		# large part of the style sheet is stolen from luas documentation
92		return '''
93			<head>
94			<title>Bam Manual</title>
95
96			<style type="text/css"><!--
97
98				body {
99					color: #000000 ;
100					background-color: #FFFFFF ;
101					font-family: sans-serif ;
102					text-align: justify ;
103					margin-right: 20px ;
104					margin-left: 20px ;
105				}
106
107				h1, h2, h3, h4, h5 {
108					font-weight: normal ;
109					font-style: italic ;
110				}
111
112				a:link {
113					color: #000080 ;
114					background-color: inherit ;
115					text-decoration: none ;
116				}
117
118				a:visited {
119					background-color: inherit ;
120					text-decoration: none ;
121				}
122
123				a:link:hover, a:visited:hover {
124					color: #000080 ;
125					background-color: #E0E0FF ;
126				}
127
128				a:link:active, a:visited:active {
129					color: #FF0000 ;
130				}
131
132				hr {
133					border: 0 ;
134					height: 1px ;
135					color: #a0a0a0 ;
136					background-color: #a0a0a0 ;
137				}
138
139				pre {
140					padding: 5px ;
141					background-color: #eeeeee ;
142				}
143
144				td {
145					border-width: 1px;
146					border-style: dotted;
147					padding: 2px;
148				}
149
150				.identifier {
151					font-family: monospace ;
152				}
153
154				li {
155					list-style-type: none;
156				}
157
158			--></style>
159			</head>
160			<body>
161			<!-- COMMENTS "BASE" -->
162			<hr/>
163			%s<h1>%s</h1>
164			<small>%s</small>
165
166			<hr/>
167			%s
168		''' %(img, self.docinfo.name, self.docinfo.note, self.docinfo.copyright)
169	def render_end(self):
170		return '''
171			<hr/>
172			<small>Generated at %s.</small>
173			</body>
174		''' % (time.asctime())
175
176	def index_begin(self): return '<h2>Contents</h2><ul>'
177	def index_end(self): return '</ul><hr/>'
178	def index_node_begin(self, node):
179		return '<li><a href="#%s">%s - %s</a></li><ul>'%(node.index,node.index,node.indexname)
180	def index_node_end(self, node):
181		if len(node.index) == 1:
182			return '</ul><p></p>'
183		return '</ul>'
184
185	def format_header(self, node):
186		i = (len(node.index)-1)/2 + 1
187		header = '<h%d><a name="%s"></a><a name="%s">%s</a> - <a name="%s">%s</a></h%d>'%(i,node.indexname,node.index,node.index,node.name,node.name,i)
188		if node.tag == function_tag:
189			header = '<hr/>' + header
190		return header
191
192	def format_body(self, node):
193		body = node.body
194		body = re.sub('\^(?P<ident>[^\^]+)\^', '<span class="identifier">\g<ident></span>', body)
195		body = re.sub('\[(?P<ident>[^\]]+)\]', '<a href="#\g<ident>">\g<ident></a>', body)
196		body = re.sub('{{{{', '<pre>', body)
197		body = re.sub('}}}}', '</pre>', body)
198		body = re.sub('!IMG (?P<filename>.+)', '<img src="\g<filename>"/>', body)
199		body = re.sub('\\\\t', '&nbsp;&nbsp;&nbsp;&nbsp;', body)
200		body = re.sub('\n\n', '</p><p>', body)
201
202
203		body = '<p class="body">' + body + '</p>\n'
204		body += '\n<!-- COMMENTS "%s" -->\n' % (node.indexname)
205		return body
206
207def ParseTextFile(rootnode, filename, addbr=False):
208	group = rootnode
209	for line in file(filename):
210		if group_tag in line:
211			group_name = line.split(group_tag)[-1].split(end_tag)[0].strip()
212			group = Node(group_name)
213			rootnode.nodes += [group]
214		else:
215			if addbr:
216				group.body += line.strip() + "<br/>\n"
217			else:
218				group.body += line.strip() + "\n"
219
220	return rootnode
221
222def ParseFile(rootnode, filename):
223	# 0 = scaning for start tag
224	# 1 = scaning for end tag,
225	# 2 = outputting function decl
226	state = 0
227	group = rootnode
228	for line in file(filename):
229		if state == 0:
230			if group_tag in line:
231				group_name = line.split(group_tag)[-1].split(end_tag)[0].strip()
232				group = Node(group_name)
233				rootnode.nodes += [group]
234			else:
235				for t in tags:
236					if t in line:
237						title = line.split(t)[-1].strip()
238						tag = t
239						body = ""
240						state = 1
241						break
242		elif state == 1:
243			if end_tag in line:
244				state = 3
245			elif "@PAUSE" in line:
246				state = 2
247			else:
248				body += line.strip() + "\n"
249		elif state == 2:
250			if "@RESUME" in line:
251				state = 1
252		else:
253			if tag == function_tag:
254				if len(title) == 0:
255					title = line.replace("function", "").strip()
256				title = title.replace("(", " (")
257			node = Node(title)
258			node.body = body
259			node.tag = tag
260			group.nodes += [node]
261			state = 0
262	return rootnode
263