#!/bin/ksh
# If using with 'bash' either:
#      change #!/bin/ksh to #!/bin/bash  or
#      ln -s /bin/bash /bin/ksh    to make a symbolic link.
# @(#) cabe - v02.00.00 - resave filePro processing tables encoded
# @(#)                    or in ASCII format, or tokenize them
#      Following modifications made by Jerry Rains.
#      Modified to work with Linux 1/17/01.  This consisted of:
#      Changing FP[((i+=1))]= to 'i=`expr $i + 1` ; FP[i]='
#      Changing ksh print statements to $ECHO.
#      Removed whence command and just used awk.
#      Wrote routine to use 'type' to find fastest awk - 1/31/01
#      Changed logic from ( -z $PFDATA || -z $PFDIR ) to && - 1/31/01
#      Wrote whence script so whence can be used in Linux - 2/20/01
#
# For a usage message, execute:  cabe -h
#
# NOTE: If there is a syntax or other error on any table, filePro
#       will report "*** A filePro Error Has Occurred ***", with
#       information about the error, on the standard error output.
#       You must send the script a QUIT signal (<ctrl>+\) to exit
#       that process, or otherwise kill the process, then fix the
#       offending table.
#
# NOTE: 'cabe' must be in a directory in PATH when executed by the
#       user "root".
#
# NOTE: For making this program availabe to regular users, see the
#       discussion of it at the bottom of this file.
#
#=#=#=#=#=#=#=#=#=#=#=#=#  User Definable Parameters  #=#=#=#=#=#=#=#=#=#=#=#=#
#
#   By default, filePro associates tables saved using the [dr]cabe
# menu choice 3 (Output Processing) with the table "prc.automatic".
# This can cause a problem when dummy variables are defined both on
# the table being saved and on the automatic table:  when the table
# is saved, filePro notes the multiply defined dummies and prompts
# with "Press [ENTER] to continue:", which can't be anticipated in
# the stream of commands being sent to the CABE program's standard
# input.
#
# Default automatic tables ("prc.automatic") are saved using CABE
# menu choice 1 (Automatic Processing), which avoids the certain
# reporting of multiply defined dummies were they to be saved with
# menu choice 3.
#
# To have ALL tables saved and NOT associated with the default
# automatic table set NO_AUTO to " -y '' ":
NO_AUTO=" -y '' "
#
# To have all tables saved in association with the default
# automatic table set NO_AUTO to NUL (""):
# NO_AUTO=""
#
# *** Any tables required to be saved in association with automatic tables
# *** other than the default "prc.automatic" must be resaved individually.
# *** This is of concern only when tokenizing tables.
#                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Assign to PFTOKSIZE a value great enough to assure success:
PFTOKSIZE=200000
#
# Assign to PFAUTOKSIZE a value great enough to assure success:
PFAUTOKSIZE=200000
#
# Assign the pathname for a LOG file (assign "/dev/null" for no log):
LOG=/tmp/cabe.$$
#
#=#=#=#=#=#=#=#=#=#=#=#  End User Definable Parameters  #=#=#=#=#=#=#=#=#=#=#=#

# execute this section of code only on initial startup:
[[ $@ != "$PROG.$pid" ]] && {
  PROG=$0 ; export PROG
  if [ `echo "x\c"` = "x" ]
  then
      # Then the standard command will work just fine.
      ECHO="echo"
  else
      # Otherwise we need to enable the 'backslash' processing.
      ECHO="echo -e"
  fi
  export ECHO
  # See if any of PFPROG, PFDATA, & PFDIR are not in the environment;
  # prefer PFPROG, PFDATA & PFDIR, but accept FPPROG, FPDATA or FPDIR.
  # If any are missing, read /etc/default/fppath putting defaults for
  # PFPROG, PFDATA & PFDIR in the array elements FP[1], FP[2] & FP[3]:
  : ${PFPROG:=$FPPROG} ${PFDATA:=$FPDATA} ${PFDIR:=$FPDIR} ${PFDSK:=$FPDSK}
  [[ -z $PFPROG || ( -z $PFDATA && -z $PFDIR ) ]] && {
    [[ -r /etc/default/fppath ]] && { typeset -i i=0
      while read ; do i=`expr $i + 1` ; FP[i]=$REPLY ; done </etc/default/fppath
    } || {
      $ECHO "\n  $PROG:  Can't read \"/etc/default/fppath\".\n" ; exit 2
    }
  }
  # Put the filePro programs' and the current directories in the PATH:
  PATH=$PFPROG/fp:$PWD:$PATH
  # See if the filePro files directory can be found:
  [[ -d ${PFDATA=${FP[2]}}${PFDIR=${FP[3]}}/filepro ]] || {
    $ECHO "\n  $PROG:  Can't find the filePro Files.\n" ; exit 2
  }
  [[ -w $PFPROG/fp/lib/errmsg ]] || {
    $ECHO "\n  $PROG:  Must be run by \"root\" or \"filepro\".\n" ; exit 2
  }

#jmr Test to see if whence is a good function.  If not use whence script.
tst=`type whence`
case $tst in
  *shell?builtin) WHENCE=whence ;;
      *not?found) {
               [ -x whence ] && instdir=`pwd`
               [ -x $PFPROG/fp/util/bin/whence ] && instdir=$PFPROG/fp/util/bin
               [ -x $instdir/whence ] && WHENCE=$instdir/whence
               };;
               *) WHENCE=`whence whence` ;;
