Subversion Repositories SvarDOS

Rev

Rev 1717 | Rev 1720 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1717 Rev 1719
Line 184... Line 184...
184
 
184
 
185
  return(1);
185
  return(1);
186
}
186
}
187
 
187
 
188
 
188
 
-
 
189
static struct {
-
 
190
  struct TINYDTA far *dtabuf_root;
-
 
191
  char order[8]; /* GNESD values (ucase = lower first ; lcase = higher first) */
-
 
192
} glob_sortcmp_dat;
-
 
193
 
-
 
194
 
-
 
195
/* translates an order string like "GNE-S" into values fed into the order[]
-
 
196
 * table of glob_sortcmp_dat. returns 0 on success, non-zero otherwise. */
-
 
197
static int process_order_directive(const char *ordstring) {
-
 
198
  const char *gnesd = "gnesd"; /* must be lower case */
-
 
199
  int ordi, orderi = 0, i;
-
 
200
 
-
 
201
  /* tabula rasa */
-
 
202
  glob_sortcmp_dat.order[0] = 0;
-
 
203
 
-
 
204
  /* parsing */
-
 
205
  for (ordi = 0; ordstring[ordi] != 0; ordi++) {
-
 
206
    if (ordstring[ordi] == '-') {
-
 
207
      if ((ordstring[ordi + 1] == '-') || (ordstring[ordi + 1] == 0)) return(-1);
-
 
208
      continue;
-
 
209
    }
-
 
210
    if (orderi == sizeof(glob_sortcmp_dat.order)) return(-1);
-
 
211
 
-
 
212
    for (i = 0; gnesd[i] != 0; i++) {
-
 
213
      if ((ordstring[ordi] | 32) == gnesd[i]) { /* | 32 is lcase-ing the char */
-
 
214
        if ((ordi > 0) && (ordstring[ordi - 1] == '-')) {
-
 
215
          glob_sortcmp_dat.order[orderi] = gnesd[i];
-
 
216
        } else {
-
 
217
          glob_sortcmp_dat.order[orderi] = gnesd[i] ^ 32;
-
 
218
        }
-
 
219
        orderi++;
-
 
220
        break;
-
 
221
      }
-
 
222
    }
-
 
223
    if (gnesd[i] == 0) return(-1);
-
 
224
  }
-
 
225
 
-
 
226
  return(0);
-
 
227
}
-
 
228
 
-
 
229
 
-
 
