Files
mars-dosutils/ndir.c
Mario Fetka 6d2d3f367f dosutils: use NCP87 DOS info fields in NDIR
Add a Client32 NCP87 helper for obtaining DOS namespace file and
subdirectory information and use it in NDIR.

The new helper reads the classic NCP87 subfunction 6 RIM_ALL DOS info
block, including timestamps, inherited rights, directory identifiers and
size metadata.

Use the NCP87 inherited rights mask for the inherited-rights column while
keeping the existing Client32 effective-rights path for the effective
rights column.  Also use the NCP87 modify, archive, last-access and
creation date fields for the /DATES display, falling back to DOS
findfirst timestamps when the NCP87 info request is not available.

Tighten the /DATES layout so the full Created/Copied timestamp remains
within an 80-column DOS screen.
2026-05-25 09:17:56 +02:00

804 lines
22 KiB
C

/* ndir.c - first Novell NDIR-like directory listing utility */
#include "net.h"
#include "c32ncp.h"
#include <dos.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef S_IFDIR
#define S_IFDIR 0040000
#endif
#ifndef _A_NORMAL
#define _A_NORMAL 0x00
#endif
#ifndef _A_RDONLY
#define _A_RDONLY 0x01
#endif
#ifndef _A_HIDDEN
#define _A_HIDDEN 0x02
#endif
#ifndef _A_SYSTEM
#define _A_SYSTEM 0x04
#endif
#ifndef _A_SUBDIR
#define _A_SUBDIR 0x10
#endif
#ifndef _A_ARCH
#define _A_ARCH 0x20
#endif
#define NDIR_OPT_FILES_ONLY 0x0001
#define NDIR_OPT_DIRS_ONLY 0x0002
#define NDIR_OPT_RIGHTS 0x0004
#define NDIR_OPT_DATES 0x0008
#define NDIR_OPT_SUB 0x0010
#define NDIR_OPT_SHORT 0x0020
/* NCP effective-rights bits returned by NCP87 subfunction 29. */
#define NDIR_NCP_RIGHT_READ 0x0001
#define NDIR_NCP_RIGHT_WRITE 0x0002
#define NDIR_NCP_RIGHT_CREATE 0x0008
#define NDIR_NCP_RIGHT_DELETE 0x0010
#define NDIR_NCP_RIGHT_OWNER 0x0020
#define NDIR_NCP_RIGHT_SEARCH 0x0040
#define NDIR_NCP_RIGHT_MODIFY 0x0080
#define NDIR_NCP_RIGHT_SUPER 0x0100
static void ndir_dos_date(unsigned date, char *out);
static void ndir_dos_datetime(unsigned date, unsigned time, char *out);
#define NDIR_OLD_RIGHT_S 0x01
#define NDIR_OLD_RIGHT_R 0x02
#define NDIR_OLD_RIGHT_W 0x04
#define NDIR_OLD_RIGHT_C 0x08
#define NDIR_OLD_RIGHT_E 0x10
#define NDIR_OLD_RIGHT_M 0x20
#define NDIR_OLD_RIGHT_F 0x40
#define NDIR_OLD_RIGHT_A 0x80
static void ndir_usage(void)
{
fprintf(stdout, "usage: NDIR [path] [/option...]\n");
fprintf(stdout, "path: [path] [filename] [,filename, ...] (up to 16 in chain)\n");
fprintf(stdout, "options: [format], [flag], [sortspec], [restriction], [FO] (files only),\n");
fprintf(stdout, " [DO] (directories only), [SUBdirectories], [Continuous], [HELP]\n");
fprintf(stdout, "\n");
fprintf(stdout, "format: DATES, RIGHTS, MACintosh, LONGnames\n");
fprintf(stdout, "\n");
fprintf(stdout, "flag: [NOT] RO, S, A, X, H, SY, T, I, P, RA, WA, CI, DI, RI\n");
fprintf(stdout, "\n");
fprintf(stdout, "sortspec: [REVerse] SORT [OWner], [SIze], [UPdate], [CReate],\n");
fprintf(stdout, " [ACcess], [ARchive], [UNsorted]\n");
fprintf(stdout, "\n");
fprintf(stdout, "restriction: OWner <operator> <name>\n");
fprintf(stdout, " SIze <operator> <number>\n");
fprintf(stdout, " UPdate <operator> <date>\n");
fprintf(stdout, " CReate <operator> <date>\n");
fprintf(stdout, " ACcess <operator> <date>\n");
fprintf(stdout, " ARchive <operator> <date>\n");
fprintf(stdout, "\n");
fprintf(stdout, "operator: [NOT] Less than, GReater than,\n");
fprintf(stdout, " EQual to, BEfore, AFter\n");
fprintf(stdout, "\n");
fprintf(stdout, "To search filenames equivalent to any of the capitalized KEYWORD options\n");
fprintf(stdout, "shown above, the filename must be preceded by a drive letter or path.\n");
}
static int ndir_is_help(char *s)
{
if (!s) return(0);
return(tool_is_help_arg(s) || tool_strsame(s, "/HELP") ||
tool_strsame(s, "-HELP") || tool_strsame(s, "HELP"));
}
static int ndir_is_files_only(char *s)
{
if (!s) return(0);
return(tool_strsame(s, "/FO") || tool_strsame(s, "-FO") ||
tool_strsame(s, "/FILESONLY") || tool_strsame(s, "-FILESONLY") ||
tool_strsame(s, "FO") || tool_strsame(s, "FILESONLY"));
}
static int ndir_is_dirs_only(char *s)
{
if (!s) return(0);
return(tool_strsame(s, "/DO") || tool_strsame(s, "-DO") ||
tool_strsame(s, "/DIRSONLY") || tool_strsame(s, "-DIRSONLY") ||
tool_strsame(s, "/DIRECTORIES") || tool_strsame(s, "-DIRECTORIES") ||
tool_strsame(s, "DO") || tool_strsame(s, "DIRSONLY") ||
tool_strsame(s, "DIRECTORIES"));
}
static int ndir_is_continuous(char *s)
{
if (!s) return(0);
return(tool_strsame(s, "/CONTINUOUS") || tool_strsame(s, "-CONTINUOUS") ||
tool_strsame(s, "/CONTINUE") || tool_strsame(s, "-CONTINUE") ||
tool_strsame(s, "/C") || tool_strsame(s, "-C") ||
tool_strsame(s, "CONTINUOUS") || tool_strsame(s, "CONTINUE"));
}
static int ndir_is_rights(char *s)
{
if (!s) return(0);
return(tool_strsame(s, "/RIGHTS") || tool_strsame(s, "-RIGHTS") ||
tool_strsame(s, "RIGHTS"));
}
static int ndir_is_dates(char *s)
{
if (!s) return(0);
return(tool_strsame(s, "/DATES") || tool_strsame(s, "-DATES") ||
tool_strsame(s, "DATES"));
}
static int ndir_is_subdirs(char *s)
{
if (!s) return(0);
return(tool_strsame(s, "/SUB") || tool_strsame(s, "-SUB") ||
tool_strsame(s, "/SUBDIRECTORIES") || tool_strsame(s, "-SUBDIRECTORIES") ||
tool_strsame(s, "SUB") || tool_strsame(s, "SUBDIRECTORIES"));
}
static int ndir_is_short(char *s)
{
if (!s) return(0);
return(tool_strsame(s, "/SHORT") || tool_strsame(s, "-SHORT") ||
tool_strsame(s, "/BRIEF") || tool_strsame(s, "-BRIEF") ||
tool_strsame(s, "SHORT") || tool_strsame(s, "BRIEF"));
}
static int ndir_is_accepted_stub(char *s)
{
if (!s) return(0);
/*
* Keep this version tolerant of common NDIR format/options so users
* can compare command lines while unimplemented formats remain harmless.
*/
return(0);
}
static int ndir_path_is_dir(char *path)
{
struct stat st;
if (!path || !*path || tool_is_current_path(path))
return(1);
if (stat(path, &st) == 0) {
if (st.st_mode & S_IFDIR)
return(1);
}
return(0);
}
static void ndir_split_spec(char *spec, char *dir, char *pat)
{
if (!spec || !*spec || tool_is_current_path(spec)) {
strmaxcpy(dir, ".", 259);
strmaxcpy(pat, "*.*", 259);
return;
}
if (!tool_has_wildcards(spec) && ndir_path_is_dir(spec)) {
strmaxcpy(dir, spec, 259);
strmaxcpy(pat, "*.*", 259);
return;
}
tool_parent_pattern(dir, pat, spec, 260, 260);
}
static void ndir_dos_date(unsigned date, char *out)
{
int year;
int month;
int day;
year = ((date >> 9) & 0x7f) + 1980;
month = (date >> 5) & 0x0f;
day = date & 0x1f;
sprintf(out, "%02d-%02d-%02d", month, day, year % 100);
}
static void ndir_dos_datetime_or_blank(unsigned date, unsigned time, char *out)
{
if (!date) {
strcpy(out, "0-00-00 0:00 A");
return;
}
ndir_dos_datetime(date, time, out);
}
static void ndir_dos_date_or_blank(unsigned date, char *out)
{
if (!date) {
strcpy(out, "0-00-00");
return;
}
ndir_dos_date(date, out);
}
static void ndir_dos_datetime(unsigned date, unsigned time, char *out)
{
int year;
int month;
int day;
int hour;
int minute;
char ap;
year = ((date >> 9) & 0x7f) + 1980;
month = (date >> 5) & 0x0f;
day = date & 0x1f;
hour = (time >> 11) & 0x1f;
minute = (time >> 5) & 0x3f;
ap = (hour >= 12) ? 'p' : 'a';
if (hour == 0)
hour = 12;
else if (hour > 12)
hour -= 12;
sprintf(out, "%02d-%02d-%02d %2d:%02d%c",
month, day, year % 100, hour, minute, ap);
}
static unsigned long ndir_blocks_for_size(unsigned long size)
{
/*
* Novell NDIR reports allocated bytes/blocks. For this first DOS
* findfirst/findnext implementation, approximate with 4 KiB allocation
* units so small test files match the observed Novell output more closely.
*/
if (size == 0L)
return(0L);
return((size + 4095L) / 4096L);
}
static void ndir_flags(unsigned attr, char *out)
{
/*
* Keep the first positions close to Novell's default NDIR display,
* for example [RW-A------------].
*/
out[0] = '[';
out[1] = 'R';
out[2] = (attr & _A_RDONLY) ? 'O' : 'W';
out[3] = (attr & _A_SYSTEM) ? 'S' : '-';
out[4] = (attr & _A_ARCH) ? 'A' : '-';
out[5] = (attr & _A_HIDDEN) ? 'H' : '-';
memset(out + 6, '-', 11);
out[17] = ']';
out[18] = '\0';
}
static void ndir_parent_path(char *dst, char *src, int max)
{
char tmp[260];
char *p;
tool_upcopy(tmp, src, sizeof(tmp));
p = strrchr(tmp, '\\');
if (!p) p = strrchr(tmp, ':');
if (p) {
if (*p == ':') {
p[1] = '\0';
} else {
*p = '\0';
}
strmaxcpy(dst, tmp, max - 1);
} else {
dst[0] = '\0';
}
}
static void ndir_old_rights_string(uint8 old_rights, char *out)
{
out[0] = (old_rights & NDIR_OLD_RIGHT_S) ? 'S' : '-';
out[1] = (old_rights & NDIR_OLD_RIGHT_R) ? 'R' : '-';
out[2] = (old_rights & NDIR_OLD_RIGHT_W) ? 'W' : '-';
out[3] = (old_rights & NDIR_OLD_RIGHT_C) ? 'C' : '-';
out[4] = (old_rights & NDIR_OLD_RIGHT_E) ? 'E' : '-';
out[5] = (old_rights & NDIR_OLD_RIGHT_M) ? 'M' : '-';
out[6] = (old_rights & NDIR_OLD_RIGHT_F) ? 'F' : '-';
out[7] = (old_rights & NDIR_OLD_RIGHT_A) ? 'A' : '-';
out[8] = '\0';
}
static int ndir_get_ncp_info(char *path, C32_NDIR_INFO *info)
{
uint8 connid = 0;
uint8 dhandle = 0;
if (!info)
return(1);
memset(info, 0, sizeof(*info));
if (tool_current_dhandle(&connid, &dhandle))
return(1);
return(c32_ncp87_obtain_ndir_info(tool_is_current_path(path) ? "" : path,
(uint16)dhandle,
info,
NULL, NULL, NULL));
}
static void ndir_inherited_rights(char *path, char *out)
{
C32_NDIR_INFO info;
strcpy(out, "--------");
if (!ndir_get_ncp_info(path, &info))
ndir_old_rights_string((uint8)info.inherited_rights, out);
}
static void ndir_rights_string(uint16 ncp_rights, char *out)
{
out[0] = (ncp_rights & NDIR_NCP_RIGHT_SUPER) ? 'S' : '-';
out[1] = (ncp_rights & NDIR_NCP_RIGHT_READ) ? 'R' : '-';
out[2] = (ncp_rights & NDIR_NCP_RIGHT_WRITE) ? 'W' : '-';
out[3] = (ncp_rights & NDIR_NCP_RIGHT_CREATE) ? 'C' : '-';
out[4] = (ncp_rights & NDIR_NCP_RIGHT_DELETE) ? 'E' : '-';
out[5] = (ncp_rights & NDIR_NCP_RIGHT_MODIFY) ? 'M' : '-';
out[6] = (ncp_rights & NDIR_NCP_RIGHT_SEARCH) ? 'F' : '-';
out[7] = (ncp_rights & NDIR_NCP_RIGHT_OWNER) ? 'A' : '-';
out[8] = '\0';
}
static void ndir_effective_rights(char *path, char *out)
{
uint8 connid = 0;
uint8 dhandle = 0;
uint8 eff_old = 0;
uint16 ncp_rights = 0;
char usepath[260];
int newhandle;
strcpy(out, "--------");
if (tool_current_dhandle(&connid, &dhandle))
return;
/*
* Prefer Client32 NCP87 effective-rights. If that fails for a listed
* entry, fall back to the older directory-handle effective-rights path
* that RIGHTS also uses.
*/
if (!c32_ncp87_get_effective_rights(tool_is_current_path(path) ? "" : path,
(uint16)dhandle,
&ncp_rights,
NULL, NULL, NULL)) {
ndir_rights_string(ncp_rights, out);
return;
}
ndir_parent_path(usepath, path, sizeof(usepath));
newhandle = alloc_temp_dir_handle(dhandle, usepath, 0, &eff_old);
if (newhandle >= 0) {
dealloc_dir_handle(newhandle);
ndir_old_rights_string(eff_old, out);
return;
}
if (usepath[0]) {
int subdir = 1;
int r = ncp_16_02(dhandle, (uint8 *)usepath, &subdir,
NULL, NULL, NULL);
if (r >= 0)
ndir_old_rights_string((uint8)r, out);
} else {
ndir_old_rights_string(0xff, out);
}
}
static int ndir_is_dot_dir(char *name)
{
if (!name) return(0);
if (name[0] == '.' && name[1] == '\0') return(1);
if (name[0] == '.' && name[1] == '.' && name[2] == '\0') return(1);
return(0);
}
static void ndir_print_file(char *dir, struct find_t *ff, int options,
int *line_count, int *continuous)
{
char dt[24];
char d[12];
char fl[20]; /* [RW-A------------] plus NUL */
char path[260];
char eff[10];
char inh[10];
char arch[24];
char acc[12];
char crea[24];
C32_NDIR_INFO info;
int have_info = 0;
tool_join_path(path, dir, ff->name, sizeof(path));
have_info = !ndir_get_ncp_info(path, &info);
if (have_info)
ndir_dos_datetime(info.modify_date, info.modify_time, dt);
else
ndir_dos_datetime(ff->wr_date, ff->wr_time, dt);
ndir_dos_date(ff->wr_date, d);
ndir_flags(ff->attrib, fl);
if (options & NDIR_OPT_RIGHTS) {
ndir_effective_rights(path, eff);
ndir_inherited_rights(path, inh);
fprintf(stdout, "%-16.16s %-18.18s [%8.8s] [%8.8s]\n",
ff->name, fl, inh, eff);
} else if (options & NDIR_OPT_DATES) {
/*
* DOS findfirst gives us the update timestamp only. Keep the Novell
* /DATES layout and use placeholders for archive/access data until
* full NetWare namespace date fields are available.
*/
if (have_info) {
ndir_dos_datetime_or_blank(info.archive_date, info.archive_time, arch);
ndir_dos_date_or_blank(info.last_access_date, acc);
ndir_dos_datetime_or_blank(info.creation_date, info.creation_time, crea);
fprintf(stdout, "%-16.16s %-17.17s %-17.17s %-8.8s %-17.17s\n",
ff->name, dt, arch, acc, crea);
} else {
fprintf(stdout, "%-16.16s %-17.17s 0-00-00 0:00 A %-8.8s %-17.17s\n",
ff->name, dt, d, dt);
}
} else {
fprintf(stdout, "%-16.16s %12lu %-17.17s %-18.18s\n",
ff->name, (unsigned long)ff->size, dt, fl);
}
tool_page_line(line_count, continuous);
}
static void ndir_print_dir(char *dir, struct find_t *ff, int options,
int *line_count, int *continuous)
{
char dt[24];
char path[260];
char eff[10];
char inh[10];
C32_NDIR_INFO info;
tool_join_path(path, dir, ff->name, sizeof(path));
if (!ndir_get_ncp_info(path, &info))
ndir_dos_datetime(info.creation_date, info.creation_time, dt);
else
ndir_dos_datetime(ff->wr_date, ff->wr_time, dt);
if (options & (NDIR_OPT_RIGHTS | NDIR_OPT_DIRS_ONLY)) {
ndir_effective_rights(path, eff);
ndir_inherited_rights(path, inh);
fprintf(stdout, "%-16.16s [%8.8s] [%8.8s] %-17.17s\n",
ff->name, inh, eff, dt);
} else {
fprintf(stdout, "%-16.16s <DIR> %-17.17s\n", ff->name, dt);
}
tool_page_line(line_count, continuous);
}
static int ndir_scan_files(char *dir, char *search, int options,
int *line_count, int *continuous,
int *file_count, unsigned long *total_bytes,
unsigned long *total_blocks)
{
struct find_t ff;
int rc;
int shown = 0;
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
while (rc == 0) {
if (!(ff.attrib & _A_SUBDIR)) {
ndir_print_file(dir, &ff, options, line_count, continuous);
(*file_count)++;
*total_bytes += (unsigned long)ff.size;
*total_blocks += ndir_blocks_for_size((unsigned long)ff.size);
shown = 1;
}
rc = _dos_findnext(&ff);
}
return(shown);
}
static int ndir_scan_dirs(char *dir, char *search, int options,
int *line_count, int *continuous,
int *dir_count)
{
struct find_t ff;
int rc;
int shown = 0;
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
while (rc == 0) {
if ((ff.attrib & _A_SUBDIR) && !ndir_is_dot_dir(ff.name)) {
ndir_print_dir(dir, &ff, options, line_count, continuous);
(*dir_count)++;
shown = 1;
}
rc = _dos_findnext(&ff);
}
return(shown);
}
static int ndir_list_one(char *spec, int options, int *continuous)
{
char dir[260];
char pat[260];
char search[260];
char display[300];
int got = 0;
int files_shown = 0;
int dirs_shown = 0;
int file_count = 0;
int dir_count = 0;
unsigned long total_bytes = 0L;
unsigned long total_blocks = 0L;
int line_count = 0;
ndir_split_spec(spec, dir, pat);
tool_join_path(search, dir, pat, sizeof(search));
tool_header_path(display, dir, sizeof(display));
fprintf(stdout, "%s\n", display);
tool_page_line(&line_count, continuous);
if (!(options & NDIR_OPT_DIRS_ONLY)) {
if (!(options & NDIR_OPT_SHORT)) {
if (options & NDIR_OPT_RIGHTS) {
fprintf(stdout, "Files: Flags Rights Rights Owner\n");
fprintf(stdout, "---------------- ------------------ ----------- ----------- --------\n");
} else if (options & NDIR_OPT_DATES) {
fprintf(stdout, "Files: Last Updated Last Archived Accessed Created/Copied\n");
fprintf(stdout, "---------------- ----------------- ----------------- -------- -----------------\n");
} else {
fprintf(stdout, "Files: Size Last Updated Flags Owner\n");
fprintf(stdout, "---------------- ---------------- ----------------- ------------------ --------\n");
}
tool_page_line(&line_count, continuous);
tool_page_line(&line_count, continuous);
}
files_shown = ndir_scan_files(dir, search, options, &line_count,
continuous, &file_count,
&total_bytes, &total_blocks);
if (files_shown)
got = 1;
}
if (!(options & NDIR_OPT_FILES_ONLY)) {
if (!(options & NDIR_OPT_DIRS_ONLY) && !(options & NDIR_OPT_SHORT))
fprintf(stdout, "\n");
if (!(options & NDIR_OPT_SHORT)) {
if (options & (NDIR_OPT_RIGHTS | NDIR_OPT_DIRS_ONLY)) {
fprintf(stdout, "Directories: Rights Rights Owner Created/Copied\n");
fprintf(stdout, "---------------- ----------- ----------- ----------- -----------------\n");
} else {
fprintf(stdout, "Directories:\n");
fprintf(stdout, "----------------\n");
}
tool_page_line(&line_count, continuous);
tool_page_line(&line_count, continuous);
}
dirs_shown = ndir_scan_dirs(dir, search, options, &line_count,
continuous, &dir_count);
if (dirs_shown)
got = 1;
}
if (!got && (options & NDIR_OPT_DIRS_ONLY) && !(options & NDIR_OPT_SHORT))
fprintf(stdout, "No files of given specification found or directory is empty.\n");
if (!(options & NDIR_OPT_DIRS_ONLY)) {
if (options & NDIR_OPT_SHORT) {
if (file_count)
fprintf(stdout, " %lu bytes, %d files, %lu blocks\n",
total_bytes, file_count, total_blocks);
} else {
fprintf(stdout, "\n");
fprintf(stdout, "%12lu bytes in %5d files\n", total_bytes, file_count);
fprintf(stdout, "%12lu bytes in %5lu blocks\n", total_blocks * 4096L,
total_blocks);
}
}
return(got ? 0 : 1);
}
static int ndir_spec_has_output(char *spec, int options)
{
struct find_t ff;
char dir[260];
char pat[260];
char search[260];
int rc;
ndir_split_spec(spec, dir, pat);
tool_join_path(search, dir, pat, sizeof(search));
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
while (rc == 0) {
if (ff.attrib & _A_SUBDIR) {
if (!ndir_is_dot_dir(ff.name) && !(options & NDIR_OPT_FILES_ONLY))
return(1);
} else {
if (!(options & NDIR_OPT_DIRS_ONLY))
return(1);
}
rc = _dos_findnext(&ff);
}
return(0);
}
static int ndir_list_subdirs(char *dir, char *pattern, int options,
int *continuous)
{
struct find_t ff;
char search[260];
char subdir[260];
char subspec[260];
int rc;
int result = 0;
int had_any = 0;
tool_join_path(search, dir, "*.*", sizeof(search));
rc = _dos_findfirst(search, _A_NORMAL | _A_RDONLY | _A_HIDDEN |
_A_SYSTEM | _A_ARCH | _A_SUBDIR, &ff);
while (rc == 0) {
if ((ff.attrib & _A_SUBDIR) && !ndir_is_dot_dir(ff.name)) {
tool_join_path(subdir, dir, ff.name, sizeof(subdir));
tool_join_path(subspec, subdir, pattern, sizeof(subspec));
if (!(options & NDIR_OPT_SHORT) ||
ndir_spec_has_output(subspec, options & ~NDIR_OPT_SUB)) {
fprintf(stdout, "\n");
if (ndir_list_one(subspec, options & ~NDIR_OPT_SUB, continuous))
result = 1;
}
had_any = 1;
if (ndir_list_subdirs(subdir, pattern, options, continuous))
result = 1;
}
rc = _dos_findnext(&ff);
}
if (!had_any)
return(result);
return(result);
}
static int ndir_list(char *spec, int options, int *continuous)
{
char dir[260];
char pat[260];
int result;
result = ndir_list_one(spec, options & ~NDIR_OPT_SUB, continuous);
if (!(options & NDIR_OPT_SUB))
return(result);
ndir_split_spec(spec, dir, pat);
if (!pat[0])
strmaxcpy(pat, "*.*", sizeof(pat) - 1);
return(ndir_list_subdirs(dir, pat, options, continuous) ? 1 : result);
}
int func_ndir(int argc, char *argv[], int mode)
{
char *path = ".";
int have_path = 0;
int options = 0;
int continuous = 0;
int i;
(void)mode;
if (argc > 1 && ndir_is_help(argv[1])) {
ndir_usage();
return(0);
}
for (i = 1; i < argc; i++) {
if (ndir_is_help(argv[i])) {
ndir_usage();
return(0);
}
if (ndir_is_files_only(argv[i])) {
options |= NDIR_OPT_FILES_ONLY;
continue;
}
if (ndir_is_dirs_only(argv[i])) {
options |= NDIR_OPT_DIRS_ONLY;
continue;
}
if (ndir_is_continuous(argv[i])) {
continuous = 1;
continue;
}
if (ndir_is_rights(argv[i])) {
options |= NDIR_OPT_RIGHTS;
continue;
}
if (ndir_is_dates(argv[i])) {
options |= NDIR_OPT_DATES;
continue;
}
if (ndir_is_subdirs(argv[i])) {
options |= NDIR_OPT_SUB;
continue;
}
if (ndir_is_short(argv[i])) {
options |= NDIR_OPT_SHORT;
continue;
}
if (ndir_is_accepted_stub(argv[i])) {
continue;
}
if (tool_is_option(argv[i])) {
fprintf(stdout, "Type \"ndir /help\" on the command line for usage information.\n");
return(1);
}
if (have_path) {
fprintf(stdout, "Too many filenames in chain.\n");
return(1);
}
path = argv[i];
have_path = 1;
}
if ((options & NDIR_OPT_FILES_ONLY) && (options & NDIR_OPT_DIRS_ONLY)) {
fprintf(stdout, "No files of given specification found or directory is empty.\n");
return(1);
}
return(ndir_list(path, options, &continuous));
}