esac
[ -z "$WHENCE" ] && {
  $ECHO "whence not found."
  $ECHO "Either use /bin/ksh or run cabe from the directory that contains whence."
  exit
  }
  # Use the fastest AWK in the user's PATH:
  : ${AWK:=$($WHENCE mawk)} ${AWK:=$($WHENCE gawk)} ${AWK:=$($WHENCE awk)}
  [ "$AWK" ] || AWK="awk"

  # Compose the string needed to save a processing table:
  SAVE=$($ECHO -n "\033\033")
  
  # Test if ABE=ASCII is set in the environment:
  case $ABE in
    [Aa][Ss][Cc][Ii][Ii]) a=$so-a$se e=-e ;;
                       *) e=$so-e$se a=-a ;;
  esac

  # See if 'rcabe' is available:
  [[ -x $PFPROG/fp/rcabe ]] && {
    tok="|-t" ; t=t
    Tok="\n    -t - Tokenize all processing tables that are not up-to-date"
  }

  # Construct a usage message:
  Usage="$cl
  $PROG [-f filename] [-a|-e] [-r$tok]\n
    -f filename - filename may be a quoted list of space separated
                  filePro file names (including regular characters
                  and/or shell metacharacters)
    $a - Save processing tables in ASCII format
    $e - Save processing tables encoded
    $so-r$se - Resave processing tables$Tok\n
  * Default flags are highlighted.
  * Executed with no arguments, the program is interactive.
  * Can be executed only by the user \"filepro\" or \"root\".
  * Tables processed are listed in a log file (/tmp/cabe.\$$).
  * If you see a message similar to:\n
      *** A filePro Error Has Occurred ***
      ...
      Standard Input Redirected\n
    break out by sending the program a QUIT signal (<ctrl>\).\n"

  # Change to the "filepro" directory:
  cd $PFDATA$PFDIR/filepro
  
  # Test for command line flags on the initial execution:
  (( $# > 0 )) && {
    # Get command line flags:
    REM_ABE=$ABE ; ABE=XXXXX
    while getopts aer${t}f: flag 2>/dev/null
    do case $flag in
         f) eval $( $AWK -v OPTARG="$OPTARG" '
              BEGIN { x = split(OPTARG,files)
                for (i=1;i<=x;i++) $ECHO "FILE[" i "]=" files[i] "/map" }' ) ;;
         a) [[ $ABE = XXXXX ]] && ABE=ASCII ;;
         e) [[ $ABE = XXXXX ]] && ABE="" ;;
         r) CABE=$PFPROG/fp/dcabe ;;
         t) CABE=$PFPROG/fp/rcabe ;;
        \?) $ECHO "$Usage" ; exit 2 ;;
       esac
    done
    shift $(( $OPTIND - 1 ))
    [[ $ABE = XXXXX ]] && ABE=$REM_ABE
  }
  [[ -z $CABE ]] && CABE=$PFPROG/fp/dcabe

  # Test if no filePro files were already specified:
  (( ${#FILE[@]} == 0 )) && {
    trap ' $ECHO -n "$CN" ; trap 0 ; exit ' EXIT HUP INT QUIT TERM
    export Interactive=1
    : ${cl:=$(tput clear)} ${ho:=$(tput home)} ${md:=$(tput bold)}
    : ${se:=$(tput rmso )} ${so:=$(tput smso)} ${up:=$(tput cuu1)}
    : ${CO:=$(tput civis)} ${CF:=$CO} ${CN:=$(tput cnorm)} ${ce:=$(tput el)}
    [[ -z $CN ]] && CF=
    H=$cl
    [[ -n $Tok ]] && {
      header="$so CABE $se -$md Resave or Tokenize Processing Tables$se"
      msg0="\n\n  $so R ${se}esave or $so T ${se}okenize Processing Tables ?  ( $so r $se or t ):$ce $CN"
#jmr Changed for Linux
      until [ "$R_or_T" = r -o "$R_or_T" = t ]
      do $ECHO -n "$CF$H\n  $header$msg0"
         read R_or_T
         case $R_or_T in R) R_or_T=r ;; T) R_or_T=t ;; esac
         [ -z "$R_or_T" ] && R_or_T=r
         H=$ho
      done
      case $R_or_T in
        [Rr]) header="$so CABE $se -$md Resave Processing Tables$se$ce"
              what="${md}Resaved$se" ; CABE=$PFPROG/fp/dcabe ;;
        [Tt]) header="$so CABE $se -$md Tokenize Processing Tables$se$ce"
              what="${md}Tokenized$se" ; CABE=$PFPROG/fp/rcabe ;;
      esac
    } || {
      header="$so CABE $se -$md Resave Processing Tables$se"
    }
    [[ $a = "-a" ]] && dflt2="  [default]" || dflt1="  [default]"