230
static int sortcmp(const void *dtaid1, const void *dtaid2) {
-
 
231
  struct TINYDTA far *dta1 = &(glob_sortcmp_dat.dtabuf_root[*((unsigned short *)dtaid1)]);
-
 
232
  struct TINYDTA far *dta2 = &(glob_sortcmp_dat.dtabuf_root[*((unsigned short *)dtaid2)]);
-
 
233
  char *ordconf = glob_sortcmp_dat.order;
-
 
234
 
-
 
235
  /* debug stuff
-
 
236
  {
-
 
237
    int i;
-
 
238
    printf("%lu vs %lu | ", dta1->size, dta2->size);
-
 
239
    for (i = 0; dta1->fname[i] != 0; i++) printf("%c", dta1->fname[i]);
-
 
240
    printf(" vs ");
-
 
241
    for (i = 0; dta2->fname[i] != 0; i++) printf("%c", dta2->fname[i]);
-
 
242
    printf("\n");
-
 
243
  } */
-
 
244
 
-
 
245
  for (;;) {
-
 
246
    int r = -1;
-
 
247
    if (*ordconf & 32) r = 1;
-
 
248
 
-
 
249
    switch (*ordconf | 32) {
-
 
250
      case 'g': /* sort by type (directories first, then files) */
-
 
251
        if ((dta1->time_sec2 & DOS_ATTR_DIR) > (dta2->time_sec2 & DOS_ATTR_DIR)) return(0 - r);
-
 
252
        if ((dta1->time_sec2 & DOS_ATTR_DIR) < (dta2->time_sec2 & DOS_ATTR_DIR)) return(r);
-
 
253
        break;
-
 
254
      case ' ': /* default (last resort) sort: by name */
-
 
255
      case 'e': /* sort by extension */
-
 
256
      case 'n': /* sort by filename */
-
 
257
      {
-
 
258
        const char far *f1 = dta1->fname;
-
 
259
        const char far *f2 = dta2->fname;
-
 
260
        int i, limit = 12;
-
 
261
        /* special handling for '.' and '..' entries */
-
 
262
        if ((f1[0] == '.') && (f2[0] != '.')) return(0 - r);
-
 
263
        if ((f2[0] == '.') && (f1[0] != '.')) return(r);
-
 
264
 
-
 
265
        if ((*ordconf | 32) == 'e') {
-
 
266
          /* fast-forward to extension or end of filename */
-
 
267
          while ((*f1 != 0) && (*f1 != '.')) f1++;
-
 
268
          while ((*f2 != 0) && (*f2 != '.')) f2++;
-
 
269
          limit = 4; /* TINYDTA structs are not nul-terminated */
-
 
270
        }
-
 
271
        /* cmp */
-
 
272
        for (i = 0; i < limit; i++) {
-
 
273
          if ((*f1 | 32) < (*f2 | 32)) return(0 - r);
-
 
274
          if ((*f1 | 32) > (*f2 | 32)) return(r);
-
 
275
          if (*f1 == 0) break;
-
 
276
          f1++;
-
 
277
          f2++;
-
 
278
        }
-
 
279
      }
-
 
280
        break;
-
 
281
      case 's': /* sort by size */
-
 
282
        if (dta1->size > dta2->size) return(r);
-
 
283
        if (dta1->size < dta2->size) return(0 - r);
-
 
284
        break;
-
 
285
      case 'd': /* sort by date */
-
 
286
        if (dta1->date_yr < dta2->date_yr) return(0 - r);
-
 
287
        if (dta1->date_yr > dta2->date_yr) return(r);
-
 
288
        if (dta1->date_mo < dta2->date_mo) return(0 - r);
-
 
289
        if (dta1->date_mo > dta2->date_mo) return(r);
-
 
290
        if (dta1->date_dy < dta2->date_dy) return(0 - r);
-
 
291
        if (dta1->date_dy > dta2->date_dy) return(r);
-
 
292
        if (dta1->time_hour < dta2->time_hour) return(0 - r);
-
 
293
        if (dta1->time_hour > dta2->time_hour) return(r);
-
 
294
        if (dta1->time_min < dta2->time_min) return(0 - r);
-
 
295
        if (dta1->time_min > dta2->time_min) return(r);
-
 
296
        break;
-
 
297
    }
-
 
298
 
-
 
299
    if (*ordconf == 0) break;
-
 
300
    ordconf++;
-
 
301
  }
-
 
302
 
-
 
303
  return(0);
-
 
304
}
-
 
305
 
189
 
306
 
190
#define DIR_ATTR_DEFAULT (DOS_ATTR_RO | DOS_ATTR_DIR | DOS_ATTR_ARC)
307
#define DIR_ATTR_DEFAULT (DOS_ATTR_RO | DOS_ATTR_DIR | DOS_ATTR_ARC)
191
 
308
 
