summaryrefslogtreecommitdiff
path: root/support/pydocstrip/docstrip.py
diff options
context:
space:
mode:
Diffstat (limited to 'support/pydocstrip/docstrip.py')
-rw-r--r--support/pydocstrip/docstrip.py629
1 files changed, 629 insertions, 0 deletions
diff --git a/support/pydocstrip/docstrip.py b/support/pydocstrip/docstrip.py
new file mode 100644
index 0000000000..99a985967b
--- /dev/null
+++ b/support/pydocstrip/docstrip.py
@@ -0,0 +1,629 @@
+#!/usr/bin/env python
+import string,re,sys,stat,os,getopt,time
+
+## <VERSION
+SELF_VER = 1796
+## VERSION>
+
+SELF_INFOR = "ktv-docstrip (version Python.%d)" % SELF_VER
+GEN_DATE = "%d/%02d/%02d" % time.localtime()[:3]
+
+## :: Regular Expression
+
+## file DTX
+re_begin = re.compile("%<\*([!a-zA-Z(][()a-zA-Z0-9_|&!]*)>") # begin block
+re_end = re.compile("%</([!a-zA-Z(][()a-zA-Z0-9_|&!]*)>") # end block
+re_sblock = re.compile("%<([!a-zA-Z(][()a-zA-Z0-9_|&!]*)>(.+\n)")# inline block
+re_code = re.compile("^[^%]") # code
+
+## file KINS
+re_from = re.compile("\$from\(([^)]+)\)")
+re_gen = re.compile("\$gen\(([^)]+)\)[ ]*\(([^)]+)\)[ ]*(.*)")
+re_asg = re.compile("\$([a-z][a-z0-9_]*)[ ]*=[ ]*(.*)")
+## re_asg = re.compile("\$([a-z][a-z0-9_]*)[ ]*=[ ]*(.*)")
+re_kasg = re.compile("([a-z][a-zA-Z0-9_]*)[ ]*=[ ]*(.*)")
+re_com = re.compile("#.*") ## comment line
+re_isnum = re.compile("[+|-]*[0-9]+")
+re_local = re.compile("\$local\(([^)]+)\)")
+re_eof = re.compile("\$eof=([01])")
+## re_eoj = re.compile("\$eoj=([01])")
+re_import = re.compile("\$import\(([^)]+)\)") ## add, Ky Anh, 2003/12/25
+re_if = re.compile("\$if\(([^)]+)\)")
+re_elif = re.compile("\$elif\(([^)]+)\)")
+re_exec = re.compile("\$<<<(.*)")
+## re_expand = re.compile("\$\([a-z][a-z0-9_]*\)")
+
+def _xsplit(st):
+ """Tao list cac terminal/guard, bo qua &,|,!,(,)
+ Chi tra ve cac list chua co trong danh sach __guards ma thoi
+ """
+ ## last modify: Ky Anh, 2003/12/27
+ ## : use global __guards
+ global __guards
+ for ops in ['&', '(', ')', '!', '|', ',', ' ']:
+ st = string.replace(st, ops, ':')
+ tmp = []
+ for ops in string.split(st, ':'):
+ if (ops != '') and (not ops in __guards):
+ tmp.append(ops)
+ __guards.extend(tmp)
+ __use(tmp,0)
+
+def _translate(st): #
+ """Dich mot bieu thuc logic thanh loi chuan cua PYTHON"""
+ st = "(%s)" % st
+ idx = 0
+ tmpst = ""
+ find_next_op = 0
+ group_level = 0
+ while idx < len(st):
+ if st[idx] == '!':
+ tmpst = tmpst + "(not "
+ find_next_op = 1
+ elif st[idx] == '(':
+ tmpst = tmpst + '('
+ group_level = group_level + 1
+ elif st[idx] == ')':
+ tmpst = tmpst + ')'
+ group_level = group_level - 1
+ else: # !
+ if find_next_op:
+ while (find_next_op > 0) and (idx < len(st)):
+ if (st[idx] in __block_ops) or (group_level == 0):
+ tmpst = tmpst + ')' + st[idx]
+ find_next_op = 0
+ else:
+ tmpst = tmpst + st[idx]
+ idx = idx + 1
+ else:
+ tmpst = tmpst + st[idx]
+ idx = idx +1
+
+ idx = string.count(tmpst,'(') - string.count(tmpst,')')
+ while idx > 0 :
+ tmpst = tmpst + ')'
+ idx = idx - 1
+ return tmpst[1:-1]
+
+def __setval(guard, value=1):
+ ## add, Ky Anh, 2003/12/27
+ exec("global %s\n%s=%d" % (guard,guard,value))
+
+def __use(options, value=1):
+ ## add, Ky Anh, 2003/12/27
+ ## mod, Ky Anh, 2003/12/30, v1792, remove __alpha/__beta option check
+ for weapon in options:
+ tmpst = string.strip(weapon)
+ if tmpst: __setval(tmpst,value)
+## if tmpst in __alpha_options:
+## __setval(tmpst,1)
+## elif tmpst in __beta_options:
+## __setval(tmpst,0)
+## else:
+
+def _use(opts_string, value=1):
+ __use(string.split(opts_string, ","), value)
+
+def _do_global():
+ ## add, Ky Anh, 2003/12/27
+## _force_
+## _gonly_
+## _kins_nopre
+## _kins_nopost
+## _kins_debug
+## _kins_destdir
+## jobnames ## list of job (<kins> files)
+## __guards ## list of guard in DTX files
+## add, Ky Anh, 2003/12/27
+## NO ## list of NO-equivalent (0, No, NO, etc.)
+## __block_ops ## list of operators in a DTX guard (block)
+## __kins_vars ## list of global kins variables
+## __global_kins_vars ## kins variables that are also the global
+## variables in this program
+## __no_skip_vars ## variables appear in the third part of |$gen|
+## command; these variables arenot the <test>
+## __alpha_options ## this DTX options will always be set to 1
+## __beta_options ## - 0
+## _tex_ ## output as the INS file
+ global\
+ _force_,\
+ _gonly_,\
+ _kins_nopre,\
+ _kins_nopost,\
+ _kins_debug,\
+ _kins_destdir,\
+ jobnames,\
+ __guards,\
+ NO,\
+ __block_ops,\
+ __kins_vars,\
+ __global_kins_vars,\
+ __no_skip_vars,\
+ _tex_,\
+ _kins_pre_def,\
+ _kins_pos_def
+## __alpha_options,\
+## __beta_options
+
+ NO = ['0','no']
+
+ __block_ops = ['&','|'] ## donot accept the !. See the _translate()
+ __global_kins_vars = ["pre", "post"]
+ __no_skip_vars = ["append", "nopost", "nopre",\
+ "destdir", "source", "debug"]
+## __alpha_options = ["alpha", "com"]
+## __beta_options = []
+
+ jobnames = []
+ __guards = []
+
+ _force_ = 0
+ _gonly_ = 0
+ _tex_ = 0
+
+ ## initialize the global variables
+ ## these variable can be exported, i.e.,
+ ## we can use `--exec cmd' at command line.
+ _kins_nopre = '0'
+ _kins_nopost = '0'
+ _kins_debug = '0'
+ _kins_destdir = '.'
+ __kins_vars = ["nopre", "nopost", "destdir", "debug"]
+ _kins_pre_def = "%% This file was generate\n\
+%% \tfrom the file `$source'\n\
+%% \twith option `$option'\n\
+%% GenDate: $date\n\
+%% Generator: $generator\n"
+ _kins_pos_def = "%% End of file `$dest'"
+
+ ## init the <special> guards
+ ## we neednot do this, because if a guard appears in a DTX file
+ ## it is recognize by _xsplit and then set the value by __use
+ ## see the defintionof _xplist for more details
+ ## __use(__alpha_options + __beta_options)
+
+def _xstrip(options, debug=0):
+ """Tach ma tu file DTX voi options"""
+ global __ilines, __output
+ _use(options, 1)
+ __output = []
+ __level = 0
+ __prints = [1]
+ if debug: print "%s" % ("=" * 72),
+ for weapon in __ilines:
+ print_code = 0
+ if re_begin.match(weapon):
+ __level = __level + 1
+ if __prints[__level - 1]: # previous block
+ current_bblock = re_begin.match(weapon).group(1)
+ exec("print_code=%s" % _translate(current_bblock))
+ __prints.append(int(print_code))
+ if debug: print "\nlevel%2d %s *%s -> "\
+ % (__level,__prints,re_begin.match(weapon).group(1)),
+ elif re_end.match(weapon):
+ __level = __level - 1
+ if __level < 0: break
+ __prints.pop()
+ if debug: print "\nlevel%2d %s /%s -> "\
+ % (__level,__prints,re_end.match(weapon).group(1)),
+ elif re_sblock.match(weapon): #
+ if __prints[__level]:
+ current_bblock = re_sblock.match(weapon).group(1)
+ exec("print_code=%s" % _translate(current_bblock))
+ if debug: print "\nlevel%2d %s %s -> "\
+ % (__level,__prints,re_sblock.match(weapon).group(1)),
+ if print_code:
+ if debug: sys.stdout.write('s')
+ else: __output.append(re_sblock.match(weapon).group(2))
+ if debug:
+ print "\nlevel%2d %s -> " % (__level,__prints),
+ elif re_code.match(weapon):
+ if __prints[__level]:
+ if debug: sys.stdout.write('n')
+ else: __output.append(weapon)
+ if __level:
+ print \
+"\nThe blocks of your DTX file donot balance.\n\
+To debug, use <docstrip> with `--debug' option."
+ if debug: print "\n%s" % ("=" * 72)
+
+ _use(options, 0) # reset options' value to 0
+
+def _readkins(filename):
+ ## add, Ky Anh, 2003/12/25
+ """Read a KINS file, remove the comment line, and strip the lines.
+ This function returns a LIST of KINS lines."""
+ mykinslines = []
+ f = open(filename, 'r')
+ iline = f.readline()
+ while iline:
+ iline = re_com.split(iline)[0]
+ iline = string.strip(iline)
+ if re_eof.match(iline):
+ if re_eof.match(iline).group(1) == '1':
+ break ## reach END OF FILE
+ elif iline:
+ mykinslines.append(iline)
+ iline = f.readline()
+ f.close()
+ return mykinslines
+
+def _dokins(filename):
+ """Excute the KINS code. The original name is |_readkins|; this version
+ wasnot support |$import|. To do |$import|, a new function |_readkins| was
+ added, and this function is now named |_dokins|."""
+ global _kins_pre, _kins_post, kins_lines, _kins_pre_def, _kins_pos_def
+ kins_lines = []
+ __imported = [] # list of imported files
+
+ _kins_pre = _kins_pre_def # default preamble/
+ _kins_post = _kins_pos_def # default /postamble
+ _kins_source= ''
+
+ in_pre = in_post = 0
+ in_if = [1]
+ __iflevel = 0
+ __ifcont = []
+
+ kins_lines = _readkins(filename)
+
+ while kins_lines:
+ iline = kins_lines.pop(0)
+## :: = $if
+ if re_if.match(iline):
+ if_value = 0
+ __iflevel = __iflevel + 1
+ if in_if[__iflevel - 1]:
+ var_name = re_if.match(iline).group(1)
+ if re_kasg.match(var_name):
+ var_value = re_kasg.match(var_name).group(2)
+ var_name = re_kasg.match(var_name).group(1)
+ try:
+ if var_name in __kins_vars:
+ exec("tmp_value=_kins_%s" % var_name)
+ else:
+ exec("tmp_value=_gen_%s" % var_name)
+ if var_value == tmp_value:
+ if_value = 1
+ except NameError: pass
+ in_if.append(if_value)
+## :: = $elif
+ elif re_elif.match(iline):
+ __iflevel = __iflevel - 1
+ iline = "$if%s" % iline[5:]
+ kins_lines.insert(0, iline)
+## :: = $else
+ elif iline == "$else":
+ in_if[__iflevel] = 1 - in_if[__iflevel]
+## :: = $enif
+ elif iline == "$enif":
+ __iflevel = __iflevel - 1
+ if __iflevel < 0:
+ sys.stderr.write(\
+ "\nerror: to much $enif. The program is going to stop.\n")
+ sys.exit(1)
+ else:
+ in_if.pop()
+ if __iflevel == 0:
+ kins_lines[0:0], __ifcont = __ifcont, []
+ elif __iflevel:
+ if in_if[__iflevel]:
+ __ifcont.append(iline)
+## :: = pre, post
+ elif iline == "$pre": _kins_pre, in_pre = "", 1
+ elif iline == "$post": _kins_post, in_post = "", 1
+ elif iline == "$enpre": in_pre = 0
+ elif iline == "$enpost": in_post = 0
+## ## :: = $(.+)
+## elif re_expand.match(iline):
+## var_name = re_expand.match(iline).group(1)
+## :: = $<<<<
+ elif re_exec.match(iline):
+ try:
+ exec(re_exec.match(iline).group(1))
+ except:
+ sys.stderr.write("E")
+## :: = if in_pre, in_post
+ ## hai do`ng sau pha?i dde^? sau bo^'n do`ng tre^n
+ elif in_pre: _kins_pre = _kins_pre + iline + '\n'
+ elif in_post: _kins_post = _kins_post + iline + '\n'
+## :: = $from
+ elif re_from.match(iline): # from macro
+ _kins_source = re_from.search(iline).group(1)
+ _readsource(_kins_source)
+ sys.stderr.write('_')
+## :: = $import
+ elif re_import.match(iline):
+ _i_file = re_import.match(iline).group(1)
+ if not _i_file in __imported:
+ __imported.append(_i_file)
+ if not string.lower(_i_file[-5:]) == ".kins":
+ _i_file = _i_file + ".kins"
+ kins_lines[0:0] = _readkins(_i_file)
+ sys.stderr.write('=')
+ else:
+ sys.stderr.write('*')
+## :: = assign
+ elif re_asg.match(iline):
+ var_name = re_asg.match(iline).group(1)
+ var_value= re_asg.match(iline).group(2)
+## :: = = $docstrip
+ if var_name == 'docstrip': #
+ if SELF_VER < int(var_value):
+ sys.stderr.write(\
+"need docstrip %d or higher. Current docstrip's version: %d.\n"\
+ % (int(var_value), SELF_VER))
+ return
+## :: = = global kins variables
+ elif var_name in __global_kins_vars:
+ exec('global _kins_%s\n_kins_%s="""%s"""'\
+ % (var_name, var_name, var_value))
+## :: = = other kins variables
+ else:
+ if not var_name in __kins_vars:
+ __kins_vars.append(var_name)
+ exec('_kins_%s="""%s"""' % (var_name,var_value))
+ if var_name == 'source': _readsource(_kins_source)
+## :: = $local
+ elif re_local.match(iline):
+ zzz = re_local.match(iline).group(1)
+ if re_kasg.match(zzz):
+ var_name = re_kasg.match(zzz).group(1)
+ var_value = re_kasg.match(zzz).group(2)
+ exec('_gen_%s="""%s"""' % (var_name,var_value))
+## :: = $gen
+ elif re_gen.match(iline): # gen macro
+ gen_des = re_gen.match(iline).group(1)
+ if (not _gonly_) or (only_files.search(gen_des)):
+ gen_opt = re_gen.match(iline).group(2)
+ ## neu $gen co them tham so thu ba
+ ## tham so nay phai de trong ngoac: (.+)
+ kins_skip = 0
+ _gen_append = '0' # <initial value must be '0'>
+ _gen_nopre = _kins_nopre # get the global value
+ _gen_nopost = _kins_nopost # as the initialization
+ _gen_destdir = _kins_destdir# add 2003/12/10
+ _gen_debug = _kins_debug #
+ if re_gen.search(iline).group(3) != "":
+ gen_optlist = string.split(\
+ re_gen.search(iline).group(3)[1:-1],',')
+ for item in gen_optlist:
+ item = string.strip(item)
+ if item == "append": _gen_append = '1'
+ elif item == "nopost": _gen_nopost = '1'
+ elif item == "nopre" : _gen_nopre = '1'
+ else:
+ zzz = re_kasg.match(item)
+ if zzz:
+ var_name = zzz.group(1)
+ var_value= str(zzz.group(2))
+ if var_name in __no_skip_vars:
+ exec('_gen_%s="""%s"""' % (var_name,var_value))
+ else:
+ try:
+ if var_name in __kins_vars:
+ exec("tmp_value=_kins_%s" % var_name)
+ else:
+ exec("tmp_value=_gen_%s" % var_name)
+ if not var_value == tmp_value:
+ kins_skip = 1
+ break # break the FOR loop
+ ## donot mention other check
+ except NameError:
+ exec('_gen_%s="""%s"""' % (var_name,var_value))
+ if kins_skip:
+ sys.stderr.write('o')
+ else:
+ gen_des = "%s/%s" % (_gen_destdir, gen_des)
+ _gen(gen_des,gen_opt,\
+ _gen_append,\
+ _gen_nopre,_gen_nopost,\
+ _kins_source, _gen_debug)
+ else:
+ sys.stderr.write('o')
+## :: = anything else
+ else: pass
+ if __iflevel != 0:
+ sys.stderr.write("\nerror: missing $if or $enif\n")
+
+def _readsource(source):
+ ## last modify: Ky Anh, 2003/12/27
+ ## : according to changes of _xsplit
+ global __ilines,\
+ src_time
+ __ilines = []
+ src_time = os.stat(source)[stat.ST_MTIME]
+ f = open(source, 'r')
+ iline = f.readline() #
+ while iline:
+ if re_code.match(iline): # code
+ __ilines.append(iline)
+ elif re_begin.match(iline): # begin block
+ __ilines.append(iline)
+ _xsplit(re_begin.match(iline).group(1))
+ elif re_sblock.match(iline):# single block
+ __ilines.append(iline)
+ _xsplit(re_sblock.match(iline).group(1))
+ elif re_end.match(iline): # end block
+ __ilines.append(iline)
+ iline = f.readline()
+ f.close()
+
+def _gen(filename, opt,\
+ _gen_append='0',\
+ _gen_nopre='0', _gen_nopost='0',\
+ source_name='', _gen_debug='0'):
+
+ if not _gen_debug in NO: #yes, debug is ON
+ sys.stderr.write('-')
+ print "f(%s)s(%s)o(%s)a(%s)npre(%s)npos(%s)bug(%s)"\
+ % (filename, source_name, opt,\
+ _gen_append, _gen_nopre, _gen_nopost, _gen_debug)
+ _xstrip(opt, 1)
+ else:
+ des = string.split(filename, '/')[-1:][0]
+ try:
+ dest_time = os.stat(filename)[stat.ST_MTIME]
+ except os.error:
+ dest_time = 0
+
+ if _force_ or (src_time > dest_time):
+ try:
+ if _gen_append in NO:
+ g = open(filename, 'w')
+ sys.stderr.write('.')
+ else:
+ g = open(filename, 'a')
+ g.write('\n')
+ sys.stderr.write('+')
+ except IOError:
+ sys.stderr.write('X')
+ return
+
+ if _gen_nopre in NO:
+ global _kins_pre
+ ## expand |preample|
+ tmp__pre = string.replace(_kins_pre,"$date", GEN_DATE)
+ tmp__pre = string.replace(tmp__pre, "$c", '#')
+ tmp__pre = string.replace(tmp__pre, "$generator", SELF_INFOR)
+ tmp__pre = string.replace(tmp__pre, "$option", opt)
+ tmp__pre = string.replace(tmp__pre, "$dest", des)
+ tmp__pre = string.replace(tmp__pre, "$source", source_name)
+ g.write(tmp__pre)
+## if _tex_:
+## if tmp__pre[-1:] == '\n':
+## tmp__pre = tmp__pre[:-1]
+## print "\def\ktvpre{^^A"
+## print string.replace(tmp__pre, "\n", "^^J^^A\n"),
+## print "}\usepreamble\ktvpre"
+ _xstrip(opt, 0)
+ g.writelines(__output)
+ if _tex_:
+ print "\\generate{\\file{%s}{\\from{%s}{%s}}}"\
+ % (filename, source_name, opt)
+
+ if _gen_nopost in NO:
+ global _kins_post
+ tmp__pre = _kins_post
+ ## expand |posamble|. Only macro "$dest" is allowed.
+ tmp__pre = string.replace(_kins_post,"$dest", des)
+ tmp__pre = string.replace(tmp__pre, "$c", "#")
+ g.write(tmp__pre)# the tail
+
+ g.close()
+ os.utime(filename, (src_time, src_time))
+ else:
+ sys.stderr.write('|')
+
+def usage():
+ sys.stdout.write(\
+"""Usage: docstrip [options] file1 file2...
+ -e --exec code excute <code> before any job
+ (only the assignments are accepted)
+ -g --gen expr generate only files whose names
+ match the regular expression <expr>
+ -j --job job specify the kins file named <job>
+ (the extension `.kins' can be omitted)
+ -t --tex print the (TeX) INS code
+ -d --debug print debug information (donot generate any file)
+ -f --force force generatation (skip time check)
+ -h --help show this message
+ -v --version print version information and exit
+Report:
+ . generate sucessfully
+ + generate in `append' mode
+ o skip file (specified by <kins> file)
+ ? some things wrong occur
+ _ opening new source file
+ = importing a kins file
+ * file is already imported. Inogre it!
+ X cannot open file for writting
+ E failed on excuting embeded python code
+ | skip file (the source time <= the destination time)
+Within the `--debug' option:
+ - debugging
+ n normal code
+ s single block code
+""")
+
+if __name__ == '__main__':
+ try:
+ opts, args\
+ = getopt.getopt(sys.argv[1:],\
+ "vdhftg:e:j:",\
+ ["debug","tex","job=","version", "gen=","force","help","exec="])
+ except:
+ sys.stderr.write("Please try |docstrip.py --help|\n")
+ sys.exit(1)
+
+ _do_global()
+
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ usage()
+ sys.exit(0)
+ elif o in ("-v", "--version"):
+ sys.stdout.write("%s\n" % SELF_INFOR)
+ sys.exit(0)
+ elif o in ("-f", "--force"):
+ _force_ = 1
+ elif o in ("-t", "--tex"):
+ _tex_ = 1
+ elif o in ("-d", "--debug"):
+ _kins_debug = '1'
+ elif o in ("-g", "--gen"):
+ _gonly_ = 1
+ only_files = re.compile(a)
+ sys.stderr.write(" genonly = %s\n" % a)
+ elif o in ("-j", "--job"):
+ if not string.lower(a[-5:]) == ".kins":
+ a = a + ".kins"
+ jobnames.append(a)
+ elif o in ("-e", "--exec"):
+ a = string.split(a, ';')
+ for code in a:
+ zzz = re_kasg.match(string.strip(code))
+ if zzz:
+ var_name = zzz.group(1)
+ var_value= zzz.group(2)
+ exec('_kins_%s="""%s"""' % (var_name,var_value))
+ if not var_name in __kins_vars:
+ __kins_vars.append(var_name)
+ sys.stderr.write(" %s = %s\n" % (var_name,var_value))
+ else:
+ sys.stderr.write(" ?code: %s\n" % code)
+
+ for item in args:
+ if not string.lower(item[-5:]) == ".kins":
+ item = item + ".kins"
+ jobnames.append(item)
+
+ if jobnames == []:
+ sys.stderr.write("Please try |docstrip.py --help|\n")
+ sys.exit(1)
+
+ if _tex_:
+ print\
+"%%%% This file was generated by `%s'\n\
+%%%% from the source(s) %s\n\
+\\input docstrip.tex" % (SELF_INFOR, jobnames)
+
+ for jobname in jobnames:
+ if os.path.isfile(jobname):
+ sys.stderr.write("\n<<%s>>\n" % jobname)
+ _dokins(jobname)
+ else:
+ sys.stderr.write("\n<<%s>>: cannot open this file\n" % jobname)
+ if _tex_:
+ print "\\endbatchfile\n\\endinput\n%% End of file."
+
+ sys.stderr.write("(ok)\n")
+
+####################
+## END OF PROGRAM ##
+####################
+
+## TO DO:
+
+## 2003/12/27:
+## $if, $fi, $else, $elif