;/* DirComp.c - AmigaMail Directory Compare example using MatchFirst()/Next().
lc -cfis -v -d0 -b0 -j73 DirComp.c
blink from DirComp.o to DirComp lib lib:amiga.lib ; if you don't have pragmas
quit
 *
 * Pure code if pragmas are used.
 * Monday, 15-Jul-91 16:07:31, Ewout
 *
 * Compiled with SAS/C 5.10a
 */
/* (c)  Copyright 1991 Commodore-Amiga, Inc.   All rights reserved.
The information contained herein is subject to change without notice,
and is provided "as is" without warranty of any kind, either expressed
or implied.  The entire risk as to the use of this information is
assumed by the user.
*/

#include <exec/memory.h>
#include <dos/dosextens.h>
#include <dos/rdargs.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>

/* undef PRAGMAS if you don't have them */
#undef PRAGMAS
#ifdef PRAGMAS
#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#else
struct ExecBase *SysBase;
struct DosLibrary *DOSBase;

#endif

/* Default size of buffer to build full targetpaths in */
#define BUFFERSIZE 256

static UBYTE   *VersTag = "\0$VER: DirComp 37.1 (15.07.91)";

LONG            main(VOID);
LONG            GetPath(UBYTE * path, UBYTE * buffer, LONG buffersize);
UBYTE          *ItsWild(UBYTE * string);
UWORD           StrLen(UBYTE *);

