Subversion Repositories SvarDOS

Rev

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

Rev 2190 Rev 2193
Line 141... Line 141...
141
    *availrows = screen_getheight() - 1;
141
    *availrows = screen_getheight() - 1;
142
  }
142
  }
143
}
143
}
144
 
144
 
145
 
145
 
-
 
146
/* add a new dirname to path, C:\XXX\*.EXE + YYY -> C:\XXX\YYY\*.EXE */
-
 
147
static void path_add(char *path, const char *dirname) {
-
 
148
  short i, ostatni = -1, slen;
-
 
149
  printf("path_add(%s,%s) -> ", path, dirname);
-
 
150
  /* find the last backslash */
-
 
151
  for (i = 0; path[i] != 0; i++) {
-
 
152
    if (path[i] == '\\') ostatni = i;
-
 
153
  }
-
 
154
  /* abort on error */
-
 
155
  if (ostatni == -1) return;
-
 
156
  /* do the trick */
-
 
157
  slen = strlen(dirname);
-
 
158
  memmove(path + ostatni + slen + 1, path + ostatni, slen + 1);
-
 
159
  memcpy(path + ostatni + 1, dirname, slen);
-
 
160
  printf("'%s'\n", path);
-
 
161
}
-
 
162
 
-
 
163
 
-
 
164
/* take back last dir from path, C:\XXX\YYY\*.EXE -> C:\XXX\*.EXE */
-
 
165
static void path_back(char *path) {
-
 
166
  short i, ostatni = -1, przedostatni = -1;
-
 
167
  /* find the two last backslashes */
-
 
168
  for (i = 0; path[i] != 0; i++) {
-
 
169
    if (path[i] == '\\') {
-
 
170
      przedostatni = ostatni;
-
 
171
      ostatni = i;
-
 
172
    }
-
 
173
  }
-
 
174
  /* abort on error */
-
 
175
  if (przedostatni == -1) return;
-
 
176
  /* do the trick */
-
 
177
  for (i = przedostatni; path[i] != 0; i++) {
-
 
178
    path[i] = path[ostatni++];
-
 
179
  }
-
 
180
}
-
 
181
 
-
 
182
 
146
/* parse an attr list like "Ar-hS" and fill bitfield into attrfilter_may and attrfilter_must.
183
/* parse an attr list like "Ar-hS" and fill bitfield into attrfilter_may and attrfilter_must.
147
 * /AHS   -> adds S and H to mandatory attribs ("must")
184
 * /AHS   -> adds S and H to mandatory attribs ("must")
148
 * /A-S   -> removes S from allowed attribs ("may")
185
 * /A-S   -> removes S from allowed attribs ("may")
149
 * returns non-zero on error. */
186
 * returns non-zero on error. */
150
static int dir_parse_attr_list(const char *arg, unsigned char *attrfilter_may, unsigned char *attrfilter_must) {
187
static int dir_parse_attr_list(const char *arg, unsigned char *attrfilter_may, unsigned char *attrfilter_must) {
Line 415... Line 452...
415
          req->flags |= DIR_FLAG_PAUSE;
452
          req->flags |= DIR_FLAG_PAUSE;
416
          if (neg) req->flags &= (0xff ^ DIR_FLAG_PAUSE);
453
          if (neg) req->flags &= (0xff ^ DIR_FLAG_PAUSE);
417
          break;
454
          break;
418
        case 's':
455
        case 's':
419
        case 'S':
456
        case 'S':
420
          /* TODO */
-
 
421
          outputnl("/S NOT IMPLEMENTED YET");
457
          req->flags |= DIR_FLAG_RECUR;
422
          return(-1);
-
 
423
          break;
458
          break;
424
        case 'w':
459
        case 'w':
425
        case 'W':
460
        case 'W':
426
          req->format = DIR_OUTPUT_WIDE;
461
          req->format = DIR_OUTPUT_WIDE;
427
          break;
462
          break;
Line 440... Line 475...
440
 
475
 
441
  return(0);
476
  return(0);
442
}
477
}
443
 
478
 
444
 
479
 
-
 
480
#define MAX_SORTABLE_FILES 8192
-
 
