194,7 → 194,7 |
|
/* translates an order string like "GNE-S" into values fed into the order[] |
* table of glob_sortcmp_dat. returns 0 on success, non-zero otherwise. */ |
static int process_order_directive(const char *ordstring) { |
static int dir_process_order_directive(const char *ordstring) { |
const char *gnesd = "gnesd"; /* must be lower case */ |
int ordi, orderi = 0, i; |
|
313,79 → 313,28 |
|
#define DIR_ATTR_DEFAULT (DOS_ATTR_RO | DOS_ATTR_DIR | DOS_ATTR_ARC) |
|
static enum cmd_result cmd_dir(struct cmd_funcparam *p) { |
const char *filespecptr = NULL; |
struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */ |
struct TINYDTA far *dtabuf = NULL; /* used to buffer results when sorting is enabled */ |
unsigned short dtabufcount = 0; |
unsigned short i; |
unsigned short availrows; /* counter of available rows on display (used for /P) */ |
unsigned short screenw = screen_getwidth(); |
unsigned short wcols = screenw / WCOLWIDTH; /* number of columns in wide mode */ |
unsigned char wcolcount; |
struct { |
struct nls_patterns nls; |
char buff64[64]; |
char path[128]; |
unsigned short orderidx[65535 / sizeof(struct TINYDTA)]; |
} *buf = (void *)(p->BUFFER); |
unsigned long summary_fcount = 0; |
unsigned long summary_totsz = 0; |
unsigned char drv = 0; |
unsigned char attrfilter_may = DIR_ATTR_DEFAULT; |
unsigned char attrfilter_must = 0; |
struct dirrequest { |
unsigned char attrfilter_may; |
unsigned char attrfilter_must; |
const char *filespecptr; |
|
#define DIR_FLAG_PAUSE 1 |
#define DIR_FLAG_RECUR 4 |
#define DIR_FLAG_LCASE 8 |
#define DIR_FLAG_SORT 16 |
unsigned char flags = 0; |
unsigned char flags; |
|
#define DIR_OUTPUT_NORM 1 |
#define DIR_OUTPUT_WIDE 2 |
#define DIR_OUTPUT_BARE 3 |
unsigned char format = DIR_OUTPUT_NORM; |
unsigned char format; |
}; |
|
/* make sure there's no risk of buffer overflow */ |
if (sizeof(buf) > p->BUFFERSZ) { |
outputnl("INTERNAL MEM ERROR IN " __FILE__); |
return(CMD_FAIL); |
} |
|
bzero(&glob_sortcmp_dat, sizeof(glob_sortcmp_dat)); |
|
if (cmd_ishlp(p)) { |
nls_outputnl(37,0); /* "Displays a list of files and subdirectories in a directory" */ |
outputnl(""); |
nls_outputnl(37,1); /* "DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]" */ |
outputnl(""); |
nls_outputnl(37,2); /* "/P Pauses after each screenful of information" */ |
nls_outputnl(37,3); /* "/W Uses wide list format" */ |
outputnl(""); |
nls_outputnl(37,4); /* "/A Displays files with specified attributes:" */ |
nls_outputnl(37,5); /* " D Directories R Read-only files H Hidden files" */ |
nls_outputnl(37,6); /* " A Ready for archiving S System files - prefix meaning "not"" */ |
outputnl(""); |
nls_outputnl(37,7); /* "/O List files in sorted order:" */ |
nls_outputnl(37,8); /* " N by name S by size E by extension" */ |
nls_outputnl(37,9); /* " D by date G group dirs first - prefix to reverse order" */ |
outputnl(""); |
nls_outputnl(37,10); /* "/S Displays files in specified directory and all subdirectories" */ |
nls_outputnl(37,11); /* "/B Uses bare format (no heading information or summary)" */ |
nls_outputnl(37,12); /* "/L Uses lowercases" */ |
return(CMD_OK); |
} |
|
i = nls_getpatterns(&(buf->nls)); |
if (i != 0) nls_outputnl_doserr(i); |
|
/* disable usage of thousands separator on narrow screens */ |
if (screenw < 80) buf->nls.thousep[0] = 0; |
|
/* parse command line */ |
for (i = 0; i < p->argc; i++) { |
if (p->argv[i][0] == '/') { |
const char *arg = p->argv[i] + 1; |
static int dir_parse_cmdline(struct dirrequest *req, const char **argv) { |
for (; *argv != NULL; argv++) { |
if (*argv[0] == '/') { |
const char *arg = *argv + 1; |
char neg = 0; |
/* detect negations and get actual argument */ |
if (*arg == '-') { |
398,89 → 347,159 |
case 'A': |
arg++; |
/* preset defaults */ |
attrfilter_may = DIR_ATTR_DEFAULT; |
attrfilter_must = 0; |
req->attrfilter_may = DIR_ATTR_DEFAULT; |
req->attrfilter_must = 0; |
/* /-A only allowed without further parameters (used to cancel possible previous /Asmth) */ |
if (neg) { |
if (*arg != 0) { |
nls_outputnl_err(0, 2); /* invalid switch */ |
return(CMD_FAIL); |
return(-1); |
} |
} else { |
/* skip colon if present */ |
if (*arg == ':') arg++; |
/* start with "allow everything" */ |
attrfilter_may = (DOS_ATTR_ARC | DOS_ATTR_DIR | DOS_ATTR_HID | DOS_ATTR_SYS | DOS_ATTR_RO); |
if (dir_parse_attr_list(arg, &attrfilter_may, &attrfilter_must) != 0) { |
req->attrfilter_may = (DOS_ATTR_ARC | DOS_ATTR_DIR | DOS_ATTR_HID | DOS_ATTR_SYS | DOS_ATTR_RO); |
if (dir_parse_attr_list(arg, &(req->attrfilter_may), &(req->attrfilter_must)) != 0) { |
nls_outputnl_err(0, 3); /* invalid parameter format */ |
return(CMD_FAIL); |
return(-1); |
} |
} |
break; |
case 'b': |
case 'B': |
format = DIR_OUTPUT_BARE; |
req->format = DIR_OUTPUT_BARE; |
break; |
case 'l': |
case 'L': |
flags |= DIR_FLAG_LCASE; |
req->flags |= DIR_FLAG_LCASE; |
break; |
case 'o': |
case 'O': |
if (neg) { |
flags &= (0xff ^ DIR_FLAG_SORT); |
req->flags &= (0xff ^ DIR_FLAG_SORT); |
break; |
} |
if (process_order_directive(arg+1) != 0) { |
if (dir_process_order_directive(arg+1) != 0) { |
nls_output_err(0, 3); /* invalid parameter format */ |
output(": "); |
outputnl(arg); |
return(CMD_FAIL); |
return(-1); |
} |
flags |= DIR_FLAG_SORT; |
req->flags |= DIR_FLAG_SORT; |
break; |
case 'p': |
case 'P': |
flags |= DIR_FLAG_PAUSE; |
if (neg) flags &= (0xff ^ DIR_FLAG_PAUSE); |
req->flags |= DIR_FLAG_PAUSE; |
if (neg) req->flags &= (0xff ^ DIR_FLAG_PAUSE); |
break; |
case 's': |
case 'S': |
/* TODO */ |
outputnl("/S NOT IMPLEMENTED YET"); |
return(CMD_FAIL); |
return(-1); |
break; |
case 'w': |
case 'W': |
format = DIR_OUTPUT_WIDE; |
req->format = DIR_OUTPUT_WIDE; |
break; |
default: |
nls_outputnl_err(0, 2); /* invalid switch */ |
return(CMD_FAIL); |
return(-1); |
} |
} else { /* filespec */ |
if (filespecptr != NULL) { |
if (req->filespecptr != NULL) { |
nls_outputnl_err(0, 4); /* too many parameters */ |
return(CMD_FAIL); |
return(-1); |
} |
filespecptr = p->argv[i]; |
req->filespecptr = *argv; |
} |
} |
|
if (filespecptr == NULL) filespecptr = "."; |
if (req->filespecptr == NULL) req->filespecptr = "."; |
return(0); |
} |
|
|
static enum cmd_result cmd_dir(struct cmd_funcparam *p) { |
struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */ |
struct TINYDTA far *dtabuf = NULL; /* used to buffer results when sorting is enabled */ |
unsigned short dtabufcount = 0; |
unsigned short i; |
unsigned short availrows; /* counter of available rows on display (used for /P) */ |
unsigned short screenw = screen_getwidth(); |
unsigned short wcols = screenw / WCOLWIDTH; /* number of columns in wide mode */ |
unsigned char wcolcount; |
struct { |
struct nls_patterns nls; |
char buff64[64]; |
char path[128]; |
unsigned short orderidx[65535 / sizeof(struct TINYDTA)]; |
} *buf = (void *)(p->BUFFER); |
unsigned long summary_fcount = 0; |
unsigned long summary_totsz = 0; |
unsigned char drv = 0; |
|
struct dirrequest req; |
|
/* preload req with default values */ |
bzero(&req, sizeof(req)); |
req.attrfilter_may = DIR_ATTR_DEFAULT; |
/* req.attrfilter_must = 0; |
req.flags = 0; */ |
req.format = DIR_OUTPUT_NORM; |
|
/* make sure there's no risk of buffer overflow */ |
if (sizeof(buf) > p->BUFFERSZ) { |
outputnl("INTERNAL MEM ERROR IN " __FILE__); |
return(CMD_FAIL); |
} |
|
bzero(&glob_sortcmp_dat, sizeof(glob_sortcmp_dat)); |
|
if (cmd_ishlp(p)) { |
nls_outputnl(37,0); /* "Displays a list of files and subdirectories in a directory" */ |
outputnl(""); |
nls_outputnl(37,1); /* "DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]" */ |
outputnl(""); |
nls_outputnl(37,2); /* "/P Pauses after each screenful of information" */ |
nls_outputnl(37,3); /* "/W Uses wide list format" */ |
outputnl(""); |
nls_outputnl(37,4); /* "/A Displays files with specified attributes:" */ |
nls_outputnl(37,5); /* " D Directories R Read-only files H Hidden files" */ |
nls_outputnl(37,6); /* " A Ready for archiving S System files - prefix meaning "not"" */ |
outputnl(""); |
nls_outputnl(37,7); /* "/O List files in sorted order:" */ |
nls_outputnl(37,8); /* " N by name S by size E by extension" */ |
nls_outputnl(37,9); /* " D by date G group dirs first - prefix to reverse order" */ |
outputnl(""); |
nls_outputnl(37,10); /* "/S Displays files in specified directory and all subdirectories" */ |
nls_outputnl(37,11); /* "/B Uses bare format (no heading information or summary)" */ |
nls_outputnl(37,12); /* "/L Uses lowercases" */ |
return(CMD_OK); |
} |
|
i = nls_getpatterns(&(buf->nls)); |
if (i != 0) nls_outputnl_doserr(i); |
|
/* disable usage of thousands separator on narrow screens */ |
if (screenw < 80) buf->nls.thousep[0] = 0; |
|
/* parse command line */ |
if (dir_parse_cmdline(&req, p->argv) != 0) return(CMD_FAIL); |
|
availrows = screen_getheight() - 2; |
|
/* special case: "DIR drive:" (truename() fails on "C:" under MS-DOS 6.0) */ |
if ((filespecptr[0] != 0) && (filespecptr[1] == ':') && (filespecptr[2] == 0)) { |
if ((filespecptr[0] >= 'a') && (filespecptr[0] <= 'z')) { |
buf->path[0] = filespecptr[0] - ('a' - 1); |
if ((req.filespecptr[0] != 0) && (req.filespecptr[1] == ':') && (req.filespecptr[2] == 0)) { |
if ((req.filespecptr[0] >= 'a') && (req.filespecptr[0] <= 'z')) { |
buf->path[0] = req.filespecptr[0] - ('a' - 1); |
} else { |
buf->path[0] = filespecptr[0] - ('A' - 1); |
buf->path[0] = req.filespecptr[0] - ('A' - 1); |
} |
i = curpathfordrv(buf->path, buf->path[0]); |
} else { |
i = file_truename(filespecptr, buf->path); |
i = file_truename(req.filespecptr, buf->path); |
} |
if (i != 0) { |
nls_outputnl_doserr(i); |
487,7 → 506,7 |
return(CMD_FAIL); |
} |
|
if (format != DIR_OUTPUT_BARE) { |
if (req.format != DIR_OUTPUT_BARE) { |
drv = buf->path[0]; |
if (drv >= 'a') { |
drv -= 'a'; |
510,7 → 529,7 |
if (buf->path[i - 1] == '\\') strcat(buf->path, "????????.???"); |
|
/* ask DOS for list of files, but only with allowed attribs */ |
i = findfirst(dta, buf->path, attrfilter_may); |
i = findfirst(dta, buf->path, req.attrfilter_may); |
if (i != 0) { |
nls_outputnl_doserr(i); |
return(CMD_FAIL); |
517,7 → 536,7 |
} |
|
/* if sorting is involved, then let's buffer all results (and sort them) */ |
if (flags & DIR_FLAG_SORT) { |
if (req.flags & DIR_FLAG_SORT) { |
/* allocate a memory buffer - try several sizes until one succeeds */ |
const unsigned short memsz[] = {65500, 32000, 16000, 8000, 4000, 2000, 1000, 0}; |
unsigned short max_dta_bufcount = 0; |
540,7 → 559,7 |
|
do { |
/* filter out files with uninteresting attributes */ |
if (filter_attribs(dta, attrfilter_must, attrfilter_may) == 0) continue; |
if (filter_attribs(dta, req.attrfilter_must, req.attrfilter_may) == 0) continue; |
|
/* normalize "size" of directories to zero because kernel returns garbage |
* sizes for directories which might confuse the sorting routine later */ |
578,15 → 597,15 |
for (;;) { |
|
/* filter out attributes (skip if entry comes from buffer, then it was already veted) */ |
if (filter_attribs(dta, attrfilter_must, attrfilter_may) == 0) continue; |
if (filter_attribs(dta, req.attrfilter_must, req.attrfilter_may) == 0) continue; |
|
/* turn string lcase (/L) */ |
if (flags & DIR_FLAG_LCASE) _strlwr(dta->fname); /* OpenWatcom extension, probably does not care about NLS so results may be odd with non-A-Z characters... */ |
if (req.flags & DIR_FLAG_LCASE) _strlwr(dta->fname); /* OpenWatcom extension, probably does not care about NLS so results may be odd with non-A-Z characters... */ |
|
summary_fcount++; |
if ((dta->attr & DOS_ATTR_DIR) == 0) summary_totsz += dta->size; |
|
switch (format) { |
switch (req.format) { |
case DIR_OUTPUT_NORM: |
/* print fname-space-extension (unless it's "." or "..", then print as-is) */ |
if (dta->fname[0] == '.') { |
647,7 → 666,7 |
break; |
} |
|
if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows); |
if (req.flags & DIR_FLAG_PAUSE) dir_pagination(&availrows); |
|
/* take next entry, either from buf or disk */ |
if (dtabufcount > 0) { |
662,11 → 681,11 |
|
if (wcolcount != 0) { |
outputnl(""); /* in wide mode make sure to end on a clear row */ |
if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows); |
if (req.flags & DIR_FLAG_PAUSE) dir_pagination(&availrows); |
} |
|
/* print out summary (unless bare output mode) */ |
if (format != DIR_OUTPUT_BARE) { |
if (req.format != DIR_OUTPUT_BARE) { |
unsigned short alignpos; |
unsigned char uint32maxlen = 13; /* 13 is the max len of a 32 bit number with thousand separators (4'000'000'000) */ |
if (screenw < 80) uint32maxlen = 10; |
680,7 → 699,7 |
output(buf->buff64 + i + 1); |
output(" "); |
nls_outputnl(37,23); /* "bytes" */ |
if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows); |
if (req.flags & DIR_FLAG_PAUSE) dir_pagination(&availrows); |
/* xxxx bytes free */ |
i = cmd_dir_df(&summary_totsz, drv); |
if (i != 0) nls_outputnl_doserr(i); |
690,7 → 709,7 |
output(buf->buff64 + i + 1); |
output(" "); |
nls_outputnl(37,24); /* "bytes free" */ |
if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows); |
if (req.flags & DIR_FLAG_PAUSE) dir_pagination(&availrows); |
} |
|
/* free the buffer memory (if used) */ |