Subversion Repositories SvarDOS

Rev

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

Rev 533 Rev 538
1
/* This file is part of the SvarCOM project and is published under the terms
1
/* This file is part of the SvarCOM project and is published under the terms
2
 * of the MIT license.
2
 * of the MIT license.
3
 *
3
 *
4
 * Copyright (C) 2021 Mateusz Viste
4
 * Copyright (C) 2021 Mateusz Viste
5
 *
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
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
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:
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
12
 *
13
 * The above copyright notice and this permission notice shall be included in
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
14
 * all copies or substantial portions of the Software.
15
 *
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
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,
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
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
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
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
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 * DEALINGS IN THE SOFTWARE.
22
 * DEALINGS IN THE SOFTWARE.
23
 */
23
 */
24
 
24
 
25
/*
25
/*
26
 * dir
26
 * dir
27
 *
27
 *
28
 * Displays a list of files and subdirectories in a directory.
28
 * Displays a list of files and subdirectories in a directory.
29
 *
29
 *
30
 * 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]
31
 *
31
 *
32
 * /P Pauses after each screenful of information.
32
 * /P Pauses after each screenful of information.
33
 * /W Uses wide list format.
33
 * /W Uses wide list format.
34
 *
34
 *
35
 * /A Displays file with specified attributes:
35
 * /A Displays file with specified attributes:
36
 *     D Directories           R Read-only files     H Hidden files
36
 *     D Directories           R Read-only files     H Hidden files
37
 *     A Ready for archiving   S System files        - prefix meaning "not"
37
 *     A Ready for archiving   S System files        - prefix meaning "not"
38
 *
38
 *
39
 * /O List files in sorted order:
39
 * /O List files in sorted order:
40
 *     N by name            S by size              E by extension
40
 *     N by name            S by size              E by extension
41
 *     D by date            G group dirs first     - prefix to reverse order
41
 *     D by date            G group dirs first     - prefix to reverse order
42
 *
42
 *
43
 * /S Displays files in specified directory and all subdirectories.
43
 * /S Displays files in specified directory and all subdirectories.
44
 * /B Uses bare format (no heading information or summary)
44
 * /B Uses bare format (no heading information or summary)
45
 * /L Uses lowercases
45
 * /L Uses lowercases
46
 */
46
 */
47
 
47
 
48
/* 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
49
 *       the specified attributes are matched. This is different from how DOS
49
 *       the specified attributes are matched. This is different from how DOS
50
 *       itself matches attributes hence DIR cannot rely on the attributes
50
 *       itself matches attributes hence DIR cannot rely on the attributes
51
 *       filter within FindFirst.
51
 *       filter within FindFirst.
52
 *
52
 *
53
 * 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.
54
 */
54
 */
55
 
55
 
56
#define WCOLWIDTH 15  /* width of a column in wide mode output */
56
#define WCOLWIDTH 15  /* width of a column in wide mode output */
57
 
57
 
58
 
58
 
59
/* fills freebytes with free bytes for drv (A=0, B=1, etc)
59
/* fills freebytes with free bytes for drv (A=0, B=1, etc)
60
 * returns DOS ERR code on failure */
60
 * returns DOS ERR code on failure */
