designated initializer conversion
Hi.
Near the end of May, there was a thread on the kernel mailing list about converting structure initializers from the present form like ...
struct foo_operations foo_ops = {
op1: func1,
op2: func2,
}to the C99 format like ...
struct foo_operations foo_ops = {
.op1 = func1,
.op2 = func2,
}The format with the colons is described in the GCC info pages in the "C Extensions" -> "Designated Inits" section. The info page lists this format as being obsolete since GCC 2.5, so there was talk about cleaning up the kernel to move off this extension and convert the ISO standard format. I haven't seen any patches make their way out doing this change, though as I'm running the 2.4 series kernels, maybe some have filtered into 2.5.
One day while getting frustrated with something I was working on, I decided to change gears and tackle this conversion. I cooked up a nifty little Perl script that does this, and can say I'm running a kernel now (2.4.19-rc1-ac1) that the script has ISOized. The script is passed a directory
as an argument, and will change all files in that directory and any subdirectory that seem to warrant the change. I went nuts and did my whole kernel, and out of the stuff I built, especially many filesystem modules , I only encountered a problem with the fs/affs/file.c file. The '.writepage' and '.sync_page' lines around 792 were commented out, and my conversion script dropped the comments. Other than that, my conversion went without a hitch. I built my kernel with gcc-2.95.4 (Debian), so I know it works with that GCC release. GCC 3.X will also work, as I've tried 3.1.1 earlier when fiddling around with the script.
To use the script, simply pass a directory in which you want to start the conversion. For example, if you want to convert the code in the fs/ext2 directory ...
$ perl conv_script.pl /path/to/kernel/code/fs/ext2
To do all the file systems ...
$ perl conv_script.pl /path/to/kernel/code/fs
... and for the bold, to do the whole enchilada ...
$ perl conv_script.pl /path/to/kernel/code
Any file that the script converts is renamed with a ".old" extension, so you'll be able to diff the changes. I also have a simple shell script that can rename the changed file with a ".new" extension, and swap the ".old" back. The shell script is also included in this mail.
My hope is this script is useful to anyone wanting to test out this code conversion, and will ease the conversion to the ".foo" format if that is the path the kernel developers wish to take.
My thanks to everyone working on the kernel.
Enough blabbering, here's the script ...
====================================================
#!/usr/bin/perl
#
# quick scanner for possible obsolete format # for the designated initializers #
use strict;
die "No starting directory given!\n" unless (@ARGV);
my $startdir = shift(@ARGV);
die "Can't find directory `$startdir'! $!\n" unless (-d $startdir);
my %operations = (
'block_device' => {
'open' => 1,
'release' => 1,
'ioctl' => 1,
'check_media_change' => 1,
'revalidate' => 1
},
'file' => {
'llseek' => 1,
'read' => 1,
'write' => 1,
'readdir' => 1,
'poll' => 1,
'ioctl' => 1,
'mmap' => 1,
'open' => 1,
'flush' => 1,
'release' => 1,
'fsync' => 1,
'fasync' => 1,
'lock' => 1,
'readv' => 1,
'writev' => 1,
'sendpage' => 1,
'get_unmapped_area' => 1
},
'inode' => {
'create' => 1,
'lookup' => 1,
'link' => 1,
'unlink' => 1,
'symlink' => 1,
'mkdir' => 1,
'rmdir' => 1,
'mknod' => 1,
'rename' => 1,
'readlink'=> 1,
'follow_link' => 1,
'truncate' => 1,
'permission' => 1,
'revalidate' => 1,
'setattr' => 1,
'getattr' => 1
},
'super' => {
'read_inode' => 1,
'read_inode2' => 1,
'dirty_inode' => 1,
'write_inode' => 1,
'put_inode' => 1,
'delete_inode' => 1,
'put_super' => 1,
'write_super' => 1,
'write_super_lockfs' => 1,
'unlockfs' => 1,
'statfs' => 1,
'remount_fs' => 1,
'clear_inode' => 1,
'umount_begin' => 1,
'fh_to_dentry' => 1,
'dentry_to_fh' => 1,
'show_options' => 1
},
'dquot' => {
'initialize' => 1,
'drop' => 1,
'alloc_space' => 1,
'alloc_inode' => 1,
'free_space' => 1,
'free_inode' => 1,
'transfer' => 1
},
'vm' => {
'open' => 1,
'close' => 1,
'nopage' => 1
},
'dentry' => {
'd_revalidate' => 1,
'd_hash' => 1,
'd_compare' => 1,
'd_delete' => 1,
'd_release' => 1,
'd_iput' => 1
},
'parport' => {
'write_data' => 1,
'read_data' => 1,
'write_control' => 1,
'read_control' => 1,
'frob_control' => 1,
'read_status' => 1,
'enable_irq' => 1,
'disable_irq' => 1,
'data_forward' => 1,
'data_reverse' => 1,
'init_state' => 1,
'save_state' => 1,
'restore_state' => 1,
'inc_use_count' => 1,
'dec_use_count' => 1,
'epp_write_data' => 1,
'epp_read_data' => 1,
'epp_write_addr' => 1,
'epp_read_addr' => 1,
'ecp_write_data' => 1,
'ecp_read_data' => 1,
'ecp_write_addr' => 1,
'compat_write_data' => 1,
'nibble_read_data' => 1,
'byte_read_data' => 1
},
'address_space' => {
'writepage' => 1,
'readpage' => 1,
'sync_page' => 1,
'prepare_write' => 1,
'commit_write' => 1,
'bmap' => 1,
'flushpage' => 1,
'releasepage' => 1,
'direct_IO' => 1,
'removepage' => 1
},
'seq' => {
'start' => 1,
'stop' => 1,
'next' => 1,
'show' => 1
},
'usb' => {
'allocate' => 1,
'deallocate' => 1,
'get_frame_number' => 1,
'submit_urb' => 1,
'unlink_urb' => 1
}
);my @dirs = ();push(@dirs,$startdir);
while(defined(my $dir = pop(@dirs))) {
opendir(DIR,$dir) || die "Can't open directory `$dir'! $!\n"; my @files = grep(!/^\.\.?$/, readdir(DIR)); closedir(DIR);
foreach (@files) {
my $fname = join("/", $dir, $_);
if (-d $fname) {
push(@dirs, $fname);
next;
}
next unless ($fname =~ /\.c$/);
open(CFILE,"<$fname") || die "Can't open `$fname'! $!\n";
my @newlines = ();
my $opflag = 0;
my $writeflag = 0;
my $key = '';
while(<CFILE>) {
if (/(block_device|file|inode|super|dquot|vm|dentry|parport|address_space|seq|usb)_operations\s+\S+\s+\=/) {
$key = $1;
$opflag = 1;
}
unless ($opflag) {
push(@newlines,$_);
next;
}
if (m!([\w_]+):\s+(.+)$!) {
if (exists($operations{$key}->{$1})) {
$writeflag++;
push(@newlines,"\t.$1 = $2\n");
} else {
push(@newlines,$_);
}
} else{
push(@newlines,$_);
}
if (m!\};!) {
$opflag = 0;
}
}
close(CFILE);
if ($writeflag) {
my $newname = join(".", $fname, 'new');
open(NEWFILE,">$newname") || die "Can't create `$newname'! $!\n";
print NEWFILE @newlines;
close(NEWFILE) || die "Error writing `$newname'! $!\n";
my $oldname = join(".", $fname, 'old');
rename($fname, $oldname) || die "Can't rename '$fname'! $!\n";
rename($newname, $fname) || die "Can't rename '$newname'! $!\n";
} }
}
===================================================
... and now here's the shell script that renames the files ...
==========================================
#!/bin/sh
#
# small script to rename files #
if [ -z $1 ]; then
echo "Pass a directory!"
exit 1
fi
dir=$1
if [ ! -d ${dir} ]; then
echo "Can't find directory ${dir}!"
exit 1fi
for file in $(find ${dir} -name "*\.c\.old")
do
testfile=${file%%.old}
if [ -f ${testfile} ]; then
echo "Replacing ${testfile}"
mv ${testfile} ${testfile}.new
mv ${file} ${testfile}
fidone
============================================
Comments welcomed.
Art Haas
Signature · 3 lines
They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety. -- Benjamin Franklin, Historical Review of Pennsylvania, 1759
Quoted 5 lines · On Wed, 10 Jul 2002 21:52:48 -0500 Art Haas <[email protected]> wrote:
Hi.
Near the end of May, there was a thread on the kernel mailing list about converting structure initializers from the present form like ...
If you're game, try sending these, one file at a time, to [email protected].
Cheers!
Rusty.
Signature · 2 lines
there are those who do and those who hang on and you don't see too many doers quoting their contemporaries. -- Larry McVoy