Flex - File List EXecute - issues a command on a list of files.

* Function: (See the macro flexhelp)
* To run:   Type "MACRO FLEX [-options] <"command"> [file masks]" from
*           the KEDIT command line.  The required argument
*           specifies the command to execute. (See the macro flexhelp)
*
* Requires: KEDIT 4.0.
* Version:  1.0 (June 1989)
* Author:   Dan McAnarney
*
*? how to handle a filled up ring
*? message in same column if files are on different paths.
*       or using ring option and files are different lengths.
*? don't perform function on dir.dir file or dir.rng file
*  exit gracefully when lastmsg contains error.
*       - check to see if file should be qquit or kept in ring
*       - only give message on first error in file list.
*       - return to dir file
*  exit gracefully when finished
*       - put cursor back on command line
* nEEDS TO SKIP INVISIBLE LINES
*
* If argument is '?' or null show help.
*
 if (arg(1) = '?') | (arg(1) = '')
 then do
   'macro flexhelp'
    exit
 end
*
*  Default options:
*     all default options are false (0) initially
*
 print_width        = 3
 keep_all_files     = 0
 save_changed_files = 0
 keep_changed_files = 0
 dont_keep_message  = 0
 keep_first_word    = 0
 dir_append         = 0
 curr_dir           = 0
 search_ring        = 0
 curr_this_dir      = 0
*
 parameters = arg(1)
 curr_pos = 1
 *
 *  Extract command string
 *  Dec 15, 92 moved above extract options to allow for -'s in command string
 *
 do
    command_start_pos = pos( '"', parameters, curr_pos)
    if command_start_pos = 0
    then do
      'emsg Error: command string does not begin with a double-quote char'
       exit
       end
    curr_pos = command_start_pos + 1
    command_end_pos = pos( '"', parameters, curr_pos)
    if command_end_pos = 0
    then do
       *
       * may be due to use of linend char to perform multiple commands.
       * make a macro to call instead of using the linend char.
       *
      'emsg Error: command string does not end with a double-quote char'
       exit
       end
    command_str = substr( parameters, command_start_pos+ 1, command_end_pos - command_start_pos-1 )
 end
 *
 * EXTRACT OPTION SWITCHES
 *
 curr_pos = 1
 do forever
    switch_pos = pos( '-', parameters, curr_pos)
    curr_pos = switch_pos + 1
    if switch_pos = 0 then leave
    if (switch_pos > command_start_pos ) & (switch_pos < command_end_pos )
    then iterate
    option = substr( parameters, curr_pos, 1 )
         if lower(option) = 'k' then keep_all_files     = 1
    else if lower(option) = 'r' then search_ring        = 1
    else if lower(option) = 's' then save_changed_files = 1
*   else if lower(option) = 'f' then keep_changed_files = 1
    else if lower(option) = 'a' then dir_append         = 1
    else if lower(option) = 'l' then curr_dir           = 1
    else if lower(option) = 't' then curr_this_dir      = 1
    else if lower(option) = 'n' then dont_keep_message  = 1
    else if lower(option) = 'w' then keep_first_word    = 1
    else do
      'emsg Invalid option:' option
       exit
       end
 end
 *
 *  Extract File mask
 *
 curr_pos = command_end_pos + 1
 if length( parameters) > curr_pos
 then do length( parameters) - curr_pos
         mask_start_char = substr( parameters, curr_pos, 1 )
         if mask_start_char \= ' ' then leave
         curr_pos = curr_pos + 1
      end
 file_mask = substr( parameters, curr_pos, length(parameters) - curr_pos + 1 )
 *
 *  Extract ring information
 *
'extract /ring'
 if curr_this_dir \= 0
 then dir_file_name = fileid.1()
 else if search_ring \= 0
 then do
    dir_file_name = 'dir.rng'
   'kedit ' dir_file_name '(nomsg new'
   * if the file was already in the ring, clean it out.
   * need to fix. Shouldn't process command on the file dir.rng.
   'nomsg delete all'
    do i = 1 to ring.0
       file_name = substr(lower(ring.i), 1, pos(" ", ring.i, 1) )
       if file_name ^= dir_file_name
       then 'input' file_name
