| @ -1,317 +0,0 @@ | |||||
| #!/usr/bin/perl | |||||
| use strict; | |||||
| use warnings; | |||||
| use constant | |||||
| { | |||||
| PROG_EDIT => 'vim', | |||||
| }; | |||||
| sub open_smart; | |||||
| sub edit; | |||||
| sub stdin_to_editor; | |||||
| sub reveal; | |||||
| sub header_edit; | |||||
| sub wait_or_not; | |||||
| sub usage | |||||
| { | |||||
| print STDERR <<"!"; | |||||
| Usage: $0 -[efWwRh] | |||||
| -e: edit | |||||
| -f: stdin-edit | |||||
| -W: wait for exit (true by default for editing) | |||||
| -w: don't wait for exit | |||||
| -R: reveal | |||||
| -h: header search | |||||
| ! | |||||
| exit 1; | |||||
| } | |||||
| my $cmd = \&open_smart; | |||||
| my(@files, @args); | |||||
| my %opts = ( | |||||
| 'e' => 0, | |||||
| 'f' => 0, | |||||
| 'W' => 0, | |||||
| 'R' => 0, | |||||
| 'h' => 0, | |||||
| ); | |||||
| my $wait_set = 0; | |||||
| usage() unless @ARGV; | |||||
| for(my $i = 0; $i < @ARGV; ++$i){ | |||||
| $_ = $ARGV[$i]; | |||||
| if($_ eq '--'){ | |||||
| push @files, @ARGV[$i + 1 .. $#ARGV]; | |||||
| last; | |||||
| } | |||||
| if(/^-([a-z])$/i){ | |||||
| my $k = $1; | |||||
| if(exists $opts{$k}){ | |||||
| $opts{$k} = 1; | |||||
| $wait_set = 1 if $k eq 'W'; | |||||
| }elsif($k eq 'w'){ | |||||
| $opts{W} = 0; | |||||
| $wait_set = 1; | |||||
| }else{ | |||||
| usage(); | |||||
| } | |||||
| }elsif($_ eq '--args'){ | |||||
| push @args, @ARGV[$i + 1 .. $#ARGV]; | |||||
| last; | |||||
| }elsif(/^-/){ | |||||
| usage(); | |||||
| }else{ | |||||
| push @files, $_; | |||||
| } | |||||
| } | |||||
| if($opts{e} + $opts{f} + $opts{R} + $opts{h} > 1){ | |||||
| print STDERR "Can't combine -e, -f, -R and -h\n"; | |||||
| usage(); | |||||
| } | |||||
| my $should_wait = 1; | |||||
| if($opts{e}){ | |||||
| $cmd = \&edit; | |||||
| }elsif($opts{f}){ | |||||
| # <STDIN> | $EDITOR - | |||||
| $cmd = \&stdin_to_editor; | |||||
| }elsif($opts{R}){ | |||||
| # open with rox | |||||
| $cmd = \&reveal; | |||||
| $should_wait = 0; | |||||
| }elsif($opts{h}){ | |||||
| # search /usr/include/$_ for @files | |||||
| $cmd = \&header_edit; | |||||
| } | |||||
| $opts{W} = 1 if $should_wait and not $wait_set; | |||||
| exit(&{$cmd}(( | |||||
| wait => !!$opts{W}, | |||||
| args => [@args], | |||||
| files => [@files]))); | |||||
| # end --- | |||||
| sub read_maps | |||||
| { | |||||
| my $rc = "$ENV{HOME}/.openrc"; | |||||
| open F, '<', $rc or die "open $rc: $!\n"; | |||||
| my %maps; | |||||
| my $prog_reveal = ''; | |||||
| my $mode = 0; | |||||
| while(<F>){ | |||||
| chomp; | |||||
| s/#.*//; | |||||
| if(/^\[(.*)\]$/){ | |||||
| if($1 eq 'full'){ | |||||
| $mode = $1; | |||||
| }elsif($1 eq 'suffix'){ | |||||
| $mode = $1; | |||||
| }elsif($1 eq 'directories'){ | |||||
| $mode = $1; | |||||
| }else{ | |||||
| die "invalid section \"$1\" in $rc\n"; | |||||
| } | |||||
| }elsif(!($mode eq 'directories') and my($prog, $matches) = /^([^:]+): *(.*)/){ | |||||
| sub getenv | |||||
| { | |||||
| my $k = shift; | |||||
| return $ENV{$k} if $ENV{$k}; | |||||
| my %backup = ( | |||||
| "TERM" => "urxvt", | |||||
| "VISUAL" => "vim", | |||||
| ); | |||||
| return $backup{$k} if $backup{$k}; | |||||
| return "\$$k"; | |||||
| } | |||||
| my @matches = split / *, */, $matches; | |||||
| $prog =~ s/\$([A-Z_]+)/getenv($1)/e; | |||||
| my $key = $prog; | |||||
| if($mode eq 'suffix'){ | |||||
| # compare file extensions case insensitively | |||||
| $key = lc $key; | |||||
| } | |||||
| push @{$maps{$key}}, [ $_, $mode ] for @matches; | |||||
| }elsif($mode eq 'directories' && length){ | |||||
| if(length($prog_reveal)){ | |||||
| die "already have dir program, in $rc\n"; | |||||
| } | |||||
| $prog_reveal = $_; | |||||
| }elsif(length){ | |||||
| die "invalid confiuration line: \"$1\" in $rc\n"; | |||||
| } | |||||
| } | |||||
| if(!length($prog_reveal)){ | |||||
| die "no directory program specified, in $rc\n"; | |||||
| } | |||||
| close F; | |||||
| return $prog_reveal, \%maps; | |||||
| } | |||||
| sub open_smart | |||||
| { | |||||
| my $ec = 0; | |||||
| my %h = @_; | |||||
| my @to_open; | |||||
| my ($prog_reveal, $maps) = read_maps(); | |||||
| file: | |||||
| for my $fnam (@{$h{files}}){ | |||||
| #print "maps:\n"; | |||||
| if(-d $fnam){ | |||||
| push @to_open, [($h{wait}, $prog_reveal, @{$h{args}}, $fnam)]; | |||||
| next file; | |||||
| } | |||||
| (my $fnam_for_test = $fnam) =~ s/\.[a-zA-Z]+$/lc($&)/e; | |||||
| for my $prog (keys %$maps){ | |||||
| #print " $_:\n"; | |||||
| for(@{$maps->{$prog}}){ | |||||
| my($reg, $mode) = ($_->[0], $_->[1]); | |||||
| if($mode eq 'suffix'){ | |||||
| $reg = "\\.$reg\$"; | |||||
| } | |||||
| #print " $reg\n" | |||||
| if($fnam_for_test =~ /$reg/){ | |||||
| push @to_open, [($h{wait}, $prog, @{$h{args}}, $fnam)]; | |||||
| next file; | |||||
| } | |||||
| } | |||||
| } | |||||
| die "no program found for $fnam\n"; | |||||
| } | |||||
| wait_or_not(@{$_}) for @to_open; | |||||
| return 0; | |||||
| } | |||||
| sub wait_or_not | |||||
| { | |||||
| my($wait, @rest) = @_; | |||||
| my $pid = fork(); | |||||
| die "fork(): $!\n" unless defined $pid; | |||||
| if($pid == 0){ | |||||
| if($rest[0] =~ / /){ | |||||
| my $a = shift @rest; | |||||
| unshift @rest, split / +/, $a; | |||||
| } | |||||
| exec @rest; | |||||
| die; | |||||
| }else{ | |||||
| # parent | |||||
| if($wait){ | |||||
| my $reaped = wait(); | |||||
| my $ret = $?; | |||||
| die "wait(): $!\n" if $reaped == -1; | |||||
| warn "unexpected dead child $reaped (expected $pid)\n" if $reaped != $pid; | |||||
| return $ret; | |||||
| } | |||||
| } | |||||
| } | |||||
| sub edit | |||||
| { | |||||
| my %h = @_; | |||||
| my $e = $ENV{VISUAL} || $ENV{EDITOR} || PROG_EDIT; | |||||
| return wait_or_not($h{wait}, $e, @{$h{args}}, @{$h{files}}); | |||||
| } | |||||
| sub stdin_to_editor | |||||
| { | |||||
| my $tmp = "/tmp/stdin_$$"; | |||||
| open F, '>', $tmp or die "open $tmp: $!\n"; | |||||
| print F $_ while <STDIN>; | |||||
| close F; | |||||
| my %h = @_; | |||||
| push @{$h{files}}, $tmp; | |||||
| my $r = edit(%h); | |||||
| unlink $tmp; | |||||
| return $r; | |||||
| } | |||||
| sub reveal | |||||
| { | |||||
| my %h = @_; | |||||
| my ($prog_reveal) = read_maps(); | |||||
| return wait_or_not($h{wait}, $prog_reveal, @{$h{args}}, @{$h{files}}); | |||||
| } | |||||
| sub header_edit | |||||
| { | |||||
| my %h = @_; | |||||
| my @files = @{$h{files}}; | |||||
| @{$h{files}} = (); | |||||
| for my $name (@files){ | |||||
| sub find_header | |||||
| { | |||||
| my @inc = ("", "arpa", "net", "sys"); | |||||
| my $r = shift; | |||||
| my @matches; | |||||
| for(my @tmp = @inc){ | |||||
| push @inc, "x86_64-linux-gnu/$_"; | |||||
| } | |||||
| for my $inc (@inc){ | |||||
| $inc = "/usr/include/$inc"; | |||||
| opendir D, $inc or next; | |||||
| push @matches, map { "$inc/$_" } grep /$r/, readdir D; | |||||
| closedir D; | |||||
| } | |||||
| return @matches; | |||||
| } | |||||
| my @paths = find_header($name); | |||||
| push @{$h{files}}, @paths if @paths; | |||||
| } | |||||
| return edit(%h); | |||||
| } | |||||