481
 
445
static enum cmd_result cmd_dir(struct cmd_funcparam *p) {
482
static enum cmd_result cmd_dir(struct cmd_funcparam *p) {
446
  struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */
483
  struct DTA *dta = (void *)0x80; /* set DTA to its default location at 80h in PSP */
447
  struct TINYDTA far *dtabuf = NULL; /* used to buffer results when sorting is enabled */
484
  struct TINYDTA far *dtabuf = NULL; /* used to buffer results when sorting is enabled */
448
  unsigned short dtabufcount = 0;
485
  unsigned short dtabufcount = 0;
449
  unsigned short i;
486
  unsigned short i;
Line 453... Line 490...
453
  unsigned char wcolcount;
490
  unsigned char wcolcount;
454
  struct {
491
  struct {
455
    struct nls_patterns nls;
492
    struct nls_patterns nls;
456
    char buff64[64];
493
    char buff64[64];
457
    char path[128];
494
    char path[128];
-
 
495
    struct DTA dtastack[64]; /* used for /S, max number of subdirs in DOS5 is 42 (A/B/C/...) */
-
 
496
    unsigned char dirpending; /* set if a dir has been added to dtastack */
-
 
497
    unsigned char dtastacklen;
458
    unsigned short orderidx[65535 / sizeof(struct TINYDTA)];
498
    unsigned short orderidx[MAX_SORTABLE_FILES / sizeof(struct TINYDTA)];
459
  } *buf = (void *)(p->BUFFER);
499
  } *buf;
460
  unsigned long summary_fcount = 0;
500
  unsigned long summary_fcount = 0;
461
  unsigned long summary_totsz = 0;
501
  unsigned long summary_totsz = 0;
462
  unsigned char drv = 0;
502
  unsigned char drv = 0;
463
  struct dirrequest req;
503
  struct dirrequest req;
464
 
504
 
465
  /* make sure there's no risk of buffer overflow */
-
 
466
  if (sizeof(*buf) > p->BUFFERSZ) {
-
 
467
    sprintf(p->BUFFER, "INTERNAL DIR ERROR: p->BUFFERSZ=%u / required=%u", p->BUFFERSZ, sizeof(*buf));
-
 
468
    outputnl(p->BUFFER);
-
 
469
    return(CMD_FAIL);
-
 
470
  }
-
 
471
 
-
 
472
  if (cmd_ishlp(p)) {
505
  if (cmd_ishlp(p)) {
473
    nls_outputnl(37,0); /* "Displays a list of files and subdirectories in a directory" */
506
    nls_outputnl(37,0); /* "Displays a list of files and subdirectories in a directory" */
474
    outputnl("");
507
    outputnl("");
475
    nls_outputnl(37,1); /* "DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]" */
508
    nls_outputnl(37,1); /* "DIR [drive:][path][filename] [/P] [/W] [/A[:]attributes] [/O[[:]sortorder]] [/S] [/B] [/L]" */
476
    outputnl("");
509
    outputnl("");
Line 486... Line 519...
486
    nls_outputnl(37,9); /* "    D by date                G group dirs first       - prefix to reverse order" */
519
    nls_outputnl(37,9); /* "    D by date                G group dirs first       - prefix to reverse order" */
487
    outputnl("");
520
    outputnl("");
488
    nls_outputnl(37,10); /* "/S Displays files in specified directory and all subdirectories" */
521
    nls_outputnl(37,10); /* "/S Displays files in specified directory and all subdirectories" */
489
    nls_outputnl(37,11); /* "/B Uses bare format (no heading information or summary)" */
522
    nls_outputnl(37,11); /* "/B Uses bare format (no heading information or summary)" */
490
    nls_outputnl(37,12); /* "/L Uses lowercases" */
523
    nls_outputnl(37,12); /* "/L Uses lowercases" */
491
    return(CMD_OK);
524
    goto OK;
-
 
525
  }
-
 
526
 
-
 
527
  /* allocate buf */
-
 
528
  buf = calloc(sizeof(*buf), 1);
-
 
529
  if (buf == NULL) {
-
 
530
    nls_output_err(255, 8); /* insufficient memory */
-
 
531
    goto FAIL;
492
  }
532
  }
493
 
533
 
494
  /* zero out glob_sortcmp_dat and init the collation table */
534
  /* zero out glob_sortcmp_dat and init the collation table */
495
  bzero(&glob_sortcmp_dat, sizeof(glob_sortcmp_dat));
535
  bzero(&glob_sortcmp_dat, sizeof(glob_sortcmp_dat));
496
  for (i = 0; i < 256; i++) {
536
  for (i = 0; i < 256; i++) {
Line 582... Line 622...
582
    cmd_explode(buf->buff64, dircmd, argvptrs);
622
    cmd_explode(buf->buff64, dircmd, argvptrs);
583
    if ((dir_parse_cmdline(&req, argvptrs) != 0) || (req.filespecptr != NULL)) {
623
    if ((dir_parse_cmdline(&req, argvptrs) != 0) || (req.filespecptr != NULL)) {
584
      nls_output(255, 10);/* bad environment */
624
      nls_output(255, 10);/* bad environment */
585
      output(" - ");
625
      output(" - ");
586
      outputnl("DIRCMD");
626
      outputnl("DIRCMD");
587
      return(CMD_FAIL);
627
      goto FAIL;
588
    }
628
    }
589
  }
629
  }
590
  }
630
  }
