Cover V04, I02
Article
Figure 1
Listing 1
Listing 2
Listing 3
Listing 4

mar95.tar


Listing 1: The Indir script

#! /usr/gnu/bin/bash
#

# Copyright (C) 1994 Martin Leisner
#               leisner@sdsp.mc.xerox.com

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# Inspired by the X11R5 script
# $Id: lndir.sh,v 1.12 1995/02/13 13:51:14 leisner Exp leisner $

# Major enhancements include:
#       A filter directory list
#       Ability to filter files (which match regular expressions
#               (i.e. *.o)
#       An update option

function cp
{
command /usr/gnu/bin/cp $*
}

function mkdir
{
command /usr/gnu/bin/mkdir $*
}

default_filter_directories="CVS RCS SCCS"

filter_list=${LNDIR_FILTERLIST:-$default_filter_directories}

function pushd {
builtin pushd $1 2>/dev/null 1>& 2
if [ $? -ne 0 ]; then
echo pushd $1 failed at $PWD
fi
}

function popd {
builtin popd  2>/dev/null 1>& 2
}

function echo {
builtin echo -e "$*"
}

function match
{
if [ $# -ne 2 ]; then
echo need to call match with 2 argument, called with $# arguments
exit
fi

case $1 in
$2)
return 0
;;
*)
return 1
;;
esac
}

# see if arg1 in in $filter_filter
# return 1 for not matched
function check_file
{
if [ $# -ne 1 ]; then
echo check_file needs one arg
exit
fi

if [ -z "$file_filter" ]; then
return 1
fi
set -f

for i in "$file_filter"
do
match $1 $i
if [ $? -eq 0 ]; then
set +f
return 0
fi
done
set +f

# not matched
return 1
}

function usage {
echo "Usage: $0 [-v] [-u] [-s] [-f files] [-i dirs] source [destination ]"
echo "\t-v will be verbose when running"
echo "\t-s will give statistics at the end"
echo "\t-u will only do updates (new files, without pruning)"
echo "\t-f will filter files (will be regexp)"
echo "\n\t-i will specify a list of directories to filter"
echo "\tDefault is $default_filter_directories"
if [ -z "$LNDIR_FILTERLIST" ]; then
echo "\tOr use environment variable LNDIR_FILTERLIST"
else
echo "\tLNDIR_FILTERLIST = $LNDIR_FILTERLIST"
fi
exit 1
}


# figure out if argument is in the filter directory list
# return 1 if we don't care, 0 if we have a match
function filter_directories {
if [ X"$filter_list" = "X" ]; then
return 1        # no filter list
fi

for i in $filter_list
do
if [ $i = $1 ]; then
return 0
fi
done
return 1
}

# if not a directory, print a message and exit
function test_dirs
{
for i in $*
do
if [ ! -d $i ]; then
echo $i is not a directory relative to $PWD
exit 1
fi
done
}

function copy_tree {
# $1 is  source, $2 is destination, $3 is a string of blanks we increment
#       when we submit

local directories_to_copy=0
local files_to_copy=0
local submit_string="$3   "

#       if [ ! -z $verbose ]; then
#               echo copy_tree from $1 to $2 at $PWD
#       fi
if [ $# -ne 3 ]; then
echo have incorrect count $*
exit 1
fi

pushd $2

test_dirs $1

pushd $1
local files="$(echo *)"
popd
if [ "$files" = '*' ]; then
echo $1 is empty, PWD=$PWD
popd
return  # nothing to do
fi

local to_move=""
local directories=""
local to_link=""

# check to see if starting with absolute path
case $1 in
/* ) local prefix=$1 ;;
*  ) local prefix=../$1 ;;
esac

for file in $files
do
local try=$1/$file
if [ ! -e $try  ]; then
# this also gets rid of hanging symlinks
echo "something wrong, $try doesn't exist at $PWD"
continue
fi

if [ -L $try ]; then
set -v
# figure out if symbolic link is a directory
if [ ! -d $try ]; then
check_file $file
else  # must be a
filter_directories $file
fi
#  code is whether or not to file
if [ $? -ne 1 ]; then
to_link="$to_link $file"
fi
set +v
continue
fi


# must not be a symlink
if [  -f $try   ]
then
if [ ! -z "$file_filter" ]; then
check_file $file
if [ $? -eq 0 ]; then
continue
fi
fi
to_move="$to_move $try"
files_to_copy=$[files_to_copy+1]
# link all files
else
filter_directories $file
if  [ $? -eq 1 ]
then
directories_to_copy=$[directories_to_copy+1]
directories="$directories $file"
fi
fi
done

# make directies and recurse into them
if [ ! -z "$directories" ]; then
mkdir $directories
num_mkdirs=$[num_mkdirs+1]
if [  $verbose ]; then
echo making $directories
fi
if [ $? -ne 0 -a  ! -z "$update" ]; then
echo have problem making $directories
echo aborting
exit 1
fi
for i in $directories
do
echo  "$submit_string" $i/
copy_tree $prefix/$i $i "$submit_string"
done

fi

# link the files...
if [ ! -z "$to_move" ]; then
cp -s $to_move .
if [ $? -ne 0 -a ! -z "$update" ]; then
echo had an error in copy $to_move
fi
num_copies=$[num_copies+1]
if [ $verbose ]; then
echo  linking $files_to_copy files
fi
fi

# link the sym links
if [ ! -z "$to_link" ]; then
cp -a $to_link .
if [ $? -ne 0 -a ! -z "$update" ]; then
echo had an error in cp -a  $to_link .
fi
num_copies=$[num_links+1]
if [ $verbose ]; then
echo  linking $to_link symfiles
fi
fi

popd
}

echo $DIRFROM $DIRTO

#       filter_list="$filter_list " $2

# echo filtering $filter_list

if [ $# -eq 0 ]; then
usage
fi

# set to true when we want statistics
statistics=""

# set to echo all operations
verbose=""

# set  when we're in update mode
update=""

# filter files which match this regexp
file_filter=""

while getopts svf:t:i: c; do
case $c in
s)      statistics=true ;;
v)      verbose=true    ;;
u)      update=true     ;;
i)
filter_list="$OPTARG"
;;
f)
file_filter="$OPTARG"
;;
*)
echo illegal argument
usage
;;
esac
done

shift $(expr $OPTIND - 1 )

DIRFROM=$1

if [ $# -eq 2 ];
then
DIRTO=$2
else
DIRTO=.
fi

if [ ! -d $DIRTO ]
then
echo "$0: $DIRTO is not a directory"
usage
fi

if [ ! -d $DIRFROM ]
then
echo "$0: $DIRFROM is not a directory"
usage
fi

# this isn't really sufficient -- we need to do inode/device numbers
if [ `(cd $DIRFROM; pwd)` = $PWD ]
then
echo "$pwd: FROM and TO are identical!"
exit 1
fi

# initialize counts
num_copies=0
num_links=0
num_mkdirs=0
total_directories=0
total_files=0

copy_tree $DIRFROM $DIRTO ""

if [ ! -z $statistics ]; then
echo Num copies = $num_copies
echo Num mkdirs = $num_mkdirs
echo Num links  = $num_links
fi