home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / common / filepart.c < prev    next >
C/C++ Source or Header  |  2002-01-18  |  11KB  |  476 lines

  1. /*
  2.  * This file contains pathfind(), fparse(), makename(), and smatch().
  3.  */
  4. #include "../h/gsupport.h"
  5.  
  6. static char *pathelem    (char *s, char *buf);
  7. static char *tryfile    (char *buf, char *dir, char *name, char *extn);
  8.  
  9. /*
  10.  * The following code is operating-system dependent [@filepart.01].
  11.  *
  12.  *  Define symbols for building file names.
  13.  *  1. Prefix: the characters that terminate a file name prefix
  14.  *  2. FileSep: the char to insert after a dir name, if any
  15.  *  2. DefPath: the default IPATH/LPATH, if not null
  16.  *  3. PathSep: allowable IPATH/LPATH separators, if not just " "
  17.  */
  18.  
  19. #if PORT
  20.    #define Prefix "/"
  21.    #define FileSep '/'
  22.    Deliberate Syntax Error
  23. #endif                    /* PORT */
  24.  
  25. #if AMIGA
  26.    #define Prefix "/:"
  27.    #define FileSep '/'
  28. #endif                    /* AMIGA */
  29.  
  30. #if ARM
  31.    #define Prefix ".:"
  32.    #define DefPath "Icon: Lib:Icon."
  33. #endif                    /* ARM */
  34.  
  35. #if MSDOS || OS2
  36.    #define Prefix "/:\\"
  37.    #define DefPath ";"
  38.    #if HIGHC_386
  39.       #define FileSep '\\'
  40.    #else                /* HIGHC_386 */
  41.       #define FileSep '/'
  42.    #endif                /* HIGHC_386 */
  43. #endif                    /* MSDOS || OS2 */
  44.  
  45. #if MACINTOSH
  46.    #define Prefix ":"
  47.    #define FileSep ':'
  48.    #if MPW || LWC
  49.       #define DefPath ":"
  50.    #endif                /* MPW || LSC */
  51.    #if MPW
  52.       #define PathSep ","
  53.    #endif                /* MPW */
  54. #endif                    /* MACINTOSH */
  55.  
  56. #if UNIX
  57.    #define Prefix "/"
  58.    #define FileSep '/'
  59.    #define PathSep " :"
  60. #endif                    /* UNIX */
  61.  
  62. #if VMS
  63.    #define Prefix "]:"
  64. #endif                    /* VMS */
  65.  
  66. /*
  67.  * End of operating-system specific code.
  68.  */
  69.  
  70. #ifndef DefPath
  71.    #define DefPath ""
  72. #endif                    /* DefPath */
  73.  
  74. #ifndef PathSep
  75.    #define PathSep " "
  76. #endif                    /* PathSep */
  77.  
  78. /*
  79.  * pathfind(buf,path,name,extn) -- find file in path and return name.
  80.  *
  81.  *  pathfind looks for a file on a path, begining with the current
  82.  *  directory.  Details vary by platform, but the general idea is
  83.  *  that the file must be a readable simple text file.  pathfind
  84.  *  returns buf if it finds a file or NULL if not.
  85.  *
  86.  *  buf[MaxFileName] is a buffer in which to put the constructed file name.
  87.  *  path is the IPATH or LPATH value, or NULL if unset.
  88.  *  name is the file name.
  89.  *  extn is the file extension (.icn or .u1) to be appended, or NULL if none.
  90.  */
  91. char *pathfind(buf, path, name, extn)
  92. char *buf, *path, *name, *extn;
  93.    {
  94.    char *s;
  95.    char pbuf[MaxFileName];
  96.  
  97.    if (tryfile(buf, (char *)NULL, name, extn))    /* try curr directory first */
  98.       return buf;
  99.    if (!path)                /* if no path, use default */
  100.       path = DefPath;
  101.    s = path;
  102.  
  103.    while ((s = pathelem(s, pbuf)) != 0)        /* for each path element */
  104.       if (tryfile(buf, pbuf, name, extn))    /* look for file */
  105.          return buf;
  106.    return NULL;                /* return NULL if no file found */
  107.    }
  108.  
  109. /*
  110.  * pathelem(s,buf) -- copy next path element from s to buf.
  111.  *
  112.  *  Returns the updated pointer s.
  113.  */
  114. static char *pathelem(s, buf)
  115. char *s, *buf;
  116.    {
  117.    char c;
  118.  
  119.    while ((c = *s) != '\0' && strchr(PathSep, c))
  120.       s++;
  121.    if (!*s)
  122.       return NULL;
  123.    while ((c = *s) != '\0' && !strchr(PathSep, c)) {
  124.       *buf++ = c;
  125.       s++;
  126.       }
  127.  
  128. #ifdef FileSep
  129.    /*
  130.     * We have to append a path separator here.
  131.     *  Seems like makename should really be the one to do that.
  132.     */
  133.    if (!strchr(Prefix, buf[-1])) {    /* if separator not already there */
  134.       *buf++ = FileSep;
  135.       }
  136. #endif                    /* FileSep */
  137.  
  138.    *buf = '\0';
  139.    return s;
  140.    }
  141.  
  142. /*
  143.  * tryfile(buf, dir, name, extn) -- check to see if file is readable.
  144.  *
  145.  *  The file name is constructed in buf from dir + name + extn.
  146.  *  findfile returns buf if successful or NULL if not.
  147.  */
  148. static char *tryfile(buf, dir, name, extn)
  149. char *buf, *dir, *name, *extn;
  150.    {
  151.    FILE *f;
  152.    makename(buf, dir, name, extn);
  153.    if ((f = fopen(buf, ReadText)) != NULL) {
  154.       fclose(f);
  155.       return buf;
  156.       }
  157.    else
  158.       return NULL;
  159.    }
  160.  
  161. /*
  162.  * fparse - break a file name down into component parts.
  163.  *  Result is a pointer to a struct of static pointers good until the next call.
  164.  */
  165. struct fileparts *fparse(s)
  166. char *s;
  167.    {
  168.    static char buf[MaxFileName+2];
  169.    static struct fileparts fp;
  170.    int n;
  171.    char *p, *q;
  172.  
  173. #if ARM
  174.    static char buf[MaxFileName+2];
  175.    static struct fileparts fp;
  176.    char *p;
  177.    char *ext = 0;
  178.    char *extend = 0;
  179.    char *dirend = 0;
  180.    char *s1;
  181.    char *bp = buf;
  182.  
  183.    /* First, skip any filing system prefix */
  184.    s1 = strchr(s,':');
  185.    if (s1 == NULL)
  186.       s1 = s;
  187.    else
  188.       ++s1;
  189.  
  190.    /* Now, scan backwards through the filename, looking for dots.
  191.     * Record the positions of the final two, for later use.
  192.     */
  193.    p = s1 + strlen(s1);
  194.    fp.name = 0;
  195.  
  196.    while (--p > s1)
  197.    {
  198.          if (*p != '.')
  199.             continue;
  200.  
  201.       if (fp.name == NULL)
  202.       {
  203.          fp.name = p + 1;
  204.          extend = p;
  205.       }
  206.       else
  207.       {
  208.          ext = p + 1;
  209.          dirend = p;
  210.          break;
  211.       }
  212.    }
  213.  
  214.    /* This is the simple case. The filename is a simple name, with no
  215.     * directory part. The extension is therefore null, and the directory
  216.     * is just the filing system prefix, if any.
  217.     */
  218.    if (fp.name == NULL)
  219.    {
  220.       fp.name = s1;
  221.  
  222.       if (s1 == s)
  223.       {
  224.          fp.ext = "";
  225.          fp.dir = "";
  226.       }
  227.       else
  228.       {
  229.          fp.ext = "";
  230.          strncpy(buf, s, s1 - s);
  231.          buf[s1-s] = '\0';
  232.          fp.dir = buf;
  233.       }
  234.  
  235.       return &fp;
  236.    }
  237.  
  238.    /* Now worry about the more complicated cases. First, check the
  239.     * supposed extension, to see if it is one of the valid cases,
  240.     * SourceSuffix, U1Suffix, U2Suffix, or USuffix. For this code
  241.     * to work, these four defined values must start with a dot, and
  242.     * be all in lower case.
  243.     */
  244.    *buf = '.';
  245.    bp = buf + 1;
  246.  
  247.    for (p = ext ? ext : s1; p < extend; ++p)
  248.    {
  249.       *bp++ = tolower(*p);
  250.    }
  251.  
  252.    *bp++ = '\0';
  253.  
  254.    if (strcmp(buf,SourceSuffix) == 0 || strcmp(buf,U1Suffix) == 0
  255.     || strcmp(buf,U2Suffix) == 0 || strcmp(buf,USuffix) == 0)
  256.    {
  257.       fp.ext = buf;
  258.    }
  259.    else
  260.    {
  261.       fp.ext = "";
  262.       bp = buf;
  263.       dirend = extend;
  264.    }
  265.  
  266.    /* We now have the name and extension sorted out. So we just need
  267.     * to copy the directory part into buf (at bp), and set fp.dir.
  268.     */
  269.    if (dirend == NULL)
  270.    {
  271.       if (s1 == s)
  272.          fp.dir = "";
  273.       else
  274.       {
  275.          fp.dir = bp;
  276.  
  277.          while (s < s1)
  278.             *bp++ = *s++;
  279.  
  280.          *bp = '\0';
  281.       }
  282.    }
  283.    else
  284.    {
  285.       fp.dir = bp;
  286.  
  287.       while (s <= dirend)
  288.          *bp++ = *s++;
  289.  
  290.       *bp = '\0';
  291.    }
  292.  
  293.    return &fp;
  294.  
  295. #else                    /* ARM */
  296.  
  297.    q = s;
  298.    fp.ext = p = s + strlen(s);
  299.    while (--p >= s) {
  300.       if (*p == '.' && *fp.ext == '\0')
  301.          fp.ext = p;
  302.       else if (strchr(Prefix,*p)) {
  303.          q = p+1;
  304.          break;
  305.          }
  306.       }
  307.  
  308.    fp.dir = buf;
  309.    n = q - s;
  310.    strncpy(fp.dir,s,n);
  311.    fp.dir[n] = '\0';
  312.    fp.name = buf + n + 1;
  313.    n = fp.ext - q;
  314.    strncpy(fp.name,q,n);
  315.    fp.name[n] = '\0';
  316.  
  317. #if VMS
  318.    /* if a version is included, get separate extension and version */
  319.    if (p = strchr(fp.ext, ';')) {
  320.       fp.version = p;
  321.       p = fp.ext;
  322.       fp.ext = fp.name + n + 1;
  323.       n = fp.version - p;
  324.       strncpy(fp.ext, p, n);
  325.       fp.ext[n] = '\0';
  326.       }
  327.    else
  328.       fp.version = fp.name + n;        /* point version to '\0' */
  329. #endif                                  /* VMS */
  330.  
  331.    return &fp;
  332. #endif                    /* ARM */
  333.    }
  334.  
  335. /*
  336.  * makename - make a file name, optionally substituting a new dir and/or ext
  337.  */
  338. char *makename(dest,d,name,e)
  339. char *dest, *d, *name, *e;
  340.    {
  341.    struct fileparts fp;
  342.    fp = *fparse(name);
  343.    if (d != NULL)
  344.       fp.dir = d;
  345.    if (e != NULL)
  346.       fp.ext = e;
  347.  
  348. #if ARM
  349.    {
  350.       char *p = (*fp.ext ? fp.ext + 1 : "");
  351.       sprintf(dest, "%s%s%s%s", fp.dir, p, (*p ? "." : ""), fp.name);
  352.    }
  353. #else                    /* ARM */
  354.    sprintf(dest,"%s%s%s",fp.dir,fp.name,fp.ext);
  355. #endif                    /* ARM */
  356.  
  357.    return dest;
  358.    }
  359.  
  360. /*
  361.  * smatch - case-insensitive string match - returns nonzero if they match
  362.  */
  363. int smatch(s,t)
  364. char *s, *t;
  365.    {
  366.    char a, b;
  367.    for (;;) {
  368.       while (*s == *t)
  369.          if (*s++ == '\0')
  370.             return 1;
  371.          else
  372.             t++;
  373.       a = *s++;
  374.       b = *t++;
  375.       if (isupper(a))  a = tolower(a);
  376.       if (isupper(b))  b = tolower(b);
  377.       if (a != b)
  378.          return 0;
  379.       }
  380.    }
  381.  
  382. #if MSDOS
  383. #if NT
  384. #include <sys/stat.h>
  385. #include <direct.h>
  386. #endif                    /* NT */
  387.  
  388. /*
  389.  * this version of pathfind, unlike the one above, is looking on
  390.  * the real path to find an executable.
  391.  */
  392. int pathFind(char target[], char buf[], int n)
  393.    {
  394.    char *path;
  395.    register int i;
  396.    int res;
  397.    struct stat sbuf;
  398.  
  399.    if ((path = getenv("PATH")) == 0)
  400.       path = "";
  401.  
  402.    if (!getcwd(buf, n)) {        /* get current working directory */
  403.       *buf = 0;        /* may be better to do something nicer if we can't */
  404.       return 0;        /* find out where we are -- struggling to achieve */
  405.       }            /* something can be better than not trying */
  406.  
  407.    /* attempt to find the icode file in the current directory first */
  408.    /* this mimicks the behavior of COMMAND.COM */
  409.    if ((i = strlen(buf)) > 0) {
  410.       i = buf[i - 1];
  411.       if (i != '\\' && i != '/' && i != ':')
  412.          strcat(buf, "/");
  413.       }
  414.    strcat(buf, target);
  415.    res = stat(buf, &sbuf);
  416.  
  417.    while(res && *path) {
  418.       for (i = 0; *path && *path != ';'; ++i)
  419.          buf[i] = *path++;
  420.       if (*path)            /* skip the ; or : separator */
  421.          ++path;
  422.       if (i == 0)            /* skip empty fragments in PATH */
  423.          continue;
  424.       if (i > 0 && buf[i - 1] != '/' && buf[i - 1] != '\\' &&
  425.          buf[i - 1] != ':')
  426.             buf[i++] = '/';
  427.       strcpy(buf + i, target);
  428.       res = stat(buf, &sbuf);
  429.       /* exclude directories (and any other nasties) from selection */
  430.       if (res == 0 && sbuf.st_mode & S_IFDIR)
  431.          res = -1;
  432.       }
  433.    if (res != 0)
  434.       *buf = 0;
  435.    return res == 0;
  436.    }
  437. #endif                    /* MSDOS */
  438.  
  439. #if MSDOS || OS2
  440. FILE *pathOpen(fname, mode)
  441.    char *fname;
  442.    char *mode;
  443.    {
  444. #if OS2
  445.    char buf[260 + 1];
  446. #else                    /* OS2 */
  447.    char buf[150 + 1];
  448. #endif                    /* OS2 */
  449.    int i, use = 1;
  450.  
  451. #if SCCX_MX
  452.    /* Avoid compiler warning */
  453.    for( i = 0; (buf[i] = fname[i]) != 0; ++i)
  454. #else
  455.    for( i = 0; buf[i] = fname[i]; ++i)
  456. #endif                    /* SCCX_MX */
  457.  
  458.       /* find out if a path has been given in the file name */
  459.       if (buf[i] == '/' || buf[i] == ':' || buf[i] == '\\')
  460.          use = 0;
  461.  
  462.    /* If a path has been given with the file name, don't bother to
  463.       use the PATH */
  464.  
  465. #if OS2
  466.    if (use && DosSearchPath(SEARCH_CUR_DIRECTORY | SEARCH_ENVIRONMENT,
  467.                             "PATH", fname, buf, 260))
  468. #else                    /* OS2 */
  469.    if (use && !pathFind(fname, buf, 150))
  470. #endif                    /* OS2 */
  471.        return 0;
  472.  
  473.    return fopen(buf, mode);
  474.    }
  475. #endif                    /* MSDOS || OS2 */
  476.