/*
    $VER: DirList V3.11 - (C)Amiga Foundation Classes

    Written  By: Fabio Rotondo

    V2.10  - Added setmode() which can be used to select operating modes
             via tags. (Modes will grow as time goes by)

             At the moment this flags (TRUE/FALSE) are present
             DIR_COMPLETEPATH - Stores the complete path of the file/dir
             DIR_MARKDIR      - Marks dir with the leading (DIR) prefix


    V3.00  - Restructured code.

     -->   - EDefObj Compliant.

    V3.10  - Now DirList supports resourceTracker

    V3.11  - Recompiled to support the new StringNode
*/

OPT PREPROCESS

#define DO_DIRLIST_MOD

#ifdef DO_DIRLIST_MOD
OPT MODULE
OPT EXPORT
#endif

MODULE 'afc/stringnode', 'dos/dos',
       'afc/resourceTracker'


CONST DIRLIST_BASE = $00030000

ENUM DIRTAG_COMPLETEPATH=DIRLIST_BASE, DIRTAG_MARKDIR

ENUM DLERR_NOMEMORY=DIRLIST_BASE,
     DLERR_INIT, DLERR_LOCK, DLERR_NOINIT, DLERR_NODIR, DLERR_EXAMINE

CONST DIRLIST_VERSION = 3
CONST DIRLIST_REVISION = 11

-> /// main docs
/*
@node "Main" "Amiga Foundation Classes Module: DirList"



                  ** DirList - Original By Fabio Rotondo **

                      * Part of Amiga Foundation Classes *

                          --- NO LONGER SUPPORTED ---

        @{" Introduction " link "introduction" }             @{" Author's Infos " link "author" }      @{" Amiga Foundation Classes " LINK "afc.guide/main"}


   Requires: @{" NodeMaster      " LINK "NodeMaster.guide/main"}
             @{" StringNode      " LINK "StringNode.guide/main"}
             @{" resourceTracker " LINK "resourceTracker.guide/main"}

   Base: $0003


   NOTE: DirList inherits completely @{" StringNode " LINK "stringnode.guide/main"} so, please, refer
         to this class for further documentation.

   NEW COMMANDS                          BRIEF DESCRIPTION
   -------------------------------------------------------------------------
   @{" dirlist(resTracker=NIL)         " link "DirList" } Initailizes the object
   @{" dirname()                       " link "dirname" } Returns current dir name
   @{" read(dirs, files, match)        " link "read" } Scans a Directory
   @{" setattrs(tags)                  " link "setmode" } Set objects behaviours
   @{" setdir(path)                    " link "setdir" } Set Directory to read
   @{" version()                       " link "version"} Returns class version and revision

   @{" Tags Table                      " link "Tags" } Possible DirList's Tags

   @{" Errors Table                    " LINK "ErrorTable"} Error Table
@endnode

@node "Introduction" "Introduction"

    INTRODUCTION


    DirList Object is something I created for my own needs.

    Now  it  is grown to a powerful and stable object, so I decided to share it
with all the rest of Amiga Foundation Classes community.

    Main features are:

        * Accept AmigaDOS Pattern Matching.

        * Very fast scanning algorithms.

        * Easy to use.

        * Relys on StringNode Object. (See StringNode_oo)


NEW V2.10 Features:

        * Added a new method called tagset():
          With this method you will be able to change some DirList
          behaviours via tags (at the moment, just two different tags
          are implemented, but many others will do as time goes by)

        * Now dirname() returns also the "/" when needed.

        * Example program now working ;)

        * New examples added.

NEW V3.00 Features:

        * Restructured code.

        * Part of the Amiga Foundation Classes

NEW V3.10 Features:

        * Added resourceTracker Support.
@endnode

@node author "Author(s) Info"

    Original By:  Fabio Rotondo  (fsoft@intercom.it)

    E Version By: Fabio Rotondo



    Address:

            Fabio Rotondo
            C.so Vercelli 9
            28100 Novara
            ITALY

            e-mail: fsoft@intercom.it
                    Fabio.Rotondo@deagostini.it

            Phone:  (ITA) - (0)321 -   459676  (home)
                    (ITA) - (0)321 -   424272  (office)
                    (ITA) - (0)338 -  7336477  (GSM Phone)

            Fax:    (ITA) - (0)321 -   424560

            Web:    http://www.intercom.it/~fsoft               (my home page)

                    http://www.intercom.it/~fsoft/ablast.html   (Amiga Blast Home Page)
@endnode

@node Tags "Amiga Foundation Classes Modules: DirList/Tag Table"


    TAG NAME        | VALUES (DEFAULT)| DESCRIPTION
+-------------------+-----------------+-----------------------------------
 TAGDIR_MARKDIR     |TRUE/FALSE(TRUE) | If TRUE, DirList will add the
                    |                 | leading "(DIR) " prefix to dir names.
                    |                 |
TAGDIR_COMPLETEPATH |TRUE/FALSE(FALSE)| If TRUE, DirList will add complete path
                    |                 | to the dirs and files read.
                    |                 |

Please, see also @{" StringNode/Tags Table" LINK "StringNode.guide/StringNode_TagsTable"}
@endnode

@node ErrorTable "Amiga Foundation Classes Modules: DirList / Error Table "
ERROR VALUE         | DESCRIPTION
--------------------+------------------------------------------------------
    $0000           | No memory.
    $0001           | Initialization failed.
    $0002           | Could not lock desired dir (ie. dir not found)
    $0003           | You are trying to use a class which failed to init.
    $0004           | You are trying to read "nothing" (ie: you haven't set a valid dir)
    $0005           | Examine() call failed.

Please, see also @{" StringNode/Error Table" LINK "StringNode.guide/StringNode_ErrorTable"}

@endnode

*/
-> ///

