The File System Module (filesys.hhf)
The filesys functions perform file system manipulations (as opposed to the fileio package that operates on files).
These functions test and manipulate pathname strings. Most of them do not do any actual file system access, they simply modify a string passed to them.
The file and pathname string functions are relatively OS-neutral. As long as you avoid a few OS-specific filename features (such as Win32 drive letter prefixes and the use of backslash [‘\’] characters in Unix-like OS filenames), you’ll find that these functions are highly portable between various operating systems. These functions automatically convert pathname separator characters to the native OS (except for the functions that explicitly produce Win32-style or Unix-style pathnames). So you can write applications that process pathnames and automatically work with whatever OS the application is running under.
This documentation will use the standard UNIX ‘/’ pathname separator character. Anywhere you see a “/” used in the following examples, just note that you can also use a “\” and the function will still work properly (you can even have a mixture of these two separator characters in the same pathname string and the function will accept this). Keep in mind that most filesys pathname functions will convert all ‘/’ and ‘\’ characters to the native directory separator character; take care if you expect to process Win32 filenames under a UNIX-like OS and you need to keep the Win32 separator characters.
For the purposes of the filesys string functions, a pathname is considered to contain up to five components: a UNC prefix, a path component, a filename component, a basename component, and an extension. These components are not necessarily unique (that is, some of them overlap one another). Not all pathnames contain all of these components. Consider the following valid pathname string:
fsType://computerName/SharedFolder/path1/path2/base.ext
This example pathname contains the following components:
UNC: fsType://computerName/SharedFolder
path: fsType://computerName/SharedFolder/path1/path2
filename: base.ext
basename: base
extension ext
UNC (Universal Naming Convention) names take two basic forms:
//computerName/sharedFolderName
fsType://computerName/sharedFolderName
UNC names contain an optional file system type name followed by a colon. All UNC names contain ‘//’ followed by a computer name which is then followed by a ‘/’ and a shared folder name.
Path components consist of everything to the left of the last ‘/’ appearing in a path name string. Note that a UNC component is also part of a path component. Indeed, if a UNC immediately precedes a filename, then the UNC sequence is the path component (note, however, that a path component may include other subdirectory names in addition to the UNC character sequence). If there is nothing to the left of the last (i.e., only) ‘/’ in a pathname string, then the “/” is the path component.
The filename component is everything appearing to the right of the last ‘/’ character in the pathname string, or the whole pathname string if there is no ‘/’ character in the pathname string.
The basename and extension components are part of the filename. If the filename contains at least one period and that period is not the first character of the filename, then everything to the left of the (last) period is the basename and everything to the right of the (last) period is the extension. If a filename contains multiple periods, then everything up to (but not including) the last period is the basename. If the filename contains only one period and it begins with that period, then the filename has no extension and the basename is equal to the filename. Likewise, if a filename contains no periods at all, it has no extension and the basename is equal to the filename.
procedure filesys.hasDriveLetter( pathname:string ); @returns( "@c" );
This function returns the Win32 drive letter if the pathname argument begins with a single alphabetic character, immediately followed by a colon (‘:’) and the colon is not immediately followed by a pair of slashes (indicating a UNC name). Drive letters are Win32-specific, although this function can be called on any pathname string. If a drive letter is present, this function returns the drive letter in AL, converted to uppercase, and also returns with the carry flag set. If there is no drive letter at the beginning of the name (or if it looks like a UNC name), then this function returns with EAX containing zero and the carry flag clear.
Note that the function “returns” value for this function is “@c” (that is, the carry flag) and not “AL”. This allows you to use the function call within a boolean expression (e.g., in an “if” statement) and test for true/false return values.
HLA high-level calling sequence examples:
if( filesys.hasDriveLetter( somePath )) then
stdout.put( “Drive
is “, (type char al), nl );
str.delete(
somePath, 0, 2 ); //
Delete the drive letter
endif;
HLA low-level calling sequence example:
push( somePath );
call
filesys.hasDriveLetter;
jnc noDriveLetter;
push(
somePath );
pushd(
0 );
pushd(
2 );
call
str.delete;
noDriveLetter:
procedure filesys.hasExtension( pathname:string ); @returns( "@c" );
This function returns true if the filename component of the pathname argumen contains an extension. An extension is the last part of a pathname following the last period in the filename. Note that if a filename begins with a period and that is the only period in the filename, then the following characters are not an extension (and the extension is the empty string for such a name). Note that periods found in the path to the filename are not considered when this function searches for the extension. Extensions only belong to filename components, not to path components.
Examples:
filesys.hasExtension( “/path/file.ext” ); // true, extension = “ext”
filesys.hasExtension( “file” ); // false
filesys.hasExtension( “.ext” ); // false
filesys.hasExtension( “file.ext” ); // true, extension = “ext”
filesys.hasExtension( “file.abc.ext” ); // true, extension = “ext”
filesys.hasExtension( “..ext” ); // true, extension = “ext”
filesys.hasExtension( “path.ext/file” ); // false
The true/false
result is returned both in the carry flag and in the EAX/AX/AL register. The
carry flag is set if the argument has an extension, it is clear otherwise.
Similarly, true (1) is returned in EAX/AX/AL if the argument has an extension,
false (0) is returned otherwise.
HLA high-level calling sequence examples:
filesys.hasExtension( somePath );
mov( al, somePathHasExtension );
if( @c ) then
<< do
something if somePath has an extension >>
endif;
HLA low-level calling sequence example:
push( somePath );
call
filesys.hasExtension;
jnc noExtension;
<<
Do something if somePath has an extension>>
noExtension:
procedure filesys.hasUncName( pathname:string ); @returns( "@c" );
This function tests the pathname argument to see if it begins with a UNC (universal naming convention) pathname prefix. UNC prefixes take one of two forms (as far as this code is concerned):
//computername/sharedfolder/<path>
<type>://computername/sharedfolder/<path>
<type> can be any string of filename-compatible characters (length one or greater), such as ‘file’, ‘smb’, and so on. <path> may be any OS-compatible pathname of length zero or greater (up to the maximum length supported by the native OS). Portable code should not allow the pathname string (including the UNC) to except about 250 characters.
This function returns true or false in the carry flag indicating whether a UNC, if present, is syntactically correct. That is, this function returns carry clear if there is something that looks like a UNC but is syntactically illegal. Note that a pathname, without an explicit “//computername/sharedfolder/” prefix is still a syntactically correct pathname as far as this function is concerned. That is, this function returns true for pathnames like “name” or “/path/name” even though an explicit UNC item is not present.
This function returns information about the UNC prefix in the EAX register. If this function returns with EAX equal to zero and the carry set, then there is no UNC present in the pathname. If this function returns with EAX containing a value other than zero (and the carry flag set), then a UNC is present and EAX contains an offset into the string that is the start of the pathname just beyond the end of the UNC sequence (i.e., beyond the ‘/’ or ‘\’ that marks the end of the UNC name).
Note: on failure (carry = 0 ), EAX will be returned containing zero.
HLA high-level calling sequence examples:
if( filesys.hasUncName( somePath ) && eax <> 0 ) then
str.delete(
somePath, 0, eax ); //
Delete the UNC prefix
endif;
HLA low-level calling sequence example:
push( somePath );
call
filesys.hasUncName;
jnc noUNC;
test( eax, eax );
jz noUNC;
push(
somePath );
pushd(
0 );
push(
eax );
call
str.delete;
noUNC:
procedure filesys.hasPath( pathname:string ); @returns( "@c" );
This function returns true if the pathname/filename argument contains a path component. Specifically, this function returns true if the pathname string contains any directory separator characters (‘/’ or ‘\’). True is returned in the carry flag (set) and in the EAX/AX/AL register (1). False is carry = 0 or the EAX/AX/AL register equals 0. Note that UNC prefixes immediately before a filename are considered ‘paths’ and this function will return true if a UNC is present.
Examples:
filesys.hasPath( “/path/file.ext” ); // true
filesys.hasPath( “file” ); // false
filesys.hasPath( “.ext” ); // false
filesys.hasPath( “file.ext” ); // false
filesys.hasPath( “file.abc.ext” ); // false
filesys.hasPath( “//machine/folder/file” ); // true
filesys.hasPath( “/” ); // true
HLA high-level calling sequence examples:
filesys.hasPath( somePath );
mov( al, somePathHasAPathComponent );
if( @c ) then
<< do
something if somePath has a path component>>
endif;