目次

背景

最近、全然書かなくなってきたので、復習?というかいま(2007-03-13)どんな感じの書き方が 自分のトレンドなのかを残しておいて、あとで一人ニヤニヤwするためにmkfileを書いてみました。 元々の動機は Solarisにある mkfile(1)が Linuxになかったので、 きっと類するのはあるかなと思いつつ、perlで書いてみようということでできた産物ですw

win/linux/solarisでは動くことを確認してます。 ただ win/unixのどちらにも対応する為に関数のreferenceを使っているので、 perlのversionは 5.6以上必須です。

ちなみにsolarisのmkfileの実装をパクってます。

解説

TBD
  • いつも通り、コメント無しのコードは載せても解説はとりあえず書きませんwバグレポートや解説の希望とかあれば、コメントしてください。 -- 2007-03-13 (Tue) 18:25:52

コード

#!/usr/bin/env perl
use strict;
use Fcntl qw(:seek);
use Config;

$::size;
@::files;
$::cmd = "mkfile.pl";
$::debug = 0;
$::nobytes = 0;
$::verbose = 0;
$::onekbuf;
$::onekb = 1024;
$::devnull;
$::devnullpath = "/dev/null";
$::osname = $Config{osname};

&parseArgs(@ARGV);
&init();
&mainloop();

$::init;
$::generateBuffer;

sub mainloop {
    my $f;
    foreach $f ( @::files ) {
        &validateFile($f);
        &doIt($f);
    }
}

sub init {
    &_init();
    &$::init();
}

sub doIt {
    my $file = $_[0];
    my ($fd, $loop, $wbuf);

    $loop = 1;
    if ( $::size > $::onekb ) {
        my $loopSp = $::size % $::onekb;
        $loop = ( ($::size - $::loopSp) / $::onekb );
    } 
    
    open(WR, ">$file") or die "$!\n";
    $fd = \*WR;

    if ( $::nobytes ) {
        my $sentinel = pack("C", 0x0);
        seek($fd, $::size-1, SEEK_SET) or die "$!\n";
        print $fd "$sentinel";
    } else {
        printf("loop : %d\n", $loop) if ( $::debug );
        my ($alreadyWrite, $requestLength);
        # init
        $alreadyWrite = 0;
        do {
            $requestLength = $loop > 1 
                ? $::onekb : ($::size - $alreadyWrite);
            $wbuf = &$::generateBuffer($requestLength);
            print $fd "$wbuf";
            $alreadyWrite += $requestLength;
            $loop -= 1;
        } while ( $loop > 0 );
    }

    close($fd);

    if ( $::verbose ) {
        printf("%s %d bytes\n", $file, $::size);
    }
}


sub validateSize {
    my $eflag = 0;
    my $backup = $_;
    my ($s);

    printf("\$::size = %s\n", $::size) if ( $::debug );

    if ( $::size =~ /([0-9]{1,})([a-zA-Z])/ ) {
        $s = $1;
        $_ = $2;
        VALIDATESIZE_SW:{
            /m/ && do {
                $::size = $s * 1024 * 1024;
                last VALIDATESIZE_SW;
            };
            /k/ && do {
                $::size = $s * 1024;
                last VALIDATESIZE_SW;
            };
            /.*/ && do {
                printf STDERR ("%s is NOT match suffix\n", $_);
                exit(1);
                last VALIDATESIZE_SW;
            };
        };# end of VALIDATESIZE_SW
    } elsif ( $::size =~ /[0-9]{1,}/ ) {
        # do nothing
    } else {
        $eflag = 1;
    }

    if ( $::size < 1 ) {
        printf STDERR ("%d is lower than 0\n", $::size);
        $eflag = 1;
    }

    &usage() if ( $eflag == 1 );
    $_ = $backup;
}

sub validateFile {
    my $file = $_[0];
    # windows is NOT suppoted
    printf("\$file = %s\n", $file) if ( $::debug );
    my @_p = split(/\//, $file);
    my ($i, $pp);
    foreach $i ( 0 .. $#_p-1 ) {
        $pp .= "$_p[$i]/";
    }
    
    if ( defined($pp)  && !(-e $pp) ) {
        printf STDERR ("Directory %s is NOT exist\n", $pp);
        exit(1);
    }
}

sub usage {
    print <<"EOF";
Usage: $::cmd [-nv] <size>[k|m] <name1> [<name2>] ...
    -n : specified size. suffix 'k' or 'm' can be parsed.
    -v : verbose. Report the names and size of craeted file.
EOF
    exit(1);
}

sub parseArgs {
    my @argv = @_;
    my $backup = $_;
    my ($i, $st);
    my @flags = ();

    if ( $argv[0] =~ /^\-.*$/ ) {
        @flags = split(//, $argv[0]);
        foreach ( (@flags)[1 .. $#flags] ) {
            GETOPT_SW:{
                /n/ && do {
                    $::nobytes = 1;
                    last GETOPT_SW;
                };
                /v/ && do {
                    $::verbose = 1;
                    last GETOPT_SW;
                };
                /.*/ && do {
                    printf("illegal option %s\n", $_);
                    &usage();
                    last GETOPT_SW;
                };
            };# end of GETOPT_SW
        }
    }

    $st = ( $#flags == -1 ) ? 0 : 1;
    $::size = $argv[$st];
    &validateSize();

    foreach $i ( $st+1 .. $#argv ) {
        push(@::files, $argv[$i]);
    }

    &usage() if ( !defined($::size) || $#::files < 0 );
    printf("-n : %d -v : %d\n", $::nobytes, $::verbose) if ( $::debug );

    $_ = $backup;
}

# default impl /w /dev/null
sub init_unix {
    my $rbuf;
    open(ZERO, "/dev/null") or die "$!\n";
    $::devnull = \*ZERO;
    read(ZERO, $rbuf, 1024);
    $::onekbuf = pack("C1024", $rbuf);
}

sub generateBuffer_unix {
    my $rbuf;

    my $buflen = $_[0];
    my $pstr = sprintf("C%d", $buflen);

    printf("alloc $buflen PACK str = %s\n", $pstr) if ( $::debug );
    if ( $buflen == $::onekb ) {
        $rbuf = $::onekbuf;
    } else {
        my $t;
        read($::devnull, $t, $buflen);
        $rbuf = pack($pstr, $t);
    }

    return $rbuf;
}

# alternate impl if /dev/null does NOT exist.
sub init_win {
    my @bzeros = (
        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
        0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
    );
    my $i = 8;
    my @zeros;
    do {
        push(@zeros, @bzeros);
        $i -= 1;
    } while ( $i > 0 );
    $::onekbuf = pack("C1024", @zeros);

}

sub generateBuffer_win {
    my $buf;
    my $buflen = $_[0];
    my $pstr = sprintf("C%d", $buflen);
    
    my $zero = pack("C", 0x0);
    my @zeros = ();

    printf("alloc $buflen PACK str = %s\n", $pstr) if ( $::debug );
    if ( $buflen == $::onekb ) {
        $buf = $::onekbuf;
    } else {
        while ( $buflen > 0 ) {
            push(@zeros, $zero);
            $buflen -= 1;
        }

        $buf = pack($pstr, @zeros);
    }

    return $buf;
}

sub _init {
    printf("osname = %s\n", $::osname) if ( $::debug );
    if ( $::osname =~ /.*windows.*/i ) {
        $::init = \&init_win;
        $::generateBuffer = \&generateBuffer_win;
    } else {
        $::init = \&init_unix;
        $::generateBuffer = \&generateBuffer_unix;
    }
}

Last-modified: 2007-03-13 18:31:26