*     'input' file_name
       end
    end
 *
 *  Make a directory of files to process
 *
 else do
    dir_file_name = 'dir.dir'
    if curr_dir
    then do
       'kedit ' dir_file_name
       * need to fix.  give an error message if file is empty.
    end
    else if dir_append
         then 'nomsg dira' file_mask
         else 'nomsg dir' file_mask
    if rc \= 0
    then do
      'emsg Invalid file mask or no files match mask'
       exit
       end
 end
 *
 *  We have the list of files to process.  Begin processing files in the list.
 *
 *  The variable file_counter is used to prevent an infinite loop on a
 *  command which modifies the dir.dir file ( "dir" or "dira" )
 *
 do file_counter = 1 to size.1()
   ':'file_counter
   'sos makecurr'
*
*   If you look into subdirs it probably will trash your dir.dir file.
*   So make it only not skip when user specifies this file
*   Plus we now have to do a "dir" instead of a "kedit" on these items.
*
    if substr(curline.3(), 17, 5) = '' & ^curr_this_dir
    then iterate
    *
    * edit the file and extract the alteration count to determine if
    *  the command changes the file.
    *
    *  Jul 17 96 added double quotes around file name to allow for spaces in NT names
    *
    if substr(curline.3(), 17, 5) = ''
    then 'dir"'dirfileid.1()'"'
    else 'kedit"'dirfileid.1()'"(nodefext'
   'extract /alt/'
    *
    * Process the command on the file, extracting the last message.
    *
    *
    * need to check.  Do we want 'sos execute' instead of 'command'?
    *
   'command' command_str
    return_code = rc
   'extract /lastmsg/'
    if lower(word( lastmsg.1, 1 )) = 'error'
    then do
* need to add and first file
      'emsg Error occured executing flex command.' command_str
*     'emsg 'lastmsg.1
      'emsg Do you wish to continue? [Y/N]'
      'readv key'
       if ( lower(readv.2) = 'n' )
       then exit
       * exit gracefully
    end
    changed = (alt.1 ^= alt.1() )
    if ( changed ^= 0 )
    then if ( save_changed_files = 1 )
         then 'save'
         else 'qquit'
   *
   * probably have already kept or tossed this file: it looks as if the
   * option to use the files in the ring won't keep them in the ring
   *
   *  Keep this file in the ring?
   *    if we're keeping all files, keep it.
   *    otherwise check to see if the file was originally in the ring
   *       before we toss it.
   *
    if ( search_ring = 0 ) & ( keep_all_files = 0 )
    then do
       keep_in_ring = 0
       do i = 1 to ring.0
          * should drop out of loop when found and not check against entire
          * ring
          if (lower(fileid.1()) = lower(substr(ring.i,1,pos(' ',ring.i))))
          then keep_in_ring = 1
       end
       * need to fix.  if we changed the file and keep flag and save flag are
       *    both false we default to keep ( by not using QQuit).  Is this ok?
       if \keep_in_ring then 'quit'
    end
    *
    *  go back to the directory and add the last message to the file
    *
   'kedit ' dir_file_name
   'sos current'
   'sos endchar'
   'cursor right'
*
* need two spaces before we append the message
*
    if ^dont_keep_message
    then if keep_first_word
         then 'text ' word( lastmsg.1, 1 )
         else 'text ' lastmsg.1
   'refresh'
    if eof()
    then leave
 end
 *
 * display the command issued
 *
 *Apr 12 91 added cursor cmdline
'cursor cmdline'
'msg command issued on files in list was:' command_str
*'restore'
 *
 * drop all used variables.
 *
 drop alt changed command_end_pos command_start_pos command_str curr_dir
 drop curr_pos curr_this_dir dir_append file_mask i keep_all_files
 drop keep_in_ring lastmsg mask_start_char option
 drop parameters print_width return_code ring save_changed_files search_ring
 drop switch_pos file_counter dir_file_name dont_keep_message keep_first_word
 drop file_name