* ifdata: Patch from KELEMEN Peter to add support for printing hardware
[moreutils.git] / vidir
blob708216286859c4c539b80516267dadd2d1ade8b7
1 #!/usr/bin/perl
3 =head1 NAME
5 vidir - edit directory
7 =head1 SYNOPSIS
9 B<vidir> [--verbose] [directory|file|-] ...
11 =head1 DESCRIPTION
13 vidir allows editing of the contents of a directory in a text editor. If no
14 directory is specified, the current directory is edited. Each item in the
15 directory is listed. Delete items to remove them from the directory, or
16 edit their names to rename them.
18 Note that if "-" is specified as the directory to edit, it reads a list of
19 filenames from stdin and displays those for editing. Alternatively, a list
20 of files can be specified on the command line.
22 =head1 OPTIONS
24 =over 4
26 =item -v, --verbose
28 Verbosely display the actions taken by the program.
30 =back
32 =head1 ENVIRONMENT VARIABLES
34 =over 4
36 =item EDITOR
38 Editor to use. Defaults to vi if not set.
40 =item VISUAL
42 Also supported to determine what editor to use.
44 =back
46 =head1 BUGS
48 Does not support deletion of directories. Does not support recursive
49 editing of contents of a directory.
51 =head1 AUTHOR
53 Copyright 2006 by Joey Hess <joey@kitenet.net>
55 Licensed under the GNU GPL.
57 =cut
59 use File::Temp;
60 use Getopt::Long;
62 my $error=0;
64 my $verbose=0;
65 if (! GetOptions("verbose|v" => \$verbose)) {
66 die "Usage: $0 [--verbose] [directory|file|-]\n";
69 my @dir;
70 if (! @ARGV) {
71 push @ARGV, "."
73 foreach my $item (@ARGV) {
74 if ($item eq "-") {
75 push @dir, map { chomp; $_ } <STDIN>;
76 close STDIN;
77 open(STDIN, "/dev/tty") || die "reopen: $!\n";
79 elsif (-d $item) {
80 opendir(DIR, $item) || die "$0: cannot read $item: $!\n";
81 push @dir, sort readdir(DIR);
82 closedir DIR;
84 else {
85 push @dir, $item;
89 my $tmp=File::Temp->new(template => "dirXXXXX");
90 open (OUT, ">".$tmp->filename) || die "$0: cannot write ".$tmp->filename.": $!\n";
92 my %item;
93 my $c=0;
94 foreach (@dir) {
95 next if $_ eq '.' || $_ eq '..';
96 $item{++$c}=$_;
97 print OUT "$c.\t$_\n";
99 @dir=();
100 close OUT;
102 my $editor="vi";
103 if (exists $ENV{EDITOR}) {
104 $editor=$ENV{EDITOR};
106 if (exists $ENV{VISUAL}) {
107 $editor=$ENV{VISUAL};
109 $ret=system($editor, $tmp);
110 if ($ret != 0) {
111 die "$editor exited nonzero, aborting\n";
114 open (IN, $tmp->filename) || die "$0: cannot read ".$tmp->filename.": $!\n";
115 while (<IN>) {
116 chomp;
117 if (/^(\d+)\.\t(.*)/) {
118 my $num=$1;
119 my $name=$2;
120 if (! exists $item{$num}) {
121 print STDERR "$0: unknown item number $num\n";
122 $error=1;
124 elsif ($name ne $item{$num}) {
125 my $src=$item{$num};
127 # deal with swaps
128 if (-e $name || -l $name) {
129 my $tmp=$name."~";
130 my $c=0;
131 while (-e $tmp || -l $tmp) {
132 $c++;
133 $tmp=$name."~$c";
135 if (! rename($name, $tmp)) {
136 print STDERR "$0: failed to rename $name to $tmp: $!\n";
137 $error=1;
139 elsif ($verbose) {
140 print "'$name' -> '$tmp'\n";
142 foreach my $item (keys %item) {
143 if ($item{$item} eq $name) {
144 $item{$item}=$tmp;
149 if (! rename($src, $name)) {
150 print STDERR "$0: failed to rename $src to $name: $!\n";
151 $error=1;
153 elsif ($verbose) {
154 print "'$src' -> '$name'\n";
157 delete $item{$num};
159 else {
160 die "$0: unable to parse line \"$_\", aborting\n";
163 close IN;
164 unlink($tmp.'~') if -e $tmp.'~';
166 foreach my $item (sort values %item) {
167 if (! unlink($item)) {
168 print STDERR "$0: failed to remove $item: $!\n";
169 $error=1;
171 if ($verbose) {
172 print "removed '$item'\n";
176 exit $error;