diff options
Diffstat (limited to 'support/pydocstrip/docstrip.py')
-rw-r--r-- | support/pydocstrip/docstrip.py | 629 |
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 |