import HEAD into svn+ssh://svn.samba.org/home/svn/samba/trunk
[metze/old/v3-2-winbind-ndr.git] / source / script / genstruct.pl
1 #!/usr/bin/perl -w
2 # a simple system for generating C parse info
3 # this can be used to write generic C structer load/save routines
4 # Copyright 2002 Andrew Tridgell <genstruct@tridgell.net>
5 # released under the GNU General Public License v2 or later
6
7 use strict;
8
9 my(%enum_done) = ();
10 my(%struct_done) = ();
11
12 ###################################################
13 # general handler
14 sub handle_general($$$$$$$$)
15 {
16         my($name) = shift;
17         my($ptr_count) = shift;
18         my($size) = shift;
19         my($element) = shift;
20         my($flags) = shift;
21         my($dump_fn) = shift;
22         my($parse_fn) = shift;
23         my($tflags) = shift;
24         my($array_len) = 0;
25         my($dynamic_len) = "NULL";
26
27         # handle arrays, currently treat multidimensional arrays as 1 dimensional
28         while ($element =~ /(.*)\[(.*?)\]$/) {
29                 $element = $1;
30                 if ($array_len == 0) {
31                         $array_len = $2;
32                 } else {
33                         $array_len = "$2 * $array_len";
34                 }
35         }
36
37         if ($flags =~ /_LEN\((\w*?)\)/) {
38                 $dynamic_len = "\"$1\"";
39         }
40
41         if ($flags =~ /_NULLTERM/) {
42                 $tflags = "FLAG_NULLTERM";
43         }
44
45         print OFILE "{\"$element\", $ptr_count, $size, offsetof(struct $name, $element), $array_len, $dynamic_len, $tflags, $dump_fn, $parse_fn},\n";
46 }
47
48
49 ####################################################
50 # parse one element
51 sub parse_one($$$$)
52 {
53         my($name) = shift;
54         my($type) = shift;
55         my($element) = shift;
56         my($flags) = shift;
57         my($ptr_count) = 0;
58         my($size) = "sizeof($type)";
59         my($tflags) = "0";
60         
61         # enums get the FLAG_ALWAYS flag
62         if ($type =~ /^enum /) {
63                 $tflags = "FLAG_ALWAYS";
64         }
65
66
67         # make the pointer part of the base type 
68         while ($element =~ /^\*(.*)/) {
69                 $ptr_count++;
70                 $element = $1;
71         }
72
73         # convert spaces to _
74         $type =~ s/ /_/g;
75
76         my($dump_fn) = "gen_dump_$type";
77         my($parse_fn) = "gen_parse_$type";
78
79         handle_general($name, $ptr_count, $size, $element, $flags, $dump_fn, $parse_fn, $tflags);
80 }
81
82 ####################################################
83 # parse one element
84 sub parse_element($$$)
85 {
86         my($name) = shift;
87         my($element) = shift;
88         my($flags) = shift;
89         my($type);
90         my($data);
91
92         # pull the base type
93         if ($element =~ /^struct (\S*) (.*)/) {
94                 $type = "struct $1";
95                 $data = $2;
96         } elsif ($element =~ /^enum (\S*) (.*)/) {
97                 $type = "enum $1";
98                 $data = $2;
99         } elsif ($element =~ /^unsigned (\S*) (.*)/) {
100                 $type = "unsigned $1";
101                 $data = $2;
102         } elsif ($element =~ /^(\S*) (.*)/) {
103                 $type = $1;
104                 $data = $2;
105         } else {
106                 die "Can't parse element '$element'";
107         }
108
109         # handle comma separated lists 
110         while ($data =~ /(\S*),[\s]?(.*)/) {
111                 parse_one($name, $type, $1, $flags);
112                 $data = $2;
113         }
114         parse_one($name, $type, $data, $flags);
115 }
116
117
118 my($first_struct) = 1;
119
120 ####################################################
121 # parse the elements of one structure
122 sub parse_elements($$)
123 {
124         my($name) = shift;
125         my($elements) = shift;
126
127         if ($first_struct) {
128                 $first_struct = 0;
129                 print "Parsing structs: $name";
130         } else {
131                 print ", $name";
132         }
133
134         print OFILE "int gen_dump_struct_$name(TALLOC_CTX *mem_ctx, struct parse_string *, const char *, unsigned);\n";
135         print OFILE "int gen_parse_struct_$name(TALLOC_CTX *mem_ctx, char *, const char *);\n";
136
137         print OFILE "static const struct parse_struct pinfo_" . $name . "[] = {\n";
138
139
140         while ($elements =~ /^.*?([a-z].*?);\s*?(\S*?)\s*?$(.*)/msi) {
141                 my($element) = $1;
142                 my($flags) = $2;
143                 $elements = $3;
144                 parse_element($name, $element, $flags);
145         }
146
147         print OFILE "{NULL, 0, 0, 0, 0, NULL, 0, NULL, NULL}};\n";
148
149         print OFILE "
150 int gen_dump_struct_$name(TALLOC_CTX *mem_ctx, struct parse_string *p, const char *ptr, unsigned indent) {
151         return gen_dump_struct(mem_ctx, pinfo_$name, p, ptr, indent);
152 }
153 int gen_parse_struct_$name(TALLOC_CTX *mem_ctx, char *ptr, const char *str) {
154         return gen_parse_struct(mem_ctx, pinfo_$name, ptr, str);
155 }
156
157 ";
158 }
159
160 my($first_enum) = 1;
161
162 ####################################################
163 # parse out the enum declarations
164 sub parse_enum_elements($$)
165 {
166         my($name) = shift;
167         my($elements) = shift;
168
169         if ($first_enum) {
170                 $first_enum = 0;
171                 print "Parsing enums: $name";
172         } else {
173                 print ", $name";
174         }
175
176         print OFILE "static const struct enum_struct einfo_" . $name . "[] = {\n";
177
178         my(@enums) = split(/,/s, $elements);
179         for (my($i)=0; $i <= $#{@enums}; $i++) {
180                 my($enum) = $enums[$i];
181                 if ($enum =~ /\s*(\w*)/) {
182                         my($e) = $1;
183                         print OFILE "{\"$e\", $e},\n";
184                 }
185         }
186
187         print OFILE "{NULL, 0}};\n";
188
189         print OFILE "
190 int gen_dump_enum_$name(struct parse_string *p, const char *ptr, unsigned indent) {
191         return gen_dump_enum(einfo_$name, p, ptr, indent);
192 }
193
194 int gen_parse_enum_$name(char *ptr, const char *str) {
195         return gen_parse_enum(einfo_$name, ptr, str);
196 }
197
198 ";
199 }
200
201 ####################################################
202 # parse out the enum declarations
203 sub parse_enums($)
204 {
205         my($data) = shift;
206
207         while ($data =~ /^GENSTRUCT\s+enum\s+(\w*?)\s*{(.*?)}\s*;(.*)/ms) {
208                 my($name) = $1;
209                 my($elements) = $2;
210                 $data = $3;
211
212                 if (!defined($enum_done{$name})) {
213                         $enum_done{$name} = 1;
214                         parse_enum_elements($name, $elements);
215                 }
216         }
217
218         if (! $first_enum) {
219                 print "\n";
220         }
221 }
222
223 ####################################################
224 # parse all the structures
225 sub parse_structs($)
226 {
227         my($data) = shift;
228
229         # parse into structures 
230         while ($data =~ /^GENSTRUCT\s+struct\s+(\w+?)\s*{\s*(.*?)\s*}\s*;(.*)/ms) {
231                 my($name) = $1;
232                 my($elements) = $2;
233                 $data = $3;
234                 if (!defined($struct_done{$name})) {
235                         $struct_done{$name} = 1;
236                         parse_elements($name, $elements);
237                 }
238         }
239
240         if (! $first_struct) {
241                 print "\n";
242         } else {
243                 print "No GENSTRUCT structures found?\n";
244         }
245 }
246
247
248 ####################################################
249 # parse a header file, generating a dumper structure
250 sub parse_data($)
251 {
252         my($data) = shift;
253
254         # collapse spaces 
255         $data =~ s/[\t ]+/ /sg;
256         $data =~ s/\s*\n\s+/\n/sg;
257         # strip debug lines
258         $data =~ s/^\#.*?\n//smg;
259
260         parse_enums($data);
261         parse_structs($data);
262 }
263
264
265 #########################################
266 # display help text
267 sub ShowHelp()
268 {
269     print "
270 generator for C structure dumpers
271 Copyright Andrew Tridgell <genstruct\@tridgell.net>
272
273 Sample usage:
274    genstruct -o output.h gcc -E -O2 -g test.h
275
276 Options:
277     --help                this help page
278     -o OUTPUT             place output in OUTPUT
279 ";
280     exit(0);
281 }
282
283 ########################################
284 # main program
285 if ($ARGV[0] ne "-o" || $#ARGV < 2) {
286         ShowHelp();
287 }
288
289 shift;
290 my($opt_ofile)=shift;
291
292 print "creating $opt_ofile\n";
293
294 open(OFILE, ">$opt_ofile") || die "can't open $opt_ofile";    
295
296 print OFILE "/* This is an automatically generated file - DO NOT EDIT! */\n\n";
297
298 parse_data(`@ARGV -DGENSTRUCT=GENSTRUCT`);
299 exit(0);