/*rx
    $VER: $Id: ExamineIndex.rexx,v 1.10 1995/07/26 18:05:56 tf Exp $

    This script compares the LOCAL index file with the Aminet INDEX
    file and reports differences in existance, path and comment.
    If either COMMENT or RELOCATE keyword (or both) were given in the
    command-line then the file position or filenote will be modified
    respectively if needed.

    (The Aminet directory hierarchy can be created using 'MakeTree.rexx')

    This ARexx script needs the AmigaDOS commands "List", "Sort",
    "Search", "Filenote", "Copy" and "Delete" available in your path.

    Initial revision by Tobias Ferber, 24-Feb-94
*/


options failat 21

call pragma('S',102400)

/* initialize globals */

mirrorpath  = ""  /* e.g. downloads:aminet/      */
kickpath    = ""  /* e.g. incoming:              */
localindex  = ""  /* e.g. downloads:aminet/LOCAL */
masterindex = ""  /* e.g. downloads:aminet/INDEX */

fastprefix  = "FAST."
tempfile    = "T:ExamineIndexTemp." || pragma('Id')
template    = "FILE/K/A,WITH/K/A,PATH/K,RELOCATE/S,KICK/K,COMMENT/S,MAKEPATH/S,FAST/S"
args        = ""
cliopts     = ""

signal on HALT
signal on BREAK_C
signal on BREAK_D


/* parse args */

if ( arg() < 1 ) | ( (arg() = 1) & arg(1)= '?' )  then do
  options prompt template': '
  parse pull args
  end
else do n=1 for arg() /* RXFB_TOKEN for RX ?! */
  args= args || arg(n)
  end

do while words(args) > 0
  av= next_arg()
  select
    when upper(av) = "FILE" then do
      if words(args) > 0 then localindex= next_arg()
      else exit bad_args("Missing local index filename after FILE keyword")
      end /* FILE */

    when upper(av) = "WITH" then do
      if words(args) > 0 then masterindex= next_arg()
      else exit bad_args("Missing master index filename after WITH keyword")
      end /* WITH */

    when upper(av) = "PATH" then do
      if words(args) > 0 then do
        mirrorpath= next_arg()
        if words(mirrorpath) < 1 then mirrorpath= pragma('D')
        end
      else exit bad_args("Missing mirror pathname after PATH keyword")
      end /* PATH */

    when upper(av) = "KICK" then do
      if words(args) > 0 then do
        kickpath= next_arg()
        if words(kickpath) < 1 then kickpath= pragma('D')
        end
      else exit bad_args("Missing destination pathname after KICK keyword")
      end /* KICK */

    when upper(av) = "RELOCATE" then cliopts = cliopts || 'cd'
    when upper(av) = "COMMENT"  then cliopts = cliopts || 'n'
    when upper(av) = "MAKEPATH" then cliopts = cliopts || 'm'
    when upper(av) = "FAST"     then cliopts = cliopts || 'f'

    otherwise do
      if av ~= '?' then exit bad_args("Unknown keyword" av)
                   else exit bad_args("")
      end

  end /* select */

end /* do */

call pragma('W','N')


/* try to get missing local index file */

if ( words(localindex) < 1 ) & ( exists('c:RequestFile') ) then do
  cwd= strip(pragma('D'),'B','"')
  address command 'RequestFile >' tempfile 'DRAWER "' || cwd || '" TITLE "Select local index file..." NOICONS'
  if open('fp',tempfile,'R') then do
    localindex= strip(readln('fp'),'B','"')
    call close('fp')
    address command 'Delete QUIET FILE' tempfile
    end
  else localindex= ""
  end

if words(localindex) < 1 then exit bad_args("Local index filename missing")

if ~exists(localindex) then do
  say 'Failed to locate your local index file "'localindex'"'
  exit 10
  end


/* try to get missing master index path or filename */

