home *** CD-ROM | disk | FTP | other *** search
/ PC Extra Super CD 1998 January / PCPLUS131.iso / DJGPP / V2 / DJLSR201.ZIP / src / libc / posix / sys / stat / fixpath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-05  |  4.4 KB  |  200 lines

  1. /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  2. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  3. #include <libc/stubs.h>
  4. #include <stdio.h>        /* For FILENAME_MAX */
  5. #include <stdlib.h>
  6. #include <errno.h>        /* For errno */
  7. #include <ctype.h>        /* For tolower */
  8. #include <string.h>        /* For strlen() */
  9. #include <fcntl.h>        /* For LFN stuff */
  10. #include <go32.h>
  11. #include <dpmi.h>        /* For dpmisim */
  12. #include <crt0.h>        /* For crt0 flags */
  13. #include <sys/stat.h>
  14. #include <libc/dosio.h>
  15.  
  16. static unsigned use_lfn;
  17.  
  18. static char *__get_current_directory(char *out, int drive_number);
  19.  
  20. static char *
  21. __get_current_directory(char *out, int drive_number)
  22. {
  23.   __dpmi_regs r;
  24.   char tmpbuf[FILENAME_MAX];
  25.  
  26.   memset(&r, 0, sizeof(r));
  27.   if(use_lfn)
  28.     r.x.ax = 0x7147;
  29.   else
  30.     r.h.ah = 0x47;
  31.   r.h.dl = drive_number + 1;
  32.   r.x.si = __tb_offset;
  33.   r.x.ds = __tb_segment;
  34.   __dpmi_int(0x21, &r);
  35.  
  36.   if (r.x.flags & 1)
  37.   {
  38.     errno = r.x.ax;
  39.     return out;
  40.   }
  41.   else
  42.   {
  43.     dosmemget(__tb, sizeof(tmpbuf), tmpbuf);
  44.     strcpy(out+1,tmpbuf);
  45.  
  46.     /* Root path, don't insert "/", it'll be added later */
  47.     if (*(out + 1) != '\0')
  48.       *out = '/';
  49.     else
  50.       *out = '\0';
  51.     return out + strlen(out);
  52.   }
  53. }
  54.  
  55. __inline__ static int
  56. is_slash(int c)
  57. {
  58.   return c == '/' || c == '\\';
  59. }
  60.  
  61. __inline__ static int
  62. is_term(int c)
  63. {
  64.   return 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.  */
  76. void
  77. _fixpath(const char *in, char *out)
  78. {
  79.   int        drive_number;
  80.   const char    *ip = in;
  81.   char        *op = out;
  82.   int        preserve_case = _preserve_fncase();
  83.   char        *name_start;
  84.  
  85.   use_lfn = _USE_LFN;
  86.  
  87.   /* Add drive specification to output string */
  88.   if (((*ip >= 'a' && *ip <= 'z') ||
  89.        (*ip >= 'A' && *ip <= 'Z'))
  90.       && (*(ip + 1) == ':'))
  91.   {
  92.     if (*ip >= 'a' && *ip <= 'z')
  93.     {
  94.       drive_number = *ip - 'a';
  95.       *op++ = *ip++;
  96.     }
  97.     else
  98.     {
  99.       drive_number = *ip - 'A';
  100.       if (*ip <= 'Z')
  101.     *op++ = drive_number + 'a';
  102.       else
  103.     *op++ = *ip;
  104.       ++ip;
  105.     }
  106.     *op++ = *ip++;
  107.   }
  108.   else
  109.   {
  110.     __dpmi_regs r;
  111.     r.h.ah = 0x19;
  112.     __dpmi_int(0x21, &r);
  113.     drive_number = r.h.al;
  114.     *op++ = drive_number + (drive_number < 26 ? 'a' : 'A');
  115.     *op++ = ':';
  116.   }
  117.  
  118.   /* Convert relative path to absolute */
  119.   if (!is_slash(*ip))
  120.     op = __get_current_directory(op, drive_number);
  121.  
  122.   /* Step through the input path */
  123.   while (*ip)
  124.   {
  125.     /* Skip input slashes */
  126.     if (is_slash(*ip))
  127.     {
  128.       ip++;
  129.       continue;
  130.     }
  131.  
  132.     /* Skip "." and output nothing */
  133.     if (*ip == '.' && is_term(*(ip + 1)))
  134.     {
  135.       ip++;
  136.       continue;
  137.     }
  138.  
  139.     /* Skip ".." and remove previous output directory */
  140.     if (*ip == '.' && *(ip + 1) == '.' && is_term(*(ip + 2)))
  141.     {
  142.       ip += 2;
  143.       /* Don't back up over drive spec */
  144.       if (op > out + 2)
  145.     /* This requires "/" to follow drive spec */
  146.     while (!is_slash(*--op));
  147.       continue;
  148.     }
  149.  
  150.     /* Copy path component from in to out */
  151.     *op++ = '/';
  152.     while (!is_term(*ip)) *op++ = *ip++;
  153.   }
  154.  
  155.   /* If root directory, insert trailing slash */
  156.   if (op == out + 2) *op++ = '/';
  157.  
  158.   /* Null terminate the output */
  159.   *op = '\0';
  160.  
  161.   /* switch FOO\BAR to foo/bar, downcase where appropriate */
  162.   for (op = out + 3, name_start = op - 1; *name_start; op++)
  163.   {
  164.     char long_name[FILENAME_MAX], short_name[13];
  165.  
  166.     if (*op == '\\')
  167.       *op = '/';
  168.     if (!preserve_case && (*op == '/' || *op == '\0'))
  169.     {
  170.       memcpy(long_name, name_start+1, op - name_start - 1);
  171.       long_name[op - name_start - 1] = '\0';
  172.       if (!strcmp(_lfn_gen_short_fname(long_name, short_name), long_name))
  173.       {
  174.     while (++name_start < op)
  175.       if (*name_start >= 'A' && *name_start <= 'Z')
  176.         *name_start += 'a' - 'A';
  177.       }
  178.       else
  179.     name_start = op;
  180.     }
  181.     else if (*op == '\0')
  182.       break;
  183.   }
  184. }
  185.  
  186. #ifdef TEST
  187.  
  188. int main (int argc, char *argv[])
  189. {
  190.   char fixed[FILENAME_MAX];
  191.   if (argc > 1)
  192.     {
  193.       _fixpath (argv[1], fixed);
  194.       printf ("You mean %s?\n", fixed);
  195.     }
  196.   return 0;
  197. }
  198.  
  199. #endif
  200.