LONG
main(VOID)
{
#ifdef PRAGMAS
  struct DosLibrary *DOSBase;

#endif
  struct RDArgs  *readargs;
  LONG            rargs[5], vargs[5];
  UBYTE          *source, *target;
  ULONG           buffersize = 0;
  UBYTE          *sourcedir, *targetdir;
  UBYTE          *textbuffer, *tmp, *tmp1, *tmp2;
  struct AnchorPath *anchorpath;
  struct FileInfoBlock *fib, *targetfib;
  struct Process *process;
  APTR            wptr;
  BPTR            dirlock, filelock;
  BOOL            checkdatestamp, all;
  LONG            date, error, rc = 0;

#ifndef PRAGMAS
  /* set up SysBase */
  SysBase = (*((struct Library **) 4));
#endif

  /* Fail silently if < 37 */
  if (DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37))
  {
    rargs[0] = 0L;
    rargs[1] = 0L;
    rargs[2] = 0L;
    rargs[3] = 0L;
    rargs[4] = 0L;

    if (readargs = ReadArgs("SOURCE/A,TARGET/A,DATE/S,ALL/S,BUFFER/K/N", rargs, NULL))
    {

      source = (UBYTE *) rargs[0];
      target = (UBYTE *) rargs[1];
      checkdatestamp = (BOOL) rargs[2];
      all = (BOOL) rargs[3];

      if (!(sourcedir = AllocMem(StrLen(source) + 129, MEMF_CLEAR)))
        error = ERROR_NO_FREE_STORE;
      else
      {
        /* 128 bytes to print informative text */
        textbuffer = sourcedir + StrLen(source) + 1;

        /* use user specified buffersize if indicated */
        if (rargs[4])
          buffersize = *((LONG *) rargs[4]);
        if (buffersize < BUFFERSIZE || buffersize > 4096)
          buffersize = BUFFERSIZE;

        if (!(targetdir = AllocMem(buffersize, MEMF_CLEAR)))
          error = ERROR_NO_FREE_STORE;
        else
        {
          if (!(targetfib = AllocDosObject(DOS_FIB, NULL)))
            error = ERROR_NO_FREE_STORE;
          else
          {

            /*
             * Check if source and target are valid.
             *
             * Separate source path from pattern (if any). Use the source path figure
             * out what to append to the target.
             */

            /* No requesters */
            process = (struct Process *) FindTask(NULL);
            wptr = process->pr_WindowPtr;
            process->pr_WindowPtr = (APTR) - 1L;

            if ((error = GetPath(source, sourcedir, StrLen(source) + 1) == 0))
            {
              if (!(dirlock = Lock(sourcedir, SHARED_LOCK)))
                error = IoErr();
              else
              {
                UnLock(dirlock);
                if (!(dirlock = Lock(target, SHARED_LOCK)))
                  error = IoErr();
                else
                {
                  UnLock(dirlock);

                  if (anchorpath = AllocMem(sizeof(struct AnchorPath) + buffersize,
                                            MEMF_CLEAR))
                  {
                    anchorpath->ap_Strlen = buffersize;

                    /* Allow to break on CTRL-C */
                    anchorpath->ap_BreakBits = SIGBREAKF_CTRL_C;

                    if ((error = MatchFirst(source, anchorpath)) == 0)
                    {

                      do
                      {
                        fib = &(anchorpath->ap_Info);

                        /*
                         * APF_DIDDIR indicates that we used returned from a
                         * directory. In that case we clear both APF_DIDDIR and
                         * APF_DODIR, so we can start afresh with the next one.
                         */


                        if (anchorpath->ap_Flags & APF_DIDDIR)
                          anchorpath->ap_Flags &= ~(APF_DODIR | APF_DIDDIR);
                        else
                        {

                          /*
                           * Make a filename for the target directory. First copy
                           * targetname into buffer.
                           */
                          targetdir[0] = '\0';
                          tmp = targetdir;
                          tmp1 = target;
                          while (*tmp++ = *tmp1++);

                          /* Skip sourcename in ap_Buf */
                          tmp1 = sourcedir;
                          tmp2 = anchorpath->ap_Buf;
                          while (*tmp1++ == *tmp2++);
                          /* Skip back 1 if not after a separator */
                          if (*(tmp2 - 1) != '/')
                            tmp2--;

                          /*
                           * We hit the source itself, don't compare it, but enter
                           * it.
                           */
                          if (*tmp2 == 0)
                          {
                            anchorpath->ap_Flags |= APF_DODIR;
                            continue;
                          }

                          /* Build it */
                          if (AddPart(targetdir, tmp2, buffersize - 1))
                            vargs[0] = (LONG) targetdir;
                          else
                          {
                            PrintFault(ERROR_NO_FREE_STORE, NULL);
                            break;
                          }

                          /* Lock it and check it out */
                          if (filelock = Lock(targetdir, SHARED_LOCK))
                          {
                            if ((Examine(filelock, targetfib)) == DOSTRUE)
                            {
                              textbuffer[0] = '\0';

                              /*
                               * To get nice output without work I use AddPart() to
                               * add differences to the textbuffer.
                               */
                              if (targetfib->fib_DirEntryType
                                  != fib->fib_DirEntryType)
                                AddPart(textbuffer, "of different type", 128);
                              else
                              {
                                if (targetfib->fib_Size < fib->fib_Size)
                                  AddPart(textbuffer, "smaller", 128);
                                else if (targetfib->fib_Size > fib->fib_Size)
                                  AddPart(textbuffer, "larger", 128);

                                if (checkdatestamp)
                                {
                                  date = CompareDates((struct DateStamp *)
                                        & (fib->fib_Date),
                                      (struct DateStamp *) & (targetfib->fib_Date));
                                  if (date < 0)
                                    AddPart(textbuffer, "older", 128);
                                  else if (date > 0)
                                    AddPart(textbuffer, "newer", 128);
                                }
                              }


                              if (*textbuffer != NULL)
                              {
                                vargs[1] = (LONG) textbuffer;
                                VFPrintf(Output(), "%s: object %s\n", vargs);
                              }
                            }
                            else
                              PrintFault(IoErr(), targetdir);
                            UnLock(filelock);
                          }
                          else
                          {
                            PrintFault(IoErr(), targetdir);

                            /*
                             * If and error occured on a directory name, don't enter
                             * it.
                             */
                            if (fib->fib_DirEntryType > 0)
                              continue;

                          }

                          /*
                           * If the ALL keyword has been used and this is a directory
                           * enter it by setting the APF_DODIR flag.
                           */

                          if (fib->fib_DirEntryType > 0 && all != FALSE)
                            anchorpath->ap_Flags |= APF_DODIR;

                        }

                      } while ((error = MatchNext(anchorpath)) == 0);
                    }

                    MatchEnd(anchorpath);

                    if (error == ERROR_NO_MORE_ENTRIES)
                      error = 0;

                    FreeMem(anchorpath, sizeof(struct AnchorPath) + buffersize);
                  }
                }
              }
              /* Reset windowpointer */
              process->pr_WindowPtr = wptr;
            }
            else
              PrintFault(error, NULL);
            FreeDosObject(DOS_FIB, targetfib);
          }
          FreeMem(targetdir, buffersize);
        }
        FreeMem(sourcedir, StrLen(sourcedir) + 129);
      }
      FreeArgs(readargs);
    }
    else
      error = IoErr();

    SetIoErr(error);
    if (error)
    {
      PrintFault(error, NULL);
      if (error = ERROR_BREAK)
        rc = RETURN_WARN;
      else
        error = RETURN_FAIL;
    }
    CloseLibrary((struct Library *) DOSBase);
  }
  return (rc);
}

