home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / libsrc / c / gen / fixpath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-18  |  4.0 KB  |  198 lines

  1. /*
  2.   (c) Copyright 1992 Eric Backus
  3.  
  4.   This software may be used freely so long as this copyright notice is
  5.   left intact.  There is no warrantee on this software.
  6. */
  7.  
  8. #include <dos.h>        /* For intdos() */
  9. #include <errno.h>        /* For errno */
  10. #include <string.h>        /* For strlen() */
  11. #include <ctype.h>        /* for tolower() */
  12.  
  13. int
  14. _get_default_drive(void)
  15. {
  16.     union REGS    regs;
  17.  
  18.     regs.h.ah = 0x19;        /* DOS Get Default Drive call */
  19.     regs.h.al = 0;
  20.     (void) intdos(®s, ®s);
  21.     return regs.h.al;
  22. }
  23.  
  24. static char *
  25. get_current_directory(char *out, int drive_number)
  26. {
  27.     union REGS    regs;
  28.  
  29.     regs.h.ah = 0x47;
  30.     regs.h.dl = drive_number + 1;
  31.     regs.x.si = (unsigned long) (out + 1);
  32.     (void) intdos(®s, ®s);
  33.     if (regs.x.cflag != 0)
  34.     {
  35.     errno = regs.x.ax;
  36.     return out;
  37.     }
  38.     else
  39.     {
  40.     /* Root path, don't insert "/", it'll be added later */
  41.     if (*(out + 1) != '\0')
  42.         *out = '/';
  43.     else
  44.         *out = '\0';
  45.     return out + strlen(out);
  46.     }
  47. }
  48.  
  49. static int
  50. is_slash(int c)
  51. {
  52.     return c == '/' || c == '\\';
  53. }
  54.  
  55. static int
  56. is_term(int c)
  57. {
  58.     return c == '/' || c == '\\' || c == '\0';
  59. }
  60.   
  61. static int
  62. is_sep(int c)
  63. {
  64.     return c == '/' || c == '\\' || c == '.' || c == '\0';
  65. }
  66.  
  67. /* Takes as input an arbitrary path.  Fixes up the path by:
  68.    1. Removing consecutive slashes
  69.    2. Removing trailing slashes
  70.    3. Making the path absolute if it wasn't already
  71.    4. Removing "." in the path
  72.    5. Removing ".." entries in the path (and the directory above them)
  73.    6. Adding a drive specification if one wasn't there
  74.    7. Converting all slashes to '/'
  75.    8. Converting to lowercase
  76.    9. Stripping characters that would be ignored by MS-DOS
  77.  */
  78. void
  79. _fixpath(const char *in, char *out)
  80. {
  81.     int        drive_number, count;
  82.     const char    *ip = in;
  83.     char    *op = out;
  84.     char    *p;
  85.  
  86.     /* Add drive specification to output string */
  87.     if (*(ip + 1) == ':' && ((*ip >= 'a' && *ip <= 'z') ||
  88.                  (*ip >= 'A' && *ip <= 'Z')))
  89.     {
  90.     if (*ip >= 'a' && *ip <= 'z')
  91.         drive_number = *ip - 'a';
  92.     else
  93.         drive_number = *ip - 'A';
  94.     *op++ = tolower(*ip++);
  95.     *op++ = tolower(*ip++);
  96.     }
  97.     else
  98.     {
  99.     drive_number = _get_default_drive();
  100.     *op++ = drive_number + 'a';
  101.     *op++ = ':';
  102.     }
  103.  
  104.     /* Convert relative path to absolute */
  105.     if (!is_slash(*ip))
  106.     {
  107.     p = op;
  108.       op = get_current_directory(op, drive_number);
  109.     /* Convert path to lowercase, in case it wasn't already */
  110.     while (p < op)
  111.     {
  112.         *p = tolower(*p);
  113.         p++;
  114.     }
  115.     }
  116.  
  117.     /* Step through the input path */
  118.     while (*ip != '\0')
  119.     {
  120.     /* Skip input slashes */
  121.     if (is_slash(*ip))
  122.     {
  123.         ip++;
  124.         continue;
  125.     }
  126.  
  127.     /* Skip "." and output nothing */
  128.     if (*ip == '.' && is_term(*(ip + 1)))
  129.     {
  130.         ip++;
  131.         continue;
  132.     }
  133.  
  134.     /* Skip ".." and remove previous output directory */
  135.     if (*ip == '.' && *(ip + 1) == '.' && is_term(*(ip + 2)))
  136.     {
  137.         ip += 2;
  138.         /* Don't back up over drive spec */
  139.         if (op > out + 2)
  140.         /* This requires "/" to follow drive spec */
  141.         while (!is_slash(*--op));
  142.         continue;
  143.     }
  144.  
  145.     /* Copy path component from in to out */
  146.     *op++ = '/';
  147.     count = 0;
  148.     /* Copy up to eight characters in filename */
  149.     while (!is_sep(*ip))
  150.     {
  151.         if (count++ < 8)
  152.         *op++ = tolower(*ip);
  153.         ip++;
  154.     }
  155.     /* Copy dot */
  156.     if (*ip == '.')
  157.         *op++ = *ip++;
  158.     count = 0;
  159.     /* Copy up to three characters in extension */
  160.     while (!is_sep(*ip))
  161.     {
  162.         if (count++ < 3)
  163.         *op++ = tolower(*ip);
  164.         ip++;
  165.     }
  166.     /* Copy dot */
  167.     if (*ip == '.')
  168.         *op++ = *ip++;
  169.     /* Skip over extra garbage in the input path */
  170.     while (!is_term(*ip)) ip++;
  171.     }
  172.  
  173.     /* If root directory, insert trailing slash */
  174.     if (op == out + 2) *op++ = '/';
  175.  
  176.     /* Null terminate the output */
  177.     *op = '\0';
  178. }
  179.  
  180. #ifdef    TEST
  181. #include <stdio.h>
  182.  
  183. int
  184. main(int argc, char **argv)
  185. {
  186.     char    path[90];
  187.     int        i;
  188.  
  189.     for (i = 1; i < argc; i++)
  190.     {
  191.     _fixpath(argv[i], path);
  192.     (void) printf("'%s' -> '%s'\n", argv[i], path);
  193.     }
  194.  
  195.     return 0;
  196. }
  197. #endif
  198.