if ( words(masterindex) < 1 ) & ( exists('c:RequestFile') ) then do
  cwd= strip(pragma('D'),'B','"')
  if pos('f',cliopts) > 0 then address command 'RequestFile >' tempfile 'DRAWER "' || cwd || '" TITLE "Select fast index path..." DRAWERSONLY NOICONS'
                          else address command 'RequestFile >' tempfile 'DRAWER "' || cwd || '" TITLE "Select master index file..." NOICONS'

  if open('fp',tempfile,'R') then do
    masterindex= strip(readln('fp'),'B','"')
    call close('fp')
    address command 'Delete QUIET FILE' tempfile
    end
  else masterindex= ""
  end

if words(masterindex) < 1 then exit bad_args("Master index pathname missing")

if ~exists(masterindex) then do
  say 'Failed to locate your master index "'masterindex'"'
  exit 10
  end


/* eventually try to get missing from path */

if (pos('cd',cliopts) > 0) | (pos('n',cliopts) > 0) | (pos('m',cliopts) > 0) | (words(kickpath) > 0) then do
  if ( words(mirrorpath) < 1 ) & ( exists('c:RequestFile') ) then do
    cwd= strip(pragma('D'),'B','"')
    address command 'RequestFile >' tempfile 'DRAWER "' || cwd || '" TITLE "Select the mirror direcory..." DRAWERSONLY NOICONS'
    if open('fp',tempfile,'R') then do
      mirrorpath= strip(readln('fp'),'B','"')
      call close('fp')
      address command 'Delete QUIET FILE ' tempfile
      end
    else mirrorpath= ""
    end

  if words(mirrorpath) < 1 then exit bad_args("Missing mirror pathname for PATH/K")

  if ~exists(mirrorpath) then do
    say 'Failed to locate your mirror directory "'mirrorpath'"'
    exit 10
    end
  end


/* eventually create the kick path */

if (words(kickpath) > 0) then do
  if ~exists(kickpath) & canexist(kickpath) then do
    if pos('m',cliopts) > 0 then call makepath(kickpath)
    else do
      options prompt 'Destination path "'kickpath'" does not exist.  Shall I create it? (Y/n) '
      pull yn
      if left(yn,1) ~= 'N' then call makepath(kickpath)
      end
    if exists(kickpath) then say '  ' kickpath'   [created]'
    end

  if ~exists(kickpath) then do
    say 'Failed to locate or create your destination directory "'kickpath'"'
    exit 10
    end
  end

signal on ERROR
signal on IOERR

signal on FAILURE
/*signal on NOVALUE*/
signal on SYNTAX


/* do the hard part */

if ~open('fp',localindex,'R') then do
  say 'Error: couldn''t open local index file "'localindex'"'
  exit 10
  end

