{Begin SubSec Deleting, Copying, and Renaming Files}
{Title Deleting, Copying, and Renaming Files}
{Text


{index Deleting files}

{FnDef {FnName DELFILE} {FnArgs FILE}
{Text
Deletes {arg FILE} if possible.  The file must be closed.  Returns the full name of the file if deleted, else {lisp NIL}.  Recognition mode for {arg FILE} is {lisp OLDEST}, i.e., if {arg FILE} does not have a version number specified, then {fn DELFILE} deletes the oldest version of the file.
}}


{index Copying files}

{FnDef {Name COPYFILE} {Args FROMFILE TOFILE}
{Text
Copies {arg FROMFILE} to a new file named {arg TOFILE}.  The source and destination may be on any combination of hosts/devices.  {fn COPYFILE} attempts to preserve the {lisp TYPE} and {lisp CREATIONDATE} where possible.  If the original file's file type is unknown, {fn COPYFILE} attempts to infer the type (file type is {lisp BINARY} if any of its 8-bit bytes have their high bit on).

{Fn COPYFILE} uses {fn COPYCHARS} ({PageRef Fn COPYCHARS}) if the source and destination hosts have different {lisp EOL} conventions.  Thus, it is possible for the source and destination files to be of different lengths.
}}


{index Renaming files}

{FnDef {FnName RENAMEFILE} {FnArgs OLDFILE NEWFILE}
{Text
Renames {arg OLDFILE} to be {arg NEWFILE}.  Causes an error, {index FILE NOT FOUND Error}{lisp FILE NOT FOUND} if {arg FILE} does not exist.  Returns the full name of the new file, if successful, else {lisp NIL} if the rename cannot be performed.

If {arg OLDFILE} and {arg NEWFILE} are on the same host/device, and the device implements a renaming primitive, {fn RENAMEFILE} can be very fast.  However, if the device does not know how to rename files in place, or if {arg OLDFILE} and {arg NEWFILE} are on different devices, {fn RENAMEFILE} works by copying {arg OLDFILE} to {arg NEWFILE} and then deleting {arg OLDFILE}.
}}


}{End SubSec Deleting, Copying, and Renaming Files}




{Begin SubSec Searching File Directories}
{Title Searching File Directories}
{Text


{index *PRIMARY* Directories}
{index *PRIMARY* File directories}
{index *PRIMARY* Searching file directories}



{VarDef {Name DIRECTORIES}
{Text
Global variable containing the list of directories searched (in order) by {fn SPELLFILE} and {fn FINDFILE} (below) when not given an explicit {arg DIRLST} argument.  In this list, the atom {lisp NIL} stands for the login directory (the value of {var LOGINHOST/DIR}), and the atom {lisp T} stands for the currently connected directory.  Other elements should be {it full} directory specifications, e.g., {lisp {bracket TWENTY}PS:<LISPUSERS>}, not merely {lisp LISPUSERS}.
}}


{VarDef {Name LISPUSERSDIRECTORIES}
{Text
Global variable containing a list of directories to search for "library" package files.  Used by the {lisp FILES} file package command ({PageRef FileCom FILES}).
}}

{index *PRIMARY* Spelling correction on file names}

{FnDef {FnName SPELLFILE} {FnArgs FILE NOPRINTFLG NSFLG DIRLST}
{Text
Searches for the file name {arg FILE}, possibly performing spelling correction (see {PageRef Term Spelling correction}).  Returns the corrected file name, if any, otherwise {lisp NIL}.

If {arg FILE} has a directory field, {fn SPELLFILE} attempts spelling correction against the files in that particular directory.  Otherwise, {fn SPELLFILE} searches for the file on the directory list {arg DIRLST} before attempting any spelling correction.

If {arg NOPRINTFLG} is {lisp NIL}, {fn SPELLFILE} asks the user to confirm any spelling correction done, and prints out any files found, even if spelling correction is not done.  If {arg NOPRINTFLG}={lisp T}, {fn SPELLFILE} does not do any printing, nor ask for approval.

If {arg NSFLG}={lisp T} (or {index NOSPELLFLG Var}{var NOSPELLFLG}={lisp T}, see {PageRef Var NOSPELLFLG}), no spelling correction is attempted, though searching through {arg DIRLST} still occurs.

{arg DIRLST} is the list of directories searched if {arg FILE} does not have a directory field.  If {arg DIRLST} is {lisp NIL}, the value of the variable {index DIRECTORIES Var}{var DIRECTORIES} is used.

Note:  If {arg DIRLST} is {lisp NIL}, and {arg FILE} is not found by searching the directories on {var DIRECTORIES}, but the root name of {arg FILE} has a {lisp FILEDATES} property ({PageRef Prop FILEDATES}) indicating that a file by that name has been loaded, then the directory indicated in the {lisp FILEDATES} property is searched, too.  This additional search is not done if {arg DIRLST} is non-{lisp NIL}.
}}


{var ERRORTYPELST} ({PageRef Var ERRORTYPELST}) initially contains the entry {lisp ((23 (SPELLFILE (CADR ERRORMESS) NIL NOFILESPELLFLG)))}, which causes {fn SPELLFILE} to be called in case of a {lisp FILE NOT FOUND} error.  If the variable {index *PRIMARY* NOFILESPELLFLG Var}{var NOFILESPELLFLG} is {lisp T} (its initial value), then spelling correction is not done on the file name, but {var DIRECTORIES} is still searched.  If {fn SPELLFILE} is successful, the operation will be reexecuted with the new (corrected) file name.

{FnDef {FnName FINDFILE} {FnArgs FILE NSFLG DIRLST}
{Text
Uses {fn SPELLFILE} to search for a file named {arg FILE}.  If it finds one, returns its full name, with no user interaction.  Specifically, it calls {lisp (SPELLFILE {arg FILE} T {arg NSFLG} {arg DIRLST})}, after first performing two simple checks:  If {arg FILE} has an explicit directory, it checks to see if a file so named exists, and if so returns that file.  If {arg DIRLST} is {lisp NIL}, it looks for {arg FILE} on the connected directory before calling {fn SPELLFILE}.
}}

}{End SubSec Searching File Directories}


