style.py (7827:49b7d40ee88a) style.py (7828:817c662677d1)
1#! /usr/bin/env python
2# Copyright (c) 2006 The Regents of The University of Michigan
3# Copyright (c) 2007 The Hewlett-Packard Development Company
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met: redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer;
10# redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the
12# documentation and/or other materials provided with the distribution;
13# neither the name of the copyright holders nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29# Authors: Nathan Binkert
30
31import re
32import os
33import sys
34
35sys.path.insert(0, os.path.dirname(__file__))
36
37from file_types import lang_type
38
39tabsize = 8
40lead = re.compile(r'^([ \t]+)')
41trail = re.compile(r'([ \t]+)$')
42any_control = re.compile(r'\b(if|while|for)[ \t]*[(]')
43good_control = re.compile(r'\b(if|while|for) [(]')
44
45whitespace_types = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons'))
46format_types = set(('C', 'C++'))
47
48def checkwhite_line(line):
49 match = lead.search(line)
50 if match and match.group(1).find('\t') != -1:
51 return False
52
53 match = trail.search(line)
54 if match:
55 return False
56
57 return True
58
59def checkwhite(filename):
60 if lang_type(filename) not in whitespace_types:
61 return
62
63 try:
64 f = file(filename, 'r+')
65 except OSError, msg:
66 print 'could not open file %s: %s' % (filename, msg)
67 return
68
69 for num,line in enumerate(f):
70 if not checkwhite_line(line):
71 yield line,num + 1
72
73def fixwhite_line(line):
74 if lead.search(line):
75 newline = ''
76 for i,c in enumerate(line):
77 if c == ' ':
78 newline += ' '
79 elif c == '\t':
80 newline += ' ' * (tabsize - len(newline) % tabsize)
81 else:
82 newline += line[i:]
83 break
84
85 line = newline
86
87 return line.rstrip() + '\n'
88
89def fixwhite(filename, fixonly=None):
90 if lang_type(filename) not in whitespace_types:
91 return
92
93 try:
94 f = file(filename, 'r+')
95 except OSError, msg:
96 print 'could not open file %s: %s' % (filename, msg)
97 return
98
99 lines = list(f)
100
101 f.seek(0)
102 f.truncate()
103
104 for i,line in enumerate(lines):
105 if fixonly is None or i in fixonly:
106 line = fixwhite_line(line, tabsize)
107
108 print >>f, line,
109
110def linelen(line):
111 tabs = line.count('\t')
112 if not tabs:
113 return len(line)
114
115 count = 0
116 for c in line:
117 if c == '\t':
118 count += tabsize - count % tabsize
119 else:
120 count += 1
121
122 return count
123
124class ValidationStats(object):
125 def __init__(self):
126 self.toolong = 0
127 self.toolong80 = 0
128 self.leadtabs = 0
129 self.trailwhite = 0
130 self.badcontrol = 0
131 self.cret = 0
132
133 def dump(self):
134 print '''\
135%d violations of lines over 79 chars. %d of which are 80 chars exactly.
136%d cases of whitespace at the end of a line.
137%d cases of tabs to indent.
138%d bad parens after if/while/for.
139%d carriage returns found.
140''' % (self.toolong, self.toolong80, self.trailwhite, self.leadtabs,
141 self.badcontrol, self.cret)
142
143 def __nonzero__(self):
144 return self.toolong or self.toolong80 or self.leadtabs or \
145 self.trailwhite or self.badcontrol or self.cret
146
147def validate(filename, stats, verbose, exit_code):
148 if lang_type(filename) not in format_types:
149 return
150
151 def msg(lineno, line, message):
152 print '%s:%d>' % (filename, lineno + 1), message
153 if verbose > 2:
154 print line
155
156 def bad():
157 if exit_code is not None:
158 sys.exit(exit_code)
159
160 try:
161 f = file(filename, 'r')
162 except OSError:
163 if verbose > 0:
164 print 'could not open file %s' % filename
165 bad()
166 return
167
168 for i,line in enumerate(f):
169 line = line.rstrip('\n')
170
171 # no carriage returns
172 if line.find('\r') != -1:
173 self.cret += 1
174 if verbose > 1:
175 msg(i, line, 'carriage return found')
176 bad()
177
178 # lines max out at 79 chars
179 llen = linelen(line)
180 if llen > 79:
181 stats.toolong += 1
182 if llen == 80:
183 stats.toolong80 += 1
184 if verbose > 1:
185 msg(i, line, 'line too long (%d chars)' % llen)
186 bad()
187
188 # no tabs used to indent
189 match = lead.search(line)
190 if match and match.group(1).find('\t') != -1:
191 stats.leadtabs += 1
192 if verbose > 1:
193 msg(i, line, 'using tabs to indent')
194 bad()
195
196 # no trailing whitespace
197 if trail.search(line):
198 stats.trailwhite +=1
199 if verbose > 1:
200 msg(i, line, 'trailing whitespace')
201 bad()
202
203 # for c++, exactly one space betwen if/while/for and (
204 if cpp:
205 match = any_control.search(line)
206 if match and not good_control.search(line):
207 stats.badcontrol += 1
208 if verbose > 1:
209 msg(i, line, 'improper spacing after %s' % match.group(1))
210 bad()
211
212def modified_lines(old_data, new_data, max_lines):
213 from itertools import count
214 from mercurial import bdiff, mdiff
215
216 modified = set()
217 counter = count()
218 for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data):
219 for i in counter:
220 if i < fbeg:
221 modified.add(i)
222 elif i + 1 >= fend:
223 break
224 elif i > max_lines:
225 break
226 return modified
227
228def do_check_style(ui, repo, *files, **args):
229 """check files for proper m5 style guidelines"""
230 from mercurial import mdiff, util
231
232 if files:
233 files = frozenset(files)
234
235 def skip(name):
236 return files and name in files
237
238 def prompt(name, func, fixonly=None):
239 if args.get('auto', False):
240 result = 'f'
241 else:
242 while True:
243 result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", default='a')
244 if result in 'aif':
245 break
246
247 if result == 'a':
248 return True
249 elif result == 'f':
250 func(repo.wjoin(name), fixonly)
251
252 return False
253
254 modified, added, removed, deleted, unknown, ignore, clean = repo.status()
255
256 for fname in added:
257 if skip(fname):
258 continue
259
260 ok = True
261 for line,num in checkwhite(repo.wjoin(fname)):
262 ui.write("invalid whitespace in %s:%d\n" % (fname, num))
263 if ui.verbose:
264 ui.write(">>%s<<\n" % line[-1])
265 ok = False
266
267 if not ok:
268 if prompt(fname, fixwhite):
269 return True
270
271 try:
272 wctx = repo.workingctx()
273 except:
274 from mercurial import context
275 wctx = context.workingctx(repo)
276
277 for fname in modified:
278 if skip(fname):
279 continue
280
281 if lang_type(fname) not in whitespace_types:
282 continue
283
284 fctx = wctx.filectx(fname)
285 pctx = fctx.parents()
286
287 file_data = fctx.data()
288 lines = mdiff.splitnewlines(file_data)
289 if len(pctx) in (1, 2):
290 mod_lines = modified_lines(pctx[0].data(), file_data, len(lines))
291 if len(pctx) == 2:
292 m2 = modified_lines(pctx[1].data(), file_data, len(lines))
293 # only the lines that are new in both
294 mod_lines = mod_lines & m2
295 else:
296 mod_lines = xrange(0, len(lines))
297
298 fixonly = set()
299 for i,line in enumerate(lines):
300 if i not in mod_lines:
301 continue
302
303 if checkwhite_line(line):
304 continue
305
306 ui.write("invalid whitespace: %s:%d\n" % (fname, i+1))
307 if ui.verbose:
308 ui.write(">>%s<<\n" % line[:-1])
309 fixonly.add(i)
310
311 if fixonly:
312 if prompt(fname, fixonly):
313 return True
314
315def do_check_format(ui, repo, **args):
316 modified, added, removed, deleted, unknown, ignore, clean = repo.status()
317
318 verbose = 0
319 stats = ValidationStats()
320 for f in modified + added:
321 validate(f, stats, verbose, None)
322
323 if stats:
324 stats.dump()
325 result = ui.prompt("invalid formatting\n(i)gnore or (a)bort?",
326 "^[ia]$", "a")
327 if result.startswith('i'):
328 pass
329 elif result.startswith('a'):
330 return True
331 else:
332 raise util.Abort(_("Invalid response: '%s'") % result)
333
334 return False
335
336def check_hook(hooktype):
337 if hooktype not in ('pretxncommit', 'pre-qrefresh'):
338 raise AttributeError, \
339 "This hook is not meant for %s" % hooktype
340
341def check_style(ui, repo, hooktype, **kwargs):
342 check_hook(hooktype)
343 args = {}
1#! /usr/bin/env python
2# Copyright (c) 2006 The Regents of The University of Michigan
3# Copyright (c) 2007 The Hewlett-Packard Development Company
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are
8# met: redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer;
10# redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the
12# documentation and/or other materials provided with the distribution;
13# neither the name of the copyright holders nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29# Authors: Nathan Binkert
30
31import re
32import os
33import sys
34
35sys.path.insert(0, os.path.dirname(__file__))
36
37from file_types import lang_type
38
39tabsize = 8
40lead = re.compile(r'^([ \t]+)')
41trail = re.compile(r'([ \t]+)$')
42any_control = re.compile(r'\b(if|while|for)[ \t]*[(]')
43good_control = re.compile(r'\b(if|while|for) [(]')
44
45whitespace_types = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons'))
46format_types = set(('C', 'C++'))
47
48def checkwhite_line(line):
49 match = lead.search(line)
50 if match and match.group(1).find('\t') != -1:
51 return False
52
53 match = trail.search(line)
54 if match:
55 return False
56
57 return True
58
59def checkwhite(filename):
60 if lang_type(filename) not in whitespace_types:
61 return
62
63 try:
64 f = file(filename, 'r+')
65 except OSError, msg:
66 print 'could not open file %s: %s' % (filename, msg)
67 return
68
69 for num,line in enumerate(f):
70 if not checkwhite_line(line):
71 yield line,num + 1
72
73def fixwhite_line(line):
74 if lead.search(line):
75 newline = ''
76 for i,c in enumerate(line):
77 if c == ' ':
78 newline += ' '
79 elif c == '\t':
80 newline += ' ' * (tabsize - len(newline) % tabsize)
81 else:
82 newline += line[i:]
83 break
84
85 line = newline
86
87 return line.rstrip() + '\n'
88
89def fixwhite(filename, fixonly=None):
90 if lang_type(filename) not in whitespace_types:
91 return
92
93 try:
94 f = file(filename, 'r+')
95 except OSError, msg:
96 print 'could not open file %s: %s' % (filename, msg)
97 return
98
99 lines = list(f)
100
101 f.seek(0)
102 f.truncate()
103
104 for i,line in enumerate(lines):
105 if fixonly is None or i in fixonly:
106 line = fixwhite_line(line, tabsize)
107
108 print >>f, line,
109
110def linelen(line):
111 tabs = line.count('\t')
112 if not tabs:
113 return len(line)
114
115 count = 0
116 for c in line:
117 if c == '\t':
118 count += tabsize - count % tabsize
119 else:
120 count += 1
121
122 return count
123
124class ValidationStats(object):
125 def __init__(self):
126 self.toolong = 0
127 self.toolong80 = 0
128 self.leadtabs = 0
129 self.trailwhite = 0
130 self.badcontrol = 0
131 self.cret = 0
132
133 def dump(self):
134 print '''\
135%d violations of lines over 79 chars. %d of which are 80 chars exactly.
136%d cases of whitespace at the end of a line.
137%d cases of tabs to indent.
138%d bad parens after if/while/for.
139%d carriage returns found.
140''' % (self.toolong, self.toolong80, self.trailwhite, self.leadtabs,
141 self.badcontrol, self.cret)
142
143 def __nonzero__(self):
144 return self.toolong or self.toolong80 or self.leadtabs or \
145 self.trailwhite or self.badcontrol or self.cret
146
147def validate(filename, stats, verbose, exit_code):
148 if lang_type(filename) not in format_types:
149 return
150
151 def msg(lineno, line, message):
152 print '%s:%d>' % (filename, lineno + 1), message
153 if verbose > 2:
154 print line
155
156 def bad():
157 if exit_code is not None:
158 sys.exit(exit_code)
159
160 try:
161 f = file(filename, 'r')
162 except OSError:
163 if verbose > 0:
164 print 'could not open file %s' % filename
165 bad()
166 return
167
168 for i,line in enumerate(f):
169 line = line.rstrip('\n')
170
171 # no carriage returns
172 if line.find('\r') != -1:
173 self.cret += 1
174 if verbose > 1:
175 msg(i, line, 'carriage return found')
176 bad()
177
178 # lines max out at 79 chars
179 llen = linelen(line)
180 if llen > 79:
181 stats.toolong += 1
182 if llen == 80:
183 stats.toolong80 += 1
184 if verbose > 1:
185 msg(i, line, 'line too long (%d chars)' % llen)
186 bad()
187
188 # no tabs used to indent
189 match = lead.search(line)
190 if match and match.group(1).find('\t') != -1:
191 stats.leadtabs += 1
192 if verbose > 1:
193 msg(i, line, 'using tabs to indent')
194 bad()
195
196 # no trailing whitespace
197 if trail.search(line):
198 stats.trailwhite +=1
199 if verbose > 1:
200 msg(i, line, 'trailing whitespace')
201 bad()
202
203 # for c++, exactly one space betwen if/while/for and (
204 if cpp:
205 match = any_control.search(line)
206 if match and not good_control.search(line):
207 stats.badcontrol += 1
208 if verbose > 1:
209 msg(i, line, 'improper spacing after %s' % match.group(1))
210 bad()
211
212def modified_lines(old_data, new_data, max_lines):
213 from itertools import count
214 from mercurial import bdiff, mdiff
215
216 modified = set()
217 counter = count()
218 for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data):
219 for i in counter:
220 if i < fbeg:
221 modified.add(i)
222 elif i + 1 >= fend:
223 break
224 elif i > max_lines:
225 break
226 return modified
227
228def do_check_style(ui, repo, *files, **args):
229 """check files for proper m5 style guidelines"""
230 from mercurial import mdiff, util
231
232 if files:
233 files = frozenset(files)
234
235 def skip(name):
236 return files and name in files
237
238 def prompt(name, func, fixonly=None):
239 if args.get('auto', False):
240 result = 'f'
241 else:
242 while True:
243 result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", default='a')
244 if result in 'aif':
245 break
246
247 if result == 'a':
248 return True
249 elif result == 'f':
250 func(repo.wjoin(name), fixonly)
251
252 return False
253
254 modified, added, removed, deleted, unknown, ignore, clean = repo.status()
255
256 for fname in added:
257 if skip(fname):
258 continue
259
260 ok = True
261 for line,num in checkwhite(repo.wjoin(fname)):
262 ui.write("invalid whitespace in %s:%d\n" % (fname, num))
263 if ui.verbose:
264 ui.write(">>%s<<\n" % line[-1])
265 ok = False
266
267 if not ok:
268 if prompt(fname, fixwhite):
269 return True
270
271 try:
272 wctx = repo.workingctx()
273 except:
274 from mercurial import context
275 wctx = context.workingctx(repo)
276
277 for fname in modified:
278 if skip(fname):
279 continue
280
281 if lang_type(fname) not in whitespace_types:
282 continue
283
284 fctx = wctx.filectx(fname)
285 pctx = fctx.parents()
286
287 file_data = fctx.data()
288 lines = mdiff.splitnewlines(file_data)
289 if len(pctx) in (1, 2):
290 mod_lines = modified_lines(pctx[0].data(), file_data, len(lines))
291 if len(pctx) == 2:
292 m2 = modified_lines(pctx[1].data(), file_data, len(lines))
293 # only the lines that are new in both
294 mod_lines = mod_lines & m2
295 else:
296 mod_lines = xrange(0, len(lines))
297
298 fixonly = set()
299 for i,line in enumerate(lines):
300 if i not in mod_lines:
301 continue
302
303 if checkwhite_line(line):
304 continue
305
306 ui.write("invalid whitespace: %s:%d\n" % (fname, i+1))
307 if ui.verbose:
308 ui.write(">>%s<<\n" % line[:-1])
309 fixonly.add(i)
310
311 if fixonly:
312 if prompt(fname, fixonly):
313 return True
314
315def do_check_format(ui, repo, **args):
316 modified, added, removed, deleted, unknown, ignore, clean = repo.status()
317
318 verbose = 0
319 stats = ValidationStats()
320 for f in modified + added:
321 validate(f, stats, verbose, None)
322
323 if stats:
324 stats.dump()
325 result = ui.prompt("invalid formatting\n(i)gnore or (a)bort?",
326 "^[ia]$", "a")
327 if result.startswith('i'):
328 pass
329 elif result.startswith('a'):
330 return True
331 else:
332 raise util.Abort(_("Invalid response: '%s'") % result)
333
334 return False
335
336def check_hook(hooktype):
337 if hooktype not in ('pretxncommit', 'pre-qrefresh'):
338 raise AttributeError, \
339 "This hook is not meant for %s" % hooktype
340
341def check_style(ui, repo, hooktype, **kwargs):
342 check_hook(hooktype)
343 args = {}
344 return do_check_style(ui, repo, **args)
345
344
345 try:
346 return do_check_style(ui, repo, **args)
347 except Exception, e:
348 import traceback
349 traceback.print_exc()
350 return True
351
346def check_format(ui, repo, hooktype, **kwargs):
347 check_hook(hooktype)
348 args = {}
352def check_format(ui, repo, hooktype, **kwargs):
353 check_hook(hooktype)
354 args = {}
349 return do_check_format(ui, repo, **args)
350
355
356 try:
357 return do_check_format(ui, repo, **args)
358 except Exception, e:
359 import traceback
360 traceback.print_exc()
361 return True
362
351try:
352 from mercurial.i18n import _
353except ImportError:
354 def _(arg):
355 return arg
356
357cmdtable = {
358 '^m5style' :
359 ( do_check_style,
360 [ ('a', 'auto', False, _("automatically fix whitespace")) ],
361 _('hg m5style [-a] [FILE]...')),
362 '^m5format' :
363 ( do_check_format,
364 [ ],
365 _('hg m5format [FILE]...')),
366}
367
368if __name__ == '__main__':
369 import getopt
370
371 progname = sys.argv[0]
372 if len(sys.argv) < 2:
373 sys.exit('usage: %s <command> [<command args>]' % progname)
374
375 fixwhite_usage = '%s fixwhite [-t <tabsize> ] <path> [...] \n' % progname
376 chkformat_usage = '%s chkformat <path> [...] \n' % progname
377 chkwhite_usage = '%s chkwhite <path> [...] \n' % progname
378
379 command = sys.argv[1]
380 if command == 'fixwhite':
381 flags = 't:'
382 usage = fixwhite_usage
383 elif command == 'chkwhite':
384 flags = 'nv'
385 usage = chkwhite_usage
386 elif command == 'chkformat':
387 flags = 'nv'
388 usage = chkformat_usage
389 else:
390 sys.exit(fixwhite_usage + chkwhite_usage + chkformat_usage)
391
392 opts, args = getopt.getopt(sys.argv[2:], flags)
393
394 code = 1
395 verbose = 1
396 for opt,arg in opts:
397 if opt == '-n':
398 code = None
399 if opt == '-t':
400 tabsize = int(arg)
401 if opt == '-v':
402 verbose += 1
403
404 if command == 'fixwhite':
405 for filename in args:
406 fixwhite(filename, tabsize)
407 elif command == 'chkwhite':
408 for filename in args:
409 for line,num in checkwhite(filename):
410 print 'invalid whitespace: %s:%d' % (filename, num)
411 if verbose:
412 print '>>%s<<' % line[:-1]
413 elif command == 'chkformat':
414 stats = ValidationStats()
415 for filename in args:
416 validate(filename, stats=stats, verbose=verbose, exit_code=code)
417
418 if verbose > 0:
419 stats.dump()
420 else:
421 sys.exit("command '%s' not found" % command)
363try:
364 from mercurial.i18n import _
365except ImportError:
366 def _(arg):
367 return arg
368
369cmdtable = {
370 '^m5style' :
371 ( do_check_style,
372 [ ('a', 'auto', False, _("automatically fix whitespace")) ],
373 _('hg m5style [-a] [FILE]...')),
374 '^m5format' :
375 ( do_check_format,
376 [ ],
377 _('hg m5format [FILE]...')),
378}
379
380if __name__ == '__main__':
381 import getopt
382
383 progname = sys.argv[0]
384 if len(sys.argv) < 2:
385 sys.exit('usage: %s <command> [<command args>]' % progname)
386
387 fixwhite_usage = '%s fixwhite [-t <tabsize> ] <path> [...] \n' % progname
388 chkformat_usage = '%s chkformat <path> [...] \n' % progname
389 chkwhite_usage = '%s chkwhite <path> [...] \n' % progname
390
391 command = sys.argv[1]
392 if command == 'fixwhite':
393 flags = 't:'
394 usage = fixwhite_usage
395 elif command == 'chkwhite':
396 flags = 'nv'
397 usage = chkwhite_usage
398 elif command == 'chkformat':
399 flags = 'nv'
400 usage = chkformat_usage
401 else:
402 sys.exit(fixwhite_usage + chkwhite_usage + chkformat_usage)
403
404 opts, args = getopt.getopt(sys.argv[2:], flags)
405
406 code = 1
407 verbose = 1
408 for opt,arg in opts:
409 if opt == '-n':
410 code = None
411 if opt == '-t':
412 tabsize = int(arg)
413 if opt == '-v':
414 verbose += 1
415
416 if command == 'fixwhite':
417 for filename in args:
418 fixwhite(filename, tabsize)
419 elif command == 'chkwhite':
420 for filename in args:
421 for line,num in checkwhite(filename):
422 print 'invalid whitespace: %s:%d' % (filename, num)
423 if verbose:
424 print '>>%s<<' % line[:-1]
425 elif command == 'chkformat':
426 stats = ValidationStats()
427 for filename in args:
428 validate(filename, stats=stats, verbose=verbose, exit_code=code)
429
430 if verbose > 0:
431 stats.dump()
432 else:
433 sys.exit("command '%s' not found" % command)