591
 
631
 
592
  /* parse user's command line */
632
  /* parse user's command line */
593
  if (dir_parse_cmdline(&req, p->argv) != 0) return(CMD_FAIL);
633
  if (dir_parse_cmdline(&req, p->argv) != 0) goto FAIL;
594
 
-
 
595
  /* if no filespec provided, then it's about the current directory */
-
 
596
  if (req.filespecptr == NULL) req.filespecptr = ".";
-
 
597
 
634
 
598
  /*** PARSING COMMAND LINE DONE *********************************************/
635
  /*** PARSING COMMAND LINE DONE *********************************************/
599
 
636
 
-
 
637
  /* if no filespec provided, then it's about the current directory */
-
 
638
  if (req.filespecptr == NULL) req.filespecptr = ".";
600
 
639
 
601
  availrows = screen_getheight() - 2;
640
  availrows = screen_getheight() - 2;
602
 
641
 
603
  /* special case: "DIR drive:" (truename() fails on "C:" under MS-DOS 6.0) */
642
  /* special case: "DIR drive:" (truename() fails on "C:" under MS-DOS 6.0) */
604
  if ((req.filespecptr[0] != 0) && (req.filespecptr[1] == ':') && (req.filespecptr[2] == 0)) {
643
  if ((req.filespecptr[0] != 0) && (req.filespecptr[1] == ':') && (req.filespecptr[2] == 0)) {
Line 611... Line 650...
611
  } else {
650
  } else {
612
    i = file_truename(req.filespecptr, buf->path);
651
    i = file_truename(req.filespecptr, buf->path);
613
  }
652
  }
614
  if (i != 0) {
653
  if (i != 0) {
615
    nls_outputnl_doserr(i);
654
    nls_outputnl_doserr(i);
616
    return(CMD_FAIL);
655
    goto FAIL;
617
  }
656
  }
618
 
657
 