192
static enum cmd_result cmd_dir(struct cmd_funcparam *p) {
309
static enum cmd_result cmd_dir(struct cmd_funcparam *p) {
193
  const char *filespecptr = NULL;
310
  const char *filespecptr = NULL;
194
  struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */
311
  struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */
195
  struct DTA far *dtabuf = NULL; /* used to buffer results when sorting is enabled */
312
  struct TINYDTA far *dtabuf = NULL; /* used to buffer results when sorting is enabled */
196
  struct DTA far *dtabuf_root = NULL;
-
 
197
  unsigned short dtabufcount = 0;
313
  unsigned short dtabufcount = 0;
198
  unsigned short i;
314
  unsigned short i;
199
  unsigned short availrows;  /* counter of available rows on display (used for /P) */
315
  unsigned short availrows;  /* counter of available rows on display (used for /P) */
200
  unsigned short screenw = screen_getwidth();
316
  unsigned short screenw = screen_getwidth();
201
  unsigned short wcols = screenw / WCOLWIDTH; /* number of columns in wide mode */
317
  unsigned short wcols = screenw / WCOLWIDTH; /* number of columns in wide mode */
202
  unsigned char wcolcount;
318
  unsigned char wcolcount;
203
  struct {
319
  struct {
204
    struct nls_patterns nls;
320
    struct nls_patterns nls;
205
    char buff64[64];
321
    char buff64[64];
206
    char path[128];
322
    char path[128];
-
 
323
    unsigned short orderidx[65535 / sizeof(struct TINYDTA)];
207
  } *buf = (void *)(p->BUFFER);
324
  } *buf = (void *)(p->BUFFER);
208
  unsigned long summary_fcount = 0;
325
  unsigned long summary_fcount = 0;
209
  unsigned long summary_totsz = 0;
326
  unsigned long summary_totsz = 0;
210
  unsigned char drv = 0;
327
  unsigned char drv = 0;
211
  unsigned char attrfilter_may = DIR_ATTR_DEFAULT;
328
  unsigned char attrfilter_may = DIR_ATTR_DEFAULT;
212
  unsigned char attrfilter_must = 0;
329
  unsigned char attrfilter_must = 0;
213
  const char far *order = NULL; /* order string (like "GNE-SD"), this may come
-
 
214
                                   either from the /O argument or from the
-
 
215
                                   DIRCMD env variable (NULL = "no sort")
-
 
216
                                   note 1: the '-' reverse relates only to
-
 
217
                                   the letter that immediately follows it
-
 
218
                                   note 2: '/O' is a shorthand for '/OGNE' */
-
 
219
 
330
 
220
  #define DIR_FLAG_PAUSE  1
331
  #define DIR_FLAG_PAUSE  1
221
  #define DIR_FLAG_RECUR  4
332
  #define DIR_FLAG_RECUR  4
222
  #define DIR_FLAG_LCASE  8
333
  #define DIR_FLAG_LCASE  8
-
 
334
  #define DIR_FLAG_SORT  16
223
  unsigned char flags = 0;
335
  unsigned char flags = 0;
224
 
336
 
225
  #define DIR_OUTPUT_NORM 1
337
  #define DIR_OUTPUT_NORM 1
226
  #define DIR_OUTPUT_WIDE 2
338
  #define DIR_OUTPUT_WIDE 2
227
  #define DIR_OUTPUT_BARE 3
339
  #define DIR_OUTPUT_BARE 3
228
  unsigned char format = DIR_OUTPUT_NORM;
340
  unsigned char format = DIR_OUTPUT_NORM;
229
 
341
 
-
 
342
  /* make sure there's no risk of buffer overflow */
-
 
343
  if (sizeof(buf) > p->BUFFERSZ) {
-
 
344
    outputnl("INTERNAL MEM ERROR IN " __FILE__);
-
 
345
    return(CMD_FAIL);
-
 
346
  }
-
 
347
 
-
 
348
  bzero(&glob_sortcmp_dat, sizeof(glob_sortcmp_dat));
-
 
349
 
230
  if (cmd_ishlp(p)) {
350
  if (cmd_ishlp(p)) {
231
    nls_outputnl(37,0); /* "Displays a list of files and subdirectories in a directory" */
351
    nls_outputnl(37,0); /* "Displays a list of files and subdirectories in a directory" */
232
    outputnl("");
352
    outputnl("");
233
    nls_outputnl(37,1); /* "DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]" */
353
    nls_outputnl(37,1); /* "DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]" */
234
    outputnl("");
354
    outputnl("");
Line 298... Line 418...
298
        case 'L':
418
        case 'L':
299
          flags |= DIR_FLAG_LCASE;
419
          flags |= DIR_FLAG_LCASE;
300
          break;
420
          break;
301
        case 'o':
421
        case 'o':
302
        case 'O':
422
        case 'O':
-
 
423
          if (process_order_directive(arg+1) != 0) {
-
 
424
            nls_output_err(0, 3); /* invalid parameter format */
-
 
425
            output(": ");
303
          order = arg+1;
426
            outputnl(arg);
-
 
427
            return(CMD_FAIL);
-
 
428
          }
-
 
429
          flags |= DIR_FLAG_SORT;
304
          break;
430
          break;
305
        case 'p':
431
        case 'p':
306
        case 'P':
432
        case 'P':
307
          flags |= DIR_FLAG_PAUSE;
433
          flags |= DIR_FLAG_PAUSE;
308
          if (neg) flags &= (0xff ^ DIR_FLAG_PAUSE);
434
          if (neg) flags &= (0xff ^ DIR_FLAG_PAUSE);
Line 378... Line 504...
378
    nls_outputnl_doserr(i);
504
    nls_outputnl_doserr(i);
379
    return(CMD_FAIL);
505
    return(CMD_FAIL);
380
  }
506
  }
381
 
507
 
382
  /* if sorting is involved, then let's buffer all results (and sort them) */
508
  /* if sorting is involved, then let's buffer all results (and sort them) */
383
  if (order != NULL) {
509
  if (flags & DIR_FLAG_SORT) {
384
    /* allocate a memory buffer - try several sizes until one succeeds */
510
    /* allocate a memory buffer - try several sizes until one succeeds */
385
    const unsigned short memsz[] = {65500, 32000, 16000, 8000, 4000, 2000, 1000, 0};
511
    const unsigned short memsz[] = {65500, 32000, 16000, 8000, 4000, 2000, 1000, 0};
386
    unsigned short max_dta_bufcount = 0;
512
    unsigned short max_dta_bufcount = 0;
387
    for (i = 0; memsz[i] != 0; i++) {
513
    for (i = 0; memsz[i] != 0; i++) {
388
      dtabuf = _fmalloc(memsz[i]);
514
      dtabuf = _fmalloc(memsz[i]);
Line 393... Line 519...
393
      nls_outputnl_doserr(8); /* out of memory */
519
      nls_outputnl_doserr(8); /* out of memory */
394
      return(CMD_FAIL);
520
      return(CMD_FAIL);
395
    }
521
    }
396
 
522
 
397
    /* remember the address so I can free it afterwards */
523
    /* remember the address so I can free it afterwards */
398
    dtabuf_root = dtabuf;
524
    glob_sortcmp_dat.dtabuf_root = dtabuf;
399
 
525
 
400
    /* compute the amount of DTAs I can buffer */
526
    /* compute the amount of DTAs I can buffer */
401
    max_dta_bufcount = memsz[i] / sizeof(struct TINYDTA);
527
    max_dta_bufcount = memsz[i] / sizeof(struct TINYDTA);
402
    printf("max_dta_bufcount = %u\n", max_dta_bufcount);
528
    /* printf("max_dta_bufcount = %u\n", max_dta_bufcount); */
403
 
529
 
404
    do {
530
    do {
405
      /* filter out files with uninteresting attributes */
531
      /* filter out files with uninteresting attributes */
406
      if (filter_attribs(dta, attrfilter_must, attrfilter_may) == 0) continue;
532
      if (filter_attribs(dta, attrfilter_must, attrfilter_may) == 0) continue;
407
 
533
 
-
 
534
      /* normalize "size" of directories to zero because kernel returns garbage
-
 
535
       * sizes for directories which might confuse the sorting routine later */
-
 
536
      if (dta->attr & DOS_ATTR_DIR) dta->size = 0;
-
 
537
 
408
      _fmemcpy(&(dtabuf[dtabufcount]), ((char *)dta) + 22, sizeof(struct TINYDTA));
538
      _fmemcpy(&(dtabuf[dtabufcount]), ((char *)dta) + 22, sizeof(struct TINYDTA));
409
 
539
 
410
      /* save attribs in sec field, otherwise zero it (this field is not
540
      /* save attribs in sec field, otherwise zero it (this field is not
411
       * displayed and dropping the attr field saves 2 bytes per entry) */
541
       * displayed and dropping the attr field saves 2 bytes per entry) */
412
      dtabuf[dtabufcount++].time_sec2 = (dta->attr & 31);
542
      dtabuf[dtabufcount++].time_sec2 = (dta->attr & 31);
413
 
543
 
414
      /* do I have any space left? */
544
      /* do I have any space left? */
415
      if (dtabufcount == max_dta_bufcount) {
545
      if (dtabufcount == max_dta_bufcount) {
-
 
546
        //TODO some kind of user notification might be nice here
416
        //outputnl("TOO MANY ENTRIES FOR SORTING! LIST IS UNSORTED");
547
        //outputnl("TOO MANY ENTRIES FOR SORTING! LIST IS UNSORTED");
417
        break;
548
        break;
418
      }
549
      }
419
 
550
 
420
    } while (findnext(dta) == 0);
551
    } while (findnext(dta) == 0);
421
 
552
 
422
    /* sort the list - the tricky part is that my array is a far address while
553
    /* sort the list - the tricky part is that my array is a far address while
423
     * qsort works only with near pointers, so I have to use an ugly auxiliary
554
     * qsort works only with near pointers, so I have to use an ugly (and
424
     * table */
555
     * global) auxiliary table */
-
 
556
    for (i = 0; i < dtabufcount; i++) buf->orderidx[i] = i;
425
    // qsort(dt); TODO
557
    qsort(buf->orderidx, dtabufcount, 2, &sortcmp);
426
 
558
 
427
    /* preload first entry */
-
 
428
    _fmemcpy(((unsigned char *)dta) + 22, dtabuf, sizeof(struct TINYDTA));
559
    /* preload first entry (last from orderidx, since entries are sorted in reverse) */
429
    dta->attr = dtabuf->time_sec2;
-
 
430
    dtabuf++;
-
 
431
    dtabufcount--;
560
    dtabufcount--;
-
 
561
    _fmemcpy(((unsigned char *)dta) + 22, &(dtabuf[buf->orderidx[dtabufcount]]), sizeof(struct TINYDTA));
-
 
562
    dta->attr = dtabuf[buf->orderidx[dtabufcount]].time_sec2; /* restore attr from the abused time_sec2 field */
432
  }
563
  }
