#!/usr/bin/perl -w
#
# lsprepare: convert "ls -lR" output to lsfs-readable form
#
# Copyright (c) 2008 Vitaly "_Vi" Shukela. Some rights reserved, GPLv2, see COPYING for license text.
# 
#

my $rcsid = ''; $rcsid .= '$Id:$';

use strict;

sub parsemode($);

sub noparse($);
sub cparse($);


my $datefields=2;
my $dfs=0; # date fileds specified
my $nameregex='.+?';

my $parsename=*noparse;

my $nolength=0;

for(;;){
    print "lsprepare -- convert file list to lsfs form\n".
	  "\t-i\tNumber of space separated date fields\n".
	  "\t-c Turn on \"c-quote\" mode\n".
	  "\t-n Set all file lengths to zero\n"
	and exit 1 if $#ARGV > -1 and $ARGV[0] eq '--help'; # Show help
    print "lsprepare-0.17\n" and exit 0 if $#ARGV > -1 and $ARGV[0] eq '--version'; # Show version
    $datefields=$ARGV[1] and $dfs=1 and shift @ARGV and shift @ARGV and next if $#ARGV > -1 and $ARGV[0] eq '-i'; # how much fields to ignore
    $parsename=*cparse and $nameregex='\".+?\"' and shift @ARGV and next if $#ARGV > -1 and $ARGV[0] eq '-c'; # c-quote mode
    if($#ARGV > -1 and $ARGV[0] eq '-n'){ $nolength=1; shift @ARGV; next; } # no length
    last;
}

print "E 0\nm 0x416D\n<\n";

my $dateregex='\s+\S+' x $datefields;

sub getnuid($){
    my $nuid;
    my $uid=shift;
    if($uid =~ /^\d+$/){
	$nuid=$uid;  
    }else{
	my @tuid = getpwnam($uid);
	   $nuid = $tuid[2];
    }
    return $nuid;
}

sub getngid($){
    my $ngid;
    my $gid=shift;
    if($gid =~ /^\d+$/){
	$ngid=$gid;  
    }else{
	my @tgid = getgrnam($gid);
	   $ngid = $tgid[2];
    }
    return $ngid;
}

my $firsttime=1;

for(<>){
    #print;   

    s/^Name (.*): //;  # for FTP  
    next if /^Connected to .*$/;
    next if /^\d\d\d\s.*$/;
    next if /^Remote system type is .*$/;
    next if /^Using .* mode to .*$/;
    next if /^ftp\> .*$/;
    next if /^\.:$/;
    next if /^\"\.\":$/;
    next if /^[^:]{0,32}$/;
    next if /^total \d+$/;

    if($firsttime and $dfs==0) {
	print STDERR $_;
	#drwxr-xr-x   17 ftp      ftp           464 May 07 00:06 altlinux
	/..........\s+\S+\s+\S+\s+\S+\s+\d+\s+\w\w\w\s+\d+\s+[0-9:]+\s+/ and $datefields=3 and $dateregex='\s+\S+' x $datefields;
	#-rwxr--r-- 1 vi vi  472 2003-09-16 12:59:52.000000000 +0300 "FrameSet.htm"
	/..........\s+\S+\s+\S+\s+\S+\s+\d+\s+\d\d\d\d-\d\d-\d\d\s+[0-9.:]+\s+\+\d+\s+/ and $datefields=3 and $dateregex='\s+\S+' x $datefields;
	/^..........\s+\S+\s+\S+\s+\S+\s+\d+$dateregex\s+\".*\"$/ and $parsename=*cparse and $nameregex='\".+?\"' 
		and print STDERR "Switching to quote-c mode\n";
	print STDERR "$datefields date fields will be ignored\n";
    }

    if(0){

    #         lrwxrwxrwx 1 root root           4 2008-07-26 11:36 cdrom1 -> scd0
    }elsif(/^(l.{9})\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)$dateregex\s+($nameregex)(?:\s->\s($nameregex)[|=\/*]?)?$/o){
	my $mode=$1;
	my $numlinks=$2;
	my $nuid=getnuid($3);
	my $ngid=getngid($4);
	my $len=$5;
	my $name=&$parsename($6);
	my $target;
	$target = &$parsename($7) if $7;
	my $nmode =&parsemode($mode);
	$firsttime=0; 

	print "E ",length $name,"\n",$name,"\n";
	print "m $nmode\n";
	print "u $nuid\n" if $nuid;
	print "g $ngid\n" if $ngid;
	print "s $len\n";
	print "_ ",length $target,"\n",$target,"\n" if $target;
	print "n $numlinks\n";
	print "<\n";

    #         crw-rw---- 1 root root     10,  61 2008-07-26 11:36 cpu_dma_latency
    }elsif(/^([cb].{9})\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+),\s+(\d+)$dateregex\s+($nameregex)$/o){
	my $mode=$1;
	my $numlinks=$2;
	my $nuid=getnuid($3);
	my $ngid=getngid($4);
	my $maj=$5;
	my $min=$6;
	my $name=&$parsename($7);
	my $nmode =&parsemode($mode);
	$firsttime=0; 

	print "E ",length $name,"\n",$name,"\n";
	print "m $nmode\n";
	print "u $nuid\n" if $nuid;
	print "g $ngid\n" if $ngid;
        print "r ",0x100*$maj+$min,"\n";
	print "n $numlinks\n";
	print "<\n";

    #    -rwxr-xr-x 1 root root  121 2008-02-27 11:08 vd*
    }elsif(/^(.{10})\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)$dateregex\s+($nameregex)[|*\/=]?$/o){
	my $mode=$1;
	my $numlinks=$2;
	my $nuid=getnuid($3);
	my $ngid=getngid($4);
	my $len=$nolength?0:$5;
	my $name=&$parsename($6);
	my $nmode =&parsemode($mode);
	$firsttime=0; 

	print "E ",length $name,"\n",$name,"\n";
	print "m $nmode\n";
	print "u $nuid\n" if $nuid;
	print "g $ngid\n" if $ngid;
	print "s $len\n";
	print "n $numlinks\n";
	print "<\n";
                               
    # ../whole:
    }elsif(/^($nameregex):$/o){
	my $dirname=&$parsename($1);
	$dirname =~ s!^\.?\.?/?!/!;
	$dirname =~ s!/$!!;
	print "D ",length $dirname,"\n",$dirname,"\n";
    }else{
	print "? ",length $_,"\n$_\n";
    }
}
print ".\n";

sub parsemode($){
    my $ret=0;
    my $n=shift;
    $ret+=0001   if (substr $n, 9, 1) eq 'x';
    $ret+=0002   if (substr $n, 8, 1) eq 'w';
    $ret+=0004   if (substr $n, 7, 1) eq 'r';
    $ret+=0010   if (substr $n, 6, 1) eq 'x';
    $ret+=0020   if (substr $n, 5, 1) eq 'w';
    $ret+=0040   if (substr $n, 4, 1) eq 'r';
    $ret+=0100   if (substr $n, 3, 1) eq 'x';
    $ret+=0200   if (substr $n, 2, 1) eq 'w';
    $ret+=0400   if (substr $n, 1, 1) eq 'r';

    $ret+=0x1000 if (substr $n, 0, 1) eq 'p'; # pipe
    $ret+=0x2000 if (substr $n, 0, 1) eq 'c'; # character special
    $ret+=0x4000 if (substr $n, 0, 1) eq 'd'; # directory
    $ret+=0x6000 if (substr $n, 0, 1) eq 'b'; # block special
    $ret+=0x8000 if (substr $n, 0, 1) eq '-'; # regular file
    $ret+=0xA000 if (substr $n, 0, 1) eq 'l'; # symbolic link
    $ret+=0xC000 if (substr $n, 0, 1) eq 's'; # socket
    $ret+=0xE000 if (substr $n, 0, 1) eq 'w'; # ???

    return $ret;
}

sub noparse($){
    return $_[0];
}

sub cparse($){
    $_[0] =~ /"(.*)"/;
    my $n = $1;
    $n =~ s/\\t/\t/;
    $n =~ s/\\n/\n/;
    $n =~ s/\\a/\a/;
    $n =~ s/\\\\/\\/;         
    $n =~ s/\\"/"/;         
    $n =~ s/\\x([0-9a-fA-F]{2})/"chr 0x$1"/ee;
    return $n;
}
