2 # -*- coding: utf-8 -*-
3 # extrace_texi_filenames.py
5 # USAGE: extract_texi_filenames.py [-o OUTDIR] FILES
7 # -o OUTDIR specifies that output files should rather be written in OUTDIR
10 # This script parses the .texi file given and creates a file with the
11 # nodename <=> filename/anchor map.
12 # The idea behind: Unnumbered subsections go into the same file as the
13 # previous numbered section, @translationof gives the original node name,
14 # which is then used for the filename/anchor.
16 # If this script is run on a file texifile.texi, it produces a file
17 # texifile_xref.map with tab-separated entries of the form
18 # NODE\tFILENAME\tANCHOR
19 # Note: The filename does not have any extension appended!
20 # This file can then be used by our texi2html init script to determine
21 # the correct file name and anchor for external refs
30 optlist, args = getopt.getopt (sys.argv[1:],'o:')
38 include_re = re.compile (r'@include ((?!../lily-).*?)\.texi$', re.M)
39 whitespaces = re.compile (r'\s+')
40 section_translation_re = re.compile (r'@(node|(?:unnumbered|appendix)(?:(?:sub){0,2}sec)?|top|chapter|(?:sub){0,2}section|(?:major|chap|(?:sub){0,2})heading|translationof) (.*?)\n')
42 def expand_includes (m, filename):
43 filepath = os.path.join (os.path.dirname (filename), m.group(1)) + '.texi'
44 if os.path.exists (filepath):
45 return extract_sections (filepath)
47 print "Unable to locate include file " + filepath
50 def extract_sections (filename):
52 f = open (filename, 'r')
55 # Replace all includes by their list of sections and extract all sections
56 page = include_re.sub (lambda m: expand_includes (m, filename), page)
57 sections = section_translation_re.findall (page)
59 result += "@" + sec[0] + " " + sec[1] + "\n"
62 # Convert a given node name to its proper file name (normalization as explained
63 # in the texinfo manual:
64 # http://www.gnu.org/software/texinfo/manual/texinfo/html_node/HTML-Xref-Node-Name-Expansion.html
65 def texinfo_file_name(title):
66 # exception: The top node is always mapped to index.html
69 # File name normalization by texinfo (described in the texinfo manual):
70 # 1/2: letters and numbers are left unchanged
71 # 3/4: multiple, leading and trailing whitespace is removed
72 title = title.strip ();
73 title = whitespaces.sub (' ', title)
74 # 5: all remaining spaces are converted to '-'
75 # 6: all other 7- or 8-bit chars are replaced by _xxxx (xxxx=ascii character code)
77 for index in range(len(title)):
79 if char == ' ': # space -> '-'
81 elif ( ('0' <= char and char <= '9' ) or
82 ('A' <= char and char <= 'Z' ) or
83 ('a' <= char and char <= 'z' ) ): # number or letter
88 result += "_%04x" % ccode
90 result += "__%06x" % ccode
91 # 7: if name begins with number, prepend 't_g' (so it starts with a letter)
92 if ord(result[0]) in range (ord('0'), ord('9')):
93 result = 't_g' + result
96 texinfo_re = re.compile (r'@.*{(.*)}')
97 def remove_texinfo (title):
98 return texinfo_re.sub (r'\1', title)
100 def create_texinfo_anchor (title):
101 return texinfo_file_name (remove_texinfo (title))
103 unnumbered_re = re.compile (r'unnumbered.*')
104 def process_sections (filename, page):
105 sections = section_translation_re.findall (page)
106 # TODO: Don't rely on the file having a 4-letter extension (texi)!!!
107 p = os.path.join (outdir, filename) [:-5] + '_xref.map'
113 this_unnumbered = False
116 # Write out the cached values to the file and start a new section:
118 f.write (this_title + "\t" + this_filename + "\t" + this_anchor + "\n")
119 this_title = remove_texinfo (sec[1])
120 this_anchor = create_texinfo_anchor (sec[1])
121 elif sec[0] == "translationof":
122 anchor = create_texinfo_anchor (sec[1])
123 # If @translationof is used, it gives the original node name, which
124 # we use for the anchor and the file name (if it is a numbered node)
126 if not this_unnumbered:
127 this_filename = anchor
129 # unnumbered nodes use the previously used file name, only numbered
130 # nodes get their own filename!
131 this_unnumbered = unnumbered_re.match (sec[0])
132 if not this_unnumbered:
133 this_filename = this_anchor
136 f.write (this_title + "\t" + this_filename + "\t" + this_anchor + "\n")
140 for filename in files:
141 print "extract_texi_filenames.py: Processing %s" % filename
142 sections = extract_sections (filename)
143 process_sections (filename, sections)