OBJECT dirlist OF stringnode
  PRIVATE
  dirname
  doslock
  dosobj:PTR TO fileinfoblock
  init

  adddir  :CHAR
  allpath :CHAR

  resTracker:PTR TO resourceTracker
ENDOBJECT

-> /// dirlist() OF dirlist
/*
@node "DirList" "Amiga Foundation Classes Modules: DirList/dirlist()"

           NAME: dirlist(resTracker=NIL:PTR TO resourceTracker)

    DESCRIPTION: Use this command to initailize the object.

          INPUT: resTracker       - (Optional) Pointer to a valid resourceTracker class.

        RESULTS: NONE.

       SEE ALSO: @{" StringNode/stringnode() " LINK "StringNode.guide/StringNode_stringnode"}
                 @{" resourceTracker         " LINK "resourceTracker.guide/main"}
@endnode

*/
PROC dirlist(resTracker=NIL:PTR TO resourceTracker) OF dirlist
  self.stringnode(NIL, resTracker)
  self.dirname:=NIL
  self.doslock:=NIL
  self.dosobj:=AllocDosObject(DOS_FIB,0)
  IF self.dosobj = NIL THEN Raise(DLERR_INIT)   -> DirList Initialization Error
  self.init:=TRUE

  self.adddir  := TRUE
  self.allpath := FALSE

  self.resTracker:=resTracker
  IF resTracker THEN resTracker.add(self, {dirlist_clean_proc})
ENDPROC
-> ///


PROC end() OF dirlist
  SUPER self.end()
  IF self.doslock
    UnLock(self.doslock)
  ENDIF
  IF self.dosobj
    FreeDosObject(DOS_FIB, self.dosobj)
  ENDIF
  IF self.dirname
    DisposeLink(self.dirname)
  ENDIF

  IF self.resTracker THEN self.resTracker.remove(self)
ENDPROC

PROC dirlist_clean_proc(dirl:PTR TO dirlist, info=NIL)
  END dirl
ENDPROC

-> /// setdir(txt:PTR TO CHAR) OF dirlist
/*
@node "setdir" "Amiga Foundation Classes Modules: DirList/setdir()"
           NAME: setdir(path:PTR TO CHAR)

    DESCRIPTION: Use this command to select directory to scan.

          INPUT: path     - PTR TO CHAR. Directory name, FULL PATH!

        RESULTS: NONE.

       SEE ALSO: @{" dirname() " LINK "dirname"}
                 @{" read()    " LINK "read"}
@endnode

*/
PROC setdir(txt:PTR TO CHAR) OF dirlist
  DEF mylock, c
  
  IF (mylock:=Lock(txt, ACCESS_READ)) = NIL THEN Raise(DLERR_LOCK)
  self.doslock:=mylock
  IF self.dirname
    DisposeLink(self.dirname)
    self.dirname:=NIL
  ENDIF
  self.dirname:=String(StrLen(txt)+1)

  c:=txt[StrLen(txt)-1]
  StrCopy(self.dirname, txt)

  IF (c<>":") AND (c<>"/") THEN StrAdd(self.dirname, '/')
ENDPROC
-> ///

-> /// dirname() OF dirlist IS self.dirname
/*
@node dirname "Amiga Foundation Classes Modules: DirList/dirname()"
           NAME: dirname()

    DESCRIPTION: This command returns the current dir name.

          INPUT: NONE.

        RESULTS: name       - A PTR TO CHAR containing current dir name.

       SEE ALSO: @{" setdir() " LINK "setdir"}
@endnode

*/
PROC dirname() OF dirlist IS self.dirname
-> ///

