Subversion Repositories SvarDOS

Rev

Rev 420 | Rev 424 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
421 mateuszvis 1
/* This file is part of the SvarCOM project and is published under the terms
2
 * of the MIT license.
3
 *
4
 * Copyright (C) 2021 Mateusz Viste
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 * DEALINGS IN THE SOFTWARE.
23
 */
24
 
368 mateuszvis 25
/*
26
 * dir
27
 *
28
 * Displays a list of files and subdirectories in a directory.
29
 *
30
 * DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]
31
 *
32
 * /P Pauses after each screenful of information.
33
 * /W Uses wide list format.
34
 *
35
 * /A Displays file with specified attributes:
36
 *     D Directories           R Read-only files     H Hidden files
37
 *     A Ready for archiving   S System files        - prefix meaning "not"
38
 *
39
 * /O List files in sorted order:
40
 *     N by name            S by size              E by extension
41
 *     D by date            G group dirs first     - prefix to reverse order
42
 *
43
 * /S Displays files in specified directory and all subdirectories.
44
 * /B Uses bare format (no heading information or summary)
45
 * /L Uses lowercases
46
 */
47
 
396 mateuszvis 48
/* NOTE: /A attributes are matched in an exclusive way, ie. only files with
49
 *       the specified attributes are matched. This is different from how DOS
50
 *       itself matches attributes hence DIR cannot rely on the attributes
51
 *       filter within FindFirst.
52
 *
53
 * NOTE: Multiple /A are not supported - only the last one is significant.
54
 */
55
 
420 mateuszvis 56
#define WCOLWIDTH 15  /* width of a column in wide mode output */
57
 
