There Is More Than One Way To Do It.

But how would you do this?

sub Counter ($) { local $/ = "\n"; my $fh; open $fh, '+<', $_[0] or open $fh, '>', $_[0] or return undef; flock $fh, 2; seek $fh, 0, 0; my $counter = <$fh>; seek $fh, 0, 0; truncate $fh, 0; print $fh ++$counter or return undef; close $fh or return undef; return $counter; }
How many ways can we find to re-write this? I'd like to see radical changes (modules, OO, maybe even an implementation using Inline::C?), not some small syntax adjustments, so please don't focus on $_[0] versus assigning @_ to something, or on the prototype.

Error checking, file locking and doing all in one open is optional. Bonus points for those who do, though :)

- Yes, I reinvent wheels.
- Spam: Visit eurotraQ.

Replies are listed 'Best First'.
(jeffa) Re: TIMTOWTDI - a counter
by jeffa (Bishop) on May 26, 2002 at 16:07 UTC
    use Tie::File; sub Counter ($) { my @array; my $o = tie @array, 'Tie::File', shift || return undef; $o->flock; $array[0]++; }
    UPDATE: added file lock

    jeffa

    with thanks to Dominus for Tie::File
Re: TIMTOWTDI - a counter
by Beatnik (Parson) on May 26, 2002 at 14:14 UTC
    perl -p  -e'$_++' -i counter

    Greetz
    Beatnik
    ... Quidquid perl dictum sit, altum viditur.
Re: TIMTOWTDI - a counter
by Kanji (Parson) on May 26, 2002 at 15:18 UTC
    I'd like to see radical changes [...], not some small syntax adjustments

    Ah, but "some small syntax adjustments" are all that's between your code working on pre 5.6 install and not.

    use Symbol; sub Counter ($) { local $/ = "\n"; my $fh = gensym(); open $fh, "+< $_[0]" or open $fh, "> $_[0]" or return undef; # ... }

    But the way I'd do it ...

    use File::CounterFile; # ... my $count = File::CounterFile->new($counter,$def_value)->inc;

        --k.


Re: TIMTOWTDI - a counter
by broquaint (Abbot) on May 26, 2002 at 19:55 UTC
    Here's an Inline::C implementation with some example usage code
    #!/usr/bin/perl use Inline C; my $cnt = Counter("counter.txt"); die("there was an error incrementing the counter") if $cnt == -1; print "current count is $cnt\n"; exit(0); __END__ __C__ int Counter(char* filename) { FILE *fh; int count; char file_count[16]; if(NULL == (fh = fopen(filename, "r+")) ) return -1; if(NULL == fgets(file_count, 16, fh)) return -1; file_count[strlen(file_count) - 1] = '\0'; count = atoi(file_count); count++; if(-1 == fseek(fh, 0, SEEK_SET)) return -1; if(fprintf(fh, "%d\n", count) < 0) return -1; fclose(fh); return count; }
    I haven't implemented flock() as I wasn't sure how portable it would be :-/
    HTH

    _________
    broquaint

Re: TIMTOWTDI - a counter
by Anonymous Monk on May 26, 2002 at 15:43 UTC
    I'd import the :DEFAULT and :flock constants from Fcntl, use sysopen with O_RDWR|O_CREAT flags, use flock with the LOCK_EX flag, test the value of the read operation or supply 0, and add tests on the flock, seek, and truncate calls as well.

      I'd

      Care to translate it into code? :)

      - Yes, I reinvent wheels.
      - Spam: Visit eurotraQ.
      

        Sorry. I meant those suggestions to be pretty much straighforward modifications or additions to your code, not anything entirely different.
        use Fcntl qw/:DEFAULT :flock/; sub counter { my $file = shift; sysopen(COUNTER, $file, O_RDWR|O_CREAT) || warn $! && return; flock(COUNTER,LOCK_EX) || warn $! && return; my $count = <COUNTER> || 0; seek(COUNTER,0,0) || warn $! && return; truncate(COUNTER,0) || warn $! && return; print(COUNTER $count + 1, "\n") || warn $! && return; close(COUNTER) || warn $! && return; return $count + 1; }
Re: TIMTOWTDI - a counter
by cLive ;-) (Prior) on May 27, 2002 at 12:00 UTC

    Here's a silly way :)

    sub counter { open(F,'>>counter') || die $!; print F 0; close(F); return (stat('counter'))[7]; }

    cLive ;-)

    --
    seek(JOB,$$LA,0);