do until eof('fp')

  str= strip( readln('fp') )
  if (words(str) > 0) & (left(str,1) ~= '|') then do
    parse var str fname pname fsize comment

    if pos('f',cliopts) > 0 then masterfile = tackon(masterindex,fastprefix) || upper(left(fname,1))
                            else masterfile = masterindex

    if exists(masterfile) then do
      say 'Searching for "'tackon(pname,fname)'" in "'masterfile'" ...'
      if pname = '.' then pname = ""

      signal off ERROR
      address command searchcmd(fname,tempfile)
      signal on ERROR

      if ~open('tfp',tempfile,'R') then do
        say 'Error: Search failed -- couldn''t open "'tempfile'"'
        call close('fp')
        exit 10
        end

      master_pname   = ""
      master_comment = ""
      matches = 0

      do until eof('tfp') | matches > 1
        str= strip( readln('tfp') )

        if words(str) > 0 then do
          parse var str f d . 40 c /* was 38 c */

          if f = fname then do
            if matches = 0 then do
              master_pname= d
              master_comment= c
              matches= matches + 1
              end
            else if (master_pname ~= d) | (master_comment ~= c) then matches= matches + 1
            end

          end

          /* else we matched the comment */

        end /* scan ifp */

      call close('tfp')
      address command 'Delete QUIET FILE "' || tempfile || '"'

      /**/

      select /* #of matches */

        when matches = 1 then do
          fromfile = tackon( tackon(mirrorpath, pname       ), fname)
          tofile   = tackon( tackon(mirrorpath, master_pname), fname)

          if exists(fromfile) then do  /* Maybe someone deleted our fromfile meanwhile... */

            if comment ~= master_comment then do
              if pos('n',cliopts) < 1 then
                say 'Filenote of "'fname'" has changed from "'comment'" to "'master_comment'"'
              else do
                say 'Changing filenote of "'fname'" from "'comment'" to "'master_comment'"'
                address command 'Filenote QUIET FILE "'fromfile'" COMMENT' transquote(master_comment)
                end
              end /* comment ~= master_comment */

            if pname ~= master_pname then do

              if pos('cd',cliopts) < 1 then
                say 'File "'fname'" has moved from "'pname'" to "'master_pname'"'

              else do
                say 'Moving "'fname'" from "'pname'" to "'master_pname'"'
                destpath= tackon(mirrorpath,master_pname)
                if ~exists(destpath) & canexist(destpath) then do
                  if pos('m',cliopts) > 0 then call makepath(destpath)
                  else do
                    options prompt 'Destination path "'destpath'" does not exist.  Shall I create it? (Y/n/a) '
                    pull yna
                    if left(yna,1) ~= 'N' then do
                      call makepath(destpath)
                      if left(yna,1) = 'A' then cliopts = cliopts || 'm'
                      end
                    end
                  if exists(destpath) then say destpath '  [created]'
                  end

                if exists(destpath) then do
                  if exists(tofile) then do
                    if pos('r',cliopts) > 0 then address command 'Copy QUIET CLONE FROM "'fromfile'" TO "'tofile'"'
                    else do
                      options prompt 'File "'tofile'" already exists.  Shall I replace it? (Y/n/a) '
                      pull yna
                      if left(yna,1) ~= 'N' then do
                        if left(yna,1) = 'A' then cliopts = cliopts || 'r'
                        address command 'Copy QUIET CLONE FROM "'fromfile'" TO "'tofile'"'
                        end
                      end
                    end
                  else address command 'Copy QUIET CLONE FROM "'fromfile'" TO "'tofile'"'

                  if exists(tofile) then address command 'Delete QUIET FILE "'fromfile'"'
                  end

                else say 'Warning: "'fname'" ignored.  (Destination path "'destpath'" not created)'
                end
              end /* pname ~= master_pname */

            end
          else say 'Warning: "'fromfile'" does not exist anymore ... ignored'
          end /* matches = 1 */

        when matches = 0 then do
          say 'Warning: file "'fname'" not found in master index file "'masterfile'"'

          if words(kickpath) > 0 then do

            fromfile = tackon(tackon(mirrorpath, pname), fname)
            tofile   = tackon(kickpath, fname)

            if exists(fromfile) then do
              if exists(tofile) then do
                options prompt 'File "'tofile'" already exists.  Shall I replace it? (Y/n) '
                pull yn
                if left(yn,1) ~= 'N' then do
                  say 'Overwriting "'tofile'" with "'fromfile'" ...'
                  address command 'Copy QUIET CLONE FROM "'fromfile'" TO "'tofile'"'
                  end
                end
              else do
                say 'Moving "'fromfile'" to "'kickpath'" ...'
                address command 'Copy QUIET CLONE FROM "'fromfile'" TO "'tofile'"'
                end

              if exists(tofile) then address command 'Delete QUIET FILE "'fromfile'"'
              end /* exists(fromfile) */

            else say 'Warning: "'fromfile'" does not exist anymore ... ignored'
            end
          end /* matches = 0 */

        otherwise do
          say 'Warning: filename "'fname'" is ambiguous... skipped'
          end

        end /* select */

      end /* exists(masterfile) */

    else say 'Master index file "'masterfile'" does not exist ... "'fname'" skipped'
    end /* have fname */

  end /* do scan fp */

