2002-07-11 02:50:11

by Art Haas

[permalink] [raw]
Subject: [SCRIPT] 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 1
fi

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}
fi
done
============================================

Comments welcomed.

Art Haas
--
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


2002-07-13 06:46:35

by Rusty Russell

[permalink] [raw]
Subject: Re: [SCRIPT] designated initializer conversion

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.
--
there are those who do and those who hang on and you don't see too
many doers quoting their contemporaries. -- Larry McVoy