2ac80029270aa4b89214da90150ccb297f744d37
[samba.git] / source4 / scripting / bin / gen_hresult.py
1 #!/usr/bin/env python3
2
3 #
4 # Unix SMB/CIFS implementation.
5 #
6 # HRESULT Error definitions
7 #
8 # Copyright (C) Noel Power <noel.power@suse.com> 2014
9 #
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 3 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License
21 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 #
23
24
25 import sys
26 from gen_error_common import parseErrorDescriptions
27
28 def write_license(out_file):
29     out_file.write("/*\n")
30     out_file.write(" * Unix SMB/CIFS implementation.\n")
31     out_file.write(" *\n")
32     out_file.write(" * HRESULT Error definitions\n")
33     out_file.write(" *\n")
34     out_file.write(" * Copyright (C) Noel Power <noel.power@suse.com> 2014\n")
35     out_file.write(" *\n")
36     out_file.write(" * This program is free software; you can redistribute it and/or modify\n")
37     out_file.write(" * it under the terms of the GNU General Public License as published by\n")
38     out_file.write(" * the Free Software Foundation; either version 3 of the License, or\n")
39     out_file.write(" * (at your option) any later version.\n")
40     out_file.write(" *\n")
41     out_file.write(" * This program is distributed in the hope that it will be useful,\n")
42     out_file.write(" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n")
43     out_file.write(" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n")
44     out_file.write(" * GNU General Public License for more details.\n")
45     out_file.write(" *\n")
46     out_file.write(" * You should have received a copy of the GNU General Public License\n")
47     out_file.write(" * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n")
48     out_file.write(" */\n")
49     out_file.write("\n")
50
51 def generateHeaderFile(out_file, errors):
52     write_license(out_file)
53     out_file.write("#ifndef _HRESULT_H_\n")
54     out_file.write("#define _HRESULT_H_\n\n")
55     macro_magic = "#if defined(HAVE_IMMEDIATE_STRUCTURES)\n"
56     macro_magic += "typedef struct {uint32_t h;} HRESULT;\n"
57     macro_magic += "#define HRES_ERROR(x) ((HRESULT) { x })\n"
58     macro_magic += "#define HRES_ERROR_V(x) ((x).h)\n"
59     macro_magic += "#else\n"
60     macro_magic += "typedef uint32_t HRESULT;\n"
61     macro_magic += "#define HRES_ERROR(x) (x)\n"
62     macro_magic += "#define HRES_ERROR_V(x) (x)\n"
63     macro_magic += "#endif\n"
64     macro_magic += "\n"
65     macro_magic += "#define HRES_IS_OK(x) (HRES_ERROR_V(x) == 0)\n"
66     macro_magic += "#define HRES_IS_EQUAL(x,y) (HRES_ERROR_V(x) == HRES_ERROR_V(y))\n"
67
68     out_file.write(macro_magic)
69     out_file.write("\n\n")
70     out_file.write("/*\n")
71     out_file.write(" * The following error codes are autogenerated from [MS-ERREF]\n")
72     out_file.write(" * see http://msdn.microsoft.com/en-us/library/cc704587.aspx\n")
73     out_file.write(" */\n")
74     out_file.write("\n")
75
76     for err in errors:
77         line = "#define {0:49} HRES_ERROR(0x{1:08X})\n".format(err.err_define ,err.err_code)
78         out_file.write(line)
79     out_file.write("\nconst char *hresult_errstr_const(HRESULT err_code);\n")
80     out_file.write("\nconst char *hresult_errstr(HRESULT err_code);\n")
81     out_file.write("\n#define FACILITY_WIN32 0x0007\n")
82     out_file.write("#define WIN32_FROM_HRESULT(x) (HRES_ERROR_V(x) == 0 ? HRES_ERROR_V(x) : ~((FACILITY_WIN32 << 16) | 0x80000000) & HRES_ERROR_V(x))\n")
83     out_file.write("#define HRESULT_IS_LIKELY_WERR(x) ((HRES_ERROR_V(x) & 0xFFFF0000) == 0x80070000)\n")
84     out_file.write("#define HRESULT_FROM_WERROR(x) (HRES_ERROR(0x80070000 | W_ERROR_V(x)))\n")
85     out_file.write("\n\n\n#endif /*_HRESULT_H_*/")
86
87
88 def generateSourceFile(out_file, errors):
89     write_license(out_file)
90     out_file.write("#include \"includes.h\"\n")
91     out_file.write("#include \"hresult.h\"\n")
92     out_file.write("/*\n")
93     out_file.write(" * The following error codes and descriptions are autogenerated from [MS-ERREF]\n")
94     out_file.write(" * see http://msdn.microsoft.com/en-us/library/cc704587.aspx\n")
95     out_file.write(" */\n")
96     out_file.write("\n")
97     out_file.write("static const struct {\n")
98     out_file.write("    HRESULT error_code;\n")
99     out_file.write("    const char *error_str;\n")
100     out_file.write("    const char *error_message;\n")
101     out_file.write("} hresult_errs[] = {\n")
102
103     for err in errors:
104         out_file.write("        {\n")
105         if err.isWinError:
106             out_file.write("            HRESULT_FROM_WIN32(%s),\n"%err.err_define)
107             out_file.write("            \"HRESULT_FROM_WIN32(%s)\",\n"%err.err_define)
108         else:
109             out_file.write("            %s,\n"%err.err_define)
110             out_file.write("            \"%s\",\n"%err.err_define)
111         out_file.write("                \"%s\"\n"%err.err_string)
112         out_file.write("        },\n")
113     out_file.write("};\n")
114     out_file.write("\n")
115     out_file.write("const char *hresult_errstr_const(HRESULT err_code)\n")
116     out_file.write("{\n")
117     out_file.write("    const char *result = NULL;\n")
118     out_file.write("    size_t i;\n")
119     out_file.write("    for (i = 0; i < ARRAY_SIZE(hresult_errs); ++i) {\n")
120     out_file.write("            if (HRES_IS_EQUAL(err_code, hresult_errs[i].error_code)) {\n")
121     out_file.write("                    result = hresult_errs[i].error_message;\n")
122     out_file.write("                    break;\n")
123     out_file.write("            }\n")
124     out_file.write("    }\n")
125     out_file.write("    /* convert & check win32 error space? */\n")
126     out_file.write("    if (result == NULL && HRESULT_IS_LIKELY_WERR(err_code)) {\n")
127     out_file.write("            WERROR wErr = W_ERROR(WIN32_FROM_HRESULT(err_code));\n")
128     out_file.write("            result = get_friendly_werror_msg(wErr);\n")
129     out_file.write("    }\n")
130     out_file.write("    return result;\n")
131     out_file.write("};\n")
132     out_file.write("\n")
133     out_file.write("const char *hresult_errstr(HRESULT err_code)\n")
134     out_file.write("{\n")
135     out_file.write("    static char msg[22];\n")
136     out_file.write("    size_t i;\n")
137     out_file.write("\n")
138     out_file.write("    for (i = 0; i < ARRAY_SIZE(hresult_errs); i++) {\n")
139     out_file.write("            if (HRES_IS_EQUAL(err_code, hresult_errs[i].error_code)) {\n")
140     out_file.write("                    return hresult_errs[i].error_str;\n")
141     out_file.write("            }\n")
142     out_file.write("    }\n")
143     out_file.write("    snprintf(msg, sizeof(msg), \"HRES code 0x%08x\", HRES_ERROR_V(err_code));\n")
144     out_file.write("    return msg;\n")
145     out_file.write("};\n")
146
147 def generatePythonFile(out_file, errors):
148     out_file.write("/*\n")
149     out_file.write(" * Errors generated from\n")
150     out_file.write(" * [MS-ERREF] http://msdn.microsoft.com/en-us/library/cc704587.aspx\n")
151     out_file.write(" */\n")
152     out_file.write("#include \"lib/replace/system/python.h\"\n")
153     out_file.write("#include \"python/py3compat.h\"\n")
154     out_file.write("#include \"includes.h\"\n\n")
155     out_file.write("static struct PyModuleDef moduledef = {\n")
156     out_file.write("\tPyModuleDef_HEAD_INIT,\n")
157     out_file.write("\t.m_name = \"hresult\",\n")
158     out_file.write("\t.m_doc = \"HRESULT defines\",\n")
159     out_file.write("\t.m_size = -1,\n")
160     out_file.write("\t};\n\n")
161     out_file.write("MODULE_INIT_FUNC(hresult)\n")
162     out_file.write("{\n")
163     out_file.write("\tPyObject *m = NULL;\n")
164     out_file.write("\tPyObject *py_obj = NULL;\n")
165     out_file.write("\tint ret;\n\n")
166     out_file.write("\tm = PyModule_Create(&moduledef);\n")
167     out_file.write("\tif (m == NULL) {\n")
168     out_file.write("\t\treturn NULL;\n")
169     out_file.write("\t}\n\n")
170     for err in errors:
171         out_file.write(f"\tpy_obj = PyLong_FromUnsignedLongLong(HRES_ERROR_V({err.err_define}));\n")
172         out_file.write(f"\tret = PyModule_AddObject(m, \"{err.err_define}\", py_obj);\n")
173         out_file.write("\tif (ret) {\n")
174         out_file.write("\t\tPy_XDECREF(py_obj);\n")
175         out_file.write("\t\tPy_DECREF(m);\n")
176         out_file.write("\t\treturn NULL;\n")
177         out_file.write("\t}\n")
178     out_file.write("\n")
179     out_file.write("\treturn m;\n")
180     out_file.write("}\n")
181
182 def transformErrorName(error_name):
183     return "HRES_" + error_name
184
185 # Very simple script to generate files hresult.c & hresult.h
186 # This script takes four inputs:
187 # [1]: The name of the text file which is the content of an HTML table
188 #      (such as that found at https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/705fb797-2175-4a90-b5a3-3918024b10b8)
189 #      copied and pasted.
190 # [2]: The name of the output generated header file with HResult #defines
191 # [3]: The name of the output generated source file with C arrays
192 # [4]: The name of the output generated python file
193
194 def main ():
195     input_file1 = None
196
197     if len(sys.argv) == 5:
198         input_file1 =  sys.argv[1]
199         gen_headerfile_name = sys.argv[2]
200         gen_sourcefile_name = sys.argv[3]
201         gen_pythonfile_name = sys.argv[4]
202     else:
203         print("usage: %s winerrorfile headerfile sourcefile pythonfile"%(sys.argv[0]))
204         sys.exit()
205
206     # read in the data
207     with open(input_file1) as file_contents:
208         errors = parseErrorDescriptions(file_contents, False, transformErrorName)
209
210     print(f"writing new header file: {gen_headerfile_name}")
211     with open(gen_headerfile_name,"w") as out_file:
212         generateHeaderFile(out_file, errors)
213     print(f"writing new source file: {gen_sourcefile_name}")
214     with open(gen_sourcefile_name,"w") as out_file:
215         generateSourceFile(out_file, errors)
216     print(f"writing new python file: {gen_pythonfile_name}")
217     with open(gen_pythonfile_name,"w") as out_file:
218         generatePythonFile(out_file, errors)
219
220 if __name__ == '__main__':
221
222     main()