dwallach@soda.berkeley.edu (Dan Wallach) (06/08/91)
Well, this is my first perl program, so you'll have to excuse the verbosity. I'm sure Larry, Randall, or Tom could probably write this in about three lines of modem noise, but it does what I want. :-) Basically, you keep a file in your home directory called .news.favorite which lists, in order, what groups you prefer reading. When 100 new newsgroups suddenly get added one day, run the program, and your favorites stay on top of the newsgroup, and the remainder are sorted first by : or !, then alphabetically. JAPH, Dan Wallach dwallach@soda.berkeley.edu P.S. Kudos to Larry and Randall for the Perl book. I just read it, sat down, and cranked this program straight out. (I call this fixnewsrc -- you can call it whatever you want :-) #!/usr/bin/perl # FixNewsrc V1.0 by Dan Wallach # dwallach@soda.berkeley.edu sub counter { $counter++; print STDERR "$counter..." if ($counter % 100) == 0; } sub tally_counter { print STDERR "$counter\n"; } sub clear_counter { $counter = 0; } sub print_favorites { print STDERR "Parsing favorites: "; foreach(<FAVORITE>) { chop; &counter; push (@output, "$newsrc{$_}\n"); undef $newsrc{$_}; } &tally_counter; } if(@ARGV) { print <<NO_MORE_HELP; fixnewsrc, V1.0 by Dan Wallach <dwallach@soda.berkeley.edu> Usage: $0 [no arguments] This program sorts your .newsrc, putting groups you read on top. In addition, if you have a file in your home directory called .news.favorite, then the list of newsgroups in this file appear at the top of your .newsrc, so you can still read groups in your favorite order. Example: rec.humor.funny alt.fan.warlord comp.windows.x.announce ucb.computing.announce comp.lang.perl Here, you will read rec.humor.funny first, and so on through comp.lang.perl, then you will continue reading active groups in alphabetical order. NO_MORE_HELP exit 0; } die "No .newsrc file!" unless -e "$ENV{HOME}/.newsrc"; open(NEWSRC, "$ENV{HOME}/.newsrc") || die "Can't open .newsrc"; # we want to keep this associative array around for printing favorites # so if we've already printed something, we just delete it from the # associative array, and go on. print STDERR "Reading groups: "; &clear_counter; foreach(<NEWSRC>) { chop; &counter; local($group) = split(/[:!]/); # not necessary, but fun $newsrc{$group} = $_; } &tally_counter; # output time... clear the counter and let's deal with the favorites file &clear_counter; if (open(FAVORITE, "$ENV{HOME}/.news.favorite")) { &print_favorites; } else { print "No .news.favorite file found. Just sorting .newsrc\n"; } print STDERR "Sorting..."; @newsrc = sort %newsrc; print STDERR "Generating output: "; # normally, when we go from the associative array to the scalar array, # we get a ton of junk -- the associative array's keys and also, for some # strange reason, blank lines where I undefined stuff earlier. The if/elsif # here weeds all that crap out. foreach(@newsrc) { if(/:/) { &counter; push (@output, "$_\n"); } elsif (/!/) { &counter; push (@output2, "$_\n"); } } &tally_counter; close(NEWSRC); rename("$ENV{HOME}/.newsrc", "$ENV{HOME}/.newsrc.bak") || die "Can't rename .newsrc"; open(NEWSRC, "> $ENV{HOME}/.newsrc") || die "Can't open .newsrc for writing"; print NEWSRC @output, @output2;
tchrist@convex.COM (Tom Christiansen) (06/08/91)
From the keyboard of dwallach@soda.berkeley.edu (Dan Wallach): :Well, this is my first perl program, so you'll have to excuse the verbosity. :I'm sure Larry, Randall, or Tom could probably write this in about three lines :of modem noise, but it does what I want. :-) Since modem noise often lacks newlines, this may indeed be possible. :-) :Basically, you keep a file in your home directory called .news.favorite :which lists, in order, what groups you prefer reading. When 100 new newsgroups :suddenly get added one day, run the program, and your favorites stay on :top of the newsgroup, and the remainder are sorted first by : or !, then :alphabetically. rn adds the new ones to the end anyway, right?, so who do you get your normal favorites messed up? : foreach(<FAVORITE>) { : chop; : &counter; : push (@output, "$newsrc{$_}\n"); : undef $newsrc{$_}; I think you what you want here is delete $newsrc{$_}; because you won't want $newsrc{$_} to have the undefined value: you want to remove the key $_ entirely. :print STDERR "Reading groups: "; :&clear_counter; :foreach(<NEWSRC>) { : chop; : &counter; : local($group) = split(/[:!]/); # not necessary, but fun : $newsrc{$group} = $_; :} You probably don't want to say local() inside an array. Remember that local() is a run-time thing, so you'll have a zillion of them by the time you're finally done with the loop. Another way to write this, btw, is ($group) = /^([^!:]+)/; $newsrc{$group} = $_; or even just $newsrc{(/^([^!:]+)/)[0]} = $_; # check your modem here folks It just looked funny to me to KNOW you'll throw away one of the second thing that you split, and to rely on local() to supply an array context for split(). :@newsrc = sort %newsrc; : :# normally, when we go from the associative array to the scalar array, :# we get a ton of junk -- the associative array's keys and also, for some :# strange reason, blank lines where I undefined stuff earlier. The if/elsif :# here weeds all that crap out. That's because when you use an %assoc array as a normal @array, which you're doing here by sending it off to be sorted, you get all the keys *AND* all the values in an arbitrary order, kinda like: (keyY,valY,keyX,valX,keyW,valW,keyZ,valZ) Normally you'd just say something like: foreach (sort keys %newsrc) The reason you're getting blank lines for the stuff you undef'd is that you only gave those keys a value of undef -- you didn't delete the keys. Use the delete operator for that, as explained previously. :close(NEWSRC); :rename("$ENV{HOME}/.newsrc", "$ENV{HOME}/.newsrc.bak") || : die "Can't rename .newsrc"; Although since you don't print $!, we'll never know why. [pet peeve] :open(NEWSRC, "> $ENV{HOME}/.newsrc") || die "Can't open .newsrc for writing"; :print NEWSRC @output, @output2; What happens if the disk fills up? It might be nice to write to a temporary file, like ".newsrc.$$", put an explicit close in there, check its status, and only if it's ok do the rename. Just a thought. --tom -- Tom Christiansen tchrist@convex.com convex!tchrist "Perl is to sed as C is to assembly language." -me