]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/makedevops.pl
This commit was generated by cvs2svn to compensate for changes in r52878,
[FreeBSD/FreeBSD.git] / sys / kern / makedevops.pl
1 #!/usr/bin/perl
2 #
3 # Copyright (c) 1992, 1993
4 #        The Regents of the University of California.  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
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 # 3. All advertising materials mentioning features or use of this software
15 #    must display the following acknowledgement:
16 #        This product includes software developed by the University of
17 #        California, Berkeley and its contributors.
18 # 4. Neither the name of the University nor the names of its contributors
19 #    may be used to endorse or promote products derived from this software
20 #    without specific prior written permission.
21 #
22 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 # ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 # SUCH DAMAGE.
33 #
34 # From @(#)vnode_if.sh        8.1 (Berkeley) 6/10/93
35 # From @(#)makedevops.sh 1.1 1998/06/14 13:53:12 dfr Exp $
36 # From @(#)makedevops.sh ?.? 1998/10/05
37 #
38 # $FreeBSD$
39
40 #
41 # Script to produce device front-end sugar.
42 #
43
44 $debug = 0;
45 $cfile = 0;          # by default do not produce any file type
46 $hfile = 0;
47
48 $keepcurrentdir = 1;
49
50 $line_width = 80;
51
52 # Process the command line
53 #
54 while ( $arg = shift @ARGV ) {
55    if ( $arg eq '-c' ) {
56       warn "Producing .c output files"
57          if $debug;
58       $cfile = 1;
59    } elsif ( $arg eq '-h' ) {
60       warn "Producing .h output files"
61          if $debug;
62       $hfile = 1;
63    } elsif ( $arg eq '-ch' || $arg eq '-hc' ) {
64       warn "Producing .c and .h output files"
65          if $debug;
66       $cfile = 1;
67       $hfile = 1;
68    } elsif ( $arg eq '-d' ) {
69       $debug = 1;
70    } elsif ( $arg eq '-p' ) {
71       warn "Will produce files in original not in current directory"
72          if $debug;
73       $keepcurrentdir = 0;
74    } elsif ( $arg eq '-l' ) {
75       if ( $line_width = shift @ARGV and $line_width > 0 ) {
76          warn "Line width set to $line_width"
77             if $debug;
78       } else {
79          die "Please specify a valid line width after -l";
80       }
81    } elsif ( $arg =~ m/\.m$/ ) {
82       warn "Filename: $arg"
83          if $debug;
84       push @filenames, $arg;
85    } else {
86       warn "$arg ignored"
87          if $debug;
88    }
89 }
90
91
92 # Validate the command line parameters
93 #
94 die "usage: $0 [-d] [-p] [-c|-h] srcfile
95 where -c   produce only .c files
96       -h   produce only .h files
97       -p   use the path component in the source file for destination dir
98       -l   set line width for output files [80]
99       -d   switch on debugging
100 "
101         unless ($cfile or $hfile)
102            and $#filenames != -1;
103
104 # FIXME should be able to do this more easily
105 #
106 $tmpdir = $ENV{'TMPDIR'};           # environment variables
107 $tmpdir = $ENV{'TMP'}
108    if !$tmpdir;
109 $tmpdir = $ENV{'TEMP'}
110    if !$tmpdir;
111 $tmpdir = '/tmp'                    # look for a physical directory
112    if !$tmpdir and -d '/tmp';
113 $tmpdir = '/usr/tmp'
114    if !$tmpdir and -d '/usr/tmp';
115 $tmpdir = '/var/tmp'
116    if !$tmpdir and -d '/var/tmp';
117 $tmpdir = '.'                       # give up and use current dir
118    if !$tmpdir;
119
120 foreach $src ( @filenames ) {
121    # Names of the created files
122    $ctmpname = "$tmpdir/ctmp.$$";
123    $htmpname = "$tmpdir/htmp.$$";
124
125    ($name, $path, $suffix) = &fileparse($src, '.m');
126    $path = '.'
127       if $keepcurrentdir;
128    $cfilename="$path/$name.c";
129    $hfilename="$path/$name.h";
130
131    warn "Processing from $src to $cfile / $hfile via $ctmp / $htmp"
132       if $debug;
133
134    die "Could not open $src, $!"
135       if !open SRC, "$src";
136    die "Could not open $ctmpname, $!"
137       if $cfile and !open CFILE, ">$ctmpname";
138    die "Could not open $htmpname, $!"
139       if $hfile and !open HFILE, ">$htmpname";
140
141    if ( $cfile ) {
142       # Produce the header of the C file
143       #
144       print CFILE "/*\n";
145       print CFILE " * This file is produced automatically.\n";
146       print CFILE " * Do not modify anything in here by hand.\n";
147       print CFILE " *\n";
148       print CFILE " * Created from\n";
149       print CFILE " *   $src\n";
150       print CFILE " * with\n";
151       print CFILE " *   $0\n";
152       print CFILE " */\n";
153       print CFILE "\n";
154       print CFILE "#include <sys/param.h>\n";
155       print CFILE "#include <sys/queue.h>\n";
156       print CFILE "#include <sys/sysctl.h>\n";
157       print CFILE "#include <sys/bus_private.h>\n";
158    }
159
160    if ( $hfile ) {
161       # Produce the header of the H file
162       #
163       print HFILE "/*\n";
164       print HFILE " * This file is produced automatically.\n";
165       print HFILE " * Do not modify anything in here by hand.\n";
166       print HFILE " *\n";
167       print HFILE " * Created from\n";
168       print HFILE " *   $src\n";
169       print HFILE " * with\n";
170       print HFILE " *   $0\n";
171       print HFILE " */\n";
172       print HFILE "\n";
173    }
174
175    %methods = ();    # clear list of methods
176    $lineno = 0;
177    $error = 0;       # to signal clean up and gerror setting
178
179    LINE: while ( $line = <SRC> ) {
180       $lineno++;
181
182       # take special notice of include directives.
183       #
184       if ( $line =~ m/^#\s*include\s+(["<])([^">]+)([">]).*/i ) {
185          warn "Included file: $1$2" . ($1 eq '<'? '>':'"')
186             if $debug;
187          print CFILE "#include $1$2" . ($1 eq '<'? '>':'"') . "\n"
188             if $cfile;
189       }
190
191       $line =~ s/#.*//;                # remove comments
192       $line =~ s/^\s+//;               # remove leading ...
193       $line =~ s/\s+$//;               # remove trailing whitespace
194
195       if ( $line =~ m/^$/ ) {          # skip empty lines
196          # nop
197
198       } elsif ( $line =~ m/^INTERFACE\s*([^\s;]*)(\s*;?)/i ) {
199          $intname = $1;
200          $semicolon = $2;
201          unless ( $intname =~ m/^[a-z_][a-z0-9_]*$/ ) {
202             warn $line
203                if $debug;
204             warn "$src:$lineno: Invalid interface name '$intname', use [a-z_][a-z0-9_]*";
205             $error = 1;
206             last LINE;
207          }
208
209          warn "$src:$lineno: semicolon missing at end of line, no problem"
210             if $semicolon !~ s/;$//;
211
212          warn "Interface $intname"
213             if $debug;
214
215          print HFILE '#ifndef _'.$intname."_if_h_\n"
216             if $hfile;
217          print HFILE '#define _'.$intname."_if_h_\n\n"
218             if $hfile;
219          print CFILE '#include "'.$intname.'_if.h"'."\n\n"
220             if $cfile;
221
222       } elsif ( $line =~ m/^CODE\s*{$/i ) {
223          $code = "";
224          $line = <SRC>;
225          $line =~ m/^(\s*)/;
226          $indent = $1;           # find the indent used
227          while ( $line !~ m/^}/ ) {
228             $line =~ s/^$indent//g; # remove the indent
229             $code .= $line;
230             $line = <SRC>;
231             $lineno++
232          }
233          if ( $cfile ) {
234              print CFILE "\n".$code."\n";
235          }
236       } elsif ( $line =~ m/^HEADER\s*{$/i ) {
237          $header = "";
238          $line = <SRC>;
239          $line =~ m/^(\s*)/;
240          $indent = $1;              # find the indent used
241          while ( $line !~ m/^}/ ) {
242             $line =~ s/^$indent//g; # remove the indent
243             $header .= $line;
244             $line = <SRC>;
245             $lineno++
246          }
247          if ( $hfile ) {
248              print CFILE $header;
249          }
250       } elsif ( $line =~ m/^(STATIC|)METHOD/i ) {
251          # Get the return type function name and delete that from
252          # the line. What is left is the possibly first function argument
253          # if it is on the same line.
254          #
255          if ( !$intname ) {
256             warn "$src:$lineno: No interface name defined";
257             $error = 1;
258             last LINE;
259          }
260          $line =~ s/^(STATIC|)METHOD\s+([^{]+?)\s*{\s*//i;
261          $static = $1;                                                    
262          @ret = split m/\s+/, $2;
263          $name = pop @ret;          # last element is name of method
264          $ret = join(" ", @ret);    # return type
265
266          warn "Method: name=$name return type=$ret"
267             if $debug;
268          
269          if ( !$name or !$ret ) {
270             warn $line
271                if $debug;
272             warn "$src:$lineno: Invalid method specification";
273             $error = 1;
274             last LINE;
275          }
276
277          unless ( $name =~ m/^[a-z_][a-z_0-9]*$/ ) {
278             warn $line
279                if $debug;
280             warn "$src:$lineno: Invalid method name '$name', use [a-z_][a-z0-9_]*";
281             $error = 1;
282             last LINE;
283          }
284
285          if ( defined($methods{$name}) ) {
286             warn "$src:$lineno: Duplicate method name";
287             $error = 1;
288             last LINE;
289          }
290
291          $methods{$name} = 'VIS';
292
293          while ( $line !~ m/}/ and $line .= <SRC> ) {
294             $lineno++
295          }
296
297          $default = "";
298          if ( $line !~ s/};?(.*)// ) { # remove first '}' and trailing garbage
299             # The '}' was not there (the rest is optional), so complain
300             warn "$src:$lineno: Premature end of file";
301             $error = 1;
302             last LINE;
303          }
304          $extra = $1;
305          if ( $extra =~ /\s*DEFAULT\s*([a-zA-Z_][a-zA-Z_0-9]*)\s*;/ ) {
306             $default = $1;
307          } else {
308             warn "$src:$lineno: Ignored '$1'"  # warn about garbage at end of line
309                if $debug and $1;
310          }
311
312          # Create a list of variables without the types prepended
313          #
314          $line =~ s/^\s+//;            # remove leading ...
315          $line =~ s/\s+$//;            # ... and trailing whitespace
316          $line =~ s/\s+/ /g;           # remove double spaces
317
318          @arguments = split m/\s*;\s*/, $line;
319          @varnames = ();               # list of varnames
320          foreach $argument (@arguments) {
321             next                       # skip argument if argument is empty
322                if !$argument;
323
324             @ar = split m/[*\s]+/, $argument;
325             if ( $#ar == 0 ) {         # only 1 word in argument?
326                warn "$src:$lineno: no type for '$argument'";
327                $error = 1;
328                last LINE;
329             }
330
331             push @varnames, $ar[-1];   # last element is name of variable
332          };
333
334          warn 'Arguments: ' . join(', ', @arguments) . "\n"
335             . 'Varnames: ' . join(', ', @varnames)
336             if $debug;
337
338          $mname = $intname.'_'.$name;  # method name
339          $umname = uc($mname);         # uppercase method name
340
341          $arguments = join(", ", @arguments);
342          $varnames = join(", ", @varnames);
343
344          $default = "0" if $default eq "";
345
346          if ( $hfile ) {
347             # the method description 
348             print HFILE "extern struct device_op_desc $mname\_desc;\n";
349             # the method typedef
350             print HFILE &format_line("typedef $ret $mname\_t($arguments);",
351                               $line_width, ', ',
352                               ',',' ' x length("typedef $ret $mname\_t("))
353                       . "\n";
354             # the method declaration
355             print HFILE "$mname\_t $umname;\n\n";
356          }
357
358          if ( $cfile ) {
359             # Print out the method desc
360             print CFILE "struct device_op_desc $mname\_desc = {\n";
361             print CFILE "\t0, 0, (devop_t) $default, \"$mname\"\n";
362             print CFILE "};\n\n";
363
364             # Print out the method itself
365             if ( 0 ) {                 # haven't chosen the format yet
366                print CFILE "$ret $umname($varnames)\n";
367                print CFILE "\t".join(";\n\t", @arguments).";\n";
368             } else {
369                print CFILE &format_line("$ret $umname($arguments)",
370                               $line_width, ', ',
371                               ',', ' ' x length("$ret $umname(")) . "\n";
372             }
373             print CFILE "{\n";
374             if ($static) {
375               print CFILE &format_line("\t$mname\_t *m = ($mname\_t *) DRVOPMETH(driver, $mname);",
376                                        $line_width-8, ' = ', ' =', "\t\t")
377                 . "\n";
378             } else {
379               print CFILE &format_line("\t$mname\_t *m = ($mname\_t *) DEVOPMETH(dev, $mname);",
380                                        $line_width-8, ' = ', ' =', "\t\t")
381                 . "\n";
382             }
383             print CFILE "\t".($ret eq 'void'? '':'return ') . "m($varnames);\n";
384             print CFILE "}\n\n";
385          }
386       } else {
387          warn $line
388             if $debug;
389          warn "$src:$lineno: Invalid line encountered";
390          $error = 1;
391          last LINE;
392       }
393    } # end LINE
394
395    # print the final '#endif' in the header file
396    #
397    print HFILE "#endif /* _".$intname."_if_h_ */\n"
398       if $hfile;
399
400    close SRC;
401    close CFILE
402       if $cfile;
403    close HFILE
404       if $hfile;
405
406    if ( !$error ) {
407       if ( $cfile ) {
408          ($rc = system("mv $ctmpname $cfilename"))
409             and warn "mv $ctmpname $cfilename failed, $rc";
410       }
411
412       if ( $hfile ) {
413          ($rc = system("mv $htmpname $hfilename"))
414             and warn "mv $htmpname $hfilename failed, $rc";
415       }
416    } else {
417       warn 'File' . ($hfile and $cfile? 's':'') . ' skipped';
418       ($rc = system("rm -f $htmpname $ctmpname"))
419          and warn "rm -f $htmpname $ctmpname failed, $rc";
420       $gerror = 1;
421    }
422 }
423
424 exit $gerror;
425
426
427 sub format_line {
428    my ($line, $maxlength, $break, $new_end, $new_start) = @_;
429    my $rline = "";
430
431    while ( length($line) > $maxlength
432            and ($i = rindex $line, $break, $maxlength-length($new_end)) != -1 ) {
433       $rline .= substr($line, 0, $i) . $new_end . "\n";
434       $line = $new_start . substr($line, $i+length($break));
435    }
436
437    return $rline . $line;
438 }
439
440 # This routine is a crude replacement for one in File::Basename. We
441 # cannot use any library code because it fouls up the Perl bootstrap
442 # when we update a perl version. MarkM
443
444 sub fileparse {
445    my ($filename, @suffix) = @_;
446    my ($dir, $name, $type, $i);
447
448    $type = '';
449    foreach $i (@suffix) {
450       if ($filename =~ m|$i$|) {
451          $filename =~ s|$i$||;
452          $type = $i;
453       }
454    }
455    if ($filename =~ m|/|) {
456       $filename =~ m|([^/]*)$|;
457       $name = $1;
458       $dir = $filename;
459       $dir =~ s|$name$||;
460    }
461    else {
462       $dir = '';
463       $name = $filename;
464    }
465    ($name, $dir, $type);
466 }