home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / dofiles < prev    next >
Encoding:
Korn shell script  |  1997-08-26  |  12.1 KB  |  437 lines

  1. #!/bin/ksh
  2. # @(#) dofiles.ksh 1.3 95/06/19
  3. # 94/11/22 john h. dubois iii (john@armory.com)
  4. # 94/12/04 Use nmv -i instead of mv if nmv is available.  Added x option.
  5. # 95/01/02 Allow letters to be given in addtion to option numbers;
  6. #          let parameters be given after options on the same line.
  7. # 95/04/11 Offer mail as an option if file is mailer text.
  8. # 95/04/29 Added [no] options; changed old n option to c.
  9. # 95/06/19 Added FBH! menu options.
  10.  
  11. # Usage: uSelect prefix prompt-string word ...
  12. # uSelect presents the words in a select list.
  13. # If prefix is non-null, it is printed before the select list.
  14. # If prompt-string is null, a default prompt is used.
  15. # Each word must have at least one capital letter in it.
  16. # A word may be selected by number or by entering the first capital letter
  17. # in it (in upper or lower case).  The letter (always capitalized) is returned
  18. # in the global var uSelect_ret.  If more than one word is entered, the extra
  19. # words are returned in the global var uSelect_params.
  20. # If a word contains '|', the part before the '|' is used in the select list.
  21. # If no extra parameters are entered, then the part after the | is used as a
  22. # secondary prompt, and the words entered in response are assigned to
  23. # uSelect_params.  The selection fails if no words are entered.
  24. # The entire selection selection string is returned in the global variable
  25. # uSelect_selected.
  26. # The return status is the number of the word selected (starting with 1),
  27. # or 0 if EOF or 'q' is entered.
  28. typeset -uL1 uSelect_ret
  29. function uSelect {
  30.     typeset PS3 Cmd word letters= Prefix=$1 Options FullOpts
  31.     typeset -uL1 l
  32.     typeset -u U
  33.     typeset -i CmdNum=1
  34.  
  35.     # Quit/help is not added as a regular menu item so that one more regular item
  36.     # will fit on the screen.  Instead, list it in prompt.
  37.     [ -n "$2" ] && PS3=$2 || 
  38. PS3="Select by # or letter.  Return for options, Q to quit: "
  39.     shift 2
  40.     set -A FullOpts -- "" "$@"
  41.     for word; do
  42.     Options[CmdNum]=${word%#*}
  43.     l=${word##*([!A-Z])}
  44.     letters=$letters$l
  45.     let CmdNum+=1
  46.     done
  47.     print -u2 "\n$Prefix"
  48.     select Cmd in "${Options[@]}"; do
  49.     set -- $REPLY
  50.     U=$1
  51.     case "$U" in
  52.     Q)  # Quit
  53.         return 0
  54.         ;;
  55.     !*) # Command to pass to shell
  56.         ${REPLY#!}
  57.         print -u2 "\n$Prefix"
  58.         continue
  59.         ;;
  60.     esac
  61.     # Do the elif test in two [[]] so that the one eval'ed is only done if
  62.     # $REPLY is an upper-case letter
  63.     if [ -n "$Cmd" ]; then
  64.         CmdNum=$1
  65. #        # If Quit option was selected by number...
  66. #        [ CmdNum -gt ${#Options[*]} ] && return 0
  67.         uSelect_ret=${Cmd##*([!A-Z])}
  68.     elif [[ "$1" = [a-zA-Z] ]] && eval [[ "$letters" = "*$U*" ]]; then
  69.         uSelect_ret=$U
  70.         letters=${letters%%$U*}
  71.         CmdNum=${#letters}+1
  72.     else
  73.         print -u2 "Invalid selection."
  74.         print -u2 "\n$Prefix"
  75.         continue
  76.     fi
  77.     shift
  78.     uSelect_params="$*"
  79.     word=${FullOpts[CmdNum]}
  80.     if [[ -z "$uSelect_params" && "$word" = *#* ]]; then
  81.         print -n -u2 "${word##*#} "
  82.         read
  83.         if [ -z "$REPLY" ]; then
  84.         print -u2 "Must give a non-null response."
  85.         print -u2 "\n$Prefix"
  86.         continue
  87.         fi
  88.         uSelect_params=$REPLY
  89.     fi
  90.     uSelect_selected=${Options[CmdNum]}
  91.     return $CmdNum
  92.     done
  93.     return 0
  94. }
  95.  
  96. # Usage: DoFile filename
  97. function DoFile {
  98.     typeset file=$1 Cmd dest conglomFile ExtraOptions f matches ftype info
  99.     typeset Command
  100.     typeset -i i=0
  101.  
  102.     if [ -n "$newer" -a ! "$file" -nt "$newer" ]; then
  103.     print -u2 -- "$file is not newer than $newer; skipping."
  104.     return 0
  105.     fi
  106.     if [ -n "$older" -a ! "$file" -ot "$older" ]; then
  107.     print -u2 -- "$file is not older than $older; skipping."
  108.     return 0
  109.     fi
  110.     if [ ! -a "$file" ]; then
  111.     print -u2 -- "$file: No such file.  Skipping."
  112.     return 1
  113.     fi
  114.     if [ ! -f "$file" ]; then
  115.     print -u2 -- "$file: Not a regular file.  Skipping."
  116.     return 1
  117.     fi
  118.     if [ ${#rmFiles[*]} -gt 0 ]; then
  119.     ExtraOptions[i]="delete files currently marKed"
  120.     let i+=1
  121.     ExtraOptions[i]="select files to Unmark"
  122.     let i+=1
  123.     fi
  124.     if $FileDone; then
  125.     ExtraOptions[i]="view file Status"
  126.     let i+=1
  127.     fi
  128.     if $conglomFound; then
  129.     ExtraOptions[i]="Conglomerate onto a specified file#Conglomerate onto:"
  130.     let i+=1
  131.     fi
  132.     if $conglom; then
  133.     conglom -l "$file" | read f matches
  134.     for f in $matches; do
  135.         ExtraOptions[i]="conglomerate Onto $f"
  136.         let i+=1
  137.     done
  138.     fi
  139.  
  140.     set -- $(file $file)
  141.     shift
  142.     ftype="$*"
  143.     if [[ "$ftype" = *mail* ]]; then
  144.     ExtraOptions[i]="read file into mAiler"
  145.     let i+=1
  146.     fi
  147.  
  148.     info=$(l -- "$file")
  149.  
  150.     while :; do
  151.  
  152.     uSelect \
  153. "Current file: $file
  154. File type: $ftype
  155. $info" \
  156. "" \
  157. "View" \
  158. "Edit" \
  159. "Move#Move to:" \
  160. "Forward file via email#Mail to:" \
  161. "uuencode Binary file & email it#Mail to:" \
  162. "Run a command on the file#Command:" \
  163. "mark for Deletion" \
  164. "Go on to next file" \
  165. "print Help" \
  166. "${ExtraOptions[@]}" && Finish
  167. # Possible ExtraOptions: Delete marked, select to Unmark, view Status,
  168. # Conglomerate, conglomerate Onto, read file into mAiler.  Q used by Quit.
  169. # A B C D E F G H K M O Q R S U V
  170.  
  171.     $debug && set -x
  172.     case "$uSelect_ret" in
  173.     A)  # Run file into mailer
  174.         mail -f "$file"
  175.         ;;
  176.     B)  # uuencode Binary file & email it
  177.         uuencode "$file" "$file" |
  178.         mail -s "File transfer ($file), uuencoded" $uSelect_params
  179.         ;;
  180.     C)  # Conglomerate
  181.         dest=$uSelect_params
  182.         if [ -n "$dest" ] && conglom -- "$file" "$dest"; then
  183.         FilesConglomerated="$FilesConglomerated $file"
  184.         break
  185.         fi
  186.         ;;
  187.     F)  # Forward file via email
  188.         mail -s "File transfer ($file)" $uSelect_params <"$file"
  189.         ;;
  190.     K)  # Delete marked files
  191.         FilesRemoved="$FilesRemoved ${rmFiles[*]}"
  192.         print "Removing: ${rmFiles[*]}"
  193.         rm -- "${rmFiles[@]}"
  194.         unset rmFiles[*]
  195.         break
  196.         ;;
  197.     E)  # Edit
  198.         "$VISUAL" "$file";;
  199.     G)  # Go on to next file
  200.         FilesUntouched="$FilesUntouched $file"
  201.         break
  202.         ;;
  203.     H)  # print Help
  204.         print -- \
  205. "Options (in the following, the parameter referred to can be given after the
  206. command; if it is not, it will be queried for):
  207. A invokes the standard mailer on the file.
  208. B and F send the file by mail to the destination given by the parameter.
  209.   If B is used, the file is uuencoded first.  The subject is set to 'File
  210.   transfer (filename)' for F and 'File transfer (filename), uuencoded' for B.
  211. C and O conglomerate the file (append it to another file and then remove it).
  212.   C takes the target file as the parameter; O offers a specific list of files.
  213. D marks the file for deletion.  It will be deleted when the K command is given,
  214.   or if the option to remove all marked files is used when $name is quit.
  215. E runs the editor on the file.  The editor is given by the environment variable
  216.   VISUAL; or if not set, the variable EDITOR; or if not set, the \"vi\" editor.
  217. G skips the file (no action is taken on it).
  218. K immediately deletes any files that have been marked for deletion.
  219. M moves the file to the new name given by the parameter.
  220. R passes the file as an argument to the command given by the parameter.
  221. S shows file status; it reports which file have been moved, removed, marked for
  222.   removal, conglomerated onto others, and left alone.
  223. U allows files that have been marked for removal to be unmarked.
  224. V views the file using a pager.  The pager is given by the environment variable
  225.   PAGER; or if it is not set, the standard pager \"more\".
  226. !command  runs command with any arguments and then returns to the menu."
  227.         print -n "Press return to continue..."
  228.         read
  229.         ;;
  230.     D)  # Mark for deletion
  231.         rmFiles[${#rmFiles[*]}]=$file
  232.         break
  233.         ;;
  234.     M)  # Move
  235.         dest=$uSelect_params
  236.         if [ -n "$dest" ] && $mv -- "$file" "$dest"; then
  237.         FilesMoved="$FilesMoved $file"
  238.         break
  239.         fi
  240.         ;;
  241.     O)  # Conglomerate onto
  242.         set -- $uSelect_selected
  243.         if conglom -- "$file" "$3"; then
  244.         FilesConglomerated="$FilesConglomerated $file"
  245.         break
  246.         fi
  247.         ;;
  248.     R)  # Run a command on file
  249.         $uSelect_params "$file"
  250.         ;;
  251.     S)  # View file status
  252.         print \
  253. "Files moved: $FilesMoved
  254.  
  255. Files removed: $FilesRemoved
  256.  
  257. Files marked for removal: ${rmFiles[*]}
  258.  
  259. Files conglomerated onto others: $FilesConglomerated
  260.  
  261. Files left alone: $FilesUntouched"
  262.         ;;
  263.     U) # Select files to unmark
  264.         UnselectFiles
  265.         ;;
  266.     V)  # View file
  267.         ${PAGER:-more} "$file";;
  268.     esac
  269.     $debug && set +x
  270.     done
  271.     FileDone=true
  272.     return 0
  273. }
  274.  
  275. function UnselectFiles {
  276.     typeset file
  277.     typeset -i filenum
  278.  
  279.     # Must have an outer loop so file list is rebuilt when a file is unmarked
  280.     while :; do
  281.     print \
  282. "These files are marked for removal.
  283. Enter the number of one to unmark, or r to return to the previous menu."
  284.     select file in "${rmFiles[@]}"; do
  285.         [[ "$REPLY" = [rR] ]] && return
  286.         if [ -n "$file" ]; then
  287.         let filenum=REPLY-1
  288.         # Print this insteead of $file to make it obvious if something
  289.         # goes wrong
  290.         print "Unmarking: ${rmFiles[filenum]}"
  291.         unset rmFiles[filenum]
  292.         # normalize indices
  293.         set -A rmFiles -- "${rmFiles[@]}"
  294.         if [ ${#rmFiles[*]} -eq 0 ]; then
  295.             print "All files unmarked."
  296.             return
  297.         fi
  298.         break
  299.         fi
  300.     done
  301.     done
  302. }
  303.  
  304. function Finish {
  305.     typeset answer
  306.  
  307.     if [ ${#rmFiles[*]} -eq 0 ]; then
  308.     print -u2 "No files marked for removal."
  309.     exit 0
  310.     fi
  311.     print \
  312. "Files marked for removal: ${rmFiles[*]}
  313. Select an option by number:"
  314.     select answer in \
  315.     "Remove all marked files" \
  316.     "Do not remove any files" \
  317.     "Select files to unmark"
  318.     do
  319.     case "$answer" in
  320.     Remove*)
  321.         print "Removing: ${rmFiles[*]}"
  322.         rm -- "${rmFiles[@]}"; break;;
  323.     Do*)
  324.         break;;
  325.     Select*)
  326.         UnselectFiles;;
  327.     esac
  328.     [ ${#rmFiles[*]} -eq 0 ] && break
  329.     done
  330.     exit 0
  331. }
  332.  
  333. type conglom > /dev/null && conglomFound=true || conglomFound=false
  334. [ -f "${CGFILES:-$HOME/.files}" ] && $conglomFound &&
  335. conglom=true || conglom=false
  336. debug=false
  337. FileDone=false
  338.  
  339.  
  340. [ -z "$VISUAL" ] && VISUAL=${EDITOR:-vi}
  341.  
  342. name=${0##*/}
  343. Usage="Usage: $name [-hc] [-n<file>] [-o<file>] file ..."
  344.  
  345. while getopts :hicxn:o: opt; do
  346.     case $opt in
  347.     h)
  348.     echo \
  349. "$name: deal with files.
  350. $name takes a list of files and for each one gives a list of options for what
  351. may be done with it.  If no filenames are given on the command line, they are
  352. read from the standard input, one per line.  The options are:
  353. View: the file is passed to a pager.
  354. Edit: the file is passed to an editor.
  355. Move: a new name is queried for, and the file is moved to it.
  356. Run a command on the file: a command line is queried for, and is run with the
  357.     filename appended to it.
  358. Mark for removal: the file is added to a list of files to be removed.
  359. Conglomerate onto another file: ask for another filename and append the
  360.     contents of this file to it; then remove the original file.
  361. Go on to next file: do not do anything to the file.
  362. Remove files currently marked: immediately removed the marked files.
  363. View file status: list what has been done with each file processed so far.
  364. Quit: ask whether marked files should be removed; if the answer is yes, 
  365.     remove then; then quit.
  366. If the 'conglom' utility finds matches for the file, conglomeration onto
  367. specific files is also offered.
  368. $Usage
  369. Options:
  370. -h: Print this help.
  371. -c: Do not offer a list of files that the file may be conglomerated onto
  372.     as an option.  This avoid running 'conglom' for each file to find matches.
  373. -n<file>: Process only files newer (more recently modified) than <file>.
  374. -o<file>: Process only files older (less recently modified) than <file>."
  375.     exit 0
  376.     ;;
  377.     c)
  378.     conglom=false
  379.     ;;
  380.     n)
  381.     newer=$OPTARG
  382.     if [ ! -a "$newer" ]; then
  383.         print -u2 -- "$newer: no such file."
  384.         exit 1
  385.     fi
  386.     ;;
  387.     o)
  388.     older=$OPTARG
  389.     if [ ! -a "$older" ]; then
  390.         print -u2 -- "$older: no such file."
  391.         exit 1
  392.     fi
  393.     ;;
  394.     x)
  395.     debug=true
  396.     ;;
  397.     +?)
  398.     print -u2 "$name: options should not be preceded by a '+'."
  399.     exit 1
  400.     ;;
  401.     :) 
  402.     print -r -u2 -- \
  403.     "$name: Option '$OPTARG' requires a value.  Use -h for help."
  404.     exit 1
  405.     ;;
  406.     ?) 
  407.     print -u2 "$name: $OPTARG: bad option.  Use -h for help."
  408.     exit 1
  409.     ;;
  410.     esac
  411. done
  412.  
  413. # remove args that were options
  414. let OPTIND=OPTIND-1
  415. shift $OPTIND
  416.  
  417. # nmv is more careful above moves
  418. if type nmv > /dev/null; then
  419.     mv='nmv -i'
  420.     $debug && print -u2 'Using nmv -i instead of mv'
  421. else
  422.     mv=mv
  423. fi
  424.  
  425. if [ $# -lt 1 ]; then
  426.     # If reading file list, use /dev/tty for user input
  427.     while read file; do
  428.     DoFile "$file" < /dev/tty
  429.     done
  430. else
  431.     for file; do
  432.     DoFile "$file"
  433.     done
  434. fi
  435.  
  436. [ ${#rmFiles[*]} -ne 0 ] && Finish
  437.