61
static unsigned short cmd_dir_df(unsigned long *freebytes, unsigned char drv) {
61
static unsigned short cmd_dir_df(unsigned long *freebytes, unsigned char drv) {
62
  unsigned short res = 0;
62
  unsigned short res = 0;
63
  unsigned short sects_per_clust = 0, avail_clusts = 0, bytes_per_sect = 0;
63
  unsigned short sects_per_clust = 0, avail_clusts = 0, bytes_per_sect = 0;
64
 
64
 
65
  _asm {
65
  _asm {
66
    push ax
66
    push ax
67
    push bx
67
    push bx
68
    push cx
68
    push cx
69
    push dx
69
    push dx
70
 
70
 
71
    mov ah, 0x36  /* DOS 2+ -- Get Disk Free Space */
71
    mov ah, 0x36  /* DOS 2+ -- Get Disk Free Space */
72
    mov dl, [drv] /* A=1, B=2, etc (0 = DEFAULT DRIVE) */
72
    mov dl, [drv] /* A=1, B=2, etc (0 = DEFAULT DRIVE) */
73
    inc dl
73
    inc dl
74
    int 0x21      /* AX=sects_per_clust, BX=avail_clusts, CX=bytes_per_sect, DX=tot_clusters */
74
    int 0x21      /* AX=sects_per_clust, BX=avail_clusts, CX=bytes_per_sect, DX=tot_clusters */
75
    cmp ax, 0xffff /* AX=0xffff on error (invalid drive) */
75
    cmp ax, 0xffff /* AX=0xffff on error (invalid drive) */
76
    jne COMPUTEDF
76
    jne COMPUTEDF
77
    mov [res], 0x0f /* fill res with DOS error code 15 ("invalid drive") */
77
    mov [res], 0x0f /* fill res with DOS error code 15 ("invalid drive") */
78
    jmp DONE
78
    jmp DONE
79
 
79
 
80
    COMPUTEDF:
80
    COMPUTEDF:
81
    /* freebytes = AX * BX * CX */
81
    /* freebytes = AX * BX * CX */
82
    mov [sects_per_clust], ax
82
    mov [sects_per_clust], ax
83
    mov [avail_clusts], bx
83
    mov [avail_clusts], bx
84
    mov [bytes_per_sect], cx
84
    mov [bytes_per_sect], cx
85
 
85
 
86
    DONE:
86
    DONE:
87
    pop dx
87
    pop dx
88
    pop cx
88
    pop cx
89
    pop bx
89
    pop bx
90
    pop ax
90
    pop ax
91
  }
91
  }
92
 
92
 
93
  /* multiple steps to avoid uint16 overflow */
93
  /* multiple steps to avoid uint16 overflow */
94
  *freebytes = sects_per_clust;
94
  *freebytes = sects_per_clust;
95
  *freebytes *= avail_clusts;
95
  *freebytes *= avail_clusts;
96
  *freebytes *= bytes_per_sect;
96
  *freebytes *= bytes_per_sect;
97
 
97
 
98
  return(res);
98
  return(res);
99
}
99
}
100
 
100
 
101
 
101
 
102
static void dir_pagination(unsigned short *availrows) {
102
static void dir_pagination(unsigned short *availrows) {
103
  *availrows -= 1;
103
  *availrows -= 1;
104
  if (*availrows == 0) {
104
  if (*availrows == 0) {
105
    press_any_key();
105
    press_any_key();
106
    *availrows = screen_getheight() - 1;
106
    *availrows = screen_getheight() - 1;
107
  }
107
  }
108
}
108
}
109
 
109
 
110
 
110
 