433
 
564
 
434
  wcolcount = 0; /* may be used for columns counting with wide mode */
565
  wcolcount = 0; /* may be used for columns counting with wide mode */
435
 
566
 
436
  for (;;) {
567
  for (;;) {
Line 507... Line 638...
507
 
638
 
508
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
639
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
509
 
640
 
510
    /* take next entry, either from buf or disk */
641
    /* take next entry, either from buf or disk */
511
    if (dtabufcount > 0) {
642
    if (dtabufcount > 0) {
512
      /* preload first entry */
-
 
513
      _fmemcpy(((unsigned char *)dta) + 22, dtabuf, sizeof(struct TINYDTA));
-
 
514
      dta->attr = dtabuf->time_sec2;
-
 
515
      dtabuf++;
-
 
516
      dtabufcount--;
643
      dtabufcount--;
-
 
644
      _fmemcpy(((unsigned char *)dta) + 22, &(dtabuf[buf->orderidx[dtabufcount]]), sizeof(struct TINYDTA));
-
 
645
      dta->attr = dtabuf[buf->orderidx[dtabufcount]].time_sec2; /* restore attr from the abused time_sec2 field */
517
    } else {
646
    } else {
518
      if (findnext(dta) != 0) break;
647
      if (findnext(dta) != 0) break;
519
    }
648
    }
520
 
649
 
521
  }
650
  }
Line 552... Line 681...
552
    nls_outputnl(37,24); /* "bytes free" */
681
    nls_outputnl(37,24); /* "bytes free" */
553
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
682
    if (flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
554
  }
683
  }
555
 
684
 
556
  /* free the buffer memory (if used) */
685
  /* free the buffer memory (if used) */
557
  if (dtabuf_root != NULL) _ffree(dtabuf_root);
686
  if (glob_sortcmp_dat.dtabuf_root != NULL) _ffree(glob_sortcmp_dat.dtabuf_root);
558
 
687
 
559
  return(CMD_OK);
688
  return(CMD_OK);
560
}
689
}