]>
git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Tools/scripts/texcheck.py
1 """ TeXcheck.py -- rough syntax checking on Python style LaTeX documents.
3 Written by Raymond D. Hettinger <python at rcn.com>
4 Copyright (c) 2003 Python Software Foundation. All rights reserved.
6 Designed to catch common markup errors including:
7 * Unbalanced or mismatched parenthesis, brackets, and braces.
8 * Unbalanced or mismatched \\begin and \\end blocks.
9 * Misspelled or invalid LaTeX commands.
10 * Use of forward slashes instead of backslashes for commands.
11 * Table line size mismatches.
13 Sample command line usage:
14 python texcheck.py -k chapterheading -m lib/librandomtex *.tex
17 -m Munge parenthesis and brackets. [0,n) would normally mismatch.
18 -k keyword: Keyword is a valid LaTeX command. Do not include the backslash.
19 -d: Delimiter check only (useful for non-LaTeX files).
21 -s lineno: Start at lineno (useful for skipping complex sections).
22 -v: Verbose. Trace the matching of //begin and //end blocks.
28 from itertools
import izip
, count
, islice
32 \section \module \declaremodule \modulesynopsis \moduleauthor
33 \sectionauthor \versionadded \code \class \method \begin
34 \optional \var \ref \end \subsection \lineiii \hline \label
35 \indexii \textrm \ldots \keyword \stindex \index \item \note
36 \withsubitem \ttindex \footnote \citetitle \samp \opindex
37 \noindent \exception \strong \dfn \ctype \obindex \character
38 \indexiii \function \bifuncindex \refmodule \refbimodindex
39 \subsubsection \nodename \member \chapter \emph \ASCII \UNIX
40 \regexp \program \production \token \productioncont \term
41 \grammartoken \lineii \seemodule \file \EOF \documentclass
42 \usepackage \title \input \maketitle \ifhtml \fi \url \Cpp
43 \tableofcontents \kbd \programopt \envvar \refstmodindex
44 \cfunction \constant \NULL \moreargs \cfuncline \cdata
45 \textasciicircum \n \ABC \setindexsubitem \versionchanged
46 \deprecated \seetext \newcommand \POSIX \pep \warning \rfc
47 \verbatiminput \methodline \textgreater \seetitle \lineiv
48 \funclineni \ulink \manpage \funcline \dataline \unspecified
49 \textbackslash \mimetype \mailheader \seepep \textunderscore
50 \longprogramopt \infinity \plusminus \shortversion \version
51 \refmodindex \seerfc \makeindex \makemodindex \renewcommand
52 \indexname \appendix \protect \indexiv \mbox \textasciitilde
53 \platform \seeurl \leftmargin \labelwidth \localmoduletable
54 \LaTeX \copyright \memberline \backslash \pi \centerline
55 \caption \vspace \textwidth \menuselection \textless
56 \makevar \csimplemacro \menuselection \bfcode \sub \release
57 \email \kwindex \refexmodindex \filenq \e \menuselection
58 \exindex \linev \newsgroup \verbatim \setshortversion
59 \author \authoraddress \paragraph \subparagraph \cmemberline
63 def matchclose(c_lineno
, c_symbol
, openers
, pairmap
):
64 "Verify that closing delimiter matches most recent opening delimiter"
66 o_lineno
, o_symbol
= openers
.pop()
68 print "\nDelimiter mismatch. On line %d, encountered closing '%s' without corresponding open" % (c_lineno
, c_symbol
)
70 if o_symbol
in pairmap
.get(c_symbol
, [c_symbol
]): return
71 print "\nOpener '%s' on line %d was not closed before encountering '%s' on line %d" % (o_symbol
, o_lineno
, c_symbol
, c_lineno
)
74 def checkit(source
, opts
, morecmds
=[]):
75 """Check the LaTeX formatting in a sequence of lines.
77 Opts is a mapping of options to option values if any:
78 -m munge parenthesis and brackets
79 -d delimiters only checking
80 -v verbose trace of delimiter matching
81 -s lineno: linenumber to start scan (default is 1).
83 Morecmds is a sequence of LaTeX commands (without backslashes) that
84 are to be considered valid in the scan.
87 texcmd
= re
.compile(r
'\\[A-Za-z]+')
88 falsetexcmd
= re
.compile(r
'\/([A-Za-z]+)') # Mismarked with forward slash
90 validcmds
= set(cmdstr
.split())
92 validcmds
.add('\\' + cmd
)
95 pairmap
= {']':'[(', ')':'(['} # Munged openers
97 pairmap
= {']':'[', ')':'('} # Normal opener for a given closer
98 openpunct
= set('([') # Set of valid openers
100 delimiters
= re
.compile(r
'\\(begin|end){([_a-zA-Z]+)}|([()\[\]])')
101 braces
= re
.compile(r
'({)|(})')
102 doubledwords
= re
.compile(r
'(\b[A-za-z]+\b) \b\1\b')
103 spacingmarkup
= re
.compile(r
'\\(ABC|ASCII|C|Cpp|EOF|infinity|NULL|plusminus|POSIX|UNIX)\s')
105 openers
= [] # Stack of pending open delimiters
106 bracestack
= [] # Stack of pending open braces
108 tablestart
= re
.compile(r
'\\begin{(?:long)?table([iv]+)}')
109 tableline
= re
.compile(r
'\\line([iv]+){')
110 tableend
= re
.compile(r
'\\end{(?:long)?table([iv]+)}')
114 startline
= int(opts
.get('-s', '1'))
117 for lineno
, line
in izip(count(startline
), islice(source
, startline
-1, None)):
120 # Check balancing of open/close parenthesis, brackets, and begin/end blocks
121 for begend
, name
, punct
in delimiters
.findall(line
):
123 print lineno
, '|', begend
, name
, punct
,
124 if begend
== 'begin' and '-d' not in opts
:
125 openers
.append((lineno
, name
))
126 elif punct
in openpunct
:
127 openers
.append((lineno
, punct
))
128 elif begend
== 'end' and '-d' not in opts
:
129 matchclose(lineno
, name
, openers
, pairmap
)
130 elif punct
in pairmap
:
131 matchclose(lineno
, punct
, openers
, pairmap
)
133 print ' --> ', openers
135 # Balance opening and closing braces
136 for open, close
in braces
.findall(line
):
138 bracestack
.append(lineno
)
143 print r
'Warning, unmatched } on line %s.' % (lineno
,)
145 # Optionally, skip LaTeX specific checks
149 # Warn whenever forward slashes encountered with a LaTeX command
150 for cmd
in falsetexcmd
.findall(line
):
151 if '822' in line
or '.html' in line
:
152 continue # Ignore false positives for urls and for /rfc822
153 if '\\' + cmd
in validcmds
:
154 print 'Warning, forward slash used on line %d with cmd: /%s' % (lineno
, cmd
)
156 # Check for markup requiring {} for correct spacing
157 for cmd
in spacingmarkup
.findall(line
):
158 print r
'Warning, \%s should be written as \%s{} on line %d' % (cmd
, cmd
, lineno
)
161 nc
= line
.find(r
'\newcommand')
163 start
= line
.find('{', nc
)
164 end
= line
.find('}', start
)
165 validcmds
.add(line
[start
+1:end
])
166 for cmd
in texcmd
.findall(line
):
167 if cmd
not in validcmds
:
168 print r
'Warning, unknown tex cmd on line %d: \%s' % (lineno
, cmd
)
170 # Check table levels (make sure lineii only inside tableii)
171 m
= tablestart
.search(line
)
173 tablelevel
= m
.group(1)
174 tablestartline
= lineno
175 m
= tableline
.search(line
)
176 if m
and m
.group(1) != tablelevel
:
177 print r
'Warning, \line%s on line %d does not match \table%s on line %d' % (m
.group(1), lineno
, tablelevel
, tablestartline
)
178 if tableend
.search(line
):
181 # Style guide warnings
182 if 'e.g.' in line
or 'i.e.' in line
:
183 print r
'Style warning, avoid use of i.e or e.g. on line %d' % (lineno
,)
185 for dw
in doubledwords
.findall(line
):
186 print r
'Doubled word warning. "%s" on line %d' % (dw
, lineno
)
189 for lineno
, symbol
in openers
:
190 print "Unmatched open delimiter '%s' on line %d" % (symbol
, lineno
)
191 for lineno
in bracestack
:
192 print "Unmatched { on line %d" % (lineno
,)
193 print 'Done checking %d lines.' % (lastline
,)
199 optitems
, arglist
= getopt
.getopt(args
, "k:mdhs:v")
200 opts
= dict(optitems
)
201 if '-h' in opts
or args
==[]:
206 print 'Please specify a file to be checked'
209 for i
, filespec
in enumerate(arglist
):
210 if '*' in filespec
or '?' in filespec
:
211 arglist
[i
:i
+1] = glob
.glob(filespec
)
213 morecmds
= [v
for k
,v
in optitems
if k
=='-k']
216 for filename
in arglist
:
218 print "Checking", filename
222 print 'Cannot open file %s.' % arglist
[0]
226 err
.append(checkit(f
, opts
, morecmds
))
232 if __name__
== '__main__':