111
static enum cmd_result cmd_dir(struct cmd_funcparam *p) {
111
static enum cmd_result cmd_dir(struct cmd_funcparam *p) {
112
  const char *filespecptr = NULL;
112
  const char *filespecptr = NULL;
113
  struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */
113
  struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */
114
  unsigned short i;
114
  unsigned short i;
115
  unsigned short availrows;  /* counter of available rows on display (used for /P) */
115
  unsigned short availrows;  /* counter of available rows on display (used for /P) */
116
  unsigned short wcols = screen_getwidth() / WCOLWIDTH; /* number of columns in wide mode */
116
  unsigned short wcols = screen_getwidth() / WCOLWIDTH; /* number of columns in wide mode */
117
  unsigned char wcolcount;
117
  unsigned char wcolcount;
118
  struct nls_patterns *nls = (void *)(p->BUFFER + (p->BUFFERSZ / 2));
118
  struct nls_patterns *nls = (void *)(p->BUFFER + (p->BUFFERSZ / 2));
119
  char *buff2 = p->BUFFER + (p->BUFFERSZ / 2) + sizeof(*nls);
119
  char *buff2 = p->BUFFER + (p->BUFFERSZ / 2) + sizeof(*nls);
120
  unsigned long summary_fcount = 0;
120
  unsigned long summary_fcount = 0;
121
  unsigned long summary_totsz = 0;
121
  unsigned long summary_totsz = 0;
122
  unsigned char drv = 0;
122
  unsigned char drv = 0;
123
 
123
 
124
  #define DIR_FLAG_PAUSE  1
124
  #define DIR_FLAG_PAUSE  1
125
  #define DIR_FLAG_RECUR  4
125
  #define DIR_FLAG_RECUR  4
126
  #define DIR_FLAG_LCASE  8
126
  #define DIR_FLAG_LCASE  8
127
  unsigned char flags = 0;
127
  unsigned char flags = 0;
128
 
128
 
129
  #define DIR_OUTPUT_NORM 1
129
  #define DIR_OUTPUT_NORM 1
130
  #define DIR_OUTPUT_WIDE 2
130
  #define DIR_OUTPUT_WIDE 2
131
  #define DIR_OUTPUT_BARE 3
131
  #define DIR_OUTPUT_BARE 3
132
  unsigned char format = DIR_OUTPUT_NORM;
132
  unsigned char format = DIR_OUTPUT_NORM;
133
 
133
 
134
  if (cmd_ishlp(p)) {
134
  if (cmd_ishlp(p)) {
135
    outputnl("Displays a list of files and subdirectories in a directory");
135
    outputnl("Displays a list of files and subdirectories in a directory");
136
    outputnl("");
136
    outputnl("");
137
    outputnl("DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]");
137
    outputnl("DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]");
138
    outputnl("");
138
    outputnl("");
139
    outputnl("/P Pauses after each screenful of information");
139
    outputnl("/P Pauses after each screenful of information");
140
    outputnl("/W Uses wide list format");
140
    outputnl("/W Uses wide list format");
141
    outputnl("");
141
    outputnl("");
142
    outputnl("/A Displays files with specified attributes:");
142
    outputnl("/A Displays files with specified attributes:");
143
    outputnl("    D Directories            R Read-only files        H Hidden files");
143
    outputnl("    D Directories            R Read-only files        H Hidden files");
144
    outputnl("    A Ready for archiving    S System files           - prefix meaning \"not\"");
144
    outputnl("    A Ready for archiving    S System files           - prefix meaning \"not\"");
145
    outputnl("");
145
    outputnl("");
146
    outputnl("/O List files in sorted order:");
146
    outputnl("/O List files in sorted order:");
147
    outputnl("    N by name                S by size                E by extension");
147
    outputnl("    N by name                S by size                E by extension");
148
    outputnl("    D by date                G group dirs first       - prefix to reverse order");
148
    outputnl("    D by date                G group dirs first       - prefix to reverse order");
149
    outputnl("");
149
    outputnl("");
150
    outputnl("/S Displays files in specified directory and all subdirectories");
150
    outputnl("/S Displays files in specified directory and all subdirectories");
151
    outputnl("/B Uses bare format (no heading information or summary)");
151
    outputnl("/B Uses bare format (no heading information or summary)");
152
    outputnl("/L Uses lowercases");
152
    outputnl("/L Uses lowercases");
153
    return(CMD_OK);
153
    return(CMD_OK);
154
  }
154
  }
155
 
155
 
156
  i = nls_getpatterns(nls);
156
  i = nls_getpatterns(nls);
157
  if (i != 0) outputnl(doserr(i));
157
  if (i != 0) nls_outputnl_doserr(i);
158
 
158
 
159
  /* parse command line */
159
  /* parse command line */
160
  for (i = 0; i < p->argc; i++) {
160
  for (i = 0; i < p->argc; i++) {
161
    if (p->argv[i][0] == '/') {
161
    if (p->argv[i][0] == '/') {
162
      char arg;
162
      char arg;
163
      char neg = 0;
163
      char neg = 0;
164
      /* detect negations and get actual argument */
164
      /* detect negations and get actual argument */
165
      if (p->argv[i][1] == '-') neg = 1;
165
      if (p->argv[i][1] == '-') neg = 1;
166
      arg = p->argv[i][1 + neg];
166
      arg = p->argv[i][1 + neg];
167
      /* */
167
      /* */
168
      switch (arg) {
168
      switch (arg) {
169
        case 'a':
169
        case 'a':
170
        case 'A':
170
        case 'A':
171
          /* TODO */
171
          /* TODO */
172
          outputnl("/A NOT IMPLEMENTED YET");
172
          outputnl("/A NOT IMPLEMENTED YET");
173
          return(CMD_FAIL);
173
          return(CMD_FAIL);
174
          break;
174
          break;
175
        case 'b':
175
        case 'b':
176
        case 'B':
176
        case 'B':
177
          format = DIR_OUTPUT_BARE;
177
          format = DIR_OUTPUT_BARE;
178
          break;
178
          break;
179
        case 'l':
179
        case 'l':
180
        case 'L':
180
        case 'L':
181
          flags |= DIR_FLAG_LCASE;
181
          flags |= DIR_FLAG_LCASE;
182
          break;
182
          break;
183
        case 'o':
183
        case 'o':
184
        case 'O':
184
        case 'O':
185
          /* TODO */
185
          /* TODO */
186
          outputnl("/O NOT IMPLEMENTED YET");
186
          outputnl("/O NOT IMPLEMENTED YET");
187
          return(CMD_FAIL);
187
          return(CMD_FAIL);
188
          break;
188
          break;
189
        case 'p':
189
        case 'p':
190
        case 'P':
190
        case 'P':
191
          flags |= DIR_FLAG_PAUSE;
191
          flags |= DIR_FLAG_PAUSE;
192
          if (neg) flags &= (0xff ^ DIR_FLAG_PAUSE);
192
          if (neg) flags &= (0xff ^ DIR_FLAG_PAUSE);
193
          break;
193
          break;
194
        case 's':
194
        case 's':
195
        case 'S':
195
        case 'S':
196
          /* TODO */
196
          /* TODO */
197
          outputnl("/S NOT IMPLEMENTED YET");
197
          outputnl("/S NOT IMPLEMENTED YET");
198
          return(CMD_FAIL);
198
          return(CMD_FAIL);
199
          break;
199
          break;
200
        case 'w':
200
        case 'w':
201
        case 'W':
201
        case 'W':
202
          format = DIR_OUTPUT_WIDE;
202
          format = DIR_OUTPUT_WIDE;
203
          break;
203
          break;
204
        default:
204
        default:
205
          outputnl("Invalid switch");
205
          outputnl("Invalid switch");
206
          return(CMD_FAIL);
206
          return(CMD_FAIL);
207
      }
207
      }
208
    } else {  /* filespec */
208
    } else {  /* filespec */
209
      if (filespecptr != NULL) {
209
      if (filespecptr != NULL) {
210
        outputnl("Too many parameters");
210
        outputnl("Too many parameters");
211
        return(CMD_FAIL);
211
        return(CMD_FAIL);
212
      }
212
      }
213
      filespecptr = p->argv[i];
213
      filespecptr = p->argv[i];
214
    }
214
    }
215
  }
215
  }
216
 
216
 
217
  if (filespecptr == NULL) filespecptr = ".";
217
  if (filespecptr == NULL) filespecptr = ".";
218
 
218
 
219
  availrows = screen_getheight() - 2;
219
  availrows = screen_getheight() - 2;
220
 
220
 
221
  /* special case: "DIR drive:" (truename() fails on "C:" under MS-DOS 6.0) */
221
  /* special case: "DIR drive:" (truename() fails on "C:" under MS-DOS 6.0) */
222
  if ((filespecptr[0] != 0) && (filespecptr[1] == ':') && (filespecptr[2] == 0)) {
222
  if ((filespecptr[0] != 0) && (filespecptr[1] == ':') && (filespecptr[2] == 0)) {
223
    if ((filespecptr[0] >= 'a') && (filespecptr[0] <= 'z')) {
223
    if ((filespecptr[0] >= 'a') && (filespecptr[0] <= 'z')) {
224
      p->BUFFER[0] = filespecptr[0] - ('a' - 1);
224
      p->BUFFER[0] = filespecptr[0] - ('a' - 1);
225
    } else {
225
    } else {
226
      p->BUFFER[0] = filespecptr[0] - ('A' - 1);
226
      p->BUFFER[0] = filespecptr[0] - ('A' - 1);
227
    }
227
    }
228
    i = curpathfordrv(p->BUFFER, p->BUFFER[0]);
228
    i = curpathfordrv(p->BUFFER, p->BUFFER[0]);
229
  } else {
229
  } else {
230
    i = file_truename(filespecptr, p->BUFFER);
230
    i = file_truename(filespecptr, p->BUFFER);
231
  }
231
  }
232
  if (i != 0) {
232
  if (i != 0) {
233
    outputnl(doserr(i));
233
    nls_outputnl_doserr(i);
234
    return(CMD_FAIL);
234
    return(CMD_FAIL);
235
  }
235
  }
236
 
236
 
237
  if (format != DIR_OUTPUT_BARE) {
237
  if (format != DIR_OUTPUT_BARE) {
238
    drv = p->BUFFER[0];
238
    drv = p->BUFFER[0];
239
    if (drv >= 'a') {
239
    if (drv >= 'a') {
240
      drv -= 'a';
240
      drv -= 'a';
241
    } else {
241
    } else {
242
      drv -= 'A';
242
      drv -= 'A';
243
    }
243
    }
244
    cmd_vol_internal(drv, buff2);
244
    cmd_vol_internal(drv, buff2);
245
    sprintf(buff2, "Directory of %s", p->BUFFER);
245
    sprintf(buff2, "Directory of %s", p->BUFFER);
246
    /* trim at first '?', if any */
246
    /* trim at first '?', if any */
247
    for (i = 0; buff2[i] != 0; i++) if (buff2[i] == '?') buff2[i] = 0;
247
    for (i = 0; buff2[i] != 0; i++) if (buff2[i] == '?') buff2[i] = 0;
248
    outputnl(buff2);
248
    outputnl(buff2);
249
    outputnl("");
249
    outputnl("");
250
    availrows -= 3;
250
    availrows -= 3;
251
  }
251
  }
252
 
252
 
253
  /* if dir: append a backslash (also get its len) */
253
  /* if dir: append a backslash (also get its len) */
254
  i = path_appendbkslash_if_dir(p->BUFFER);
254
  i = path_appendbkslash_if_dir(p->BUFFER);
255
 
255
 
256
  /* if ends with a \ then append ????????.??? */
256
  /* if ends with a \ then append ????????.??? */
257
  if (p->BUFFER[i - 1] == '\\') strcat(p->BUFFER, "????????.???");
257
  if (p->BUFFER[i - 1] == '\\') strcat(p->BUFFER, "????????.???");
258
 
258
 
259
  i = findfirst(dta, p->BUFFER, DOS_ATTR_RO | DOS_ATTR_HID | DOS_ATTR_SYS | DOS_ATTR_DIR | DOS_ATTR_ARC);
259
  i = findfirst(dta, p->BUFFER, DOS_ATTR_RO | DOS_ATTR_HID | DOS_ATTR_SYS | DOS_ATTR_DIR | DOS_ATTR_ARC);
260
  if (i != 0) {
260
  if (i != 0) {
261
    outputnl(doserr(i));
261
    nls_outputnl_doserr(i);
262
    return(CMD_FAIL);
262
    return(CMD_FAIL);
263
  }
263
  }
264
 
264
 
265
  wcolcount = 0; /* may be used for columns counting with wide mode */
265
  wcolcount = 0; /* may be used for columns counting with wide mode */
266
 
266
 
267
  do {
267
  do {
268
    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... */
268
    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... */
269
 
269
 
270
    summary_fcount++;
270
    summary_fcount++;
271
    if ((dta->attr & DOS_ATTR_DIR) == 0) summary_totsz += dta->size;
271
    if ((dta->attr & DOS_ATTR_DIR) == 0) summary_totsz += dta->size;
272
 
272
 
273
    switch (format) {
273
    switch (format) {
274
      case DIR_OUTPUT_NORM:
274
      case DIR_OUTPUT_NORM:
275
        /* print fname-space-extension (unless it's "." or "..", then print as-is) */
275
        /* print fname-space-extension (unless it's "." or "..", then print as-is) */
276
        if (dta->fname[0] == '.') {
276
        if (dta->fname[0] == '.') {
277
          output(dta->fname);
277
          output(dta->fname);
278
          i = strlen(dta->fname);
278
          i = strlen(dta->fname);
279
          while (i++ < 12) output(" ");
279
          while (i++ < 12) output(" ");
280
        } else {
280
        } else {
281
          file_fname2fcb(buff2, dta->fname);
281
          file_fname2fcb(buff2, dta->fname);
282
          memmove(buff2 + 9, buff2 + 8, 4);
282
          memmove(buff2 + 9, buff2 + 8, 4);
283
          buff2[8] = ' ';
283
          buff2[8] = ' ';
284
          output(buff2);
284
          output(buff2);
285
        }
285
        }
286
        output(" ");
286
        output(" ");
287
        /* either <DIR> or right aligned 10-chars byte size */
287
        /* either <DIR> or right aligned 10-chars byte size */
288
        memset(buff2, ' ', 10);
288
        memset(buff2, ' ', 10);
289
        if (dta->attr & DOS_ATTR_DIR) {
289
        if (dta->attr & DOS_ATTR_DIR) {
290
          strcpy(buff2 + 10, "<DIR>");
290
          strcpy(buff2 + 10, "<DIR>");
291
        } else {
291
        } else {
292
          _ultoa(dta->size, buff2 + 10, 10); /* OpenWatcom extension */
292
          _ultoa(dta->size, buff2 + 10, 10); /* OpenWatcom extension */
293
        }
293
        }
294
        output(buff2 + strlen(buff2) - 10);
294
        output(buff2 + strlen(buff2) - 10);
295
        /* two spaces and NLS DATE */
295
        /* two spaces and NLS DATE */
296
        buff2[0] = ' ';
296
        buff2[0] = ' ';
297
        buff2[1] = ' ';
297
        buff2[1] = ' ';
298
        nls_format_date(buff2 + 2, dta->date_yr + 1980, dta->date_mo, dta->date_dy, nls);
298
        nls_format_date(buff2 + 2, dta->date_yr + 1980, dta->date_mo, dta->date_dy, nls);
299
        output(buff2);
299
        output(buff2);
300
 
300
 
301
        /* one space and NLS TIME */
301
        /* one space and NLS TIME */
302
        nls_format_time(buff2 + 1, dta->time_hour, dta->time_min, 0xff, nls);
302
        nls_format_time(buff2 + 1, dta->time_hour, dta->time_min, 0xff, nls);
303
        outputnl(buff2);
303
        outputnl(buff2);
304
        break;
304
        break;
305
 
305
 
306
      case DIR_OUTPUT_WIDE: /* display in columns of 12 chars per item */
306
      case DIR_OUTPUT_WIDE: /* display in columns of 12 chars per item */
307
        i = strlen(dta->fname);
307
        i = strlen(dta->fname);
308
        if (dta->attr & DOS_ATTR_DIR) {
308
        if (dta->attr & DOS_ATTR_DIR) {
309
          i += 2;
309
          i += 2;
310
          output("[");
310
          output("[");
311
          output(dta->fname);
311
          output(dta->fname);
312
          output("]");
312
          output("]");
313
        } else {
313
        } else {
314
          output(dta->fname);
314
          output(dta->fname);
315
        }
315
        }
316
        while (i++ < WCOLWIDTH) output(" ");
316
        while (i++ < WCOLWIDTH) output(" ");
317
        if (++wcolcount == wcols) {
317
        if (++wcolcount == wcols) {
318
          wcolcount = 0;
318
          wcolcount = 0;
319
          outputnl("");
319
          outputnl("");
320
        } else {
320
        } else {
321
          availrows++; /* wide mode is the only one that does not write one line per file */
321
          availrows++; /* wide mode is the only one that does not write one line per file */
322
        }
322
        }
323
        break;
323
        break;
324
 
324
 
325
      case DIR_OUTPUT_BARE:
325
      case DIR_OUTPUT_BARE:
326
        outputnl(dta->fname);
326
        outputnl(dta->fname);
327
        break;
327
        break;
328
    }
328
    }
329
 
329
 
330
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
330
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
331
 
331
 
332
  } while (findnext(dta) == 0);
332
  } while (findnext(dta) == 0);
333
 
333
 
334
  if (wcolcount != 0) {
334
  if (wcolcount != 0) {
335
    outputnl(""); /* in wide mode make sure to end on a clear row */
335
    outputnl(""); /* in wide mode make sure to end on a clear row */
336
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
336
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
337
  }
337
  }
338
 
338
 
339
  /* print out summary (unless bare output mode) */
339
  /* print out summary (unless bare output mode) */
340
  if (format != DIR_OUTPUT_BARE) {
340
  if (format != DIR_OUTPUT_BARE) {
341
    unsigned short alignpos;
341
    unsigned short alignpos;
342
    /* x file(s) */
342
    /* x file(s) */
343
    memset(buff2, ' ', 13); /* 13 is the max len of a 32 bit number with thousand separators (4'000'000'000) */
343
    memset(buff2, ' ', 13); /* 13 is the max len of a 32 bit number with thousand separators (4'000'000'000) */
344
    i = nls_format_number(buff2 + 13, summary_fcount, nls);
344
    i = nls_format_number(buff2 + 13, summary_fcount, nls);
345
    alignpos = sprintf(buff2 + 13 + i, " %s ", "file(s)");
345
    alignpos = sprintf(buff2 + 13 + i, " %s ", "file(s)");
346
    output(buff2 + i);
346
    output(buff2 + i);
347
    /* xxxx bytes */
347
    /* xxxx bytes */
348
    i = nls_format_number(buff2 + 13, summary_totsz, nls);
348
    i = nls_format_number(buff2 + 13, summary_totsz, nls);
349
    output(buff2 + i);
349
    output(buff2 + i);
350
    output(" ");
350
    output(" ");
351
    outputnl("bytes");
351
    outputnl("bytes");
352
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
352
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
353
    /* xxxx bytes free */
353
    /* xxxx bytes free */
354
    i = cmd_dir_df(&summary_totsz, drv);
354
    i = cmd_dir_df(&summary_totsz, drv);
355
    if (i != 0) outputnl(doserr(i));
355
    if (i != 0) nls_outputnl_doserr(i);
356
    alignpos += 13 + 13;
356
    alignpos += 13 + 13;
357
    memset(buff2, ' ', alignpos); /* align the freebytes value to same column as totbytes */
357
    memset(buff2, ' ', alignpos); /* align the freebytes value to same column as totbytes */
358
    i = nls_format_number(buff2 + alignpos, summary_totsz, nls);
358
    i = nls_format_number(buff2 + alignpos, summary_totsz, nls);
359
    output(buff2 + i);
359
    output(buff2 + i);
360
    output(" ");
360
    output(" ");
361
    outputnl("bytes free");
361
    outputnl("bytes free");
362
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
362
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
363
  }
363
  }
364
 
364
 
365
  return(CMD_OK);
365
  return(CMD_OK);
366
}
366
}
367
 
367