LONG
GetPath(UBYTE * path, UBYTE * buffer, LONG buffersize)
{
  UBYTE          *pathpart, *filepart;
  UBYTE          *tmp1, *tmp2;
  BPTR            lock;
  struct FileInfoBlock *fib;
  LONG            error = 0;

  /* Open own copy of dos.library if pragmas are used so it's standalone */
#ifdef PRAGMAS
  struct Library *DOSBase;

  if (!(DOSBase = OpenLibrary("dos.library", 36)))
    return (1);
#endif

  /*
   * If there seems to be no path, the pathpart will point to the filepart too, so we
   * need to check for that.
   */
  filepart = FilePart(path);
  pathpart = PathPart(path);

  /*
   * This also handles cases where there is only a volume/device name, only a
   * directory name or a combo of those.
   */
  if (pathpart == path)
  {

    /*
     * There seems to be only one component. Copy it if it is not wild. Caller will
     * have to check whether if it exists and if it is a file or directory.
     */
    if (!(ItsWild(pathpart)))
      pathpart = NULL;
  }

  if (pathpart != path)
  {

    /*
     * If pathpart equals filepart (pointer wise) then there is only one component
     * (possible preceeded by a volume name).
     */
    if (pathpart == filepart)
    {
      if (!(ItsWild(pathpart)))
        pathpart = NULL;
    }
    else
    {
      /* Try to lock it to determine if the last component is a directory. */
      if (lock = Lock(path, SHARED_LOCK))
      {
        if (fib = AllocMem(sizeof(struct FileInfoBlock), MEMF_CLEAR))
        {
          if ((Examine(lock, fib)) == DOSTRUE)
          {
            /* Hey it's a directory after all */
            if (fib->fib_DirEntryType > 0)
              pathpart = NULL;
          }
          FreeMem(fib, sizeof(struct FileInfoBlock));
        }
        UnLock(lock);
      }                                          /* else treat it as a filename */
    }

    /* Copy the pathpart in the buffer */
    tmp1 = buffer;
    tmp2 = path;
    while ((*tmp1++ = *tmp2++) && (tmp2 != pathpart))
    {
      if (tmp1 == (buffer + buffersize))
      {
        error = ERROR_NO_FREE_STORE;
        break;
      }
    }
    *tmp1 = '\0';                                /* NULL terminate. */
  }

#ifdef PRAGMAS
  CloseLibrary(DOSBase);
#endif
  return (error);
}

UBYTE          *
ItsWild(UBYTE * string)
{
  static UBYTE   *special = "#?*%([|";
  UBYTE          *tmp = string;
  COUNT           i;

  do
  {
    for (i = 0; special[i] != '\0'; i++)
    {
      if (*tmp == special[i])
        return (tmp);
    }
    tmp++;
  } while (*tmp);

  return (NULL);
}

UWORD
StrLen(UBYTE * string)
{
  UBYTE          *length = string + 1;

  while (*string++ != '\0');
  return ((UWORD) (string - length));
}