372 mateuszvis 58
static int cmd_dir(struct cmd_funcparam *p) {
393 mateuszvis 59
  const char *filespecptr = NULL;
388 mateuszvis 60
  struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */
417 mateuszvis 61
  unsigned short i;
396 mateuszvis 62
  unsigned short availrows;  /* counter of available rows on display (used for /P) */
420 mateuszvis 63
  unsigned short wcols = screen_getwidth() / WCOLWIDTH; /* number of columns in wide mode */
64
  unsigned char wcolcount;
65
  struct nls_patterns *nls = (void *)(p->BUFFER + (BUFFER_SIZE / 3));
66
  char *buff2 = p->BUFFER + (BUFFER_SIZE / 3 * 2);
67
 
396 mateuszvis 68
  #define DIR_FLAG_PAUSE  1
69
  #define DIR_FLAG_RECUR  4
420 mateuszvis 70
  #define DIR_FLAG_LCASE  8
396 mateuszvis 71
  unsigned char flags = 0;
368 mateuszvis 72
 
420 mateuszvis 73
  #define DIR_OUTPUT_NORM 1
74
  #define DIR_OUTPUT_WIDE 2
75
  #define DIR_OUTPUT_BARE 3
76
  unsigned char format = DIR_OUTPUT_NORM;
77
 
390 mateuszvis 78
  if (cmd_ishlp(p)) {
396 mateuszvis 79
    outputnl("Displays a list of files and subdirectories in a directory");
80
    outputnl("");
81
    outputnl("DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]");
82
    outputnl("");
83
    outputnl("/P Pauses after each screenful of information");
84
    outputnl("/W Uses wide list format");
85
    outputnl("");
86
    outputnl("/A Displays files with specified attributes:");
87
    outputnl("    D Directories            R Read-only files        H Hidden files");
88
    outputnl("    A Ready for archiving    S System files           - prefix meaning \"not\"");
89
    outputnl("");
90
    outputnl("/O List files in sorted order:");
91
    outputnl("    N by name                S by size                E by extension");
92
    outputnl("    D by date                G group dirs first       - prefix to reverse order");
93
    outputnl("");
94
    outputnl("/S Displays files in specified directory and all subdirectories");
95
    outputnl("/B Uses bare format (no heading information or summary)");
96
    outputnl("/L Uses lowercases");
390 mateuszvis 97
    return(-1);
98
  }
99
 
420 mateuszvis 100
  i = nls_getpatterns(nls);
101
  if (i != 0) outputnl(doserr(i));
102
 
393 mateuszvis 103
  /* parse command line */
104
  for (i = 0; i < p->argc; i++) {
105
    if (p->argv[i][0] == '/') {
396 mateuszvis 106
      char arg;
107
      char neg = 0;
108
      /* detect negations and get actual argument */
109
      if (p->argv[i][1] == '-') neg = 1;
110
      arg = p->argv[i][1 + neg];
111
      /* */
112
      switch (arg) {
113
        case 'a':
114
        case 'A':
115
          /* TODO */
116
          outputnl("/A NOT IMPLEMENTED YET");
117
          return(-1);
118
          break;
399 mateuszvis 119
        case 'b':
120
        case 'B':
420 mateuszvis 121
          format = DIR_OUTPUT_BARE;
399 mateuszvis 122
          break;
421 mateuszvis 123
        case 'l':
124
        case 'L':
125
          flags |= DIR_FLAG_LCASE;
420 mateuszvis 126
          break;
421 mateuszvis 127
        case 'o':
128
        case 'O':
129
          /* TODO */
130
          outputnl("/O NOT IMPLEMENTED YET");
131
          return(-1);
132
          break;
396 mateuszvis 133
        case 'p':
134
        case 'P':
135
          flags |= DIR_FLAG_PAUSE;
136
          if (neg) flags &= (0xff ^ DIR_FLAG_PAUSE);
137
          break;
421 mateuszvis 138
        case 's':
139
        case 'S':
140
          /* TODO */
141
          outputnl("/S NOT IMPLEMENTED YET");
142
          return(-1);
420 mateuszvis 143
          break;
421 mateuszvis 144
        case 'w':
145
        case 'W':
146
          format = DIR_OUTPUT_WIDE;
147
          break;
393 mateuszvis 148
        default:
149
          outputnl("Invalid switch");
150
          return(-1);
151
      }
152
    } else {  /* filespec */
153
      if (filespecptr != NULL) {
154
        outputnl("Too many parameters");
155
        return(-1);
156
      }
157
      filespecptr = p->argv[i];
158
    }
159
  }
368 mateuszvis 160
 
393 mateuszvis 161
  if (filespecptr == NULL) filespecptr = ".";
162
 
417 mateuszvis 163
  /* special case: "DIR drive:" (truename() fails on "C:" under MS-DOS 6.0) */
164
  if ((filespecptr[0] != 0) && (filespecptr[1] == ':') && (filespecptr[2] == 0)) {
165
    if ((filespecptr[0] >= 'a') && (filespecptr[0] <= 'z')) {
166
      p->BUFFER[0] = filespecptr[0] - ('a' - 1);
167
    } else {
168
      p->BUFFER[0] = filespecptr[0] - ('A' - 1);
399 mateuszvis 169
    }
417 mateuszvis 170
    i = curpathfordrv(p->BUFFER, p->BUFFER[0]);
171
  } else {
172
    i = file_truename(filespecptr, p->BUFFER);
399 mateuszvis 173
  }
417 mateuszvis 174
  if (i != 0) {
175
    outputnl(doserr(i));
176
    return(-1);
177
  }
393 mateuszvis 178
 
420 mateuszvis 179
  if (format != DIR_OUTPUT_BARE) {
399 mateuszvis 180
    unsigned char drv = p->BUFFER[0];
181
    if (drv >= 'a') {
182
      drv -= 'a';
183
    } else {
184
      drv -= 'A';
185
    }
403 mateuszvis 186
    cmd_vol_internal(drv, buff2);
187
    sprintf(buff2, "Directory of %s", p->BUFFER);
399 mateuszvis 188
    /* trim at first '?', if any */
403 mateuszvis 189
    for (i = 0; buff2[i] != 0; i++) if (buff2[i] == '?') buff2[i] = 0;
190
    outputnl(buff2);
399 mateuszvis 191
    outputnl("");
192
  }
193
 
417 mateuszvis 194
  /* if dir: append a backslash (also get its len) */
195
  i = path_appendbkslash_if_dir(p->BUFFER);
393 mateuszvis 196
 
417 mateuszvis 197
  /* if ends with a \ then append ????????.??? */
198
  if (p->BUFFER[i - 1] == '\\') strcat(p->BUFFER, "????????.???");
393 mateuszvis 199
 
417 mateuszvis 200
  i = findfirst(dta, p->BUFFER, DOS_ATTR_RO | DOS_ATTR_HID | DOS_ATTR_SYS | DOS_ATTR_DIR | DOS_ATTR_ARC);
201
  if (i != 0) {
202
    outputnl(doserr(i));
203
    return(-1);
204
  }
205
 
396 mateuszvis 206
  availrows = screen_getheight();
420 mateuszvis 207
  wcolcount = 0; /* may be used for columns counting with wide mode */
396 mateuszvis 208
 
420 mateuszvis 209
  do {
210
    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... */
368 mateuszvis 211
 
420 mateuszvis 212
    switch (format) {
213
      case DIR_OUTPUT_NORM:
214
        /* print fname-space-extension (unless it's "." or "..", then print as-is) */
215
        if (dta->fname[0] == '.') {
216
          output(dta->fname);
217
          i = strlen(dta->fname);
218
          while (i++ < 12) output(" ");
219
        } else {
220
          file_fname2fcb(buff2, dta->fname);
221
          memmove(buff2 + 9, buff2 + 8, 4);
222
          buff2[8] = ' ';
223
          output(buff2);
224
        }
225
        output(" ");
226
        /* either <DIR> or right aligned 10-chars byte size */
227
        memset(buff2, ' ', 10);
228
        if (dta->attr & DOS_ATTR_DIR) {
229
          strcpy(buff2 + 10, "<DIR>");
230
        } else {
231
          _ultoa(dta->size, buff2 + 10, 10); /* OpenWatcom extension */
232
        }
233
        output(buff2 + strlen(buff2) - 10);
234
        /* two spaces and NLS DATE */
235
        buff2[0] = ' ';
236
        buff2[1] = ' ';
237
        nls_format_date(buff2 + 2, dta->date_yr + 1980, dta->date_mo, dta->date_dy, nls);
238
        output(buff2);
239
 
240
        /* one space and NLS TIME */
241
        nls_format_time(buff2 + 1, dta->time_hour, dta->time_min, nls);
242
        outputnl(buff2);
243
        break;
244
 
245
      case DIR_OUTPUT_WIDE: /* display in columns of 12 chars per item */
246
        i = strlen(dta->fname);
247
        if (dta->attr & DOS_ATTR_DIR) {
248
          i += 2;
249
          output("[");
250
          output(dta->fname);
251
          output("]");
252
        } else {
253
          output(dta->fname);
254
        }
255
        while (i++ < WCOLWIDTH) output(" ");
256
        if (++wcolcount == wcols) {
257
          wcolcount = 0;
258
          outputnl("");
259
        }
260
        break;
261
 
262
      case DIR_OUTPUT_BARE:
263
        outputnl(dta->fname);
264
        break;
396 mateuszvis 265
    }
368 mateuszvis 266
 
420 mateuszvis 267
    if ((flags & DIR_FLAG_PAUSE) && (--availrows < 2)) {
268
      press_any_key();
269
      availrows = screen_getheight();
270
    }
271
 
272
  } while (findnext(dta) == 0);
273
 
274
  if (wcolcount != 0) outputnl("");
275
 
368 mateuszvis 276
  return(-1);
277
}