diff options
author | Christopher Faylor <me@cgf.cx> | 2000-02-17 19:39:52 +0000 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2000-02-17 19:39:52 +0000 |
commit | 8a0efa53e44919bcf5ccb1d3353618a82afdf8bc (patch) | |
tree | 68c3dbf3f2c6fd5d49777def9914d77b5cd4589d /newlib/libc/sys/go32/fixpath.c | |
parent | 1fd5e000ace55b323124c7e556a7a864b972a5c4 (diff) | |
download | cygnal-8a0efa53e44919bcf5ccb1d3353618a82afdf8bc.tar.gz cygnal-8a0efa53e44919bcf5ccb1d3353618a82afdf8bc.tar.bz2 cygnal-8a0efa53e44919bcf5ccb1d3353618a82afdf8bc.zip |
import newlib-2000-02-17 snapshot
Diffstat (limited to 'newlib/libc/sys/go32/fixpath.c')
-rw-r--r-- | newlib/libc/sys/go32/fixpath.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/newlib/libc/sys/go32/fixpath.c b/newlib/libc/sys/go32/fixpath.c new file mode 100644 index 000000000..e7d61fddd --- /dev/null +++ b/newlib/libc/sys/go32/fixpath.c @@ -0,0 +1,155 @@ +/* + (c) Copyright 1992 Eric Backus + + This software may be used freely so long as this copyright notice is + left intact. There is no warrantee on this software. +*/ + +#include "dos.h" /* For intdos() */ +#include <errno.h> /* For errno */ +#include <string.h> /* For strlen() */ + +int +_get_default_drive(void) +{ + union REGS regs; + + regs.h.ah = 0x19; /* DOS Get Default Drive call */ + regs.h.al = 0; + (void) intdos(®s, ®s); + return regs.h.al; +} + +static char * +get_current_directory(char *out, int drive_number) +{ + union REGS regs; + + regs.h.ah = 0x47; + regs.h.dl = drive_number + 1; + regs.x.si = (unsigned long) (out + 1); + (void) intdos(®s, ®s); + if (regs.x.cflag != 0) + { + errno = regs.x.ax; + return out; + } + else + { + /* Root path, don't insert "/", it'll be added later */ + if (*(out + 1) != '\0') + *out = '/'; + else + *out = '\0'; + return out + strlen(out); + } +} + +static int +is_slash(int c) +{ + return c == '/' || c == '\\'; +} + +static int +is_term(int c) +{ + return c == '/' || c == '\\' || c == '\0'; +} + +/* Takes as input an arbitrary path. Fixes up the path by: + 1. Removing consecutive slashes + 2. Removing trailing slashes + 3. Making the path absolute if it wasn't already + 4. Removing "." in the path + 5. Removing ".." entries in the path (and the directory above them) + 6. Adding a drive specification if one wasn't there + 7. Converting all slashes to '/' + */ +void +_fixpath(const char *in, char *out) +{ + int drive_number; + const char *ip = in; + char *op = out; + + /* Add drive specification to output string */ + if (*(ip + 1) == ':' && ((*ip >= 'a' && *ip <= 'z') || + (*ip >= 'A' && *ip <= 'Z'))) + { + if (*ip >= 'a' && *ip <= 'z') + drive_number = *ip - 'a'; + else + drive_number = *ip - 'A'; + *op++ = *ip++; + *op++ = *ip++; + } + else + { + drive_number = _get_default_drive(); + *op++ = drive_number + 'a'; + *op++ = ':'; + } + + /* Convert relative path to absolute */ + if (!is_slash(*ip)) + op = get_current_directory(op, drive_number); + + /* Step through the input path */ + while (*ip) + { + /* Skip input slashes */ + if (is_slash(*ip)) + { + ip++; + continue; + } + + /* Skip "." and output nothing */ + if (*ip == '.' && is_term(*(ip + 1))) + { + ip++; + continue; + } + + /* Skip ".." and remove previous output directory */ + if (*ip == '.' && *(ip + 1) == '.' && is_term(*(ip + 2))) + { + ip += 2; + /* Don't back up over drive spec */ + if (op > out + 2) + /* This requires "/" to follow drive spec */ + while (!is_slash(*--op)); + continue; + } + + /* Copy path component from in to out */ + *op++ = '/'; + while (!is_term(*ip)) *op++ = *ip++; + } + + /* If root directory, insert trailing slash */ + if (op == out + 2) *op++ = '/'; + + /* Null terminate the output */ + *op = '\0'; +} + +#ifdef TEST +#include <stdio.h> + +int +main(int argc, char **argv) +{ + char path[90]; + int i; + + for (i = 1; i < argc; i++) + { + _fixpath(argv[i], path); + (void) printf("'%s' -> '%s'\n", argv[i], path); + } + + return 0; +} +#endif |