home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 235_02 / pathname.c < prev    next >
Text File  |  1987-06-17  |  13KB  |  326 lines

  1. /*  003  14-Feb-87  pathname.c
  2.  
  3.         Copyright (c) 1987 by Blue Sky Software.  All rights reserved.
  4. */
  5.  
  6. #include "ov.h"                /* only needed for Strdup() define */
  7. #include "dosfile.h"
  8.  
  9. #ifndef NULL
  10. #define NULL (0)
  11. #endif
  12.  
  13. #ifndef MAX_PATHLEN
  14. #define MAX_PATHLEN (64)               /* max pathname len under MS/PC-DOS */
  15. #endif
  16.  
  17. char *strupr(), *strrchr(), *strchr(), *qualdir();
  18.  
  19. struct search_block *nxtfile();
  20.  
  21.  
  22. /****************************************************************************
  23.                           P A R S E P A T H
  24.  ****************************************************************************/
  25.  
  26. char *
  27. parsepath(refdir,reffn,target,isdir,todirp,tofnp)
  28. char *refdir, *reffn, *target, **todirp, **tofnp;
  29. int isdir;
  30. {
  31.    /* I don't know if this should really be called parsepath, but I couldn't
  32.       think of a better name.  Here's what it does: given a reference
  33.       directory specification, a reference file name, and a traget name
  34.       (dir and/or file name) it creates a fully qualified target name
  35.       consisting of a drive specification and file name.  One of the fancier
  36.       things this routine does (or has done) is expand relative dir spec's
  37.       (e.g. ..\ov) to fully qualified dir spec's (e.g. c:\src\ov).  This
  38.       requires that the reference dir be fully qualified.  parsepath()
  39.       will also return individual dir and/or file name strings if pointers
  40.       to char pointers are passed as todirp and tofnp.  If one or both of
  41.       these strings are not desired, pass the value NULL instead of a
  42.       pointer address.  All three of the parsepath() result strings are
  43.       in dynamically allocated memory that can be free'd with the free()
  44.       function.
  45.  
  46.       Oh yea, the isdir parameter tells parsepath() if the target name
  47.       is just a dir name (isdir = true) or if it contains a file name
  48.       (and maybe a dir name) (isdir = false).  This parameter was added
  49.       for performance - parsepath() doesn't need to call isadir() each
  50.       time if the caller already knows its not just a dir name.
  51.  
  52.       Note: the refdir is used as if it were the current dir when qualifying
  53.       the target name.  If the target contains no dir spec, the refdir spec
  54.       will be used.  If the target contains a relative dir spec, the refdir
  55.       will be used as the starting point (a relative dir spec is relative to
  56.       the refdir).
  57.  
  58.       BUT if the target contains a drive code that is different than the
  59.       drive code in refdir, parsepath() will call the external function
  60.       getcdir() to get the current dir spec for the target drive and use
  61.       that as the refdir instead of the passed refdir.
  62. */
  63.  
  64.    char *tmp = NULL;
  65.    char *tardir, *tarfn, *np;
  66.  
  67.    /* make sure both the reference dir and the target use \ instead of / */
  68.  
  69.    fixdirspec(refdir);  strupr(refdir);        /* uppercase to make */
  70.    fixdirspec(target);  strupr(target);        /* compares easier   */
  71.  
  72.    /* determine if the target is on the same drive as the reference,
  73.       get a new reference dir if not */
  74.  
  75.    if (strlen(target) > 1 && target[1] == ':')        /* target have a drive? */
  76.       if (*refdir != *target) {                       /* different than ref?  */
  77.          refdir = tmp = (char *) Malloc(MAX_PATHLEN+4);    /* make new refdir */
  78.          strncpy(tmp,target,2);
  79.          tmp[2] = '\\';
  80.          getcdir(*target-'A'+1,tmp+3);       /* sorta like getcwd() for drive */
  81.       }
  82.  
  83.    /* determine if the target string has a directory and/or file name */
  84.  
  85.    if (isdir) {                /* is it only a dir (no file name)? */
  86.  
  87.       tardir = Strdup(target);
  88.       tarfn  = Strdup(reffn);
  89.  
  90.    } else              /* well is it a dir and file name? */
  91.  
  92.       if ((np = strrchr(target,'\\')) || (np = strrchr(target,':'))) {
  93.          tardir = Strndup(target,np-target+1);
  94.          tarfn  = Strdup(np+1);
  95.  
  96.       } else {         /* must be just a file name */
  97.  
  98.          tardir = NULL;
  99.          tarfn  = Strdup(target);
  100.       }
  101.  
  102.    /* if a target dir was supplied, make sure its fully qualified */
  103.  
  104.    if (tardir) {
  105.       np = tardir;
  106.       tardir = qualdir(refdir,tardir);
  107.       free(np);
  108.    } else
  109.       tardir = Strdup(refdir);
  110.  
  111.    if (tmp)                    /* free locally allocated refdir string */
  112.       free(tmp);
  113.  
  114.    /* make a copy of the fully qualified name for the user */
  115.  
  116.    target = (char *) Malloc(strlen(tardir)+strlen(tarfn)+2);
  117.    strcpy(target,tardir);
  118.    if (target[strlen(target)-1] != '\\')
  119.       strcat(target,"\\");
  120.    strcat(target,tarfn);
  121.  
  122.    /* return the seperate target dir/fn strings to user or release'm */
  123.  
  124.    if (todirp)
  125.       *todirp = tardir;
  126.    else
  127.       free(tardir);
  128.  
  129.    if (tofnp)
  130.       *tofnp = tarfn;
  131.    else
  132.       free(tarfn);
  133.  
  134.    return(target);             /* return the full target name */
  135. }
  136.  
  137.  
  138. /****************************************************************************
  139.                               Q U A L D I R
  140.  ****************************************************************************/
  141.  
  142. /* This routine expands a partial dir specification to a fully qualified
  143.    dir pathname.  It requires a fully qualified refernece dir name and the
  144.    partial dir pathname.  The reference dir spec is expected to start with
  145.    a drive code and end without a trailing '\'.  The partial dir spec may
  146.    or may not contain a drive code, the qualified result will.  If an error
  147.    is encountered, this routine returns a null string. */
  148.  
  149. char *
  150. qualdir(refdir,partdir)        /* fully qualify a partial dir spec */
  151. char *refdir, *partdir;
  152. {
  153.    register char *cp, *path;
  154.    char *psave, *sp, fullpath[MAX_PATHLEN+4];
  155.  
  156.    /* setup the drive code of the resultant dir spec */
  157.  
  158.    strncpy(fullpath,refdir,3);         /* copy over "<drive>:\" */
  159.    fullpath[3] = '\0';
  160.  
  161.    refdir += 3;                        /* don't need ref drive\root again */
  162.    if (strlen(partdir) > 1 && partdir[1] == ':')   /* and don't really */
  163.       partdir += 2;                                /* need partial drive */
  164.  
  165.    /* initialize the full pathname to the reference dir name if the partial
  166.       name doesn't start at the root */
  167.  
  168.    if (*partdir == '\\')               /* partial (relative) start at root? */
  169.       partdir++;                       /* already got \ above, don't need now */
  170.  
  171.    else {                              /* must really be partial spec */
  172.  
  173.       strcat(fullpath,refdir);                 /* start from reference dir */
  174.       if (fullpath[strlen(fullpath)-1] != '\\')    /* we want trailing \ */
  175.          strcat(fullpath,"\\");                    /*   for now */
  176.    }
  177.  
  178.    cp = fullpath + strlen(fullpath);   /* always points to end of fullpath */
  179.  
  180.    path = psave = Strdup(partdir);     /* need a copy we can modify */
  181.  
  182.    /* process the partial pathname a dir at a time - still more to do
  183.       while path has something in it */
  184.  
  185.    while(strlen(path)) {
  186.  
  187.       if (sp = strchr(path,'\\'))      /* find end of current dir name */
  188.          *sp = '\0';                   /* null terminate it */
  189.  
  190.       if (strcmp(path,".") == 0)       /* "." entry is current dir */
  191.          ;                             /*   so there is nowhere to go */
  192.  
  193.       else
  194.  
  195.          if (strcmp(path,"..") == 0) {         /* ".." means goto parent dir */
  196.             *--cp = '\0';                      /* zap trailing \ */
  197.             if (cp = strrchr(fullpath,'\\'))   /* find \ before current */
  198.                *++cp = '\0';                   /* zap curr - parent now last */
  199.             else {                             /* error, no more parents! */
  200.                *fullpath = '\0';               /* return null string */
  201.                break;                          /* stop processing */
  202.             }
  203.  
  204.          } else                /* not "." or "..", must be subdir name */
  205.  
  206.             if (strlen(fullpath) + strlen(path) < sizeof(fullpath)) { /* fit? */
  207.                strcpy(cp,path);
  208.                strcat(cp,"\\");                /* add subdir to fullpath */
  209.                cp += strlen(cp);               /* add trailing \, new end */
  210.             } else {                           /* error! pathname too big */
  211.                *fullpath = '\0';
  212.                break;
  213.             }
  214.  
  215.       if (sp)                  /* if there was a \, skip beyond to chk */
  216.          path = sp + 1;        /*   for another one, otherwise there can't */
  217.       else                     /*   be anything else to process */
  218.          break;
  219.    }
  220.  
  221.    free(psave);                                /* free local copy */
  222.  
  223.    if (strlen(fullpath) > 3)                   /* remove trailing \ if */
  224.       fullpath[strlen(fullpath)-1] = '\0';     /*   not at root */
  225.  
  226.    return(Strdup(fullpath));                   /* give caller his own copy */
  227. }
  228.  
  229.  
  230. /******************************************************************************
  231.                            F I X D I R S P E C
  232.  ******************************************************************************/
  233.  
  234. fixdirspec(dir)        /* convert /'s to \'s in dir specifications */
  235. register char *dir;
  236. {
  237.    while (dir = strchr(dir,'/'))       /* make sure all /'s turned to \'s */
  238.       *dir++ = '\\';
  239. }
  240.  
  241.  
  242. /******************************************************************************
  243.                                I S A D I R
  244.  *****************************************************************************/
  245.  
  246. isadir(refdir,dir)     /* returns 1 if dir represents a directory name, */
  247. char *refdir, *dir;    /*   0 if not. */
  248. {
  249.    int firsttime;
  250.    register int s;
  251.    char *qdir, *tmp = NULL;
  252.    register struct search_block *sbp;
  253.  
  254.     /* For MSDOS, we assume the path is a directory name if it ends in \, /,
  255.        its just a drive specifier (A:), is "." or "..", or DOS says its a
  256.        directory */
  257.  
  258.    /* check the easy cases first */
  259.  
  260.    fixdirspec(dir);            /* make all /'s into \'s */
  261.  
  262.    if ((s = dir[strlen(dir)-1]) == '\\' || s == ':' || strcmp(dir,".") == 0 ||
  263.        strcmp(dir,"..") == 0)
  264.       return(1);
  265.  
  266.    /* need to ask DOS if this is a directory */
  267.  
  268.    /* determine if the target is on the same drive as the reference,
  269.       get a new reference dir if not - this is done here so it doesn't
  270.       need to be done by isadir() callers - note parsepath() does pretty
  271.       much the same thing, maybe this should be in qualdir() */
  272.  
  273.    if (strlen(dir) > 1 && dir[1] == ':')       /* target have a drive? */
  274.       if (*refdir != *dir) {                   /* different than ref?  */
  275.          refdir = tmp = (char *) Malloc(MAX_PATHLEN+4);    /* make new refdir */
  276.          strncpy(tmp,dir,2);
  277.          tmp[2] = '\\';
  278.          getcdir(*dir-'A'+1,tmp+3);          /* sorta like getcwd() for drive */
  279.       }
  280.  
  281.    qdir = qualdir(refdir,dir);         /* qualify it first */
  282.  
  283.    firsttime = 1;
  284.    s = ((sbp = nxtfile(qdir,0x10,&firsttime)) && sbp->attrib & 0x10);
  285.  
  286.    free(qdir);
  287.    if (tmp)
  288.       free(tmp);
  289.  
  290.    return(s);
  291. }
  292.  
  293.  
  294. /******************************************************************************
  295.  **                       C H A N G E _ D I R                                **
  296.  *****************************************************************************/
  297.  
  298. change_dir(dir)        /* change the current directory */
  299. register char *dir;
  300. {
  301.    int newdir, cur_drive, rc;
  302.  
  303.    rc = 0;                             /* assume all will go okay */
  304.  
  305.    if (strlen(dir) > 1 && dir[1] == ':') {     /* isolate any drive letter */
  306.       cur_drive = current_drive();             /* current drive (A,B,...) */
  307.       newdir = toupper(*dir);                  /* wanted new dir */
  308.       change_drive(newdir);                    /* switch to named drive */
  309.       if (current_drive() != newdir)           /* did we get there? */
  310.          return(-1);                           /*   no!, give up now */
  311.       dir += 2;                                /*   yes, skip over drive: */
  312.    } else
  313.       cur_drive = 0;                           /* means no drive switch */
  314.  
  315.    if (strlen(dir) > 0)                        /* is there a dir spec? */
  316.       if (chdir(dir) != 0) {                   /* switch directories */
  317.          if (cur_drive)                        /* drive switched? */
  318.             change_drive(cur_drive);           /*   error, switch back */
  319.          rc = -1;                              /* return non 0 error code */
  320.       }
  321.  
  322.    return(rc);                 /* tell caller if we worked */
  323. }
  324.  
  325.  
  326.