#jmr Changed for Linux
    until [ "$SAVE_HOW" = "1" -o "$SAVE_HOW" = "2" ]
    do $ECHO -n "$CF$H\n  $header\n
  $so 1 $se - Save processing tables in$md ASCII$se format.${dflt1}$ce\n
  $so 2 $se - Save processing tables$md encoded$se.${dflt2}$ce\n
  Your choice: $CN$ce"
       read SAVE_HOW
       [[ -z $SAVE_HOW ]] && {
         [[ $a = "-a" ]] && SAVE_HOW=2 || SAVE_HOW=1
       }
       H=$ho
    done
    case $SAVE_HOW in
      1) ABE=ASCII ; msg2="  [ ABE=ASCII ]" ;;
      2) ABE=""    ; msg2="  [ ABE=\"\" ]" ;;
    esac
    $ECHO "$CF$cl\n  $header$msg2\n
$md  ALL$se tables in the filePro files you name will be $what.\n
  Enter the $so names $se of filePro files, one file name per line.\n
  Shell metacharacters are ${md}OK$se.  (For example, $md*$se for all filePro files,
  $md[A-Z]*$se for those with names beginning with an upper case letter, or
  ${md}fp*$se for those with names beginning with the letters \"fp\", etc.)\n
  Press $so ENTER $se alone when done:\n$CN"
    typeset -i i=0
    while ((i+=1))
    do $ECHO -n "  "
       read file ; [[ -z $file ]] && break
       FILE[i]="$file/map"
    done
  }
  for file in ${FILE[@]}
  do [[ -r $file ]] || {
       $ECHO "  $PROG:  \"`dirname $file`\" is not a filePro File."
       continue
     }
     FILES="$FILES $file"
  done
  [[ -z $FILES ]] && {
    $ECHO "\n  $PROG:  No filePro Files were named.\n"
    exit 0
  }
  PROG=$($WHENCE $PROG)
  case $CABE in
    *dcabe) SAVE="${SAVE}NN"   ;;
         *) SAVE="${SAVE}YYNN" ;;
  esac
  pid=$$
  export PFDATA PFDIR PFPROG AWK ABE FILES SAVE CABE PROG pid
  export NO_AUTO PFTOKSIZE PFAUTOKSIZE LOG
}
trap '' INT QUIT

# So we are later able to test if user "filepro" can write to all
# "prc.*" files encountered, execute the script as user "filepro":
eval `$AWK -F: '$1~/^filepro$/{print "uid="$3;exit}' /etc/passwd`
ID=`id`
case $ID in
    uid=$uid\(filepro\)*) : ;;
  *euid=$uid\(filepro\)*) : ;;
                       *) su filepro -c "$PROG $PROG.$pid" ; exit 0 ;;
esac

################################################################################
# the lines below do the work:
################################################################################
[[ -n $Interactive ]] && { IA=1 ; $ECHO "$cl  Generating Commands for . . . " ;} || IA=0
# loop through all filePro files:
for fpdir in $FILES
do fpfile=`dirname $fpdir`
   # change to the filePro file "$fpfile" directory:
   cd $PFDATA$PFDIR/filepro/$fpfile
   # continue if there are no processing tables:
   [[ "$($ECHO prc.*)" = "prc.\*" ]] && continue
   # loop through all processing tables in this filePro file:
   for prc in prc.*
   do # skip "apparent" tables user "filepro" can't write to:
      [[ -w $prc ]] || continue
      # skip 0-length processing tables
      [[ -s $prc ]] || continue
      # if tokenizing, skip tables that are up-to-date:
      case $CABE in
        *rcabe) eval `$AWK -v prc="$prc" '
                      BEGIN{print "tok=tok." substr(prc,5)}'`
                # if the tok file exists, and the prc file is not newer than
                # the tok file or if we can't write to the tok file, continue:
                [[ -e $tok && ( $tok -nt $prc || ! -w $tok ) ]] && continue
                ;;
      esac
      # print the string "filePro_File_Name Table_Name" for each table:
      $ECHO "$fpfile $prc"
   done
