#!/afs/athena/contrib/perl/perl $RCS_ID = '$Id: etbl,v 2.5 1992/06/23 10:49:02 hobbs Exp $' ; $0 =~ s-.*/-- ; $ED = "e" ; # Default after envt $LMIN = 50 ; # min line length $HelpInfo = <){ $hedfac++ ; if( /^#\s|^\s+#/ ){ next ; } # comment last ; } # col name line unless( $_ ){ die "Nothing in $file\n" ; } $place = tell - length( $_ ) ; $hedfac++ ; $hedfac++ ; # nr lines in header +1, orig file chop ; @F = split( "\t", $_ ) ; $FCOL = @F ; # nr of cols in $file if( $CBC ){ # columns by count option # chk @ARGV empty ... die error ... @cbc = split( /([a-z])/, $CBC ) ; unshift( @cbc, 'n' ) ; @tmp = @F ; while(@cbc){ $opr = shift( @cbc ) ; $cnt = shift( @cbc ) ; while( @tmp && $cnt-- ){ if( $opr eq 'n' ){ push( @ARGV, shift(@tmp) ) ; } else{ shift(@tmp) ; } } } } for $arg (@ARGV){ if( $arg =~ /^(\d+)(-*)(\d*)$/ ){ # line_spec $LINS++ ; push( @linstr, $1 ) ; if( $3 ){ push( @linend, $3 ) ; } else{ if( $2 ){ push( @linend, $HUGE ) ; } else{ push( @linend, $1 ) ; } } } elsif( $arg eq 'ne' ){ # Neg pat_spec $PATV = 1 ; } elsif( $arg =~ s|^/(.*)/$|$1| ){ # pat_spec $LINS++ ; $p_pat = $arg ; } else{ # col_spec unless( $p_pat ){ push( @COL, $arg ) ; } else{ push( @PCOL, $arg ) ; } } } for( $i=0 ; $i <= $#linstr ; $i++ ){ # check line_spec $linstr[$i] = $hedfac if $linstr[$i] < $hedfac ; $linend[$i] = $hedfac if $linend[$i] < $hedfac ; } for( $i=0 ; $i <= $#linstr ; $i++ ){ if( $linstr[$i] <= $linend[$i-1] || $linstr[$i] > $linend[$i] ){ die "$0: Bad line_spec\n" ; } } $NCOL = @COL ; # nr of cols to edit for $arg (@COL){ # check selected columns to edit $ok = $i = 0 ; for (@F){ if( $arg eq $_ ){ $ok++ ; push( @COLX, $i ); last ; } $i++ ; } if( ! $ok ){ die "Can't find column: $arg\n" ; } } for $arg (@PCOL){ # check selected columns for pattern match $ok = $i = 0 ; for (@F){ if( $arg eq $_ ){ $ok++ ; push( @PCOLX, $i ); last ; } $i++ ; } if( ! $ok ){ die "Can't find column: $arg\n" ; } } # seek( FI, $place, 0 ) ; seek( FI, 0, 0 ) ; } $TMP = "$0.t.$$" ; $new = "$file.new" ; if( ! $NPP ){ open( NW, ">$new" ) || die "Can't open $new\n" ; } if( $LINS ){ # have line_spec &grab_lines ; } else{ # NO line_spec if( $LST ){ # list format if( ! $NCOL ){ system( "tbl2lst -e -l$LEN < $file > $TMP" ) ; } else{ system( "column < $file $REV @COL | tbl2lst -e > $TMP" ) ; } } else{ # column case if( ! $NCOL ){ system( "ptbl < $file -e > $TMP" ) ; } else{ system( "column < $file $REV @COL | ptbl -e > $TMP" ) ; } } } system( "$ED $TMP" ) if ! $XBUG ; # ========================== call the editor exit if $NPP ; if( $LST ){ # list form open( TM, "lst2tbl -e < $TMP |" ) || die "Can't open pipe\n" ; } else{ # column form open( TM, "mktbl -e < $TMP |" ) || die "Can't open pipe\n" ; } if( ! $LINS ){ # NO lines to merge if( ! $NCOL ){ # NO columns to merge print NW $_ while() ; } else{ # merge columns back into original RDB table &do_cols ; } } else{ # lines to merge &do_lines ; } $SIG{'INT'} = 'IGNORE' ; # safety valve unlink( $TMP ) ; unlink( ",$TMP" ) ; if( $RCS ){ # RCS case rename( $new, $file ) ; close( NW ) ; system "ci $file" ; } else{ # normal case if( rename( $file, "$cmafile" ) ){ rename( $new, $file ) ; } } sub do_cols { # column control if NO line_spec seek( FI, $place, 0 ) ; # just after comments in header, orig file while(){ # read line fm new file $inhdr = 0 ; if( ! $inhdr && /^#\s|^\s+#/ ){ print NW $_ ; next ; } # comment $inhdr = 1 ; chop ; @T = split( /\t/, $_, 9999 ); # col name; <<< chg 9999 ??? if( !($f = )){ # read line fm orig file warn "WARNING, extra rows in edited file\n" ; do{ print NW $_, "\n" ; }while() ; last ; } chop( $f ) ; @F = split( /\t/, $f, $FCOL ); # col name line, orig file &mrg_row_pr ; } while(){ warn "WARNING, missing row in edited file\n" ; print NW $_ ; } } sub mrg_row_pr { # merge new columns into orig row, print $i = 0 ; for (@COLX){ # the column merge $F[$_] = $T[$i++] ; } while( @T > @COLX ){ warn "WARNING: extra column in edited line\n" ; push( @F, pop(@T) ) ; } print NW join( "\t", @F ), "\n" ; } sub do_lines { # line control for merge $lln = 0 ; # line nr of $file $inhdr = 1 ; while(){ $dell = "" ; next if ! /^\.\.>>>(\S*)\s+(\d+)\s+(\d+)/ ; # control line $dell = $1 ; $linnr = $2 ; $lincnt = $3 ; if( $inhdr ){ while( ){ # copy orig hdr last unless /^#\s|^\s+#/ ; # comment print NW $_ ; } } else{ $_ = ; } while( $f= ){ # copy orig file up to $linnr $lln++ ; if( $inhdr && $lincnt > 2 ){ # pass comment lines $lincnt-- ; next ; } $inhdr = 0 ; last if $lln >= $linnr ; print NW $f ; } if( ! $NCOL ){ # NO columns to merge while( --$lincnt && ($f = ) ){ $lln++ ; } # skip lines fm orig file do { redo if /^\.\.>>>/ ; print NW $_ if $dell ne 'DEL' ; } while() ; #copy, del } else{ # columns to merge $init = 0 ; do { redo if /^\.\.>>>/ ; chop ; @T = split( /\t/, $_, 9999 ) ; # <<< chg 9999 ??? if( $init++ && !($f = )){ warn "WARNING, extra rows in edited file\n" ; do{ print NW $_, "\n" if ! /^\.\.>>>/ ; }while() ; return ; } $lln++ if $init > 1 ; chop( $f ) ; @F = split( /\t/, $f, $FCOL ); &mrg_row_pr ; } while() ; } } print NW $_ while() ; # copy rest of orig file } sub grab_lines { # get selected lines from $file and write to pipe if( $LST ){ # list form if( ! $NCOL ){ open( TO, "| tbl2lst -e -l$LEN > $TMP" ) || die "Can't open pipe\n" ; } else{ open( TO, "| column $REV @COL | tbl2lst -e -l$LEN > $TMP" ) || die "Can't open pipe\n" ; } } else{ # column form if( ! $NCOL ){ open( TO, "| ptbl -e > $TMP" ) || die "Can't open pipe\n" ; } else{ open( TO, "| column $REV @COL | ptbl -e > $TMP" ) || die "Can't open pipe\n" ; } } # print header $lnr = $fhn = 0 ; # line nr, fixed header nr while(){ $lnr++ ; push( @hdr, $_ ) ; # save header if( /^#\s|^\s+#/ ){ next ; } # comment last if ++$fhn >= 2 ; } print TO "..>>> 1 $lnr CONTROL LINE, DO NOT TOUCH <<<\n"; print TO @hdr ; $i = 0 ; if( ! @linstr ){ # only pat_spec while( ){ $lnr++ ; @F = split( /\t/, $_, $FCOL ) if @PCOLX ; &chk_pat ; } } elsif( ! $p_pat ){ # only lin_spec for $start (@linstr){ $fst++ ; while( ){ $lnr++ ; next if $lnr < $start ; if( $fst ){ $x = $linend[$i] - $start +1 ; print TO "..>>> $start $x CONTROL LINE, DO NOT TOUCH <<<\n"; $fst = 0 ; } print TO $_ ; last if $lnr >= $linend[$i] ; } $i++ ; } } else{ # both pat & lin spec for $start (@linstr){ while( ){ $lnr++ ; next if $lnr < $start ; @F = split( /\t/, $_, $FCOL ) if @PCOLX ; # moved for perf. &chk_pat ; last if $lnr >= $linend[$i] ; } $i++ ; } } &pr_pat if $p_ln_st ; close( TO ); seek( FI, 0, 0 ) ; } sub chk_pat { # chk curr line for matches. If any, save line in # @p_lns and set $p_ln_st . if( &match ){ $p_ln_st = $lnr unless $p_ln_st ; push( @p_lns, $_ ) ; } else{ &pr_pat if $p_ln_st ; } } sub pr_pat { # print saved pattern lines, with control line, clear $p_ln_st. $xx = @p_lns ; print TO "..>>> $p_ln_st $xx CONTROL LINE, DO NOT TOUCH <<<\n" ; print TO @p_lns ; $p_ln_st = 0 ; @p_lns = () ; } sub match { # return 1 if curr line ($_) or cols (@PCOLX) matches, else 0. unless( @PCOLX ){ if( /$p_pat/o ){ return 1 - $PATV ; } } else{ for $cx (@PCOLX){ if( $F[$cx] =~ /$p_pat/o ){ return 1 - $PATV ; } } } $PATV ; } sub cleanup { print "INT ... cleaning up\n" ; unlink( $TMP ) ; unlink( ",$TMP" ) ; if( -f $file ){ unlink( $new ) ; exit ; } }