rda-python-miscs 2.0.0__py3-none-any.whl → 2.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rda_python_miscs/pg_docs.py +744 -0
- rda_python_miscs/pg_rst.py +1235 -0
- rda_python_miscs/rdakill.py +4 -47
- rda_python_miscs/rdakill.usg +4 -4
- rda_python_miscs/rdaps.py +3 -39
- rda_python_miscs/rdaps.usg +1 -1
- {rda_python_miscs-2.0.0.dist-info → rda_python_miscs-2.0.2.dist-info}/METADATA +1 -1
- {rda_python_miscs-2.0.0.dist-info → rda_python_miscs-2.0.2.dist-info}/RECORD +12 -10
- {rda_python_miscs-2.0.0.dist-info → rda_python_miscs-2.0.2.dist-info}/WHEEL +1 -1
- {rda_python_miscs-2.0.0.dist-info → rda_python_miscs-2.0.2.dist-info}/entry_points.txt +1 -0
- {rda_python_miscs-2.0.0.dist-info → rda_python_miscs-2.0.2.dist-info}/licenses/LICENSE +0 -0
- {rda_python_miscs-2.0.0.dist-info → rda_python_miscs-2.0.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
#
|
|
2
|
+
###############################################################################
|
|
3
|
+
#
|
|
4
|
+
# Title : pg_docs.py
|
|
5
|
+
# Author : Zaihua Ji, zjiucar.edu
|
|
6
|
+
# Date : 09/14/2020
|
|
7
|
+
# Purpose : python library module to help convert text help documents into
|
|
8
|
+
# html format with help of html templates
|
|
9
|
+
#
|
|
10
|
+
# Work File : $DSSHOME/lib/python/PgDOCS.py
|
|
11
|
+
# Github : https://github.com/NCAR/rda-shared-libraries.git
|
|
12
|
+
#
|
|
13
|
+
###############################################################################
|
|
14
|
+
#
|
|
15
|
+
import os
|
|
16
|
+
import re
|
|
17
|
+
from os import path as op
|
|
18
|
+
import PgLOG
|
|
19
|
+
import PgUtil
|
|
20
|
+
import PgFile
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PgDOCS:
|
|
24
|
+
|
|
25
|
+
Q0 = "'"
|
|
26
|
+
Q1 = "<i><b>"
|
|
27
|
+
Q2 = "</i></b>"
|
|
28
|
+
|
|
29
|
+
EMLIST = {
|
|
30
|
+
'dsarch' : 1,
|
|
31
|
+
'msarch' : 1,
|
|
32
|
+
'dsupdt' : 1,
|
|
33
|
+
'dsrqst' : 1,
|
|
34
|
+
'gatherxml' : 1,
|
|
35
|
+
'pgconvert' : 1,
|
|
36
|
+
'publish_filelist' : 1,
|
|
37
|
+
'rcm' : 1,
|
|
38
|
+
'dcm' : 1,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
SEARCH = "(Action|Info|Mode|Multi-Value|Single-Value)"
|
|
42
|
+
|
|
43
|
+
def __init__(self):
|
|
44
|
+
self.OPTS = {}
|
|
45
|
+
self.ALIAS = {}
|
|
46
|
+
|
|
47
|
+
self.SECIDS = { # section ids for category
|
|
48
|
+
'Action' : None,
|
|
49
|
+
'Info' : None,
|
|
50
|
+
'Mode' : None,
|
|
51
|
+
'Multi-Value' : None,
|
|
52
|
+
'Single-Value' : None,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# Section array with each section pointing to a hash:
|
|
56
|
+
# secid - section ID (1, 1.1, 1.1.1, ...)
|
|
57
|
+
# title - section title
|
|
58
|
+
# level - section level, 0 top level
|
|
59
|
+
# desc - section decription
|
|
60
|
+
# opts - pointer to an array of included option short names
|
|
61
|
+
self.sections = []
|
|
62
|
+
|
|
63
|
+
# Option hash keyed by short option names and each is a hash itself
|
|
64
|
+
# secid - section ID the option belongs
|
|
65
|
+
# name - option long name
|
|
66
|
+
# type - option type, 0 - Mode, 1 - Info, 2 - Action
|
|
67
|
+
# alias - array of alias option names None if none
|
|
68
|
+
# desc - option decription
|
|
69
|
+
# examples - array of example indices included for the option
|
|
70
|
+
self.options = {}
|
|
71
|
+
|
|
72
|
+
# Example array with each example pointing to a hash:
|
|
73
|
+
# opt - option short name the example belongs
|
|
74
|
+
# title - example title
|
|
75
|
+
# desc - example decription
|
|
76
|
+
self.examples = []
|
|
77
|
+
|
|
78
|
+
# global info to be used by the whole application
|
|
79
|
+
self.DOCS = {
|
|
80
|
+
'ORIGIN' : PgLOG.PGLOG['DSSHOME'] + "/dssdb/prog_usage", # directory to the original document
|
|
81
|
+
'TMPDIR' : PgLOG.PGLOG['DSSHOME'] + "/lib/templates", # directory to find the templates
|
|
82
|
+
'DCROOT' : None, # root directory to html documents
|
|
83
|
+
'DOCDIR' : "", # directory to final html documents
|
|
84
|
+
'DOCNAM' : "", # document name: dsarch, dsupdt, etc.
|
|
85
|
+
'DOCTIT' : "", # document name in upper case letters
|
|
86
|
+
'DOCLNK' : None,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
self.LINKS = ['dsarch', 'dsupdt', 'dsrqst', 'dscheck']
|
|
90
|
+
self.DOCS['DCROOT'] = PgLOG.get_environment("WEBROOT", PgLOG.PGLOG['DSSWEB']) + "/rdadocs"
|
|
91
|
+
|
|
92
|
+
#
|
|
93
|
+
# Function process_docs(docname: document name, 'dsarch', 'dsupdt'
|
|
94
|
+
# opts: option hash defined for the document
|
|
95
|
+
# alias: alias names for given opts)
|
|
96
|
+
#
|
|
97
|
+
def process_docs(self, docname, opts, alias):
|
|
98
|
+
|
|
99
|
+
self.OPTS = opts
|
|
100
|
+
self.ALIAS = alias
|
|
101
|
+
|
|
102
|
+
self.parse_docs(docname)
|
|
103
|
+
if not self.sections: PgLOG.pglog(docname + ": empty document", PgLOG.LGWNEX)
|
|
104
|
+
|
|
105
|
+
self.DOCS['DOCNAM'] = docname
|
|
106
|
+
if docname in self.LINKS: self.LINKS.remove(docname)
|
|
107
|
+
self.DOCS['DOCLNK'] = r"({})".format('|'.join(self.LINKS))
|
|
108
|
+
self.DOCS['DOCTIT'] = docname.upper()
|
|
109
|
+
self.DOCS['DOCDIR'] = "{}/{}".format(self.DOCS['DCROOT'], docname)
|
|
110
|
+
|
|
111
|
+
PgFile.change_local_directory(self.DOCS['DOCDIR'], PgLOG.LGWNEX)
|
|
112
|
+
PgLOG.pglog("Write html document '{}' under {}".format(docname, self.DOCS['DOCDIR']), PgLOG.LOGWRN)
|
|
113
|
+
|
|
114
|
+
if op.exists("index.html"): # write index file once
|
|
115
|
+
PgLOG.pglog("index.html exists already, delete first if needs to be regenerated", PgLOG.LOGWRN)
|
|
116
|
+
else:
|
|
117
|
+
self.write_index(self.sections[0])
|
|
118
|
+
|
|
119
|
+
self.write_toc()
|
|
120
|
+
|
|
121
|
+
for section in self.sections:
|
|
122
|
+
self.write_section(section)
|
|
123
|
+
|
|
124
|
+
#
|
|
125
|
+
# parse the original document and return a array of sections,
|
|
126
|
+
#
|
|
127
|
+
def parse_docs(self, docname):
|
|
128
|
+
|
|
129
|
+
docfile = "{}/{}.usg".format(self.DOCS['ORIGIN'], docname)
|
|
130
|
+
PgLOG.pglog("Parsing info for Document '{}'".format(docname), PgLOG.LOGWRN)
|
|
131
|
+
section = self.init_section('0', "Preface")
|
|
132
|
+
option = example = None
|
|
133
|
+
fh = open(docfile, 'r')
|
|
134
|
+
line = fh.readline()
|
|
135
|
+
while line:
|
|
136
|
+
if re.match(r'\s*#', line):
|
|
137
|
+
line = fh.readline()
|
|
138
|
+
continue # skip comment lines
|
|
139
|
+
ms = re.match(r'^(.*\S)\s+#', line)
|
|
140
|
+
if ms:
|
|
141
|
+
line = ms.group(1) # remove comments
|
|
142
|
+
else:
|
|
143
|
+
line = line.rstrip() # remove trailing white spaces
|
|
144
|
+
|
|
145
|
+
# check and replace temporal pattern quotes
|
|
146
|
+
while True:
|
|
147
|
+
ms = re.search(r'(<([A-Z/\-\.]+)>)', line)
|
|
148
|
+
if ms:
|
|
149
|
+
line = line.replace(ms.group(1), "<{}>".format(ms.group(2)))
|
|
150
|
+
else:
|
|
151
|
+
break
|
|
152
|
+
ms = re.match(r'^([\d\.]+)\s+(.+)$', line)
|
|
153
|
+
if ms: # start new section
|
|
154
|
+
section = self.record_section(section, option, example, ms.group(1), ms.group(2))
|
|
155
|
+
option = example = None
|
|
156
|
+
else:
|
|
157
|
+
ms = re.match(r'^ -([A-Z]{2}) or -\w+(.*)$', line)
|
|
158
|
+
if ms: # found new option
|
|
159
|
+
option = self.record_option(section, option, example, ms.group(1), ms.group(2))
|
|
160
|
+
example = None
|
|
161
|
+
elif option:
|
|
162
|
+
ms = re.match(r'^ For( | another )example, (.*)$', line)
|
|
163
|
+
if ms: # found example
|
|
164
|
+
example = self.record_example(option, example, ms.group(2))
|
|
165
|
+
elif example:
|
|
166
|
+
example['desc'] += line + "\n"
|
|
167
|
+
else:
|
|
168
|
+
option['desc'] += line + "\n"
|
|
169
|
+
else:
|
|
170
|
+
section['desc'] += line + "\n"
|
|
171
|
+
|
|
172
|
+
line = fh.readline()
|
|
173
|
+
fh.close()
|
|
174
|
+
|
|
175
|
+
self.record_section(section, option, example)
|
|
176
|
+
|
|
177
|
+
# check completion of options
|
|
178
|
+
for opt in self.OPTS:
|
|
179
|
+
if opt not in self.options:
|
|
180
|
+
PgLOG.pglog("Missing option Entry -{} (-{}) in Document '{}'".format(opt, self.OPTS[opt][1], docname), PgLOG.LOGWRN)
|
|
181
|
+
if self.sections:
|
|
182
|
+
cnt = len(self.sections)
|
|
183
|
+
s = 's' if cnt > 1 else ''
|
|
184
|
+
PgLOG.pglog("{} Section{} gathered for '{}'".format(cnt, s, docname), PgLOG.LOGWRN)
|
|
185
|
+
|
|
186
|
+
#
|
|
187
|
+
# cache section information
|
|
188
|
+
#
|
|
189
|
+
def record_section(self, section, option, exmaple, nsecid=None, ntitle=None):
|
|
190
|
+
|
|
191
|
+
if option or section['desc'] != "\n":
|
|
192
|
+
if option: self.record_option(section, option, exmaple)
|
|
193
|
+
self.sections.append(section) # record section globally
|
|
194
|
+
|
|
195
|
+
if nsecid: return self.init_section(nsecid, ntitle)
|
|
196
|
+
|
|
197
|
+
#
|
|
198
|
+
# cache option information
|
|
199
|
+
#
|
|
200
|
+
def record_option(self, section, option, example, nopt=None, ndesc=None):
|
|
201
|
+
|
|
202
|
+
if option:
|
|
203
|
+
if example: self.record_example(option, example)
|
|
204
|
+
self.options[option['opt']] = option # record option globally
|
|
205
|
+
section['opts'].append(option['opt']) # record option short name in section
|
|
206
|
+
|
|
207
|
+
if nopt: return self.init_option(section['secid'], nopt, ndesc)
|
|
208
|
+
|
|
209
|
+
def record_example(self, option, example, ndesc=None):
|
|
210
|
+
|
|
211
|
+
if example:
|
|
212
|
+
ms = re.match(r'^(.*)\.\s*(.*)$', example['desc'])
|
|
213
|
+
if ms:
|
|
214
|
+
example['title'] = ms.group(1)
|
|
215
|
+
example['desc'] = ms.group(2)
|
|
216
|
+
option['exmidxs'].append(len(self.examples)) # record example index in option
|
|
217
|
+
self.examples.append(example) # record example globally
|
|
218
|
+
|
|
219
|
+
if ndesc: return self.init_example(option['opt'], ndesc)
|
|
220
|
+
|
|
221
|
+
#
|
|
222
|
+
# initialize section dict
|
|
223
|
+
#
|
|
224
|
+
def init_section(self, secid, title):
|
|
225
|
+
|
|
226
|
+
section = {
|
|
227
|
+
'secid' : secid,
|
|
228
|
+
'title' : title,
|
|
229
|
+
'desc' : "",
|
|
230
|
+
'level' : 0,
|
|
231
|
+
'opts' : []
|
|
232
|
+
}
|
|
233
|
+
level = len(re.split(r'\.', secid))
|
|
234
|
+
section['level'] = level
|
|
235
|
+
if level == 1:
|
|
236
|
+
if re.match(r'^ACTION', section['title']):
|
|
237
|
+
self.SECIDS['Action'] = secid
|
|
238
|
+
elif re.match(r'^MODE', section['title']):
|
|
239
|
+
self.SECIDS['Mode'] = secid
|
|
240
|
+
elif re.match(r'^INFORMATION', section['title']):
|
|
241
|
+
self.SECIDS['Info'] = secid
|
|
242
|
+
elif level == 2:
|
|
243
|
+
if re.match(r'^Single-Value', section['title']):
|
|
244
|
+
self.SECIDS['Single-Value'] = secid
|
|
245
|
+
elif re.match(r'^Multi-Value', section['title']):
|
|
246
|
+
self.SECIDS['Multi-Value'] = secid
|
|
247
|
+
|
|
248
|
+
return section
|
|
249
|
+
|
|
250
|
+
#
|
|
251
|
+
# initialize option dict
|
|
252
|
+
#
|
|
253
|
+
def init_option(self, secid, opt, desc):
|
|
254
|
+
|
|
255
|
+
option = {}
|
|
256
|
+
types = ("Mode", "Info", "Info", "Action")
|
|
257
|
+
|
|
258
|
+
if opt not in self.OPTS:
|
|
259
|
+
PgLOG.pglog("{} -- option not defined for {}".format(opt, self.DOCS['DOCNAM']), PgLOG.LGWNEX)
|
|
260
|
+
option['secid'] = secid
|
|
261
|
+
option['opt'] = opt
|
|
262
|
+
ms = re.match(r'^(, | \(Alias: .*\), )(.*)', desc)
|
|
263
|
+
if ms: desc = ms.group(2)
|
|
264
|
+
option['desc'] = desc + "\n"
|
|
265
|
+
option['exmidxs'] = []
|
|
266
|
+
option['name'] = self.OPTS[opt][1]
|
|
267
|
+
if opt in self.ALIAS: option['alias'] = self.ALIAS[opt]
|
|
268
|
+
typidx = self.OPTS[opt][0]
|
|
269
|
+
if typidx > 3: typidx = 3
|
|
270
|
+
option['type'] = types[typidx]
|
|
271
|
+
|
|
272
|
+
return option
|
|
273
|
+
|
|
274
|
+
#
|
|
275
|
+
# initialize example dic
|
|
276
|
+
#
|
|
277
|
+
def init_example(self, opt, desc):
|
|
278
|
+
|
|
279
|
+
example = {'opt' : opt, 'title' : "", 'desc' : desc.title() + "\n"}
|
|
280
|
+
|
|
281
|
+
return example
|
|
282
|
+
|
|
283
|
+
#
|
|
284
|
+
# write the entry file: index.html
|
|
285
|
+
#
|
|
286
|
+
def write_index(self, section):
|
|
287
|
+
|
|
288
|
+
hash = {'TITLE' : self.DOCS['DOCTIT'], 'SECID' : section['secid']}
|
|
289
|
+
|
|
290
|
+
self.template_to_html("index", hash)
|
|
291
|
+
|
|
292
|
+
#
|
|
293
|
+
# write the table of contents: toc.html
|
|
294
|
+
#
|
|
295
|
+
def write_toc(self):
|
|
296
|
+
|
|
297
|
+
hash = {'TITLE' : self.DOCS['DOCTIT'], 'TOC' : self.create_toc()}
|
|
298
|
+
|
|
299
|
+
self.template_to_html("toc", hash)
|
|
300
|
+
|
|
301
|
+
#
|
|
302
|
+
# write a section html file
|
|
303
|
+
#
|
|
304
|
+
def write_section(self, section):
|
|
305
|
+
|
|
306
|
+
hash = {}
|
|
307
|
+
secid = section['secid']
|
|
308
|
+
hash['TITLE'] = section['title']
|
|
309
|
+
hash['SECID'] = secid
|
|
310
|
+
hash['SECTION'] = self.create_section(section)
|
|
311
|
+
|
|
312
|
+
self.template_to_html("section", hash, secid)
|
|
313
|
+
|
|
314
|
+
#
|
|
315
|
+
# convert template to html file
|
|
316
|
+
#
|
|
317
|
+
def template_to_html(self, template, hash, extra=None):
|
|
318
|
+
|
|
319
|
+
tempfile = "{}/{}.temp".format(self.DOCS['TMPDIR'], template)
|
|
320
|
+
if extra is None: extra = ""
|
|
321
|
+
htmlfile = "{}/{}{}.html".format(self.DOCS['DOCDIR'], template, extra)
|
|
322
|
+
|
|
323
|
+
tf = open(tempfile, 'r')
|
|
324
|
+
hf = open(htmlfile, 'w')
|
|
325
|
+
idx = 0
|
|
326
|
+
line = tf.readline()
|
|
327
|
+
while line:
|
|
328
|
+
idx += 1
|
|
329
|
+
if re.match(r'\s*#', line):
|
|
330
|
+
line = tf.readline()
|
|
331
|
+
continue # skip comment lines
|
|
332
|
+
ms = re.match(r'^(.*\S)\s+#', line)
|
|
333
|
+
if ms:
|
|
334
|
+
line = ms.group(1) # remove comments
|
|
335
|
+
else:
|
|
336
|
+
line = line.rstrip() # remove trailing white spaces
|
|
337
|
+
|
|
338
|
+
matches = re.findall(r'__([A-Z]+)__', line)
|
|
339
|
+
if matches:
|
|
340
|
+
for key in matches:
|
|
341
|
+
if key not in hash: PgLOG.pglog("{}: not defined at {}({}) {}".format(key, line, idx, tempfile), PgLOG.LGWNEX)
|
|
342
|
+
if not hash[key]: PgLOG.pglog(key + ": empty content", PgLOG.LGWNEX)
|
|
343
|
+
line = line.replace("__{}__".format(key), hash[key])
|
|
344
|
+
hf.write(line + "\n")
|
|
345
|
+
line = tf.readline()
|
|
346
|
+
|
|
347
|
+
tf.close()
|
|
348
|
+
hf.close()
|
|
349
|
+
PgLOG.pglog("{}{}.html created from {}.temp".format(template, extra, template), PgLOG.LOGWRN)
|
|
350
|
+
|
|
351
|
+
#
|
|
352
|
+
# create a html file for table of contents
|
|
353
|
+
#
|
|
354
|
+
def create_toc(self):
|
|
355
|
+
|
|
356
|
+
content = ""
|
|
357
|
+
|
|
358
|
+
# table content for all sections
|
|
359
|
+
lvl = 1
|
|
360
|
+
for section in self.sections:
|
|
361
|
+
secid = section['secid']
|
|
362
|
+
if section['level'] > lvl:
|
|
363
|
+
while lvl < section['level']:
|
|
364
|
+
content += "<tr><td> </td><td><table>\n"
|
|
365
|
+
lvl += 1
|
|
366
|
+
elif section['level'] < lvl:
|
|
367
|
+
while lvl > section['level']:
|
|
368
|
+
content += "</table></td></tr>\n"
|
|
369
|
+
lvl -= 1
|
|
370
|
+
lvl = section['level']
|
|
371
|
+
content += (("<tr><td align=right><small>{}.</small></td>\n".format(secid)) +
|
|
372
|
+
("<td align=left><a href=\"section{}.html\">".format(secid)) +
|
|
373
|
+
("<small>{}</small></a></td></tr>\n".format(section['title'])))
|
|
374
|
+
|
|
375
|
+
while lvl > 1:
|
|
376
|
+
content += "</table></td></tr>\n"
|
|
377
|
+
lvl -= 1
|
|
378
|
+
|
|
379
|
+
# table content for appendix A of examples
|
|
380
|
+
content += ("<tr><td align=right><small>A.</small></td>\n" +
|
|
381
|
+
"<td align=left><small>List of Examples</small></td></tr>\n" +
|
|
382
|
+
"<tr><td> </td><td><table>\n")
|
|
383
|
+
|
|
384
|
+
idx = 1 # used as exmaple index
|
|
385
|
+
for example in self.examples:
|
|
386
|
+
opt = example['opt']
|
|
387
|
+
option = self.options[opt]
|
|
388
|
+
secid = option['secid']
|
|
389
|
+
content += (("<tr><td align=right><small>A.{}.</small></td>\n".format(idx)) +
|
|
390
|
+
("<td align=left><a href=\"section{}.html#e{}\">\n".format(secid, idx)) +
|
|
391
|
+
("<small>{} Option -{} (-{})</small></a></td></tr>\n".format(option['type'], opt, option['name'])))
|
|
392
|
+
idx += 1
|
|
393
|
+
content += "</table></td></tr>\n"
|
|
394
|
+
|
|
395
|
+
return content
|
|
396
|
+
|
|
397
|
+
#
|
|
398
|
+
# create a section html content
|
|
399
|
+
#
|
|
400
|
+
def create_section(self, section):
|
|
401
|
+
|
|
402
|
+
secid = section['secid']
|
|
403
|
+
content = self.create_description(section['desc'], secid, 0)
|
|
404
|
+
|
|
405
|
+
for opt in section['opts']:
|
|
406
|
+
content += self.create_option(opt, secid)
|
|
407
|
+
|
|
408
|
+
return content
|
|
409
|
+
|
|
410
|
+
#
|
|
411
|
+
# create a option html content
|
|
412
|
+
#
|
|
413
|
+
def create_option(self, opt, secid):
|
|
414
|
+
|
|
415
|
+
option = self.options[opt]
|
|
416
|
+
content = self.create_option_name(opt, option)
|
|
417
|
+
dtype = 3 if option['type'] == "Action" else 1
|
|
418
|
+
content += self.create_description(option['desc'], secid, dtype)
|
|
419
|
+
|
|
420
|
+
if 'exmidxs' in option:
|
|
421
|
+
for idx in option['exmidxs']:
|
|
422
|
+
content += self.create_example(idx, secid)
|
|
423
|
+
|
|
424
|
+
return content
|
|
425
|
+
|
|
426
|
+
#
|
|
427
|
+
# create html text for option name
|
|
428
|
+
#
|
|
429
|
+
def create_option_name(self, opt, option):
|
|
430
|
+
|
|
431
|
+
qopt = self.Q1 + opt + self.Q2
|
|
432
|
+
nopt = self.Q1 + self.OPTS[opt][1] + self.Q2
|
|
433
|
+
content = "<p><a name={}></a>{} Option -{} (-{})".format(opt, option['type'], qopt, nopt)
|
|
434
|
+
if 'alias' in option:
|
|
435
|
+
alias = option['alias']
|
|
436
|
+
acnt = len(alias)
|
|
437
|
+
s = 'es' if acnt > 1 else ''
|
|
438
|
+
for i in range(acnt):
|
|
439
|
+
content += "<tr>"
|
|
440
|
+
if i == 0:
|
|
441
|
+
content += " (Aliass: "
|
|
442
|
+
else:
|
|
443
|
+
content += ", "
|
|
444
|
+
content += "-{}{}{}".format(self.Q1, alias[i], self.Q2)
|
|
445
|
+
content += ")"
|
|
446
|
+
|
|
447
|
+
content += " :</p>\n"
|
|
448
|
+
|
|
449
|
+
return content
|
|
450
|
+
|
|
451
|
+
#
|
|
452
|
+
# create an example html content
|
|
453
|
+
#
|
|
454
|
+
def create_example(self, exmidx, secid):
|
|
455
|
+
|
|
456
|
+
example = self.examples[exmidx]
|
|
457
|
+
exm = exmidx+1
|
|
458
|
+
content = "<br><a name=\"e{}\"></a>EXAMPLE {}. {}\n".format(exm, exm, example['title'])
|
|
459
|
+
content += self.create_description(example['desc'], secid, 2)
|
|
460
|
+
|
|
461
|
+
return content
|
|
462
|
+
|
|
463
|
+
#
|
|
464
|
+
# add links to other options
|
|
465
|
+
def replace_option_link(self, line, csecid, ptype=None, dtype=None):
|
|
466
|
+
|
|
467
|
+
if ptype is None: ptype = 0
|
|
468
|
+
if dtype is None: dtype = -1
|
|
469
|
+
|
|
470
|
+
ms = re.search(r'<([=!:])>', line)
|
|
471
|
+
if ms:
|
|
472
|
+
if ms.group(1) == ":":
|
|
473
|
+
opts = re.findall(r'(^|>)([a-zA-Z]{2,})(<:)', line)
|
|
474
|
+
else:
|
|
475
|
+
opts = re.findall(r'(^)([a-zA-Z]{2,})(<%s>)/' % ms.group(1), line)
|
|
476
|
+
elif ptype == 2:
|
|
477
|
+
opts = re.findall(r'(-\(*)([a-zA-Z]{2,})(\W|$)', line)
|
|
478
|
+
ms = re.match(r'^\s*%s(\s+[\w\.]+\s+|\s+)([a-zA-Z]{2})(\s)' % self.DOCS['DOCNAM'], line)
|
|
479
|
+
if ms: opts = opts.insert(0, ms.groups())
|
|
480
|
+
else:
|
|
481
|
+
opts = re.findall(r'(^-\(*|\W-\(*)([a-zA-Z]{2,})(\W|$)', line)
|
|
482
|
+
|
|
483
|
+
if opts is None: opts = []
|
|
484
|
+
for optary in opts:
|
|
485
|
+
opt = self.get_short_option(optary[1])
|
|
486
|
+
pre = optary[0]
|
|
487
|
+
after = optary[2]
|
|
488
|
+
secid = self.options[opt]['secid']
|
|
489
|
+
if secid == csecid:
|
|
490
|
+
link = "#" + opt
|
|
491
|
+
elif self.options[opt]['type'] == "Action":
|
|
492
|
+
link = "section{}.html".format(secid)
|
|
493
|
+
elif ptype == 2 and opt == "FN":
|
|
494
|
+
link = "#field"
|
|
495
|
+
else:
|
|
496
|
+
link = "section{}.html#{}".format(secid, opt)
|
|
497
|
+
|
|
498
|
+
ms = re.search(r'-\(({}\|\w+)\)'.format(opt), line)
|
|
499
|
+
if ms:
|
|
500
|
+
if secid == csecid and ptype == 2: continue
|
|
501
|
+
opt = ms.group(1)
|
|
502
|
+
after = ')'
|
|
503
|
+
|
|
504
|
+
replace = pre + opt + after
|
|
505
|
+
if re.search(r'<!>', after): after = after.replace(r'<!>', '<!>')
|
|
506
|
+
link = "{}<a href=\"{}\">{}</a>{}".format(pre, link, opt, after)
|
|
507
|
+
line = line.replace(replace, link)
|
|
508
|
+
|
|
509
|
+
opts = re.findall(r'(^|\W){}( Options*\W|\W|$)'.format(self.SEARCH), line)
|
|
510
|
+
for optary in opts:
|
|
511
|
+
opt = optary[1]
|
|
512
|
+
if not self.SECIDS[opt]: continue
|
|
513
|
+
secid = self.SECIDS[opt]
|
|
514
|
+
if secid == csecid or re.match(r'{}'.format(secid), csecid): continue
|
|
515
|
+
pre = optary[0]
|
|
516
|
+
after = optary[2]
|
|
517
|
+
replace = pre + opt + after
|
|
518
|
+
ms = re.search(r'(\sOptions*)\W', after)
|
|
519
|
+
if ms:
|
|
520
|
+
opt += ms.group(1)
|
|
521
|
+
after = after.replace(ms.group(1), '')
|
|
522
|
+
if ptype == 2 and re.search(r'Mode Options*', opt) and dtype == 3:
|
|
523
|
+
link = "{}<a href=\"#mode\">{}</a>{}".format(pre, opt, after)
|
|
524
|
+
else:
|
|
525
|
+
link = "{}<a href=\"section{}.html\">{}</a>{}".format(pre, secid, opt, after)
|
|
526
|
+
line = line.replace(replace, link)
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
ms = re.search(r'(https*://\S+)(\.|\,)', line)
|
|
530
|
+
if ms:
|
|
531
|
+
replace = ms.group(1)
|
|
532
|
+
link = "<a href=\"{}\" target=_top>{}</a>".format(replace, replace)
|
|
533
|
+
line = line.replace(replace, link)
|
|
534
|
+
|
|
535
|
+
pattern = r"{q}(\S+){q}".format(q=re.escape(self.Q0))
|
|
536
|
+
opts = re.findall(pattern, line)
|
|
537
|
+
for opt in opts:
|
|
538
|
+
if opt not in self.EMLIST: continue # quote only predefined ones
|
|
539
|
+
replace = self.Q0+opt+self.Q0
|
|
540
|
+
if re.search(self.DOCS['DOCLNK'], opt):
|
|
541
|
+
link = "{}<a href=\"{}/internal/docs/{}\" target=_top>{}</a>{}".format(self.Q1, PgLOG.PGLOG['DSSURL'], opt, opt, self.Q2)
|
|
542
|
+
else:
|
|
543
|
+
link = self.Q1+opt+self.Q2
|
|
544
|
+
line = line.replace(replace, link)
|
|
545
|
+
|
|
546
|
+
return line
|
|
547
|
+
|
|
548
|
+
#
|
|
549
|
+
# description type (dtype): 0 - section, 1 - option, 2 - exmaple, 3 - action
|
|
550
|
+
#
|
|
551
|
+
def create_description(self, desc, secid, dtype):
|
|
552
|
+
|
|
553
|
+
if desc == "\n": return ''
|
|
554
|
+
ptype = 0 # paragraph type: 0 - normal, 1 - table, 2 - synopsys
|
|
555
|
+
content = ''
|
|
556
|
+
cnt = 0
|
|
557
|
+
alllines = re.split(r'\n', desc)
|
|
558
|
+
lines = []
|
|
559
|
+
for line in alllines:
|
|
560
|
+
if re.match(r'^\s*\S', line):
|
|
561
|
+
lines.append(line)
|
|
562
|
+
cnt += 1
|
|
563
|
+
if ptype == 0:
|
|
564
|
+
if re.search(r':\s*$', line):
|
|
565
|
+
content += self.create_paragraph(lines, cnt, secid, dtype)
|
|
566
|
+
lines = []
|
|
567
|
+
ptype = 1
|
|
568
|
+
cnt = 0
|
|
569
|
+
elif cnt == 1 and re.match(r'^\s+%s\s(-|\[|ds\d*|\d+|[A-Z]{2}\s)' % self.DOCS['DOCNAM'], line):
|
|
570
|
+
ptype = 2
|
|
571
|
+
elif cnt > 0:
|
|
572
|
+
content += self.create_desc_content(lines, cnt, secid, dtype, ptype)
|
|
573
|
+
cnt = ptype = 0
|
|
574
|
+
lines = []
|
|
575
|
+
|
|
576
|
+
if cnt > 0:
|
|
577
|
+
content += self.create_desc_content(lines, cnt, secid, dtype, ptype)
|
|
578
|
+
|
|
579
|
+
return content
|
|
580
|
+
|
|
581
|
+
#
|
|
582
|
+
# create description content according to the paragraph type
|
|
583
|
+
#
|
|
584
|
+
def create_desc_content(self, lines, cnt, secid, dtype, ptype):
|
|
585
|
+
|
|
586
|
+
if ptype == 1:
|
|
587
|
+
return self.create_table(lines, cnt, secid)
|
|
588
|
+
elif ptype == 2:
|
|
589
|
+
return self.create_synopsis(lines, cnt, secid, dtype)
|
|
590
|
+
else:
|
|
591
|
+
return self.create_paragraph(lines, cnt, secid, dtype)
|
|
592
|
+
|
|
593
|
+
#
|
|
594
|
+
# description type (dtype): 0 - section, 1 - option, 2 - exmaple, 3 - action
|
|
595
|
+
#
|
|
596
|
+
def create_paragraph(self, lines, cnt, secid, dtype):
|
|
597
|
+
|
|
598
|
+
doreplace = 1
|
|
599
|
+
content = "<p>\n"
|
|
600
|
+
line0 = lines[0]
|
|
601
|
+
normal = 1
|
|
602
|
+
if dtype == 2:
|
|
603
|
+
ms = re.match(r'^<<(Content .*)>>$', line0)
|
|
604
|
+
if ms: # input files for examples
|
|
605
|
+
content += ms.group(1) + ":\n</p><p>\n"
|
|
606
|
+
normal = 0
|
|
607
|
+
for i in range(1, cnt):
|
|
608
|
+
line = lines[i]
|
|
609
|
+
if doreplace and line.find('<:>') > -1 and not re.match(r'^[A-Z]\w+<:>[A-Z]\w+<:>', line):
|
|
610
|
+
doreplace = 0
|
|
611
|
+
if doreplace:
|
|
612
|
+
content += self.replace_option_link(line, secid, 0) + "<br>\n"
|
|
613
|
+
else:
|
|
614
|
+
content += line + "<br>\n"
|
|
615
|
+
if re.match(r'^\[\w+\]$', line): doreplace = 1
|
|
616
|
+
content += "</p>\n"
|
|
617
|
+
if normal: # normal paragraph
|
|
618
|
+
ii = 0
|
|
619
|
+
if dtype == 3:
|
|
620
|
+
if re.match(r'^\s*Mode options* that ', line0):
|
|
621
|
+
content += "<a name=\"mode\"></a>" + self.replace_option_link(line0, secid, 0) + "\n"
|
|
622
|
+
ii = 1
|
|
623
|
+
elif re.match(r'^\s*Use Info option -FN ', line0):
|
|
624
|
+
content += "<a name=\"field\"></a>" + self.replace_option_link(line0, secid, 0) + "\n"
|
|
625
|
+
ii = 1
|
|
626
|
+
for i in range(ii, cnt):
|
|
627
|
+
line = lines[i]
|
|
628
|
+
content += self.replace_option_link(line, secid, 0) + "\n"
|
|
629
|
+
content += "</p>\n"
|
|
630
|
+
|
|
631
|
+
return content
|
|
632
|
+
|
|
633
|
+
#
|
|
634
|
+
# create table html content
|
|
635
|
+
#
|
|
636
|
+
def create_table(self, lines, cnt, secid):
|
|
637
|
+
|
|
638
|
+
line0 = lines[0]
|
|
639
|
+
ms = re.match(r'^\s+-\s+(.*)', line0)
|
|
640
|
+
if ms: # create a list
|
|
641
|
+
content = "<ol>\n<li>" + self.replace_option_link(ms.group(1), secid, 1) + "\n"
|
|
642
|
+
for i in range(1, cnt):
|
|
643
|
+
line = lines[i]
|
|
644
|
+
ms = re.match(r'^\s+-\s+(.*)', line)
|
|
645
|
+
if ms:
|
|
646
|
+
content += "</li><li>" + self.replace_option_link(ms.group(1), secid, 1) + "\n"
|
|
647
|
+
else:
|
|
648
|
+
content += self.replace_option_link(line, secid, 1) + "\n"
|
|
649
|
+
content += "</li></ol>\n"
|
|
650
|
+
elif re.search(r'=>$', line0):
|
|
651
|
+
line = re.sub(r'={1,}', '=', line0)
|
|
652
|
+
content = "  {}<br>\n".format(line)
|
|
653
|
+
for i in range(1, cnt):
|
|
654
|
+
line = lines[i]
|
|
655
|
+
line = re.sub(r'={2,}', '=', line)
|
|
656
|
+
content += "  {}<br>\n".format(line)
|
|
657
|
+
else:
|
|
658
|
+
content = "<p><table border=2 cellspacing=0 cellpadding=2 bgcolor=\"#dfcfb3\">\n"
|
|
659
|
+
if re.search(r'\S\s+-\s+\S', line0):
|
|
660
|
+
vals = ['', '']
|
|
661
|
+
for i in range(cnt):
|
|
662
|
+
line = lines[i]
|
|
663
|
+
line = line.lstrip()
|
|
664
|
+
ms = re.match(r'^(.*\S)\s+-\s+(\S.*)$', line)
|
|
665
|
+
if ms:
|
|
666
|
+
vals[0] = ms.group(1)
|
|
667
|
+
vals[1] = self.replace_option_link(ms.group(2), secid, 1)
|
|
668
|
+
if re.match(r'^-', vals[0]):
|
|
669
|
+
vals[0] = self.replace_option_link(vals[0], secid, 1)
|
|
670
|
+
else:
|
|
671
|
+
vals[0] = self.get_title_link(vals[0])
|
|
672
|
+
if i > 0: content += "<tr><td align=\"right\" nowrap>{}</td><td>{}</td></tr>\n".format(vals[0], vals[1])
|
|
673
|
+
else:
|
|
674
|
+
vals[1] += "\n" + self.replace_option_link(line, secid, 1)
|
|
675
|
+
content += "<tr><td align=\"right\" nowrap>{}</td><td>{}</td></tr>\n".format(vals[0], vals[1])
|
|
676
|
+
else:
|
|
677
|
+
for i in range(cnt):
|
|
678
|
+
line = lines[i]
|
|
679
|
+
vals = re.split(r'\s{2,}', self.replace_option_link(line, secid, 1))
|
|
680
|
+
for val in vals:
|
|
681
|
+
content += "<td>{}</td>".format(val)
|
|
682
|
+
content += "</tr>\n"
|
|
683
|
+
content += "</table></p>\n"
|
|
684
|
+
|
|
685
|
+
return content
|
|
686
|
+
|
|
687
|
+
#
|
|
688
|
+
# description type (dtype): 0 - section, 1 - option, 2 - exmaple, 3 - action
|
|
689
|
+
#
|
|
690
|
+
def create_synopsis(self, lines, cnt, secid, dtype):
|
|
691
|
+
|
|
692
|
+
content = "<p><table cellspacing=10>\n"
|
|
693
|
+
|
|
694
|
+
for i in range(cnt):
|
|
695
|
+
line = self.replace_option_link(lines[i], secid, 2, dtype)
|
|
696
|
+
if re.search(r'\sor\s', line, re.I):
|
|
697
|
+
content += "<tr><td>Or</td><td> </td></tr>"
|
|
698
|
+
else:
|
|
699
|
+
ms = re.match(r'^\s*{}\s+(.+)$'.format(self.DOCS['DOCNAM']), line)
|
|
700
|
+
if ms:
|
|
701
|
+
content += "<tr><td>{}{}{}</td><td>{}</td></tr>\n".format(self.Q1, self.DOCS['DOCNAM'], self.Q2, ms.group(1))
|
|
702
|
+
else:
|
|
703
|
+
content += "<tr><td> </td><td>{}</td></tr>\n".format(line)
|
|
704
|
+
content += "</table></p>\n"
|
|
705
|
+
|
|
706
|
+
return content
|
|
707
|
+
|
|
708
|
+
#
|
|
709
|
+
# get a short option name by searching hashes OPTS and ALIAS
|
|
710
|
+
#
|
|
711
|
+
def get_short_option(self, p):
|
|
712
|
+
|
|
713
|
+
plen = len(p)
|
|
714
|
+
if plen == 2 and p in self.options: return p
|
|
715
|
+
|
|
716
|
+
for opt in self.OPTS:
|
|
717
|
+
if re.match(r'^{}$'.format(self.OPTS[opt][1]), p, re.I): return opt
|
|
718
|
+
|
|
719
|
+
for opt in self.ALIAS:
|
|
720
|
+
for alias in self.ALIAS[opt]:
|
|
721
|
+
if re.match(r'^{}$'.format(alias), p, re.I): return opt
|
|
722
|
+
|
|
723
|
+
PgLOG.pglog("{} - unknown option for {}".format(p, self.DOCS['DOCNAM']), PgLOG.LGWNEX)
|
|
724
|
+
|
|
725
|
+
#
|
|
726
|
+
# replace with link for a given section title
|
|
727
|
+
#
|
|
728
|
+
def get_title_link(self, title):
|
|
729
|
+
|
|
730
|
+
for section in self.sections:
|
|
731
|
+
if title == section['title']:
|
|
732
|
+
return "<a href=\"section{}.html\">{}</a>".format(section['secid'], title)
|
|
733
|
+
|
|
734
|
+
return title
|
|
735
|
+
|
|
736
|
+
#
|
|
737
|
+
# get section for given section id
|
|
738
|
+
#
|
|
739
|
+
def get_section(self, secid):
|
|
740
|
+
|
|
741
|
+
for section in self.sections:
|
|
742
|
+
if section['secid'] == secid: return section
|
|
743
|
+
|
|
744
|
+
PgLOG.pglog("Uknown Section ID {}".format(secid), PgLOG.LGWNEX)
|