done |
$AWK -v LOG="$LOG" -v SAVE="$SAVE" -v ABE="$ABE" -v IA="$IA" \
     -v CABE=" $CABE " -v NO_AUTO=" $NO_AUTO " '
{
  # Remove the "prc." from the table name:
  $2 = substr($2,5)
  # when a new filePro file is encountered, add its name as an element
  # of the array "fPfile" and initialize the variable "table_num":
  if ( rem_fpfile != $1 ) {
    # count the number of filePro files
    file_num++
    fPfile[file_num] = rem_fpfile = $1 ; table_num = 0
  }
  # count the number of tables in the current filePro file:
  tables[file_num] = ++table_num
  # add the name of the table as an element in the array "table":
  table[file_num,table_num] = $2
}
END {
  # exit if there are no tables to process:
  if ( NR == 0 ) { exit 0 }
  if ( SAVE ~ /YY/ ) { adv_fmt = "Tokenizing" ; log_fmt = "Tokenizing" }
  else {
    adv_fmt = "Resaving" ; log_fmt = "Resaving"
    if ( ABE ~ /^[Aa][Ss][Cc][Ii][Ii]$/ ) {
      adv_fmt = adv_fmt " ASCII" ; log_fmt = log_fmt " ASCII"
    }
    else {
      adv_fmt = adv_fmt " ENCODED" ; log_fmt = log_fmt " ENCODED"
    }
  }
  adv_fmt = adv_fmt ": %s/prc.%s\n" ; log_fmt = log_fmt ": %s/prc.%s\n"
  # loop through the array "fPfile" for all filePro file names:
  for (i=1;i<=file_num;i++) {
    if ( IA && i > 1 ) print "" >"/dev/tty"
    # build a command to process all of these tables:
    # first the [dr]cabe menu choice for a filename (4) followed by the
    # filePro file name without a following newline:
    cmd = 4 fPfile[i]
    # if the length of the file name is less than 32, issue a newline:
    if ( length(fPfile[i]) < 32 ) cmd = cmd "\n"
    # loop through all tables in this filePro file;
    for (j=1;j<=tables[i];j++) {
      # print the "dcabe" menu choice number followed by the table name
      # (excpt for "automatic" tables) and a newline:
      if ( table[i,j] ~ /^automatic$/ ) cmd = cmd "1"
      else cmd = cmd 3 table[i,j] "\n"
      # add the string to save the table, without a following newline:
      cmd = cmd SAVE
      # write to the LOG file:
      printf log_fmt, fPfile[i], table[i,j] >LOG
      # if interactive, print a progress report to the screen:
      if ( IA ) printf adv_fmt, fPfile[i], table[i,j] >"/dev/tty"
    }
    if ( IA ) printf "  Working . . . " >"/dev/tty"
    cmd = cmd "X"
    # use system() to pipe the command to CABE:
    CABE_CMD = CABE fPfile[i] NO_AUTO ">/dev/null"
    CABE_CMD = "$ECHO \"" cmd "\" | " CABE_CMD
    if ( system(CABE_CMD) ) {
      err_msg = "  ERROR on a table in the filePro File: " fPfile[i]
      print "\n" err_msg >"/dev/stderr"
      print err_msg >LOG
    }
  }
}'

[[ -n $Interactive ]] && $ECHO "\n  Done . . .\n"
################################################################################

exit 0

#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#
#
#  To make 'cabe' available to regular users:
#  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#  This table, placed in any filePro file as "prc.cabe" makes
#  it possible for regular users to execute 'cabe':
#
#    ::end ' @(#) prc.cabe - execute 'cabe' SUID filepro:
#    @menu:::
#    ::ca = getenv["PFCABE"]:
#    :ca eq "":ca = getenv["FPCABE"]:
#    :ca eq "":ca = "cabe":
#    ::system ca:
#    ::exit:
#
#  with:
#
#    $PFPROG/fp/dclerk filename -sAnyName -y '' -z cabe
#
#  or, if 'cabe' is not in a directory in PATH, with:
#
#    PFCABE=/path/to/cabe $PFPROG/fp/dclerk filename -sAnyName -y '' -z cabe
#
#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#
#
# EOF 'cabe' - Bob Stockler - Wed Nov 29 20:20:20 EST 2000
