mirror of
https://github.com/samba-team/samba.git
synced 2024-12-27 03:21:53 +03:00
fb13eb7db8
I think this is a better location for this script. Since the subdirectory "script" of "source4" contains only scripts for "make install" and "make uninstall".
362 lines
13 KiB
Python
Executable File
362 lines
13 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
# Unix SMB/CIFS implementation.
|
|
# Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2009
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
"""Import generete werror.h/doserr.c files from WSPP HTML"""
|
|
|
|
import re
|
|
import os
|
|
import sys
|
|
import urllib
|
|
import pprint
|
|
from xml.dom import minidom
|
|
from optparse import OptionParser, OptionGroup
|
|
|
|
_wspp_werror_url = 'http://msdn.microsoft.com/en-us/library/cc231199%28PROT.10%29.aspx'
|
|
|
|
class WerrorHtmlParser(object):
|
|
"""
|
|
Parses HTML from WSPP documentation generating dictionary of
|
|
dictionaries with following keys:
|
|
- "err_hex" - hex number (as string)
|
|
- "err_name" - error name
|
|
- "err_desc" - error long description
|
|
For the key of returned dictionary err_hex is used,
|
|
i.e. "hex-error-code-str" => {error dictionary object}
|
|
"""
|
|
|
|
ERROR_PREFIX = ['ERROR_', 'NERR_', 'FRS_', 'RPC_', 'EPT_', 'OR_', 'WAIT_TIMEOUT']
|
|
ERROR_REPLACE = ['ERROR_']
|
|
|
|
def __init__(self, opt):
|
|
self.opt = opt
|
|
self._errors_skipped = []
|
|
pass
|
|
|
|
def _is_error_code_name(self, err_name):
|
|
for pref in self.ERROR_PREFIX:
|
|
if err_name.startswith(pref):
|
|
return True
|
|
return False
|
|
|
|
def _make_werr_name(self, err_name):
|
|
err_name = err_name.upper()
|
|
for pref in self.ERROR_REPLACE:
|
|
if err_name.startswith(pref):
|
|
return err_name.replace(pref, 'WERR_', 1)
|
|
return 'WERR_' + err_name
|
|
|
|
def parse_url(self, url):
|
|
errors = {}
|
|
html = self._load_url(url)
|
|
|
|
# let minidom to parse the tree, should be:
|
|
# table -> tr -> td
|
|
# p -> [hex code, br, error code]
|
|
# p -> [description]
|
|
table_node = minidom.parseString(html)
|
|
for row_node in table_node.getElementsByTagName("tr"):
|
|
# verify we got right number of td elements
|
|
td_nodes = row_node.getElementsByTagName('td')
|
|
if len(td_nodes) != 2:
|
|
continue
|
|
# now get the real data
|
|
p_nodes = row_node.getElementsByTagName('p')
|
|
if len(p_nodes) != 2: continue
|
|
if len(p_nodes[0].childNodes) != 3: continue
|
|
if len(p_nodes[1].childNodes) != 1: continue
|
|
err_hex = str(p_nodes[0].childNodes[0].nodeValue)
|
|
err_name = str(p_nodes[0].childNodes[2].nodeValue)
|
|
err_desc = p_nodes[1].childNodes[0].nodeValue.encode('utf-8')
|
|
err_desc = err_desc.replace('"', '\\"').replace("\'", "\\'")
|
|
# do some checking
|
|
if not err_hex.startswith('0x'): continue
|
|
if not self._is_error_code_name(err_name):
|
|
self._errors_skipped.append("%s - %s - %d" % (err_name, err_hex, int(err_hex, 16)))
|
|
continue
|
|
# create entry
|
|
err_name = self._make_werr_name(err_name)
|
|
err_def = {'err_hex': err_hex,
|
|
'err_name': err_name,
|
|
'err_desc': err_desc,
|
|
'code': int(err_hex, 16)}
|
|
errors[err_def['code']] = err_def
|
|
|
|
# print skipped errors
|
|
if self.opt.print_skipped and len(self._errors_skipped):
|
|
print "\nErrors skipped during HTML parsing:"
|
|
pprint.pprint(self._errors_skipped)
|
|
print "\n"
|
|
|
|
return errors
|
|
|
|
def _load_url(self, url):
|
|
html_str = ""
|
|
try:
|
|
fp = urllib.urlopen(url)
|
|
for line in fp:
|
|
html_str += line.strip()
|
|
fp.close()
|
|
except IOError, e:
|
|
print "error loading url: " + e.strerror
|
|
pass
|
|
|
|
# currently ERROR codes are rendered as table
|
|
# locate table chunk with ERROR_SUCCESS
|
|
html = [x for x in html_str.split('<table ') if "ERROR_SUCCESS" in x]
|
|
html = '<table ' + html[0]
|
|
pos = html.find('</table>')
|
|
if pos == -1:
|
|
return '';
|
|
html = html[:pos] + '</table>'
|
|
|
|
# html clean up
|
|
html = re.sub(r'<a[^>]*>(.*?)</a>', r'\1', html)
|
|
|
|
return html
|
|
|
|
|
|
class WerrorGenerator(object):
|
|
"""
|
|
provides methods to generate parts of werror.h and doserr.c files
|
|
"""
|
|
|
|
FNAME_WERRORS = 'w32errors.lst'
|
|
FNAME_WERROR_DEFS = 'werror_defs.h'
|
|
FNAME_DOSERR_DEFS = 'doserr_defs.c'
|
|
FNAME_DOSERR_DESC = 'doserr_desc.c'
|
|
|
|
def __init__(self, opt):
|
|
self.opt = opt
|
|
self._out_dir = opt.out_dir
|
|
pass
|
|
|
|
def _open_out_file(self, fname):
|
|
fname = os.path.join(self._out_dir, fname)
|
|
return open(fname, "w")
|
|
|
|
def _gen_werrors_list(self, errors):
|
|
"""uses 'errors' dictionary to display list of Win32 Errors"""
|
|
|
|
fp = self._open_out_file(self.FNAME_WERRORS)
|
|
for err_code in sorted(errors.keys()):
|
|
err_name = errors[err_code]['err_name']
|
|
fp.write(err_name)
|
|
fp.write("\n")
|
|
fp.close()
|
|
|
|
def _gen_werror_defs(self, errors):
|
|
"""uses 'errors' dictionary to generate werror.h file"""
|
|
|
|
fp = self._open_out_file(self.FNAME_WERROR_DEFS)
|
|
for err_code in sorted(errors.keys()):
|
|
err_name = errors[err_code]['err_name']
|
|
err_hex = errors[err_code]['err_hex']
|
|
fp.write('#define %s\tW_ERROR(%s)' % (err_name, err_hex))
|
|
fp.write("\n")
|
|
fp.close()
|
|
|
|
def _gen_doserr_defs(self, errors):
|
|
"""uses 'errors' dictionary to generate defines in doserr.c file"""
|
|
|
|
fp = self._open_out_file(self.FNAME_DOSERR_DEFS)
|
|
for err_code in sorted(errors.keys()):
|
|
err_name = errors[err_code]['err_name']
|
|
fp.write('\t{ "%s", %s },' % (err_name, err_name))
|
|
fp.write("\n")
|
|
fp.close()
|
|
|
|
def _gen_doserr_descriptions(self, errors):
|
|
"""uses 'errors' dictionary to generate descriptions in doserr.c file"""
|
|
|
|
fp = self._open_out_file(self.FNAME_DOSERR_DESC)
|
|
for err_code in sorted(errors.keys()):
|
|
err_name = errors[err_code]['err_name']
|
|
fp.write('\t{ %s, "%s" },' % (err_name, errors[err_code]['err_desc']))
|
|
fp.write("\n")
|
|
fp.close()
|
|
|
|
def _lookup_error_by_name(self, err_name, defined_errors):
|
|
for err in defined_errors.itervalues():
|
|
if err['err_name'] == err_name:
|
|
return err
|
|
return None
|
|
|
|
def _filter_errors(self, errors, defined_errors):
|
|
"""
|
|
returns tuple (new_erros, diff_code_errors, diff_name_errors)
|
|
new_errors - dictionary of errors not in defined_errors
|
|
diff_code_errors - list of errors found in defined_errors
|
|
but with different value
|
|
diff_name_errors - list of errors found with same code in
|
|
defined_errors, but with different name
|
|
Most critical is diff_code_errors list to be empty!
|
|
"""
|
|
new_errors = {}
|
|
diff_code_errors = []
|
|
diff_name_errors = []
|
|
for err_def in errors.itervalues():
|
|
add_error = True
|
|
# try get defined error by code
|
|
if defined_errors.has_key(err_def['code']):
|
|
old_err = defined_errors[err_def['code']]
|
|
if err_def['err_name'] != old_err['err_name']:
|
|
warning = {'msg': 'New and Old errors has different error names',
|
|
'err_new': err_def,
|
|
'err_old': old_err}
|
|
diff_name_errors.append(warning)
|
|
|
|
# sanity check for errors with same name but different values
|
|
old_err = self._lookup_error_by_name(err_def['err_name'], defined_errors)
|
|
if old_err:
|
|
if err_def['code'] != old_err['code']:
|
|
warning = {'msg': 'New and Old error defs has different error value',
|
|
'err_new': err_def,
|
|
'err_old': old_err}
|
|
diff_code_errors.append(warning)
|
|
# exclude error already defined with same name
|
|
add_error = False
|
|
# do add the error in new_errors if everything is fine
|
|
if add_error:
|
|
new_errors[err_def['code']] = err_def
|
|
pass
|
|
return (new_errors, diff_code_errors, diff_name_errors)
|
|
|
|
def generate(self, errors):
|
|
# load already defined error codes
|
|
werr_parser = WerrorParser(self.opt)
|
|
(defined_errors,
|
|
no_value_errors) = werr_parser.load_err_codes(self.opt.werror_file)
|
|
if not defined_errors:
|
|
print "\nUnable to load existing errors file: %s" % self.opt.werror_file
|
|
sys.exit(1)
|
|
if self.opt.verbose and len(no_value_errors):
|
|
print "\nWarning: there are errors defines using macro value:"
|
|
pprint.pprint(no_value_errors)
|
|
print ""
|
|
# filter generated error codes
|
|
(new_errors,
|
|
diff_code_errors,
|
|
diff_name_errors) = self._filter_errors(errors, defined_errors)
|
|
if diff_code_errors:
|
|
print("\nFound %d errors with same names but different error values! Aborting."
|
|
% len(diff_code_errors))
|
|
pprint.pprint(diff_code_errors)
|
|
sys.exit(2)
|
|
|
|
if diff_name_errors:
|
|
print("\nFound %d errors with same values but different names (should be normal)"
|
|
% len(diff_name_errors))
|
|
pprint.pprint(diff_name_errors)
|
|
|
|
# finally generate output files
|
|
self._gen_werror_defs(new_errors)
|
|
self._gen_doserr_defs(new_errors)
|
|
self._gen_werrors_list(errors)
|
|
self._gen_doserr_descriptions(errors)
|
|
pass
|
|
|
|
class WerrorParser(object):
|
|
"""
|
|
Parses errors defined in werror.h file
|
|
"""
|
|
|
|
def __init__(self, opt):
|
|
self.opt = opt
|
|
pass
|
|
|
|
def _parse_werror_line(self, line):
|
|
m = re.match('#define[ \t]*(.*?)[ \t]*W_ERROR\((.*?)\)', line)
|
|
if not m or (len(m.groups()) != 2):
|
|
return None
|
|
if len(m.group(1)) == 0:
|
|
return None
|
|
if str(m.group(2)).startswith('0x'):
|
|
err_code = int(m.group(2), 16)
|
|
elif m.group(2).isdigit():
|
|
err_code = int(m.group(2))
|
|
else:
|
|
self.err_no_values.append(line)
|
|
return None
|
|
return {'err_name': str(m.group(1)),
|
|
'err_hex': "0x%08X" % err_code,
|
|
'code': err_code}
|
|
pass
|
|
|
|
def load_err_codes(self, fname):
|
|
"""
|
|
Returns tuple of:
|
|
dictionary of "hex_err_code" => {code, name}
|
|
"hex_err_code" is string
|
|
"code" is int value for the error
|
|
list of errors that was ignored for some reason
|
|
"""
|
|
# reset internal variables
|
|
self.err_no_values = []
|
|
err_codes = {}
|
|
fp = open(fname)
|
|
for line in fp.readlines():
|
|
err_def = self._parse_werror_line(line)
|
|
if err_def:
|
|
err_codes[err_def['code']] = err_def
|
|
fp.close();
|
|
return (err_codes, self.err_no_values)
|
|
|
|
|
|
|
|
def _generate_files(opt):
|
|
parser = WerrorHtmlParser(opt)
|
|
errors = parser.parse_url(opt.url)
|
|
|
|
out = WerrorGenerator(opt)
|
|
out.generate(errors)
|
|
pass
|
|
|
|
|
|
if __name__ == '__main__':
|
|
_cur_dir = os.path.abspath(os.path.dirname(__file__))
|
|
opt_parser = OptionParser(usage="usage: %prog [options]", version="%prog 0.3")
|
|
opt_group = OptionGroup(opt_parser, "Main options")
|
|
opt_group.add_option("--url", dest="url",
|
|
default=_wspp_werror_url,
|
|
help="url for w32 error codes html - may be local file")
|
|
opt_group.add_option("--out", dest="out_dir",
|
|
default=_cur_dir,
|
|
help="output dir for generated files")
|
|
opt_group.add_option("--werror", dest="werror_file",
|
|
default=os.path.join(_cur_dir, 'werror.h'),
|
|
help="path to werror.h file")
|
|
opt_group.add_option("--print_skipped",
|
|
action="store_true", dest="print_skipped", default=False,
|
|
help="print errors skipped during HTML parsing")
|
|
opt_group.add_option("-q", "--quiet",
|
|
action="store_false", dest="verbose", default=True,
|
|
help="don't print warnings to stdout")
|
|
|
|
opt_parser.add_option_group(opt_group)
|
|
|
|
(options, args) = opt_parser.parse_args()
|
|
|
|
# add some options to be used internally
|
|
options.err_defs_file = os.path.join(options.out_dir, WerrorGenerator.FNAME_WERROR_DEFS)
|
|
options.dos_defs_file = os.path.join(options.out_dir, WerrorGenerator.FNAME_DOSERR_DEFS)
|
|
options.dos_desc_file = os.path.join(options.out_dir, WerrorGenerator.FNAME_DOSERR_DESC)
|
|
|
|
# check options
|
|
_generate_files(options)
|