Subversion Repositories SvarDOS

Rev

Rev 420 | Rev 424 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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