📄 sfldir.c
字号:
}
/* ---------------------------------------------------------------------[<]-
Function: sort_dir_list
Synopsis: Sorts the directory list as specified. Returns the number of
items in the list. To specify the sort order you pass a string holding
one or more of these characters, which are then used in order:
<TABLE>
n Sort by ascending name.
N Sort by descending name.
x Sort by ascending extension.
X Sort by descending extension.
t Sort by ascending time and date.
T Sort by descending time and date.
s Sort by ascending size.
S Sort by descending size.
</TABLE>
---------------------------------------------------------------------[>]-*/
void
sort_dir_list (NODE *file_list, const char *sort)
{
ASSERT (file_list);
sort_key = (char *) sort;
list_sort (file_list, compare_dir);
}
/* ---------------------------------------------------------------------[<]-
Function: add_dir_list
Synopsis: Adds a node to the specified directory list. Returns the
address of the new node, or NULL if there was insufficient memory.
---------------------------------------------------------------------[>]-*/
FILEINFO *
add_dir_list (NODE *file_list, const DIRST *dir)
{
FILEINFO
*file_info;
file_info = (FILEINFO *) node_create (file_list-> prev, sizeof (FILEINFO));
if (file_info)
{
memcpy (&file_info-> dir, dir, sizeof (DIRST));
fix_dir (&file_info-> dir);
file_info-> directory = (dir-> file_attrs & ATTR_SUBDIR) != 0;
}
return (file_info);
}
/* -------------------------------------------------------------------------
* compare_dir -- internal
*
* Compare two file info structures and return TRUE if SWAP is needed.
* Uses the global variable sort_key to determine sorting method.
*/
static Bool
compare_dir (LIST *p1, LIST *p2)
{
Bool
end = FALSE,
swap = FALSE;
char
*ext1,
*ext2,
*p;
int
comp;
long
date1,
date2,
time1,
time2;
ASSERT (p1);
ASSERT (p2);
if (((FILEINFO *) p1)-> directory != ((FILEINFO *) p2)-> directory)
return (((FILEINFO *) p2)-> directory);
for (p = sort_key;
*p != '\0'
&& end == FALSE
&& swap == FALSE;
p++)
{
switch (*p)
{
case 'n':
case 'N':
comp = lexcmp (((FILEINFO *) p1)-> dir.file_name,
((FILEINFO *) p2)-> dir.file_name);
if ((*p == 'n' && comp > 0)
|| (*p == 'N' && comp < 0))
swap = TRUE;
else
if (comp != 0)
end = TRUE;
break;
case 't':
case 'T':
/* Use date and time and not time_t for compare to minute,
not second */
date1 = timer_to_date (((FILEINFO *) p1)-> dir.file_time);
date2 = timer_to_date (((FILEINFO *) p2)-> dir.file_time);
if ((*p == 't' && date1 > date2)
|| (*p == 'T' && date1 < date2))
swap = TRUE;
else
if (date1 != date2)
end = TRUE;
else
{
time1 = timer_to_time
(((FILEINFO *) p1)-> dir.file_time) / 10000;
time2 = timer_to_time
(((FILEINFO *) p2)-> dir.file_time) / 10000;
if ((*p == 't' && time1 > time2)
|| (*p == 'T' && time1 < time2))
swap = TRUE;
else
if (time1 != time2)
end = TRUE;
}
break;
case 's':
case 'S':
if ((*p == 's' && ((FILEINFO *) p1)-> dir.file_size >
((FILEINFO *) p2)-> dir.file_size)
|| (*p == 'S' && ((FILEINFO *) p1)-> dir.file_size <
((FILEINFO *) p2)-> dir.file_size))
swap = TRUE;
else
if (((FILEINFO *) p1)-> dir.file_size
!= ((FILEINFO *) p2)-> dir.file_size)
end = TRUE;
break;
case 'x':
case 'X':
ext1 = strchr (((FILEINFO *) p1)-> dir.file_name, '.');
ext2 = strchr (((FILEINFO *) p2)-> dir.file_name, '.');
if (ext1 && ext2)
{
comp = lexcmp (ext1, ext2);
if ((*p == 'x' && comp > 0)
|| (*p == 'X' && comp < 0))
swap = TRUE;
else
if (comp != 0)
end = TRUE;
}
break;
}
}
return (swap);
}
/* ---------------------------------------------------------------------[<]-
Function: resolve_path
Synopsis: Accepts a path consisting of zero or more directory names and
optionally a filename plus extension. Removes '.' and '..' if they occur
in the path. '..' is resolved by also removing the preceding directory
name, if any. Returns a freshly-allocated string containing the
resulting path. The caller must free this string using mem_free() when
finished with it. The returned path may be empty. Under OS/2 and DOS,
treats '\' and '/' both as directory separators. A '..' directory at the
start of the path resolves into nothing. If the input path started with
'/', the returned path also does, else it does not. For compatibility
with DOS-based systems, '...' is treated as '../..', '....' as
'../../..', and so on.
---------------------------------------------------------------------[>]-*/
char *
resolve_path (
const char *old_path)
{
#if (defined (__UNIX__) || defined (MSDOS_FILESYSTEM) || defined (__VMS__))
char
*new_path, /* Newly-allocated path */
*new_ptr, /* Pointer into new_path */
last_char = '/'; /* Start of path counts as delim */
int
nbr_dots; /* Size of '..', '...' specifier */
ASSERT (old_path);
new_path = mem_strdup (old_path);
new_ptr = new_path;
while (*old_path)
{
if (path_delimiter (last_char) && *old_path == '.')
{
/* Handle one or more dots followed by a path delimiter */
nbr_dots = 0; /* Count number of dots */
while (old_path [nbr_dots] == '.')
nbr_dots++;
if (path_delimiter (old_path [nbr_dots]))
{
old_path += nbr_dots; /* Skip past dots */
if (*old_path)
old_path++; /* and past / if any */
/* Now backtrack in new path, dropping directories as */
/* many times as needed (0 or more times) */
while (nbr_dots > 1)
{
if (new_ptr > new_path + 1)
{
new_ptr--; /* Drop delimiter */
while (new_ptr > new_path)
{
if (path_delimiter (*(new_ptr - 1)))
break; /* and end after delimiter */
new_ptr--;
}
}
else
break; /* At start of name - finish */
nbr_dots--;
}
}
else
/* Handle '.something' */
last_char = *new_ptr++ = *old_path++;
}
else
last_char = *new_ptr++ = *old_path++;
}
*new_ptr = '\0'; /* Terminate string nicely */
return (new_path);
#else
return (mem_strdup (old_path)); /* Path resolution not supported */
#endif
}
static Bool
path_delimiter (char delim)
{
#if (defined (MSDOS_FILESYSTEM))
if (delim == '\\' || delim == '/' || delim == '\0')
return (TRUE);
else
#elif (defined (__UNIX__) || defined (__VMS__))
if (delim == '/' || delim == '\0')
return (TRUE);
else
#endif
return (FALSE);
}
/* ---------------------------------------------------------------------[<]-
Function: locate_path
Synopsis: Accepts a root directory and a path and locates the path with
respect to the root. If the path looks like an absolute directory,
returns the path after cleaning it up. Otherwise appends the path to
the root, and returns the result. In any case, the resulting directory
does not need to exist. Cleans-up the returned path by appending a '/'
if necessary, and resolving any '..' subpaths. The returned value is
held in a freshly-allocated string which the caller must free using
mem_free() when finished with..
---------------------------------------------------------------------[>]-*/
char *
locate_path (
const char *root,
const char *path)
{
#if (defined (__UNIX__) || defined (MSDOS_FILESYSTEM) || defined (__VMS__))
char
*new_path, /* Returned path value */
*resolved; /* and after .. resolution */
ASSERT (root);
ASSERT (path);
#if (defined (MSDOS_FILESYSTEM))
/* Under MSDOS, OS/2, or Windows we have a full path if we have any of:
* /directory
* D:/directory
* the variations of those with backslashes.
*/
if (path [0] == '\\' || path [0] == '/'
|| (isalpha (path [0]) && path [1] == ':'
&& (path [2] == '\\' || path [2] == '/')))
#else
/* Under UNIX or VMS we have a full path if the path starts with the
* directory marker.
*/
if (path [0] == PATHEND)
#endif
new_path = mem_strdup (path); /* Use path as supplied */
else
{
xstrcpy_debug ();
if (path_delimiter (strlast (root)))
new_path = xstrcpy (NULL, root, path, NULL);
else
new_path = xstrcpy (NULL, root, "/", path, NULL);
}
resolved = resolve_path (new_path);
mem_free (new_path);
/* Append slash if necessary */
if (!path_delimiter (strlast (resolved)))
{
new_path = resolved;
xstrcpy_debug ();
resolved = xstrcpy (NULL, new_path, "/", NULL);
mem_free (new_path);
}
return (resolved);
#else
return (mem_strdup (path)); /* Unknown system */
#endif
}
/* ---------------------------------------------------------------------[<]-
Function: clean_path
Synopsis: Returns a clean directory name; i.e. resolves the path,
removes a trailing slash unless the name consists just of '/'; on a
MS-DOS file system, cleans-up a directory name consisting of a disk
specifier. The cleaned-up directory path is in a static area that is
overwritten by each call.
---------------------------------------------------------------------[>]-*/
char *
clean_path (
const char *path)
{
#if (defined (__UNIX__) || defined (MSDOS_FILESYSTEM) || defined (__VMS__))
static char
new_path [PATH_MAX + 1]; /* Returned path value */
char
*slash;
strncpy (new_path, path, PATH_MAX);
new_path [PATH_MAX] = '\0';
# if (defined (MSDOS_FILESYSTEM))
/* For DOS filesystems, use only back slashes */
strconvch (new_path, '/', '\\');
# endif
slash = strrchr (new_path, PATHEND); /* Find last slash */
# if (defined (MSDOS_FILESYSTEM))
/* If slash is last character in string, maybe squash it */
if (slash && slash [1] == '\0')
{
if (slash > new_path && slash [-1] != ':')
*slash = '\0';
}
else /* Turn X: into X:\ */
if (new_path [1] == ':' && new_path [2] == '\0')
{
new_path [2] = '\\';
new_path [3] = '\0';
}
# else
/* If slash is last character in string, maybe squash it */
if (slash && slash [1] == '\0')
if (slash > new_path)
*slash = '\0';
# endif
return (new_path);
#else
return ((char *) path);
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -