📄 DOS File System (DFS) for Euphoria 3.1.1


                 Version 1.00, December/18/2012, by Shian Lee.


                             1. Introduction


 This library provides the elementary DOS file system routines, for the DOS32
 platform, that might be useful for any DOS application. All the routines are
 optionally supporting long-file-names (LFN).

 Only standard DOS pathnames which are using backslash (\) and drive letter
 (A: to Z:) are supported. UNC (network names) which start with \\ or // are
 not supported.

 The maximum length of pathnames that can be handled by the routines depends
 on the operating system. DOS normally allows maximum length of 66 characters
 for pathnames, in regular and LFN modes, although the formal lengths are 128
 and 260 respectively. Windows might support longer pathnames.

 The technical information for creating this (new) library is from:
 1. "Advanced MS-DOS Programming" by Ray Duncan.
 2. "The x86/MSDOS Interrupt List" by Ralf Brown.
 Both are available free on the web.


 Disclaimer
 ==========

 Use this library only at your own risk. The author will not be responsible
 for any damage or data loss.

 This library is tested on FreeDOS 1.1. The code or the documentation might
 still contain errors or mistakes, and it might work differently on another
 operating system.


 In the descriptions below, to indicate what kind of object may be passed in
 and returned, the following prefixes are used:

 x     - a general object (atom or sequence)

 s     - a sequence (usually a string)

 a     - an atom

 i     - an integer

 fn    - an integer used as a file number

 st    - a string sequence, or single-character atom



                      2. Routines by Application Area


 2.1 Drive
 =========

 curdrive       - return the letter of the current drive

 setdrive       - change to a new current drive

 drive_exists   - check if drive exists

 drive_ready    - check if drive exists and ready

 drives_list    - return a list of all existing drives

 volume_label   - return the volume label of a drive

 label_drive    - create, change or delete the volume label of a drive


 2.2 Directory
 =============

 wdir           - return complete info on file, directory or volume label

 curdir         - return the name of the current directory

 curdirs        - return the name of the current directory on any drive

 setdir         - change to a new current directory

 make_dir       - create a directory

 remove_dir     - delete an empty directory

 dir_exists     - check if directory exists


 2.3 File
 ========

 open_file      - open a file or device

 copy_file      - copy a file

 move_file      - move a file to another location

 erase_file     - delete a file

 file_exists    - check if file exists

 file_size      - return the length of file

 comp_file      - compare the content of two files

 date_file      - modify the date and time stamp of a file

 rename         - rename a file or directory

 attrib         - set the attributes of a file or directory

 file_checksum  - return the checksum of a file


 2.4 Parse Path
 ==============

 Parse path routines are string-manipulation routines which return different
 portions of a relative or absolute path. These routines do not access the
 file system to check if the path is actually exist, and do not verify that
 the syntax of the path is correct.

 drive_name     - return the drive portion of a pathname

 dir_name       - return the directory portion of a pathname

 file_name      - return the file portion of a pathname

 filebase_name  - return the base-filename portion of a pathname

 fileext_name   - return the file-extension portion of a pathname

 trim_path      - trim invalid characters from a pathname

 slash_path     - append backslash to a pathname


 2.5 Real Path
 =============

 Real path routines are converting relative path to an absolute path. These
 routines must access the file system to verify that the path exist ("real").

 real_drive     - return the real drive letter of a pathname

 real_dir       - return the real path of directory name

 real_path      - return the real path and type of a pathname

 real_temp      - return unique name for creating a temporary file or dir


 2.6 Long File Name
 ==================

 Long-file-name specific routines are useful only when the operating system
 (DOS) is supporting long file names.

 allow_lfn       - disable or enable long-file-name support in DFS.E

 check_lfn       - check the status of long-file-name support in DFS.E

 real_short_path - return the real path in short format (8.3) of a pathname

 real_long_path  - return the real path in long format of a pathname


 2.7 Critical error handling
 ===========================

 Critical error handling is specially important for applications that need to
 access removable devices. I/O errors can be detected and handled within the
 application.

 allow_error    - disable or enable the critical error handler

 check_error    - check if a critical error has occurred


 2.8 System
 ==========

 These routines are related to the file system and might be useful.

 set_time       - update the system clock time

 set_date       - update the system clock date



                   3. Alphabetical Listing of all Routines


 -------------------------------<allow_error>--------------------------------

 Syntax:      include dfs.e
              i1 = allow_error(i2)

 Description: When i2 is 1 (true) a DOS critical error (usually a hardware
              error), if occurred, will display a message on the screen:
              "Abort, Retry, Ignore, Fail?" and wait for you to choose an
              action. In many cases the result of any action might terminate
              your program or even halt the system. When i2 is 0 (false) a DOS
              critical error, if occurred, will be acknowledged and your
              program will continue normally. i1 is the previous setting of
              allow_error(), i.e. 1 or 0.

 Comments:    Initially a DOS critical error is allowed to stop your program
              and wait for you to choose an action. For some types of program
              a possible and sudden termination could leave things in a messy
              state and might result in loss of data. allow_error(0) lets you
              avoid this situation in many cases.

              allow_error(0) still allows DOS to abort your program in case
              that the critical error is actually "critical", for example, if
              the memory is corrupted.

              Using allow_error() effects only the current process. A critical
              error might still occur in another parent or child process. For
              example, calling system() routine runs a new child process that
              has its own critical error handler.

              The previous setting of allow_error(), returned in i1, should
              be saved and restored, since few routines might set or reset
              allow_error() for different purposes.

              You can tell if any critical error had occurred by calling
              check_error().

 Example:

              integer state, nul
              object x

              state = allow_error(0)             -- disable critical-error

              x = wdir("E:\\XY.Z")               -- read drive E:
              if check_error() then              -- critical error occurred?
                  puts(1, "Error: Cannot read drive E:")
              end if

              nul = allow_error(state)           -- restore previous setting


 See Also:    check_error, drive_ready


 ---------------------------------<allow_lfn>--------------------------------

 Syntax:      include dfs.e
              allow_lfn(i)

 Description: When i is 1 (true) LFN (long-file-names) are supported by DFS
              library. When i is 0 (false) LFN are not supported by DFS
              library.

 Comments:    Initially DFS library calls allow_lfn(1). LFN may be supported
              by DFS library only if it currently supported by DOS, i.e. if
              DOS do not support LFN when you call allow_lfn(1), the result is
              the same as calling allow_lfn(0).

              When LFN are supported by DFS, the routines are using newer DOS
              interrupts which are compatible with MS-DOS version 7.0 and
              later. When LFN are not supported by DFS, the routines are using
              old-style (regular) DOS interrupts which are compatible with
              MS-DOS version 3.2 and later.

              You might want to disable LFN support by DFS for higher
              compatibility with older DOS programs. For example, on FreeDOS
              version 1.1 the ASSIGN utility might not work properly with the
              newer DOS interrupts. Beside better compatibility, short names
              (8.3) might still be easier to use on DOS.

              You can tell if LFN are supported by DFS library by calling
              check_lfn().

 Example:

              allow_lfn(0)              -- disable LFN support in DFS
              puts(1, "Short name: " & curdir() & '\n')

              allow_lfn(1)              -- enable LFN support in DFS
              if check_lfn() then
                  puts(1, "Long name: " & curdir() & '\n')
              else
                  puts(1, "LFN is currently not supported by DOS and DFS.\n")
              end if


 See Also:    check_lfn, real_long_path, real_short_path


 ----------------------------------<attrib>----------------------------------

 Syntax:      include dfs.e
              i = attrib(s1, s2)

 Description: Alter the attributes of an existing file or directory. s1 is the
              path name of the file or directory. s2 is the attributes to set
              or clear. If successful, attrib() returns 1. If unsuccessful,
              attrib() returns 0. Possible attributes to set or clear are:

               "+r" or "-r" - set or clear read-only attribute
               "+h" or "-h" - set or clear hidden attribute
               "+s" or "-s" - set or clear system attribute
               "+a" or "-a" - set or clear archive attribute

              Only the attributes which are specified in s2 are altered. Other
              attributes are preserved. Volume and directory attributes cannot
              be altered. Any other characters or combinations in s2 are
              ignored.

 Comments:    The read-only attribute allows to read a file but not to modify,
              overwrite or delete.
              The hidden attribute hides the file when you type "dir".
              The system attribute protects a file from being overwritten or
              deleted.
              The archive attribute is set when a file is modified. You might
              want to clear it after creating a backup copy of the file.

              Note that most of the restrictions above should be forced by the
              programmer. i.e. you must check the attributes of a given file
              or directory and treat it as expected. DFS library routines,
              such as erase_file() or wdir(), ignore these restrictions.

              You can find out the current attributes of a file or directory
              by calling wdir().

 Example:

              -- set read-only and archive attributes:
              i = attrib("C:\\Documents", "+r+a")

              -- clear hidden and archive and set read-only attribute:
              i = attrib("C:\\WORK\\DFS.E", "-h-a+r")


 See Also:    wdir, rename, date_file, file_checksum


 ---------------------------------<check_error>------------------------------

 Syntax:      include dfs.e
              i = check_error()

 Description: Return 1 if a critical error have been occurred since the last
              call to check_error() or allow_error(). Return 0 if no critical
              error have been occurred since the last call to check_error(),
              or if allow_error(1) is set.

 Comments:    This is useful after you have called allow_error(0) which
              prevents critical errors from terminating your program.

              You can use check_error() to find out if an I/O error (usually
              a hardware error) have been occurred, while your program is
              reading or writing to devices as printer, hard-drive, USB, CD,
              floppy-disk and any other removable media or device. You might
              then display an error message as "Printer not ready" and let the
              user decide to continue or to stop printing.

              You must call check_error() *immediatly after* any statement
              that might cause an error, e.g. x = dir("A:\\"), if you wish to
              know which statement caused the error. When you cannot be sure
              what caused the critical error then you may assume that a
              "general I/O failure" have been occurred.

              The usual critical error message, "Abort, Retry, Ignore, Fail?",
              will not appear on the screen. You can only detect a critical
              error by calling check_error().

 Example 1:

              integer state
              object nul

              state = allow_error(0)             -- disable critical-error

              nul = wdir("A:\\XY.Z")             -- read floppy drive A:
              if check_error() then              -- critical error occurred?
                puts(1, "Error: Floppy drive A: is not ready.")
              end if

              nul = allow_error(state)           -- restore previous setting


 Example 2:

              sequence text, retry
              integer state, nul

              state = allow_error(0)             -- disable critical-error

              for i = 1 to length(text) do
                puts(PRINTER, text[i] & '\n')    -- print text to printer
                if check_error() then            -- maybe out of paper?
                    retry = prompt_string("Printer not ready. Retry [Y/N]? ")
                    if find(retry, {"N", "n"}) then
                        close(PRINTER)
                        exit                     -- close printer and stop.
                    end if
                end if
              end for

              nul = allow_error(state)           -- restore previous setting


 See Also:    allow_error, drive_ready


 ----------------------------------<check_lfn>-------------------------------

 Syntax:      include dfs.e
              i = check_lfn()

 Description: Return 1 (true) if LFN (long-file-names) are supported by DFS
              library. Return 0 (false) if LFN are not supported by DFS
              library.

 Comments:    This is useful after you have called allow_lfn(1) which enables
              LFN support by DFS library. You can use check_lfn() to find out
              if LFN are actually supported by DFS library.

              Some older DOS programs cannot use long file names. If you have
              to supply a path to such program, you can use check_lfn()
              together with real_short_path() to convert long file names into
              short regular DOS names.

 Example:

              object s
              s = "C:\\Existing Long File Name.TXT"

              if check_lfn() then           -- LFN are supported by DFS?
                  s = real_short_path(s)    --  then supply short path name
              end if                        --   to other programs.

              system("TYPE " & s, 2)


 See Also:    allow_lfn, real_long_path, real_short_path


 ---------------------------------<comp_file>--------------------------------

 Syntax:      include dfs.e
              i = comp_file(s1, s2)

 Description: Compare the data of two files to verify that it is identical.
              s1 is the path name of the first file. s2 is the path name of
              the second file. If files are identical, comp_file() returns 1.
              If files are different, comp_file() returns 0.

 Comments:    Currently, files up to 2 Gb in size can be handled. Beyond that,
              some file operations may not work correctly.

 Example:

              if comp_file("D:\\DATABASE.DAT", "D:\\DATABASE.BAK") then
                 puts(1, "The files are 100% identical.")
              else
                 puts(1, "Error or files are different.")
              end if


 See Also:    file_checksum, move_file, copy_file


 ---------------------------------<copy_file>--------------------------------

 Syntax:      include dfs.e
              i1 = copy_file(s1, s2, i2)

 Description: Create an identical copy of an existing file. s1 is the path
              name of the source file. s2 is the path name for creating a new
              file. When i2 is 1 (true) the content of the new file is
              compared to the source file to verify that they are identical.
              When i2 is 0 (false) the files are not compared. If successful,
              copy_file() returns 1. If unsuccessful, copy_file() returns 0.

 Comments:    copy_file() will not overwrite the new file, s2, if this file
              already exist.

              This function is useful for creating backup copies, etc.
              Comparing the files after copy when i2 is 1 is slower, but might
              be needed for important data.

              Currently, files up to 2 Gb in size can be handled. Beyond that,
              some file operations may not work correctly.

 Example:

              if copy_file("DATABASE.DAT", "DATABASE.BAK", 1) then
                 puts(1, "File copied successfully.")
              else
                 puts(1, "Error: Cannot copy the file.")
              end if


 See Also:    move_file, rename, comp_file, erase_file, file_checksum


 ----------------------------------<curdir>----------------------------------

 Syntax:      include dfs.e
              s = curdir()

 Description: Return the name of the current working directory on the current
              working drive.

 Comments:    There will be no backslash on the end of the current directory,
              except under DOS/Windows, at the top-level of a drive, e.g. C:\

              The difference between curdir() and current_dir() is that
              curdir() optionally supports long-file-names.

 Example:

              sequence s
              s = curdir()
              -- s would have "C:\EUPHORIA 3.1.1\DOC" if you were in that
              --  directory


 See Also:    curdirs, setdir, real_dir, curdrive, wdir


 ----------------------------------<curdirs>---------------------------------

 Syntax:      include dfs.e
              s = curdirs(i)

 Description: Return the name of the current working directory for the drive
              given by integer i. i must name an existing drive on the system
              in the range 'A' to 'Z'. If unsuccessful, curdirs() returns
              "x:.", where x is the non-existing drive letter.

 Comments:    There will be no backslash on the end of the current directory,
              except under DOS/Windows, at the top-level of a drive, e.g. C:\

              By using curdirs() you can get the current directory on any
              drive, without having to change the current working drive.

 Example:

              sequence s
              s = curdirs('E')
              -- s would have "E:\BACKUP\DFS" if that was the current
              --  directory on drive E:


 See Also:    curdir, setdir, real_dir, curdrive, wdir, setdrive


 ---------------------------------<curdrive>---------------------------------

 Syntax:      include dfs.e
              i = curdrive()

 Description: Return the letter of the current working drive, in the range
              'A' to 'Z'.

 Example:

              integer i
              i = curdrive()
              -- i would have 'C' if the current directory was "C:\FDOS\BIN"


 See Also:    setdrive, drive_ready, real_drive, curdir


 ---------------------------------<date_file>--------------------------------

 Syntax:      include dfs.e
              i = date_file(s1, s2)

 Description: Modify the last-written date and time stamp of the file given by
              sequence s1. s2 is the new date and time, using the following
              format: {year, month, day, hour, minute, second}. If successful,
              date_file() returns 1. If unsuccessful, date_file() returns 0.

              The range for s2 fields is:

                year -   1980..2107
                month -  1..12
                day -    1..31
                hour -   0..23
                minute - 0..59
                second - 0..59  -- odd seconds used as even, e.g. 59 --> 58

 Comments:    When long file names are supported by DFS library, i.e. if
              check_lfn() returns 1, this function can also be used to modify
              the date and time stamp of directory.

              You can use date_file() to keep the original date and time stamp
              of a file after copying or moving the file.

              Normally, the last-written date and time is updated whenever
              the file is saved to disk. However, date and time stamp can be
              used for other purposes, for example, as a version number of all
              the files in your project.

              You can find out the last-written date and time stamp of a file
              or directory by calling wdir().

 Example 1:

              -- copy file but keep its original date-time:
              f = "DFS.E"
              s = wdir("D:\\" & f)
              stamp = s[1][D_YEAR..D_SECOND]   -- keep date-time stamp of f

              if copy_file("D:\\" & f, "E:\\" & f, 0) then
                if date_file("E:\\" & f, stamp) then
                   puts(1, f & " is copied. the original date-time are kept")
                end if
              end if


 Example 2:

              -- set the same date to all the files in my project, and
              -- use the time fields as a version number (1.2.0):
              DIR = "C:\\My Project\\"
              s = wdir({DIR & "*.*", 'f'})  -- get a list of all files

              for i = 1 to length(s) do
                 if date_file(DIR & s[i][D_NAME], {2000, 5, 26, 1, 2, 0}) = 0
                 then
                    puts(1, "Error: cannot update " & s[i][D_NAME] & '\n')
                 end if
              end for


 See Also:    wdir, rename, attrib, file_checksum, check_lfn, set_date


 --------------------------------<dir_exists>--------------------------------

 Syntax:      include dfs.e
              i = dir_exists(s)

 Description: Check if the path given by sequence s is an existing directory.
              If successful, dir_exists() returns 1. If unsuccessful,
              dir_exists() returns 0.

 Comments:    It returns 0 if the path is a root directory, i.e. the top-level
              of the drive, e.g. C:\. Use real_path() to check if a path is an
              existing root directory.

 Example:

              sequence path
              path = "\\EUPHORIA\\BIN"

              if dir_exists(path) then
                  puts(1, "Directory " & real_dir(path) & " exists.\n")
              else
                  puts(1, "Error: Directory not exists.\n")
              end if


 See Also:    real_dir, real_path, drive_exists, file_exists, wdir


 ---------------------------------<dir_name>---------------------------------

 Syntax:      include dfs.e
              s1 = dir_name(s2)

 Description: Return the directory portion for the path given by sequence s2.
              s2 is a relative or absolute path. If no directory portion is
              included in s2, dir_name() returns an empty string, "".

 Comments:    This function do not access the file system to check if the path
              is actually exist, and do not verify that the syntax of the path
              is correct.

 Example:

              s = dir_name("C:\\WORK\\DFS.E")   -- s is "C:\WORK"
              s = dir_name("C:\\DFS.E")         -- s is "C:\"
              s = dir_name("..\\DFS.E")         -- s is ".."
              s = dir_name("DFS.E")             -- s is ""
              s = dir_name(".")                 -- s is "."
              s = dir_name("C:")                -- s is "C:"
              s = dir_name("C")                 -- s is ""


 See Also:    drive_name, file_name, slash_path, trim_path, real_dir


 -------------------------------<drive_exists>-------------------------------

 Syntax:      include dfs.e
              i = drive_exists(st)

 Description: Check if the path or drive-letter given by st is pointing to an
              existing drive. If successful, drive_exists() returns 1. If
              unsuccessful, drive_exists() returns 0.

 Comments:    It returns 1 even if the drive is not ready. Use drive_ready()
              to check if the drive is actually ready for use.

              The difference between drive_exists() and real_drive() is that
              real_drive() returns a drive letter if the drive exists.

 Example 1:

              sequence path
              path = "\\EUPHORIA\\BIN"      -- or path = "D:", etc

              if drive_exists(path) then
                  puts(1, "Drive " & real_drive(path) & ": exists.\n")
              else
                  puts(1, "Error: Drive not exists.\n")
              end if


 Example 2:

              integer drive
              drive = 'F'                   -- using only a drive-letter

              if drive_exists(drive) then
                  puts(1, "Drive F: exists.\n")
              else
                  puts(1, "Error: Drive not exists.\n")
              end if


 See Also:    real_drive, drive_ready, dir_exists, file_exists


 --------------------------------<drive_name>--------------------------------

 Syntax:      include dfs.e
              s1 = drive_name(s2)

 Description: Return the drive portion for the path given by sequence s2.
              s2 is a relative or absolute path. If no drive portion is
              included in s2, drive_name() returns an empty string, "".

 Comments:    This function do not access the file system to check if the path
              is actually exist, and do not verify that the syntax of the path
              is correct.

 Example:

              s = drive_name("C:\\WORK\\DFS.E")   -- s is "C"
              s = drive_name("C:\\DFS.E")         -- s is "C"
              s = drive_name("..\\DFS.E")         -- s is ""
              s = drive_name("DFS.E")             -- s is ""
              s = drive_name(".")                 -- s is ""
              s = drive_name("C:")                -- s is "C"
              s = drive_name("C")                 -- s is ""


 See Also:    dir_name, file_name, slash_path, trim_path, real_drive


 --------------------------------<drive_ready>-------------------------------

 Syntax:      include dfs.e
              i = drive_ready(st)

 Description: Check if the path or drive-letter given by st is pointing to an
              existing and ready drive. If the drive is ready, drive_ready()
              returns 1. If the drive is not ready, drive_ready() returns 0.

 Comments:    When removable drive is not ready a critical error will occur if
              you try to write or read from it. This might result in loss of
              data. Call drive_ready() before you access the drive to verify
              that the drive is ready for use.

              This function automatically updates the letter to reference a
              mapped drive (mapped drives are similar to DOS's treatment of a
              single physical floppy drive as both A: and B:).

              The difference between drive_ready() and drive_exists() or
              drives_list() is that drive_ready() tests the drive to check
              if it is actually ready, while drive_exists() and drives_list()
              retrieve their information from the system without testing the
              drive at all.

 Example 1:

              sequence path
              path = "\\EUPHORIA\\BIN"   -- or path = "A:", etc.

              if drive_ready(path) then
                  puts(1, "Drive " & real_drive(path) & ": is ready.\n")
              else
                  puts(1, "Error: Drive not ready!\n")
              end if


 Example 2:

              integer drive
              drive = 'B'                 -- using only a drive-letter

              if drive_ready(drive) then
                  puts(1, "Drive B: is ready.\n")
              else
                  puts(1, "Error: Drive not ready!\n")
              end if


 See Also:    allow_error, setdrive, drives_list, drive_exists


 -------------------------------<drives_list>--------------------------------

 Syntax:      include dfs.e
              s = drives_list(i)

 Description: Return a string of existing logical-drives letters. When i is 1
              (true) drives_list() returns all mapped-drive letters. When i is
              0 (false) drives_list() returns only the last letter which used
              to reference a mapped-drive.

 Comments:    It returns a drive letter even if the drive is not ready. Use
              drive_ready() to check if a drive is actually ready for use.

              drives_list() may return different drive-letters when called,
              since removable drives as USB drive or virtual drive might be
              removed from the system at any time.

              Normally you should call drives_list(0) when you want to display
              a drives-list. Mapped drives are special case, similar to DOS's
              treatment of a single physical floppy drive as both A: and B:.

              Logical-drives means the total number of block devices: floppy
              disks, CDs, USB drives, virtual drives, RAMdisks, hard-disk
              drives, SUBST drives, mapped drives, etc. A single physical
              hard-disk drive is frequently partitioned into two or more
              logical drives.

 Example:

              puts(1, "Regular drives list: " & drives_list(0) & '\n')
               -- could return "ACDEF", etc.

              puts(1, "All existing drives: " & drives_list(1) & '\n')
               -- could return "ABCDEF", etc.


 See Also:    drive_ready, drive_exists, setdrive, real_drive


 ---------------------------------<erase_file>-------------------------------

 Syntax:      include dfs.e
              i = erase_file(s)

 Description: Delete an existing file using the path given by sequence s.
              If successful, erase_file() returns 1. If unsuccessful,
              erase_file() returns 0.

 Comments:    Normally, you cannot delete a file with the read-only attribute
              set. Also, file should be closed before deleting it. Deleting an
              opened file may lead to unexpected result in some cases.

              This function deletes a file by replacing the first character
              of its filename in the directory with the character #E5 and
              marking the file's clusters as "free" in the disk's file
              allocation table. The actual data stored in those clusters is
              not overwritten. Therefore the file can be undelete by using an
              undelete utility immediatly after the file was deleted.

 Example:

              if erase_file("D:\\File Name.Txt") then
                  puts(1, "The file deleted successfully.\n")
              else
                  puts(1, "Error: Cannot delete the file.\n")
              end if


 See Also:    open_file, rename, remove_dir, file_exists, attrib


 -------------------------------<file_checksum>------------------------------

 Syntax:      include dfs.e
              x = file_checksum(s)

 Description: Return a checksum value for the file given by sequence s. If
              successful, file_checksum() returns a 32-bits checksum value. If
              unsuccessful, file_checksum() returns an empty string, "".

 Comments:    Variable that holds a checksum value should be declared as atom,
              rather than integer. Euphoria's integer type is limited to
              31-bits.

              The checksum value is calculated for the file's data, using the
              default CRC-32 specifications. It should be accurate enough for
              regular data integrity check.

              A checksum value should be generated when you want to verify
              that your file is not accidentally modified. file_checksum()
              will return exactly the same checksum value as long as the
              file's data is not modified. You can save the current checksum
              value and later generate a new checksum: if the new checksum is
              not equal to the saved checksum then the file is probably
              modified or corrupted.

              Currently, files up to 2 Gb in size can be handled. Beyond that,
              some file operations may not work correctly.

 Example:

              object checksum
              checksum = file_checksum("D:\\DFS.E")

              if atom(checksum) then
                  printf(1, "The checksum value is: #%08x\n", checksum)
              else
                  puts(1, "Error: Cannot generate checksum.\n")
              end if


 See Also:    comp_file, move_file, copy_file, open_file


 --------------------------------<file_exists>-------------------------------

 Syntax:      include dfs.e
              i = file_exists(s)

 Description: Check if the path given by sequence s is an existing file.
              If successful, file_exists() returns 1. If unsuccessful,
              file_exists() returns 0.

 Example:

              sequence path
              path = "\\EUPHORIA\\BIN\\EX.EXE"

              if file_exists(path) then
                  puts(1, "File " & real_path(path, 0) & " exists.\n")
              else
                  puts(1, "Error: File not exists.\n")
              end if


 See Also:    real_path, dir_exists, drive_exists, file_size, wdir


 ---------------------------------<file_name>--------------------------------

 Syntax:      include dfs.e
              s1 = file_name(s2)

 Description: Return the file portion for the path given by sequence s2.
              s2 is a relative or absolute path. If no file portion is
              included in s2, file_name() returns an empty string, "".

 Comments:    This function do not access the file system to check if the path
              is actually exist, and do not verify that the syntax of the path
              is correct.

 Example:

              s = file_name("C:\\WORK\\DFS.E")   -- s is "DFS.E"
              s = file_name("C:\\DFS.E")         -- s is "DFS.E"
              s = file_name("..\\DFS.E")         -- s is "DFS.E"
              s = file_name("DFS.E")             -- s is "DFS.E"
              s = file_name(".")                 -- s is ""
              s = file_name("C:")                -- s is ""
              s = file_name("C")                 -- s is "C"


 See Also:    filebase_name, fileext_name, dir_name, drive_name, real_path


 ---------------------------------<file_size>--------------------------------

 Syntax:      include dfs.e
              a = file_size(s)

 Description: Return the size of the file given by sequence s. s must name an
              existing file on the system. If successful, file_size() returns
              the length of the file in bytes. If unsuccessful, file_size()
              returns -1.

 Example:

              -- verify that the size of EX.EXE (Euphoria 3.1.1) is correct:
              atom size
              size = file_size("C:\\EUPHORIA\\BIN\\EX.EXE")

              if size = 477070 then
                 puts(1, "The size of EX.EXE is correct.\n")
              elsif size > -1 then
                 puts(1, "Error: The size of EX.EXE is wrong!\n")
              end if


 See Also:    wdir, real_path, file_exists, dir_exists, drive_exists


 -------------------------------<filebase_name>------------------------------

 Syntax:      include dfs.e
              s1 = filebase_name(s2)

 Description: Return the base-filename portion for the path given by sequence
              s2. s2 is a relative or absolute path. If no base-filename
              portion is included in s2, filebase_name() returns an empty
              string, "".

 Comments:    This function do not access the file system to check if the path
              is actually exist, and do not verify that the syntax of the path
              is correct.

 Example:

              s = filebase_name("C:\\WORK\\DFS.E")   -- s is "DFS"
              s = filebase_name("C:\\DFS.E")         -- s is "DFS"
              s = filebase_name("..\\DFS.E")         -- s is "DFS"
              s = filebase_name("DFS.E")             -- s is "DFS"
              s = filebase_name(".")                 -- s is ""
              s = filebase_name("C:")                -- s is ""
              s = filebase_name("C")                 -- s is "C"


 See Also:    fileext_name, file_name, dir_name, drive_name, real_path


 -------------------------------<fileext_name>-------------------------------

 Syntax:      include dfs.e
              s1 = fileext_name(s2)

 Description: Return the filename-extension portion for the path given by
              sequence s2. s2 is a relative or absolute path. If no filename-
              extension portion is included in s2, fileext_name() returns an
              empty string, "".

 Comments:    This function do not access the file system to check if the path
              is actually exist, and do not verify that the syntax of the path
              is correct.

 Example:

              s = fileext_name("C:\\WORK\\DFS.E")   -- s is "E"
              s = fileext_name("C:\\DFS.E")         -- s is "E"
              s = fileext_name("..\\DFS.E")         -- s is "E"
              s = fileext_name("DFS.E")             -- s is "E"
              s = fileext_name(".")                 -- s is ""
              s = fileext_name("C:")                -- s is ""
              s = fileext_name("C")                 -- s is ""


 See Also:    filebase_name, file_name, dir_name, drive_name, real_path


 --------------------------------<label_drive>-------------------------------

 Syntax:      include dfs.e
              i1 = label_drive(i2, s)

 Description: Create, change or delete the volume label of a drive using the
              label given by sequence s. s is an alphanumeric string of up to
              11 characters. If s is empty, "", then the current volume label,
              if exists, is deleted. i2 must name an existing drive on the
              system in the range 'A' to 'Z'. If successful, label_drive()
              returns 1. If unsuccessful, label_drive() returns 0.

 Comments:    A typical use for this function is to label removable drive that
              is used for backup, such as floppy-disk or USB-drive, with the
              current date, e.g. "BAK20120823" (i.e. BACKUP-2012-08-23).

              The function volume_label() will return the current volume label
              of a drive.

 Example:

              -- set the volume label to the current date, e.g. "BAK20120823"
              integer drive
              sequence now

              drive = 'A'
              now = date()
              now[1] += 1900        -- year is relative to 1900
              now = sprintf("BAK%4d%02d%02d", now[1..3])

              puts(1, "The current label is: " & volume_label(drive) & '\n')

              if label_drive(drive, now) then
                 puts(1, "The new label is: " & volume_label(drive) & '\n')
              else
                 puts(1, "Error: cannot create or change label.\n")
              end if


 See Also:    volume_label, attrib, rename, curdrive


 ---------------------------------<make_dir>---------------------------------

 Syntax:      include dfs.e
              i = make_dir(s)

 Description: Create a new directory using the path given by sequence s.
              If successful, make_dir() returns 1. If unsuccessful, make_dir()
              returns 0.

 Example:

              integer nul
              if make_dir("C:\\Euphoria 3.1.1") then
                  nul = setdir("C:\\Euphoria 3.1.1")
                  setdrive('C')
                  puts(1, "Current dir is: " & curdir())
              else
                  puts(1, "Error: Cannot create the directory.\n")
              end if


 See Also:    real_temp, remove_dir, rename, dir_exists, open_file


 ---------------------------------<move_file>--------------------------------

 Syntax:      include dfs.e
              i1 = move_file(s1, s2, i2)

 Description: Move an existing file to another location. s1 is the path name
              of the source file. s2 is the path name for creating a new
              file. When i2 is 1 (true) the content of the new file is
              compared to the source file to verify that they are identical.
              When i2 is 0 (false) the files are not compared. If successful,
              move_file() returns 1. If unsuccessful, move_file() returns 0.

 Comments:    The new path name, s2, must include a file name. move_file()
              will not overwrite the new file if it's already exist.

              This function is useful for moving files to a different drive
              or on the same drive. Moving files on the same drive is much
              faster and does not need comparing. Comparing the files after
              copy to a different drive when i2 is 1 is slower, but might be
              needed for important data.

              Note that this function can also rename directory if s1 and s2
              are on the same path, so be sure to specify a *file* name.

              Currently, files up to 2 Gb in size can be handled. Beyond that,
              some file operations may not work correctly.

 Example:

              if move_file("D:\\NOTES-1.TXT", "E:\\TEMP\\NOTES.TXT", 1) then
                 puts(1, "The file moved successfully.")
              else
                 puts(1, "Error: Cannot move the file.")
              end if


 See Also:    rename, copy_file, comp_file, erase_file, file_checksum


 --------------------------------<open_file>---------------------------------

 Syntax:      include dfs.e
              fn = open_file(s1, s2)

 Description: Open a file or device, to get the file number. -1 is returned if
              the open fails. s1 is the path name of the file or device. s2
              is the mode in which the file is to be opened. Possible modes
              are:

              "r" - open text file for reading
              "rb" - open binary file for reading
              "w" - create text file for writing
              "wb" - create binary file for writing
              "u" - open text file for update (reading and writing)
              "ub" - open binary file for update
              "a" - open text file for appending
              "ab" - open binary file for appending

              Files opened for read or update must already exist. Files opened
              for write or append will be created if necessary. A file opened
              for write will be set to 0 bytes. Output to a file opened for
              append will start at the end of file.

              Output to text files will have carriage-return characters
              automatically added before linefeed characters. On input, these
              carriage-return characters are removed. A control-Z character
              (ASCII 26) will signal an immediate end of file. Note: on some
              versions of DOS, a control-Z typed by the user might cause
              standard input to permanently appear to be at the end-of-file,
              until the DOS window is closed.

              I/O to binary files is not modified in any way. Any byte values
              from 0 to 255 can be read or written.

              Some typical devices that you can open on DOS or Windows are:

              "CON" - the console (screen)
              "AUX" - the serial auxiliary port
              "COM1" - serial port 1
              "COM2" - serial port 2
              "PRN" - the printer on the parallel port
              "NUL" - a non-existent device that accepts and discards output

              Currently, files up to 2 Gb in size can be handled. Beyond that,
              some file operations may not work correctly.

 Comments:    Be careful not to use the special device names in a file
              name, even if you add an extension. e.g. CON.TXT, CON.DAT,
              CON.JPG etc. all refer to the CON device, not a file.

              open_file() is an extension to open() routine. The file-number
              is actually returned by open(), which still opens the file as
              usual. Therefor, any Euphoria's routine that is related to
              files, e.g. close(), flush(), gets(), etc, can be used as usual.

              The difference between open_file() and open() is that
              open_file() optionally supports long-file-names in all open
              modes.

 Example:

              integer fn            -- file number
              sequence first_line
              constant ERROR = 2

              fn = open_file("myfile", "r")
              if fn = -1 then
                  puts(ERROR, "couldn't open myfile\n")
              else
                  first_line = gets(fn)
              end if

              fn = open_file("PRN", "w") -- open printer for output

              fn = open_file("bigdirectoryname\\verylongname.abcdefg", "w")
              if fn != -1 then
                  puts(1, "creating long-file-name for output worked!\n")
              end if


 See Also:    Euphoria 3.1: close, lock_file,
              real_temp, erase_file, rename, attrib, make_dir


 ---------------------------------<real_dir>---------------------------------

 Syntax:      include dfs.e
              x = real_dir(s)

 Description: Return the full directory name of the path given by sequence s.
              s must name an existing directory on the system. If successful,
              real_dir() returns the full directory name. If unsuccessful,
              real_dir() returns -1.

 Comments:    There will be no backslash on the end of the directory name,
              except under DOS/Windows, at the top-level of a drive, e.g. C:\

              The maximum length of a full path that can be resolved depends
              on the operating system. DOS normally supports up to 66
              characters in pathnames. Windows might support longer pathnames.

 Example:

              x = real_dir("..\\.")
              -- x would have "C:\EUPHORIA" if you were in "C:\EUPHORIA\DOC"


 See Also:    real_path, real_drive, real_temp, dir_exists, wdir


 --------------------------------<real_drive>--------------------------------

 Syntax:      include dfs.e
              i = real_drive(s)

 Description: Return the drive letter of the path given by sequence s.
              s must point to an existing drive on the system. If successful,
              real_drive() returns the drive letter. If unsuccessful,
              real_drive() returns -1.

 Comments:    This function do not access the file system to check if the path
              is actually exist, and do not verify that the syntax of the path
              is correct. It only verifies that the drive portion of the path
              is exist ("real"), whether this drive is ready or not.

 Example:

              -- assuming that D: is the current drive, and drive C: exists:
              s = real_drive("C:\\DFS.E")   -- s is 'C'
              s = real_drive("..\\DFS.E")   -- s is 'D'
              s = real_drive("DFS.E")       -- s is 'D'
              s = real_drive(".")           -- s is 'D'
              s = real_drive("C:")          -- s is 'C'
              s = real_drive("C")           -- s is 'D'
              s = real_drive("J:\\")        -- s is -1  (if J: not exists)
              s = real_drive(":\\")         -- s is -1  (invalid path)


 See Also:    real_dir, real_path, real_temp, wdir, drive_ready


 ------------------------------<real_long_path>------------------------------

 Syntax:      include dfs.e
              x = real_long_path(s)

 Description: Return the full path name of the path given by sequence s, in
              long file names format (LFN). s must name an existing path on
              the system. If successful, real_long_path() returns a full path.
              If unsuccessful, real_long_path() returns -1.

 Comments:    This function converts short file names to long file names. Use
              it when you have to communicate with older DOS programs that
              cannot supply long file names, or when allow_lfn(0) is used on
              a system that supports long file names.

              Using this function is possible whenever the operating system
              is supporting long file names (LFN), even if allow_lfn(0) is
              used.

              Short names are *dynamically* created by the operating system
              as alias to long names, for maintaining compatibility with the
              regular DOS names (8.3). i.e. when a file is deleted, a new
              file might use its alias. Therefore, short name must be
              converted *immediatly* to long name, using real_long_path(),
              to avoid possible mistakes as overwriting the wrong file.

              Note that when you use long file names with system() routine,
              for example, you must enclose the path with quotation-marks,
              e.g. system("TYPE " & '"' & "Reference Manual.txt" & '"', 2).

 Example:

              -- assuming that LFN is currently supported by the operating
              -- system, but it's disabled in DFS library:

              allow_lfn(0)          -- disable LFN support by DFS library
              p = curdir()          -- assuming that p is "D:\EUPHOR~1.1"
              p = real_long_path(p) -- convert short alias to real path name

              -- now p might be "D:\\Euphoria Version 3.1.1" - which is the
              -- real path name (not alias). Using the real path name will
              -- avoid possible mistakes whenever alias name is deleted.


 See Also:    real_short_path, real_path, allow_lfn, check_lfn


 ---------------------------------<real_path>--------------------------------

 Syntax:      include dfs.e
              x = real_path(s, i)

 Description: Return the full path name of the path given by sequence s.
              s must point to an existing directory on the system, and may
              contain also a file name. When i is 1 (true) real_path() returns
              the sequence {"full-path", 'path-type'}. When i is 0 (false)
              real_path() returns only the full-path string.
              If successful, real_path() returns a sequence according to i. If
              unsuccessful, real_path() returns -1.

              Possible values for 'path-type', when i is 1, are:

              'r' - full-path is an existing root directory, e.g. C:\
              'd' - full-path is an existing sub directory, e.g. C:\EUPHORIA
              'f' - full-path is an existing file, e.g. C:\EUPHORIA\README.DOC
              'w' - the file portion of full-path contain wildcard(s), * or ?
              'n' - the file portion of full-path is not exists

              If 'path-type' is 'w' or 'n' then it means that only the
              directory portion of full-path is exists.

 Comments:    Use this function whenever the type of a path is unknown, or
              when you have to choose an action according to the type of a
              path.

              There will be no backslash on the end of a directory name,
              except under DOS/Windows, at the top-level of a drive, e.g. C:\

              The maximum length of a full path that can be resolved depends
              on the operating system. DOS normally supports up to 66
              characters in pathnames. Windows might support longer pathnames.

 Example:

              -- if you were in the directory "C:\EU\DOC" then x would have:

              x = real_path("..\\.", 0)          --> "C:\EU"
              x = real_path("..\\.", 1)          --> {"C:\EU", 'd'}
              x = real_path("..\\..\\.", 1)      --> {"C:\", 'r'}
              x = real_path("..\\..\\..\\.", 1)  --> -1  (dir not exists)
              x = real_path("..\\readme.doc", 1) --> {"C:\EU\readme.doc", 'f'}
              x = real_path("..\\readme.*", 1)   --> {"C:\EU\readme.*", 'w'}
              x = real_path("..\\readme.XYZ", 1) --> {"C:\EU\readme.XYZ", 'n'}


 See Also:    real_dir, real_drive, real_temp, dir_exists, wdir


 -----------------------------<real_short_path>------------------------------

 Syntax:      include dfs.e
              x = real_short_path(s)

 Description: Return the full path name of the path given by sequence s, in
              short file names format (8.3). s must name an existing path on
              the system. If successful, real_short_path() returns a full
              path. If unsuccessful, real_short_path() returns -1.

 Comments:    This function converts long file names to short file names. Use
              it when you have to communicate with older DOS programs that
              cannot accept long file names.

              Using this function is possible whenever the operating system
              is supporting long file names (LFN), even if allow_lfn(0) is
              used.

              Short names are *dynamically* created by the operating system
              as alias to long names, for maintaining compatibility with the
              regular DOS names (8.3). i.e. when a file is deleted, a new
              file might use its alias. Therefore, a short name must be used
              *immediatly* after retrieving it from real_short_path().

 Example:

              -- assuming that "VIEWHTML.EXE" can only accept regular names:

              path = "D:\\Euphoria Version 3.1.1\\Reference Manual.html"
              system("VIEWHTML.EXE " & real_short_path(path), 2)
              -- short path might be "D:\EUPHOR~1.1\REFERE~1.HTM"


 See Also:    real_long_path, real_path, allow_lfn, check_lfn


 ---------------------------------<real_temp>--------------------------------

 Syntax:      include dfs.e
              x = real_temp(s)

 Description: Return a unique file name for the directory given by sequence s.
              s must name an existing directory on the system. If successful,
              real_temp() returns the full path of the unique file name. If
              unsuccessful, real_temp() returns -1.

 Comments:    The unique file name returned by this function is made of 8
              capital letters, 'A' to 'Z', without filename-extension, and
              can be used in both regular and LFN modes as it is.

              This function only returns a base-file-name which is not exists.
              The application is responsible for creating a file or directory
              with this name *immediatly* after retrieving it. Any *extension*
              may be appended safely to this file name, i.e. "D:\VGOPKSCZ"
              or "D:\VGOPKSCZ" & ".TXT" are both unique, since the base-file-
              name is not exists.

              The maximum length of a full path that can be resolved depends
              on the operating system. DOS normally supports up to 66
              characters in pathnames. Windows might support longer pathnames.

 Example 1:

              x = real_temp(".")
               -- x could have "D:\LPSZGYWG" if you were in "D:\"

              x = real_temp("C:\\TEMP")
               -- x could have "C:\TEMP\IXCDYNJD" if "C:\TEMP" exists, or -1
               -- if "C:\TEMP" not exists.


 Example 2:

              -- create backup files while you work:
              sequence d
              d = slash_path("D:\\WORK")   -- d is directory name

              if copy_file(d & "DFS.E", real_temp(d) & ".BAK", 1) then
                 puts(1, "Backup file was created!\n")
              else
                 puts(1, "Error: cannot create a backup file.\n")
              end if


 See Also:    real_path, real_dir, real_drive, dir_exists, wdir


 --------------------------------<remove_dir>--------------------------------

 Syntax:      include dfs.e
              i = remove_dir(s)

 Description: Delete an existing directory using the path given by sequence s.
              If successful, remove_dir() returns 1. If unsuccessful,
              remove_dir() returns 0.

 Comments:    You cannot delete the current directory, or directory that
              contains files in it, or, normally, directory with the read-only
              attribute set.

 Example:

              if remove_dir("D:\\Temporary Dir") then
                  puts(1, "The directory deleted successfully.\n")
              else
                  puts(1, "Error: Cannot delete the directory.\n")
              end if


 See Also:    make_dir, rename, curdir, dir_exists, attrib, erase_file


 ----------------------------------<rename>----------------------------------

 Syntax:      include dfs.e
              i = rename(s1, s2)

 Description: Rename an existing file or directory. s1 is the current path
              name of the file or directory. s2 is the new path name for the
              file or directory. If successful, rename() returns 1. If
              unsuccessful, rename() returns 0.

 Comments:    This function can also be used for moving files to another
              existing directory on the same drive. When you rename a file
              (not directory) you are allowed to specify a different path
              name for the new file name, for example:
              i = rename("C:\\EUPHORIA\\README.DOC", "C:\\README.TXT")

              To move files to another existing directory on the same or a
              different drive use move_file().

 Example:

              if rename("D:\\File Name.Txt", "D:\\Temp\\File Name.Tmp") then
                  puts(1, "The file or directory renamed successfully.")
              else
                  puts(1, "Error: Cannot rename the file or directory.")
              end if


 See Also:    move_file, copy_file, erase_file, remove_dir, attrib


 ----------------------------------<set_date>--------------------------------

 Syntax:      include dfs.e
              i = set_date(s)

 Description: Modify the system date using the new date given by sequence s.
              s is {year, month, day}. If successful, set_date() returns 1.
              If unsuccessful, set_date() returns 0.

              The range for the new date is:

                year -  1980..2099
                month - 1..12
                day -   1..31

 Comments:    Since date and time stamp of files is updated whenever a file
              is saved to disk, it's important to keep the system's date and
              time accurate.

              In applications that store the current date and time often,
              such as library database, diary database, etc, you might want
              to display the system clock and allow the user to correct the
              date and time instantly.

              You can obtain the system date and time by calling date().

 Example:

              sequence cur, new
              integer i

              -- get current system date:
              cur = date()
              cur[1] += 1900        -- date() year is relative to 1900
              printf(1, "Current date is: %d-%d-%d\n", cur[1..3])

              -- set new date, temporarily, for example:
              i = set_date({1997, 6, 21})     -- {year, month, day}
              new = date()
              new[1] += 1900
              printf(1, "New date is: %d-%d-%d\n", new[1..3])

              i = set_date(cur[1..3])   -- restore current system date


 See Also:    set_time, date_file


 ----------------------------------<set_time>--------------------------------

 Syntax:      include dfs.e
              i = set_time(s)

 Description: Modify the system time using the new time given by sequence s.
              s is {hour, minute, second}. If successful, set_time() returns 1.
              If unsuccessful, set_time() returns 0.

              The range for the new time is:

                hour -   0..23
                minute - 0..59
                second - 0..59

 Comments:    Since date and time stamp of files is updated whenever a file
              is saved to disk, it's important to keep the system's date and
              time accurate.

              In applications that store the current date and time often,
              such as library database, diary database, etc, you might want
              to display the system clock and allow the user to correct the
              date and time instantly.

              You can obtain the system date and time by calling date().

 Example:

              sequence cur, new
              integer i

              -- get current system time:
              cur = date()
              printf(1, "Current time is: %d:%02d:%02d\n", cur[4..6])

              -- set new time, temporarily, for example:
              i = set_time({10, 45, 3})     -- {hour, minute, second}
              new = date()
              printf(1, "New time is: %d:%02d:%02d\n", new[4..6])

              i = set_time(cur[4..6])   -- restore current system time


 See Also:    set_date, date_file


 ----------------------------------<setdir>----------------------------------

 Syntax:      include dfs.e
              i = setdir(s)

 Description: Set the current directory to the path given by sequence s.
              s must name an existing directory on the system. If successful,
              setdir() returns 1. If unsuccessful, setdir() returns 0.

 Comments:    By setting the current directory, you can refer to files in that
              directory using just the file name.

              The function curdir() will return the name of the current
              directory.

              On DOS32 and WIN32 the current directory is a global property
              shared by all the processes running under one shell.

              The difference between setdir() and chdir() is that setdir()
              optionally supports long-file-names.

 Example:

              if setdir("c:\\euphoria 3.1.1") then
                  fn = open_file("readme.doc", "r")
              else
                  puts(1, "Error: No euphoria directory?\n")
              end if


 See Also:    curdir, curdirs, setdrive


 ---------------------------------<setdrive>---------------------------------

 Syntax:      include dfs.e
              setdrive(i)

 Description: Set the current drive to the drive letter given by integer i.
              i must name an existing drive on the system in the range
              'A' to 'Z'.

 Comments:    By setting the current drive, you can refer to files in that
              drive using setdir() and just the file name.

              It will set the current drive even if the drive is not ready,
              i.e. invalid media in drive, drive disconnected, etc.
              Use drive_ready() to check if the drive is actually ready.

              It also updates the letter to reference a mapped drive (mapped
              drives are similar to DOS's treatment of a single physical
              floppy drive as both A: and B:).

              The function curdrive() will return the name of the current
              drive.

              On DOS32 and WIN32 the current drive is a global property
              shared by all the processes running under one shell.

 Example:

              if drive_ready("B:") then     -- check if drive B: is ready
                  setdrive('B')             -- change to drive B:
                  puts(1, curdir())         -- display the current directory
              else
                  puts(1, "Error: Drive B: is not exist or not ready.\n")
              end if


 See Also:    curdrive, drives_list, drive_ready, drive_exists, setdir


 ---------------------------------<slash_path>-------------------------------

 Syntax:      include dfs.e
              s1 = slash_path(s2)

 Description: Append backslash, \, to the path given by sequence s2. s2 is a
              relative or absolute path. If s2 is an empty string, "",
              slash_path() returns ".\", i.e. current-directory & '\'.

 Comments:    This function do not access the file system to check if the path
              is actually exist, and do not verify that the syntax of the path
              is correct.

              Use slash_path() to append a backslash to directory name, when
              you need to join directory name and file name. slash_path() only
              appends a backslash to path which does not already ends with a
              backslash or colon (\ or :).

              Use trim_path() to remove invalid backslash from a path.

 Example 1:

              s = slash_path("C:\\WORK\\DFS.E")  -- s is "C:\WORK\DFS.E\"
              s = slash_path("C:\\WORK\\")       -- s is "C:\WORK\"
              s = slash_path("..\\WORK")         -- s is "..\WORK\"
              s = slash_path("WORK")             -- s is "WORK\"
              s = slash_path("..")               -- s is "..\"
              s = slash_path("C:")               -- s is "C:"
              s = slash_path("C:\\")             -- s is "C:\"
              s = slash_path("\\")               -- s is "\"
              s = slash_path("")                 -- s is ".\"


 Example 2:

              sequence d, f

              include get.e
              d = prompt_string("Enter directory name: ")
              f = prompt_string("Enter file name: ")

              puts(1, "The full path is: " & slash_path(d) & f)


 See Also:    trim_path, drive_name, dir_name, file_name, real_path


 ---------------------------------<trim_path>--------------------------------

 Syntax:      include dfs.e
              s1 = trim_path(s2)

 Description: Remove invalid leading and trailing characters from the path
              given by sequence s2. s2 is a relative or absolute path.

 Comments:    This function do not access the file system to check if the path
              is actually exist, and do not verify that the syntax of the path
              is correct. It only removes invalid characters from the left and
              right sides of the path.

              Use trim_path() to fix common mistakes in pathnames that may be
              supplied by the user or by another program. trim_path() removes
              the following invalid characters, in the following order:

              1. Leading and trailing spaces (ASCII-32), control-characters
                 (ASCII-0..31) and quotation-marks (ASCII-34, "").
              2. Trailing backslash (ASCII-92, \), unless it is a root-dir.
              3. Trailing dots (ASCII-46, '.'), unless it is a relative-dir.

              Note that many DOS programs, including COMMAND.COM, are
              automatically removing some or most of these invalid characters,
              since these are obviously mistakes which are not part of the
              pathname itself.

              All DFS library routines which accept a pathname, are calling
              trim_path() automatically for fixing possible mistakes. So, for
              example, the string "\t\"   \"\n" is equal to empty, "".

 Example:

              s = trim_path("  C:\\WORK\\   ")   -- s is "C:\WORK"
              s = trim_path(" C:\\DFS.\\ ")      -- s is "C:\DFS"
              s = trim_path(" ..\\DFS.E...\\ ")  -- s is "..\DFS.E"
              s = trim_path(" \" DFS.E \" ")     -- s is "DFS.E"
              s = trim_path(" . \r\n")           -- s is "."
              s = trim_path(" C:\\... ")         -- s is "C:\..."
              s = trim_path(" \\ ")              -- s is "\"
              s = trim_path(" ...\\ ")           -- s is "..."


 See Also:    slash_path, drive_name, dir_name, file_name, real_path


 -------------------------------<volume_label>-------------------------------

 Syntax:      include dfs.e
              s = volume_label(i)

 Description: Return the volume label of the drive given by integer i. i must
              name an existing drive on the system in the range 'A' to 'Z'.
              If successful, volume_label() returns the volume label string.
              If unsuccessful, volume_label() returns an empty string, "".

 Comments:    Each drive may have only one volume label, at the top-level of
              the drive, e.g. in C:\

              The maximum length of a volume label is 11-characters, since
              volume labels are stored in short name format (8.3) and the dot
              before the extension is removed by this function.

              Volume label, if exists, may supply quick information about the
              content of the drive. Therefore can be useful in dialog boxes
              that display a drives-list.

              The function label_drive() will create, change or delete the
              volume label of a drive.

 Example:
              sequence s

              s = volume_label('C')
              -- s could be "FREEDOS2011", "WINXP", "", etc.

              s = volume_label('D')
              -- s could be "DATA", "GAMES", "", etc.


 See Also:    label_drive, wdir, drives_list


 -----------------------------------<wdir>-----------------------------------

 Syntax:      include dfs.e
              x = wdir(s)
              or ...
              x = wdir({s, i})

 Description: Return directory information for the file or directory named by
              s. If there is no file or directory with this name then -1 is
              returned. On Windows and DOS s can contain * and ? wildcards to
              select multiple files.
              i is the mode in which the directory is to be searched. Possible
              modes are:

              'n' - find files and directories (normal search)
              'f' - find only files
              'd' - find only directories
              'v' - find volume label (may exist only in a root dir, e.g. c:\)

              The default mode is 'n' (normal) when i is not specified in
              the first form of the syntax.

              This information is similar to what you would get from the DOS
              DIR command. A sequence is returned where each element is a
              sequence that describes one file or subdirectory.

              If s contain * and/or ? wildcards you may have entries for "."
              and "..", just as with the DOS DIR command. If s names a file
              or directory then x will have just one entry, i.e. length(x)
              will be 1. Only if s contains wildcards you may have multiple
              entries.

              Each entry contains the name, attributes and file size as well as
              the year, month, day, hour, minute and second of the last
              modification. You can refer to the elements of an entry with the
              following constants defined in include\file.e (Euphoria 3.1):

                  global constant D_NAME = 1,
                            D_ATTRIBUTES = 2,
                                  D_SIZE = 3,

                                  D_YEAR = 4,
                                 D_MONTH = 5,
                                   D_DAY = 6,

                                  D_HOUR = 7,
                                D_MINUTE = 8,
                                D_SECOND = 9

              The attributes element is a string sequence containing characters
              chosen from:

                  'd' -- directory
                  'r' -- read only file
                  'h' -- hidden file
                  's' -- system file
                  'v' -- volume-id entry
                  'a' -- archive file

              A normal file without special attributes would just have an empty
              string, "", in this field.

 Comments:    The top level directory, e.g. c:\ does not have "." or ".."
              entries.

              This function is often used just to test if a file or directory
              exists.

              The difference between wdir(), "wildcards-dir()", and dir() is
              that wdir() optionally supports long-file-names, and returns
              multiple entries *only* if s contains wildcards - this can be
              useful when you wish to get info on a directory name it self.
              The second form of wdir() lets you search more specific info
              which dir() do not.

              Remember that wdir() takes just one argument, which in the
              second form is actually a 2-element sequence.

 Example 1:

              d = wdir("C:\\EUPHORIA")      -- return directory entry

              -- d might have:
                {
                  {"EUPHORIA",     "d",     0, 2012, 10, 21, 15, 20, 32}
                }


 Example 2:

              d = wdir("C:\\EUPHORIA\\*.*")   -- return directory content

              -- d might have:
                {
                  {".",            "d",     0, 2012, 10, 21, 15, 20, 32},
                  {"..",           "d",     0, 2012, 10, 21, 15, 20, 32},
                  {"BIN",          "d",     0, 2012, 10, 21, 15, 20, 38},
                  {"DEMO",         "d",     0, 2012, 10, 21, 15, 20, 38},
                  {"DOC",          "d",     0, 2012, 10, 21, 15, 20, 40},
                  {"HTML",         "d",     0, 2012, 10, 21, 15, 20, 40},
                  {"INCLUDE",      "d",     0, 2012, 10, 21, 15, 20, 40},
                  {"SOURCE",       "d",     0, 2012, 10, 21, 15, 20, 42},
                  {"TUTORIAL",     "d",     0, 2012, 10, 21, 15, 20, 42},
                  {"FILE_ID.DIZ",  "" ,   376, 2012, 10, 21, 15, 15, 34},
                  {"LICENSE.TXT",  "" ,  1134, 2007,  8,  1, 23,  0, 12},
                  {"RAPID~10.URL", "" ,    54, 2012, 10, 21, 15, 15, 34},
                  {"README.DOC",   "" , 10097, 2012, 10,  2, 16, 29, 56},
                  {"README.HTM",   "" , 15785, 2012, 10,  2, 16, 29, 56}
                }

              d[3][D_NAME] would be "BIN"


              or ...


              d = wdir({"C:\\EUPHORIA\\*.*", 'f'})  -- return only files

              -- d might have:
                {
                  {"FILE_ID.DIZ",  "" ,   376, 2012, 10, 21, 15, 15, 34},
                  {"LICENSE.TXT",  "" ,  1134, 2007,  8,  1, 23,  0, 12},
                  {"RAPID~10.URL", "" ,    54, 2012, 10, 21, 15, 15, 34},
                  {"README.DOC",   "" , 10097, 2012, 10,  2, 16, 29, 56},
                  {"README.HTM",   "" , 15785, 2012, 10,  2, 16, 29, 56}
                }


 Example Program: bin\search.ex   -- related to dir() routine.


 See Also:    real_path, volume_label, file_exists, attrib, date_file, curdir