home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / dmake40.zip / msdos / dirlib.c < prev    next >
C/C++ Source or Header  |  1994-10-23  |  6KB  |  286 lines

  1. /*
  2.             DIRLIB for MS-DOS
  3.             -----------------
  4.  
  5. Enclosed is an implementation of the `dirlib' package for MS-DOS.  
  6. The implementation is targeted for MS-C, although any reasonably
  7. competent C compiler should manage.  The package consists of:
  8.  
  9.     dir.h        the header file
  10.     dir.c        the functions
  11.     testdir.c    a q&d test program
  12.     
  13. The package tries to view directory naming in a Un*x light; in particular,
  14. directories such as '/.' and '/..' (as well as `.' and `..' if your
  15. current directory is root) are understood.   Indefinite paths like 
  16. `/../.././../..' will correctly refer to the root (of the particular disk).
  17. Names such as `a:////./../' are okay too.
  18.  
  19. I've tried to be as sensible about DTA's as possible, since you never
  20. know who will be using one; they are set before use, and reset afterwards.
  21.  
  22. There is some cruft in the package, namely the way `seekdir' and
  23. `telldir' are done.  The code was derived from a little experimentation, 
  24. and may not work after a certain point (although I believe the 2.x version
  25. to be solid).  Caveat utilitor.
  26.  
  27. Documentation for the package is available in the public domain; the
  28. package's functionality was derived from this documentation.
  29.  
  30. Bug reports and comments are welcome.  Enjoy!
  31.  
  32.                 - Matt
  33.  
  34. -------
  35. UUCP:    {ucbvax,ihnp4,randvax,trwrb!trwspp,ism780}!ucla-cs!matt
  36. ARPA:    matt@LOCUS.UCLA.EDU
  37. Ph:    (213) 825-2756
  38.  
  39. --------
  40. Modified for use in dmake by Dennis Vadura.  Mostly just clean up and an
  41. effort to make correctly typed objects are passed to functions in find.c.
  42. Also deleted all dos version 2.0 specific code.  It is not required any
  43. more.
  44. */
  45.  
  46. /*
  47.  * revision history:
  48.  *
  49.  *    VER    MM/DD/YY    COMMENTS
  50.  *    ----    --------    --------
  51.  *    0.99    02/24/86    Beta release to INTERNET
  52.  */
  53.  
  54. #include <stdlib.h>
  55. #include <ctype.h>
  56. #include <errno.h>
  57. #include <string.h>
  58. #include <dos.h>
  59.  
  60. #include "dirent.h"
  61.  
  62. static int _err;
  63.  
  64.  
  65. static char *
  66. getdcwd(drive)
  67. int drive;
  68. {
  69.    union REGS r;
  70.    struct SREGS s;
  71.    static char xcwd[64];
  72.    char far *cwd = xcwd;
  73.  
  74.    r.h.ah = 0x47;
  75.    r.h.dl = drive;
  76.    r.x.si = FP_OFF(cwd);
  77.    s.ds = FP_SEG(cwd);
  78.    intdosx(&r, &r, &s);
  79.    _err = r.x.ax;
  80.    if (r.x.cflag)
  81.       return (char *) 0;
  82.    return xcwd;
  83. }
  84.  
  85.  
  86.  
  87. /*
  88.  * opendir
  89.  */
  90.  
  91. #define SUFFIX    "\\*.*"
  92. #define    SLASH    "\\"
  93. #define streq(a,b)    (strcmp(a,b)==0)
  94.  
  95. DIR *
  96. opendir(name)
  97. char *name;
  98. {
  99.    register DIR *nd;
  100.    char *cwd;
  101.    char drive[3];
  102.    int atroot = 0;
  103.    int rooted = 0;
  104.  
  105.    /*
  106.    * hack off drive designator if present
  107.    */
  108.  
  109.    if (name[1] == ':') {
  110.       cwd = getdcwd(toupper(name[0]) - 'A' + 1);
  111.       drive[0] = name[0]; drive[1] = ':'; drive[2] = '\0';
  112.       name += 2;
  113.    }
  114.    else {
  115.       cwd = getdcwd(0);
  116.       drive[0] = '\0';
  117.    }
  118.  
  119.    /* is the name 'rooted'? */
  120.    if ((*name == '/') || (*name == '\\')) ++rooted;
  121.  
  122.    /* see if we are at the root directory for this device */
  123.    if (!*cwd) ++atroot;
  124.  
  125.    /* 
  126.    * MSDOS '/' doesn't have a '.' or '..'
  127.    * also, double '/' sequences don't make sense.
  128.    * many ported programs expect them to work, so we fix it up...
  129.    */
  130.  
  131.    /* chop off leading . and .. if at root */
  132.    if (atroot && (*name == '.')) {
  133.       switch (*++name) {
  134.      case '\0':
  135.      case '/':
  136.      case '\\':
  137.         break;
  138.  
  139.      case '.':
  140.         switch (*++name) {
  141.            case '\0':
  142.            case '/':
  143.            case '\\':
  144.             break;
  145.            default:
  146.             --name; 
  147.             --name;
  148.         }
  149.         break;
  150.  
  151.      default:
  152.         --name;
  153.       }
  154.    }
  155.  
  156.    /* chop off leading /'s, /.'s and /..'s to make naming sensible */
  157.    while (*name && ((*name == '/') || (*name == '\\'))) {
  158.       if (*++name == '.') {
  159.      switch (*++name) {
  160.         case '\0':
  161.         case '/':
  162.         case '\\':
  163.            break;
  164.  
  165.         case '.':
  166.            switch (*++name) {
  167.           case '\0':
  168.           case '/':
  169.           case '\\':
  170.               break;
  171.  
  172.          default:
  173.               --name; 
  174.               --name;
  175.            }
  176.            break;
  177.  
  178.         default:
  179.            --name;
  180.      }
  181.       }
  182.    }
  183.  
  184.  
  185.    /*
  186.    * name should now look like: path/path/path 
  187.    * we must now construct name based on whether or not it
  188.    * was 'rooted' (started with a /)
  189.    */
  190.  
  191.    if (rooted) cwd = "";
  192.  
  193.    /* construct DIR */
  194.    if (!(nd = (DIR *)malloc(
  195.       sizeof(DIR)+strlen(drive)+strlen(cwd)+strlen(SLASH)+
  196.       strlen(name)+strlen(SUFFIX))))
  197.       return (DIR *) 0;
  198.  
  199.    /* create long name */
  200.    strcpy(nd->dd_name, drive);
  201.    if (*cwd) {
  202.       strcat(nd->dd_name, SLASH);
  203.       strcat(nd->dd_name, cwd);
  204.    }
  205.    if (*name) {
  206.       strcat(nd->dd_name, SLASH);
  207.       strcat(nd->dd_name, name);
  208.    }
  209.    strcat(nd->dd_name, SUFFIX);
  210.  
  211.    /* search */
  212.    if (!findfirst(&nd->dd_name[0], &nd->dd_dta)) {
  213.       free((char *)nd);
  214.       errno = ENOENT;
  215.       return (DIR *) 0;
  216.    }
  217.    nd->dd_stat = 0;
  218.    return nd;
  219. }
  220.  
  221.  
  222. struct dirent *
  223. readdir(dirp)
  224. DIR *dirp;
  225. {
  226.    static struct dirent dir;
  227.  
  228.    if (dirp->dd_stat)
  229.       return (struct dirent *) 0;
  230.  
  231.    /* format structure */
  232.    dir.d_ino = 0; /* not valid for DOS */
  233.    dir.d_reclen = 0;
  234.    strcpy(dir.d_name, dirp->dd_dta.name);
  235.    dir.d_namlen = strlen(dir.d_name);
  236.    strlwr(dir.d_name); /* DOSism */
  237.  
  238.    /* read ahead */
  239.    if (findnext(&dirp->dd_dta))
  240.       dirp->dd_stat = 0;
  241.    else        
  242.       dirp->dd_stat = _err;
  243.  
  244.    return &dir;
  245. }
  246.  
  247.  
  248. void
  249. closedir(dirp)
  250. DIR *dirp;
  251. {
  252.    free((char *)dirp);
  253. }
  254.  
  255.  
  256. void
  257. seekdir(dirp, pos)
  258. DIR *dirp;
  259. long pos;
  260. {
  261.    /*
  262.    * check against DOS limits
  263.    */
  264.  
  265.    if ((pos < 0) || (pos > 4095)) {
  266.       dirp->dd_stat = 1;
  267.       return;
  268.    }
  269.  
  270.    *(short *)&dirp->dd_dta.fcb[13] = pos + 1;
  271.  
  272.    /* read ahead */
  273.    if (findnext(&dirp->dd_dta))
  274.       dirp->dd_stat = 0;
  275.    else        
  276.       dirp->dd_stat = _err;
  277. }
  278.  
  279.  
  280. long
  281. telldir(dirp)
  282. DIR *dirp;
  283. {
  284.    return (long) (*(short *)&dirp->dd_dta.fcb[13] - 2);
  285. }
  286.