#!/bin/bash
# *********************************************************************
#  Written by and copyright Carlo Strozzi <carlos@linux.it>.
#
#  edittable: NoSQL trivial table editor. Requires a vi(1)-compatible
#	      full-screen editor.
#  Copyright (C) 1998-2001 Carlo Strozzi <carlos@linux.it>
#
#  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 of the License, 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.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#  2001-03-24 Beta Code
#  2001-04-06 Removed record-level locking facilities.
#  2001-05-25 Switched to lockfile(1) for table-locking
#  2001-05-26 Fixed unsupported 'if !' of early ash(1) versions.
#  2001-06-20 Better naming convention for temporary files.
#  2001-08-05 Added option '--list'.
#  2002-04-14 Added inline help.
#
# *********************************************************************

# $Id$


while [ $# -gt 0 ]
do
   case $1 in
	-l|--list)  edit_format=list ;;
	-h|--help)
	     cat <<EOF

                      NoSQL utility: edittable

NoSQL trivial table editor.

Usage: edittable [options] tablename

Options:
    --list (-l)
      Convert the table into 'list' format before editing.
      Useful with tables that contain rows wider than the
      available screen. The table is then automatically
      converted back to the usual format when editing is
      complete.

    --help (-h)
      Display this help text.

Notes:

Invokes whatever editor is defined in the EDITOR environment variable,
defaulting to vi(1) if the variable is unset. The editor should either
be vi(1) or one of its many compatible clones, like elvis(1), vim(1),
nvi(1), and so on.

Make sure not to break the table structure while editing, like altering
the number of tabs in a row or not respecting the list specification
if editing in list format. Upon leaving the editor, this program will
try and check for a broken table structure and prompt for corrections,
but those checks aren't bullet-proof and your mileage may vary.
EOF
	     exit 1
	;;
	-*) ;;				# Skip unknown options.
	*) args="$args $1" ;;
   esac
   shift
done

set - $args

if [ "$1" = "-l" ] || [ "$1" = "--list" ]
then
   edit_format=list
   shift
fi

if [ $# != 1 ]
then
   echo 'Usage: edittable [-l|--list] tablename' >&2
   exit 1
fi

tbl_path=$1

out_dir=`dirname $tbl_path`

cd $out_dir
if [ $? -ne 0 ]
then
   echo Could not access directory "'$out_dir'" >&2
   exit 1
fi

tbl_file=`basename $tbl_path`

# Lock the target table before doing anything.

lockfile -r0 $tbl_file.lock 2>/dev/null
if [ $? -ne 0 ]
then
   echo edittable: unable to lock "'$tbl_file'" for write >&2
   exit 1
fi

# We must create the work files in the same directory as the
# target table for 'mv' to work as desired.

edit_tmp=`mktemp ./$tbl_file.XXXXXX` || exit $?
tbl_tmp=`mktemp ./$tbl_file.XXXXXX` || exit $?

# Set-up trapping on signals.
trap_list="$edit_tmp $tbl_tmp $tbl_file.lock"
trap "rm -f $trap_list; trap 0; exit 0" 0 1 2 3 15

istable < $tbl_file
if [ $? -ne 0 ]
then
   echo edittable: file "'$tbl_file'" is not a valid table >&2
   exit 1
fi

if [ "$edit_format" = list ]
then
   tabletolist < $tbl_file > $edit_tmp
else
   cp $tbl_file $edit_tmp
fi

offset=1
[ "$EDITOR" = "" ] && EDITOR=vi
editor=$EDITOR

while :
do
   if [ $EDITOR = vi ]
   then
      $editor +$offset $edit_tmp
   else
      $editor $edit_tmp
   fi

   set --
   if [ "$edit_format" = list ]
   then
      set - `islist --verbose --edit < $edit_tmp`
   else
      set - `istable --verbose --edit < $edit_tmp`
   fi

   if [ "$2" = "" ]
   then
      break
   else
      offset=$2
      echo ''
      echo 'What shall I do ?'
      echo ''
      echo '1) Re-edit the table'
      echo '2) Quit without saving the changes'
      echo '3) Commit the changes anyway'
      printf '\n=> '

      # Read one line from the terminal.
      read edit_action

      [ "$edit_action" = "" ] && edit_action=2

      case $edit_action in
         1) continue ;;
         2) exit 4 ;;
         3) break ;;
      esac
   fi
done

# Keep the table sorted on the key column.
if [ "$edit_format" = list ]
then
   listtotable < $edit_tmp | sorttable > $tbl_tmp
else
   sorttable < $edit_tmp > $tbl_tmp
fi

mv $tbl_tmp $tbl_file || exit 1

# End of program.
