                  .,::      .:.::::::.  :::::::::::::::::::..   
                  `;;;,  .,;;,;;'```';;,;;;;;;;;'''';;;;``;;;;  
                    '[[,,[[' [[[     [[[\    [[      [[[,/[[['  
                     Y$$$P   "$$c  cc$$$"    $$      $$$$$$c    
                   oP"``"Yo,  "*8bo,Y88b,    88,     888b "88bo,
                ,m"       "Mm,  "*YP" "M"    MMM     MMMM   "W" 
                --------------------------------------------------
                Mystic BBS - MPL Tutor : Find Files
                --------------------------------------------------
                
There are times that we need to search and find files in our disks/bbs. MPL
has a simple but powerful way of doing this and can cover any situation about
finding and listing files. For this we use these procedures:
    
../ FindFirst

This procedure initiates and initializes the search. Without declaring this
procedure we can't search for any files. It has two parameters. The first one
is the path and search pattern, combined. For example if we want to search for
.TXT files in a folder the parameter will be something like this:
    WIN:        C:\myfolder\*.txt       Linux:  ./myfolder/*.txt
If we would like to search for any file we would type *.* instead of *.txt.
The second parameter is a file attribute, which by the time, is not very well 
documented or i didn't manage to find a good amount of info about that, sorry.


../ FindNext

FindNext is used to continue a search and find another item that matches the
criteria we gave when we executed the FindFirst procedure. We execute it, as
many times we want, but usually inside a while loop to find all files that
match the criteria. If FindNext doesn't find another file then it returns a
non zero value to the variable DosError. So... while we search and DosError
equals to zero, we continue our search, but if DosError changes then we can
figure that we don't have any other files and the search stops. You will
understand it better in the example bellow.

../ FindClose

To end our search, we have to use the FindClose procedure. With this command,
MPL understands that the search is over and stops monitoring and updating some
useful stuff, that we will see... but first... a small example.


Lets write a function that gives us the date of a file...

---[ CODE ]--------------------------------------------------------------------
Function GetFileDate(P:String):LongInt
Var Ret : Longint = 128
Begin
    FindFirst(P,16)                     // Initiate the Search. We search for
                                        // the file that holds the P var.
                                        // FindFirst also finds the first file
                                        // so we dont have to use the Findnext
                                        // procedure
    If DOSError = 0 Then Begin          // Have we found a/one file? If yes..
                                        // DOSError = 0, then we take the size
                                        // from the DirTime variable
        Ret:=DirTime                    // We pass it to our Ret variable
    End
    FindClose                           // Stop the search
    GetFileDate:=Ret                    // Assign the value of Ret to our
                                        // function result
End
-------------------------------------------------------------------------------

So, in this example we didn't care to look for many files, but just for one.
Thats why we didn't use the FindNext procedure and also we initiate the search
by giving it the exact filename and not any wildcards (*.txt, *.ans). The P 
variable should contain the full path and name of the file.

But where the hell that DirTime variable come from? Well, MPL has some pretty
useful variables to use, when searching for files. Anytime that the FindFirst 
or FindNext finds a files, simultaneously it updates those variables with 
information from that file... size, date, name etc. The names of these 
variables are straight forward... DirSize, DirName, DirTime etc. So when 
FindFirst and FindNext returns a file, we check these variables for the name,
size, date of the file. This is very useful. Lets see another example.

---[ CODE ]--------------------------------------------------------------------
procedure ListDir(dir:string)
var
  total:integer
begin
  FindFirst (dir+'*', 63)                   // Begin search for all files in
                                            // the folder
    While DosError = 0 do begin             // Did we find one? Proceed...
        total := total+1                    // Increase the counter
        WriteLn ('File Name: ', DirName)    // Display the Filename
        WriteLn ('     Size: ', DirSize)    // Display the Filesize
        WriteLn ('     Date: ', DateSTR(DirTime), 0)    // Display Date
        WriteLn ('     Time: ', TimeSTR(DirTime), 1)    // Display Time
        Write   ('Press a key to search for more.|PN'
        FindNext                            // Continue the search until we 
                                            // have found all the files.
    end
    FindClose                               // Close the search
    Writeln('Total Files found: '+int2str(total) + '|PN')   
                                            // Write how many files we have
                                            // found.
end

-------------------------------------------------------------------------------

The above example is like the DIR command in Windows, or ls in Linux. Just
finds and lists the files and folders (only their names) that exist inside a
folder.

This is the basic use of finding files with MPL. We can store this data that
we collect in Arrays or save it to files and manipulate it as we want.

Lets see and explain a complete example of a script, that uses these functions
in a clever way. This is the onlyonce.mps script. You can find it inside the
Scripts folder, of your Mystic BBS installation. It displays a file, only if 
it is newer than the last time the user was on a BBS. 

---[ CODE ]--------------------------------------------------------------------
Uses
  CFG,
  USER;                 // We use some variables about the User so we have to
                        // declare this Unit.
  
Var
  FN : String;
Begin
  GetThisUser;          // This function gets all information about the user
                        // who executes the script and is currently on

  FN := JustFileName(ParamStr(1));  // We only want a filename. Not the ext.
                                    // So we use this procedure to extract
                                    // only the filename, in case the user
                                    // entered the complete filename

  If Pos(PathChar, ParamStr(1)) = 0 Then    // Check if we have a path 
                                            // separator in our parameter
    FN := CfgTextPath + FN;         // We add the path of the Text folder to
                                    // our filename. This way the script will
                                    // look inside the Text folder to find the 
                                    // file.

  // The script searches for a file that we give only its name. So it will
  // display any file that has the name that we gave and any extension.
  // For example:, if we gave the name... "bulletin" the script will match any
  // file with name bulletin and any extension. The following filenames will
  // match:
  //            bulletin.ans
  //            bulletin.txt
  //            bulletin.nfo  
  //            etc.

  FindFirst (FN + '.*', 0);     // Search for our file with any extension

  While DosError = 0 Do Begin           // Did we find one? 
    If DirTime > UserLastOn Then Begin  // Check its datetime, is it newer
                                        // than the last time the user was on?
      DispFile(FN);                     // If yes, then display the file...
      
      Break;                            // and stop immediately the search,
                                        // cause we want to display only one 
                                        // file and not all of them, if there
                                        // are more.
    End;

    FindNext        // We use the findnext, in case we didn't match a file
                    // with the FindFirst procedure and continue the search
  End;

  FindClose;        // Finally close the search
                    // The script will not display anything unless it finds
                    // the appropriate file.
End.
-------------------------------------------------------------------------------


    ___ _          _       _                     
   /   (_)___  ___| | __ _(_)_ __ ___   ___ _ __ 
  / /\ / / __|/ __| |/ _` | | '_ ` _ \ / _ \ '__|
 / /_//| \__ \ (__| | (_| | | | | | | |  __/ |   
/___,' |_|___/\___|_|\__,_|_|_| |_| |_|\___|_|   
                                                
You are free to use this tutor as you need. Just give a mention to me (xqtr).
Credits goes to g00r00, the programmer behind Mystic BBS software and to Mystic
Guy, (Avon) of the Agency BBS, for their great job, keeping BBSing alive... :)     

Sorry for any typos... English is not my native language...                                            