-> /// read(dirs=TRUE, files=TRUE, match=NIL:PTR TO CHAR) OF dirlist
/*
@node read "Amiga Foundation Classes Modules: DirList/read()"
           NAME: read(dirs=TRUE, files=TRUE, match=NIL:PTR TO CHAR)

    DESCRIPTION: This command scans selected dir.

          INPUT: dirs       - (TRUE) If this flag is set to TRUE, DirList
                              will memorize any directory it will encounter
                              while scanning.

                 files      - (TRUE) Same as dirs flag, only with files.

                 match      - (NIL) This is a _VALID_ search pattern. This
                              pattern will be CASE INSENSITIVE and it is a
                              _STANDARD_ AmigaDOS pattern matching. (By the
                              way, DirList *USES* AmigaDOS pattern matching,
                              so it is FAST and you already should know how
                              to use it!)

                              Ex. "#?sequ#?" is a valid pattern matching
                                  string.

        RESULTS: NONE

       SEE ALSO: @{" setdir() " LINK "setdir"}
@endnode

*/
PROC read(dirs=TRUE, files=TRUE, match=NIL:PTR TO CHAR) OF dirlist
  DEF success=FALSE
  DEF s
  DEF pat=NIL:PTR TO CHAR

  IF match
    pat :=String(StrLen(match)+2)
    ParsePatternNoCase(match, pat, StrLen(match)+2)
  ENDIF

  IF (s:=String(255)) = NIL THEN Raise(DLERR_NOMEMORY)
  IF self.init=FALSE  THEN Raise(DLERR_NOINIT)
  IF self.doslock=NIL THEN Raise(DLERR_NODIR)
  IF (Examine(self.doslock, self.dosobj))=NIL THEN Raise(DLERR_EXAMINE)

  REPEAT
    IF (success:=ExNext(self.doslock, self.dosobj))
      StrCopy(s,'')
      IF self.dosobj.direntrytype>0
        IF dirs
          IF self.adddir
            StrCopy(s, '(DIR) ')
          ENDIF
          IF self.allpath THEN StrAdd(s, self.dirname)
          IF pat
            IF MatchPatternNoCase(pat, self.dosobj.filename)
              StrAdd(s, self.dosobj.filename)
              self.add(s)
            ENDIF
          ELSE
            StrAdd(s, self.dosobj.filename)
            self.add(s)
          ENDIF
        ENDIF
      ELSE
        IF files
          IF self.allpath THEN StrCopy(s, self.dirname)
          IF pat
            IF MatchPatternNoCase(pat, self.dosobj.filename)
              StrAdd(s, self.dosobj.filename)
              self.add(s)
            ENDIF
          ELSE
            StrAdd(s, self.dosobj.filename)
            self.add(s)
          ENDIF
        ENDIF
      ENDIF
    ENDIF
  UNTIL success=FALSE
  DisposeLink(s)
ENDPROC
-> ///



-> /// setattrs(tags:PTR TO LONG) OF dirlist
/*
@node "setattrs" "Amiga Foundation Classes Modules: DirList/setattrs()"
           NAME: setmode(tags:PTR TO LONG)

    DESCRIPTION: Use this command to change some of object's behaviours.
                 This method will grow as time goes by. It is implemented
                 in a very comfy way: taglists.

          INPUT: tags     - PTR TO LONG. Tags and their value.
                            See @{" Tags Table " LINK "Tags"}

        RESULTS: NONE.

           NOTE: REMEMBER to ALWAYS end taglist with 0,0, otherwise
                 strange things WILL happen.

                 You can pass to this method also StringNode's tags.
                 They will be handled correctly.

       SEE ALSO: @{" dirname() " LINK "dirname"}
                 @{" read()    " LINK "read"}

                 @{" StringNode/setattrs " LINK "StringNode.guide/StringNode_setattrs"}
@endnode

*/
PROC setattrs(tags:PTR TO LONG) OF dirlist
  DEF v:LONG, t:LONG

  WHILE (t:=Long(tags++))
    v:=Long(tags++)
    SELECT t
      CASE DIRTAG_COMPLETEPATH
        self.allpath :=v
      CASE DIRTAG_MARKDIR
        self.adddir  :=v
      DEFAULT
        SUPER self.setattrs([t,v,0,0])
    ENDSELECT
  ENDWHILE
ENDPROC
-> ///

-> /// version() OF dirlist IS DIRLIST_VERSION,DIRLIST_REVISION
/*
@node "version" "Amiga Foundation Classes Modules: DirList/version()"
           NAME: version()

    DESCRIPTION: This method returns class version and revision.

          INPUT: NONE

        RESULTS: this method return TWO values: version and revision.

       SEE ALSO:

@endnode

*/
PROC version() OF dirlist IS DIRLIST_VERSION,DIRLIST_REVISION
-> ///

#ifndef DO_DIRLIST_MOD
PROC main()
  DEF dl:PTR TO dirlist

  NEW dl.dirlist()


  dl.setattrs([DIRTAG_COMPLETEPATH, TRUE,
              DIRTAG_MARKDIR, TRUE,
              0,0
             ])



  dl.setdir('work:')
  WriteF('Reading...\n')
  dl.read(TRUE, TRUE)
  WriteF('Sorting!\n')
  dl.sort(TRUE)

  WriteF('Done!\n')

  IF dl.first()
    REPEAT
      WriteF('\s\n',dl.obj())
    UNTIL dl.succ()=FALSE
  ENDIF

  WriteF('DIR:\s\n', dl.dirname())


  END dl
ENDPROC


#endif