{Begin SubSec Listing File Directories}
{Title Listing File Directories}
{Text

{index *PRIMARY* Listing file directories}
{index *PRIMARY* Enumerating files}
{index *PRIMARY* File enumeration}

The function {fn DIRECTORY} allows the user to conveniently specify and/or program a variety of directory operations:


{FnDef {FnName DIRECTORY} {FnArgs FILES COMMANDS DEFAULTEXT DEFAULTVERS}
{Text
Returns, lists, or performs arbitrary operations on all files specified by the "file group" {arg FILES}.  A file group has the form of a regular file name, except that the character {lisp *}{index * (In File Group)} can be used to match any number of characters, including zero, in the file name.  For example, the file group {lisp A*B} matches all file names beginning with the character {lisp A} and ending with the character {lisp B}.  The file group {lisp *.DCOM} matches all files with an extension of {lisp DCOM}.

If {arg FILES} does not contain an explicit extension, it is defaulted to {arg DEFAULTEXT}; if {arg FILES} does not contain an explicit version, it is defaulted to {arg DEFAULTVERS}.  {arg DEFAULTEXT} and {arg DEFAULTVERS} themselves default to {lisp *}.  If the period or semicolon preceding the omitted extension or version, respectively, is present, the field is explicitly empty and no default is used.  All other unspecified fields default to {lisp *}.  Null version is interpreted as "highest".  Thus {arg FILES} = {lisp *} or {lisp *.*} or {lisp *.*;*} enumerates all files on the connected directory; {arg FILES} = {lisp *.} or {lisp *.;*} enumerates all versions of files with null extension; {arg FILES} = {lisp *.;} enumerates the highest version of files with null extension; and {arg FILES} = {lisp *.*;} enumerates the highest version of all files.  If {arg FILES} is {lisp NIL}, it defaults to {lisp *.*;*}.

Note: Some hosts/devices are not capable of supporting "highest version" in enumeration.  Such hosts instead enumerate {it all} versions.


For each file that matches the file group {arg FILES}, the "file commands" in {arg COMMANDS} are executed in order.  Some of the file commands allow aborting the command processing for a given file, effectively filtering the list of files.  The interpretation of the different file commands is described below.  If {arg COMMANDS} is {lisp NIL}, it defaults to {lisp (COLLECT)}, which collects the matching file names in a list and returns it as the value of {fn DIRECTORY}.
}}

The "file commands" in {arg COMMANDS} are interpreted as follows:

{Begin LabeledList interpretation of DIRECTORY commands}

{Label {lisp P}}
{Item
Prints the file's name.  For readability, {fn DIRECTORY} strips the directory from the name, printing it once as a header in front of each set of consecutive files on the same directory.
}


{Label {lisp PP}}
{Item
Prints the file's name without a version number.
}


{Label a string}
{Item
Prints the string.
}


{Label {lisp READDATE}, {lisp WRITEDATE}}
{Label {lisp CREATIONDATE}, {lisp SIZE}}
{Label {lisp LENGTH}, {lisp BYTESIZE}}
{Label {lisp PROTECTION}, {lisp AUTHOR}}
{Label {lisp TYPE}}
{Item
Prints the appropriate information returned by {fn GETFILEINFO} ({PageRef Fn GETFILEINFO}).

{note the list FILEINFOTYPES provides additional formatting information to the DIRECTORY function}
}


{Label {lisp COLLECT}}
{Item
Adds the full name of this file to an accumulating list, which will be returned as the value of {fn DIRECTORY}.
}


{Label {lisp COUNTSIZE}}
{Item
Adds the size of this file to an accumulating sum, which will be returned as the value of {fn DIRECTORY}.
}


{Label {lisp DELETE}}
{Item
Deletes the file.
}

{Label {lisp DELVER}}
{Item
If this file is not the highest version of files by its name, delete it.
}

{Label {lisp PAUSE}}
{Item
Waits until the user types any char before proceeding with the rest of the commands (good for display if you want to ponder).
}


{End LabeledList interpretation of DIRECTORY commands}

The following commands are predicates to filter the list.  If the predicate is not satisfied, then processing for this file is aborted and no further commands (such as those above) are executed for this file.

Note: if the {lisp P} and {lisp PP} commands appear in {arg COMMANDS} ahead of any of the filtering commands below except {lisp PROMPT}, they are postponed until after the filters.  Thus, assuming the caller has placed the attribute options after the filters as well, no printing occurs for a file that is filtered out.  This is principally so that functions like {fn DIR} (below) can both request printing and pass arbitrary commands through to {fn DIRECTORY}, and have the printing happen in the appropriate place.

{Begin LabeledList DIRECTORY filter commands}

{Label {lisp PROMPT {arg MESS}}}
{Item
Prompts with the yes/no question {arg MESS}; if user responds with {lisp N}o, abort command processing for this file.
}


{Label {lisp OLDERTHAN {arg N}}}
{Item
Continue command processing if the file hasn't been referenced (read or written) in {arg N} days.  {arg N} can also be a string naming an explicit date and time since which the file must not have been referenced.
}


{Label {lisp NEWERTHAN {arg N}}}
{Item
Continue command processing if the file has been written within the last {arg N} days.  {arg N} can also be a string naming an explicit date and time.  Note that this is not quite the complement of {lisp OLDERTHAN}, since it ignores the read date.
}

{Label {lisp BY {arg USER}}}
{Item
Continue command processing if the file was last written by the given user, i.e., its {lisp AUTHOR} attribute matches (case insensitively) {arg USER}.
}


{Label {lisp @ {arg X}}}
{Item
{arg X} is either a function of one argument ({arg FILENAME}), or an arbitrary expression which uses the variable {lisp FILENAME} freely.  If {arg X} returns {lisp NIL}, abort command processing for this file.

{note it is a minor efficiency hack that if FILENAME is not used in the expression, it isn't computed}
}

{End LabeledList DIRECTORY filter commands}

The following two commands apply not to any particular file, but globally to the manner in which directory information is printed.

{Begin LabeledList DIRECTORY format commands}

{Label {lisp OUT {arg FILE}}}
{Item
Directs output to {arg FILE}.
}


{Label {lisp COLUMNS {arg N}}}
{Item
Attempts to format output in {arg N} columns (rather than just 1).
}
{End LabeledList DIRECTORY format commands}



{fn DIRECTORY} uses the variable {var DIRCOMMANDS}{index *PRIMARY* DIRCOMMANDS Var}{index spelling lists} as a spelling list to correct spelling and define abbreviations and synonyms (see {PageRef Term Spelling correction}).  Currently the following abbreviations are recognized:


{Begin LabeledList abbreviations}

{Label {lisp AU}}
{Item
{lisp =>    AUTHOR}
}

{Label {lisp -}}
{Item
{lisp =>    PAUSE}
}

{Label {lisp COLLECT?}}
{Item
{lisp =>    PROMPT " ? " COLLECT}
}

{Label {lisp DA}}
{Label {lisp DATE}}
{Item
{lisp =>    CREATIONDATE}
}

{Label {lisp TI}}
{Item
{lisp =>    WRITEDATE}
}


{Label {lisp DEL}}
{Item
{lisp =>    DELETE}
}


{Label {lisp DEL?}}
{Label {lisp DELETE?}}
{Item
{lisp =>    PROMPT " delete? " DELETE}
}

{Label {lisp OLD}}
{Item
{lisp =>    OLDERTHAN 90}
}


{Label {lisp PR}}
{Item
{lisp =>    PROTECTION}
}

{Label {lisp SI}}
{Item
{lisp =>    SIZE}
}

{Label {lisp VERBOSE}}
{Item
{lisp =>    AUTHOR CREATIONDATE SIZE READDATE WRITEDATE}
}


{End LabeledList abbreviations}


{FnDef {FnName FILDIR} {FnArgs FILEGROUP}
{Text
Obsolete synonym of {lisp (DIRECTORY {arg FILEGROUP})}.
}}

{FnDef {FnName DIR} {FnArgs FILEGROUP COM{sub 1} {ellipsis} COM{sub N}}
{Type NLAMBDA NOSPREAD}
{Text
Convenient form of {fn DIRECTORY} for use in type-in at the executive.  Performs {lisp (DIRECTORY '{arg FILEGROUP} '(P {arg COM{sub 1}} {ellipsis} {arg COM{sub N}}))}.
}}


{FnDef {FnName NDIR} {FnArgs FILEGROUP COM{sub 1} {ellipsis} COM{sub N}}
{Type NLAMBDA NOSPREAD}
{Text
Version of {lisp DIR} that lists the file names in a multi-column format.  Also, by default only lists the most recent version of files (unless {arg FILEGROUP} contains an explicit version).
}}


}{End SubSec Listing File Directories}