619
  if (req.format != DIR_OUTPUT_BARE) {
658
  if (req.format != DIR_OUTPUT_BARE) {
620
    drv = buf->path[0];
659
    drv = buf->path[0];
621
    if (drv >= 'a') {
660
    if (drv >= 'a') {
Line 636... Line 675...
636
  i = path_appendbkslash_if_dir(buf->path);
675
  i = path_appendbkslash_if_dir(buf->path);
637
 
676
 
638
  /* if ends with a \ then append ????????.??? */
677
  /* if ends with a \ then append ????????.??? */
639
  if (buf->path[i - 1] == '\\') strcat(buf->path, "????????.???");
678
  if (buf->path[i - 1] == '\\') strcat(buf->path, "????????.???");
640
 
679
 
-
 
680
  NEXT_ITER: /* re-entry point for /S recursing */
-
 
681
 
641
  /* ask DOS for list of files, but only with allowed attribs */
682
  /* ask DOS for list of files, but only with allowed attribs (+directories, because
-
 
683
   * I need them for /S) */
642
  i = findfirst(dta, buf->path, req.attrfilter_may);
684
  i = findfirst(dta, buf->path, req.attrfilter_may | DIR_FLAG_RECUR);
643
  if (i != 0) {
685
  if (i != 0) {
644
    nls_outputnl_doserr(i);
686
    nls_outputnl_doserr(i);
645
    return(CMD_FAIL);
687
    goto FAIL;
646
  }
688
  }
647
 
689
 
648
  /* if sorting is involved, then let's buffer all results (and sort them) */
690
  /* if sorting is involved, then let's buffer all results (and sort them) */
649
  if (req.flags & DIR_FLAG_SORT) {
691
  if (req.flags & DIR_FLAG_SORT) {
650
    /* allocate a memory buffer - try several sizes until one succeeds */
692
    /* allocate a memory buffer - try several sizes until one succeeds */
Line 655... Line 697...
655
      if (dtabuf != NULL) break;
697
      if (dtabuf != NULL) break;
656
    }
698
    }
657
 
699
 
658
    if (dtabuf == NULL) {
700
    if (dtabuf == NULL) {
659
      nls_outputnl_doserr(8); /* out of memory */
701
      nls_outputnl_doserr(8); /* out of memory */
660
      return(CMD_FAIL);
702
      goto FAIL;
661
    }
703
    }
662
 
704
 
663
    /* remember the address so I can free it afterwards */
705
    /* remember the address so I can free it afterwards */
664
    glob_sortcmp_dat.dtabuf_root = dtabuf;
706
    glob_sortcmp_dat.dtabuf_root = dtabuf;
665
 
707
 
666
    /* compute the amount of DTAs I can buffer */
708
    /* compute the amount of DTAs I can buffer */
667
    max_dta_bufcount = memsz[i] / sizeof(struct TINYDTA);
709
    max_dta_bufcount = memsz[i] / sizeof(struct TINYDTA);
-
 
710
    if (max_dta_bufcount > MAX_SORTABLE_FILES) max_dta_bufcount = MAX_SORTABLE_FILES;
668
    /* printf("max_dta_bufcount = %u\n", max_dta_bufcount); */
711
    /* printf("max_dta_bufcount = %u\n", max_dta_bufcount); */
669
 
712
 
670
    do {
713
    do {
-
 
714
      /* if /S then remember first directory encountered (but not . nor ..) */
-
 
715
      if ((req.flags & DIR_FLAG_RECUR) && (buf->dirpending == 0) && (dta->attr & DOS_ATTR_DIR) && (dta->fname[0] != '.')) {
-
 
716
        buf->dirpending = 1;
-
 
717
        memcpy(&(buf->dtastack[buf->dtastacklen]), dta, sizeof(struct DTA));
-
 
718
      }
-
 
719
 
671
      /* filter out files with uninteresting attributes */
720
      /* filter out files with uninteresting attributes */
672
      if (filter_attribs(dta, req.attrfilter_must, req.attrfilter_may) == 0) continue;
721
      if (filter_attribs(dta, req.attrfilter_must, req.attrfilter_may) == 0) continue;
673
 
722
 
674
      /* normalize "size" of directories to zero because kernel returns garbage
723
      /* normalize "size" of directories to zero because kernel returns garbage
675
       * sizes for directories which might confuse the sorting routine later */
724
       * sizes for directories which might confuse the sorting routine later */
Line 692... Line 741...
692
 
741
 
693
    /* no match? kein gluck! (this can happen when filtering attribs with /A:xxx
742
    /* no match? kein gluck! (this can happen when filtering attribs with /A:xxx
694
     * because while findfirst() succeeds, all entries can be rejected) */
743
     * because while findfirst() succeeds, all entries can be rejected) */
695
    if (dtabufcount == 0) {
744
    if (dtabufcount == 0) {
696
      nls_outputnl_doserr(2); /* "File not found" */
745
      nls_outputnl_doserr(2); /* "File not found" */
697
      return(CMD_FAIL);
746
      goto FAIL;
698
    }
747
    }
699
 
748
 
700
    /* sort the list - the tricky part is that my array is a far address while
749
    /* sort the list - the tricky part is that my array is a far address while
701
     * qsort works only with near pointers, so I have to use an ugly (and
750
     * qsort works only with near pointers, so I have to use an ugly (and
702
     * global) auxiliary table */
751
     * global) auxiliary table */
Line 711... Line 760...
711
 
760
 
712
  wcolcount = 0; /* may be used for columns counting with wide mode */
761
  wcolcount = 0; /* may be used for columns counting with wide mode */
713
 
762
 
714
  for (;;) {
763
  for (;;) {
715
 
764
 
-
 
765
    /* if /S then remember first directory encountered */
-
 
766
      if ((req.flags & DIR_FLAG_RECUR) && (buf->dirpending == 0) && (dta->attr & DOS_ATTR_DIR) && (dta->fname[0] != '.')) {
-
 
767
      buf->dirpending = 1;
-
 
768
      puts("GOT DIR (/S)");
-
 
769
      memcpy(&(buf->dtastack[buf->dtastacklen]), dta, sizeof(struct DTA));
-
 
770
    }
-
 
771
 
716
    /* filter out attributes (skip if entry comes from buffer, then it was already veted) */
772
    /* filter out attributes (skip if entry comes from buffer, then it was already veted) */
717
    if (filter_attribs(dta, req.attrfilter_must, req.attrfilter_may) == 0) goto NEXT_ENTRY;
773
    if (filter_attribs(dta, req.attrfilter_must, req.attrfilter_may) == 0) goto NEXT_ENTRY;
718
 
774
 
719
    /* turn string lcase (/L) */
775
    /* turn string lcase (/L) */
720
    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... */
776
    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... */
Line 834... Line 890...
834
    output(" ");
890
    output(" ");
835
    nls_outputnl(37,24); /* "bytes free" */
891
    nls_outputnl(37,24); /* "bytes free" */
836
    if (req.flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
892
    if (req.flags & DIR_FLAG_PAUSE) dir_pagination(&availrows);
837
  }
893
  }
838
 
894
 
-
 
895
  /* /S processing */
-
 
896
  if (buf->dirpending) {
-
 
897
    buf->dirpending = 0;
-
 
898
    /* add dir to path and redo scan */
-
 
899
    printf("DIR PENDING: %s\n", buf->dtastack[buf->dtastacklen].fname);
-
 
900
    path_add(buf->path, buf->dtastack[buf->dtastacklen].fname);
-
 
901
    buf->dtastacklen++;
-
 
902
    goto NEXT_ITER;
-
 
903
  }
-
 
904
  while (buf->dtastacklen > 0) {
-
 
905
    /* rewind path one directory back, pop the next dta and do a FindNext */
-
 
906
    path_back(buf->path);
-
 
907
    buf->dtastacklen--;
-
 
908
    TRYNEXTENTRY:
-
 
909
    if (findnext(&(buf->dtastack[buf->dtastacklen])) != 0) continue;
-
 
910
    if ((buf->dtastack[buf->dtastacklen].attr & DOS_ATTR_DIR) == 0) goto TRYNEXTENTRY;
-
 
911
    /* something found -> add dir to path and redo scan */
-
 
912
    path_add(buf->path, buf->dtastack[buf->dtastacklen].fname);
-
 
913
    goto NEXT_ITER;
-
 
914
  }
-
 
915
 
839
  /* free the buffer memory (if used) */
916
  /* free the buffer memory (if used) */
840
  if (glob_sortcmp_dat.dtabuf_root != NULL) _ffree(glob_sortcmp_dat.dtabuf_root);
917
  if (glob_sortcmp_dat.dtabuf_root != NULL) _ffree(glob_sortcmp_dat.dtabuf_root);
841
 
918
 
-
 
919
  FAIL:
-
 
920
  free(buf);
-
 
921
  return(CMD_FAIL);
-
 
922
 
-
 
923
  OK:
-
 
924
  free(buf);
842
  return(CMD_OK);
925
  return(CMD_OK);
843
}
926
}