call close('fp')
say 'done.'
exit 0


bad_args: procedure expose template
  parse arg str
  if words(str) > 0 then say str
  say "Template:" template
  say "Usage: [rx] ExamineIndex[.rexx] FILE <local index> WITH <master index> PATH <aminet path> [RELOCATE] [COMMENT] [MAKEPATH] [FAST]"
  return 10


/* generate the search command string */

searchcmd: PROCEDURE EXPOSE tempfile
  PARSE ARG pattern,file
  return 'Search NONUM > "'tempfile'" FROM "'file'" SEARCH "'pattern'"'
  /*return 'agrep > "'tempfile'"' '"'pattern'"' '"'file'"'*/

/*@*/


/* get the next command-line argument from global 'args' string */

next_arg: procedure expose args
  args= strip(args)
  if left(args,1) = '"' then parse var args '"' a '"' args
                        else parse var args     a     args
  return strip(a,'b','"');


/* translate '"' into '*"' and '*' into '**' */

transquote: procedure
  parse arg s
  t= s
  q= max( lastpos('*',s), lastpos('"',s) )
  do while q > 0
    t= insert('*',t,q-1,1)
    s= left(s,q-1)
    q= max( lastpos('*',s), lastpos('"',s) )
    end
  return '"' || t || '"'


/* return the non-file part of a pathname */

pathonly: procedure
  parse arg path
  if (words(path) > 0) & (right(path,1) ~= ':') then do
    if right(path,1) = '/' then path= left(path,length(path)-1)
    if lastpos('/',path) > lastpos(':',path) then path= left(path,lastpos('/',path)-1)
                                             else path= left(path,lastpos(':',path))
    end
  return path


/* return the file part of a pathname */

fileonly: procedure
  parse arg path
  if right(path,1) = '/' then path= left(path,length(path)-1)
  p= max( lastpos(':',path), lastpos('/',path) )
  if(p>0) then return substr(path,p+1)
          else return path


/* concatenate the filename to the pathname and return the resulting string */

tackon: procedure
  parse arg path,file
  do while left(file,1) = '/'
    file= substr(file,2)
    path= pathonly(path)
    end
  if (words(path) > 0) & (right(path,1) ~= '/') & (right(path,1) ~= ':') then path= path || '/'
  if (right(file,1) = '/') then file= left(file,length(file)-1)
  return path || file


/* create all non-existant directories in a path */

makepath: procedure
  parse arg path
  if right(path,1) = '/' then path= left(path,length(path)-1)
  if ~exists(path) then do
    call makepath( pathonly(path) )
    address command 'MakeDir NAME "'path'"'
    end
  return 0


/*
 * return   1  if the device or volume name in given pathname exists
 *             or if no device or volume was present (current device)
 *          0  if the device or volume name does not exist
 */

canexist: procedure
  parse upper arg path
  if pos(':',path) < 1 then return 1 /* current device */
  call pragma('W','N')
  return exists( left(path,lastpos(':',path)) )


/* error/break handling */

IOERR:
ERROR:
  signal off ERROR
  signal off IOERR

  say errortext(rc) 'in line' sigl
  say 'There was a problem with external I/O ... I''ll better exit.'
  exit

FAILURE:
NOVALUE:
SYNTAX:
  signal off FAILURE
  signal off NOVALUE
  signal off SYNTAX

  say errortext(rc) 'in line' sigl
  say 'There seems to be an internal problem in line' sigl '... I''ll better exit.'
  exit

HALT:
BREAK_C:
BREAK_D:
  signal off HALT
  signal off BREAK_C
  signal off BREAK_D

  say 'Execution halted.'
  exit
