summaryrefslogtreecommitdiff
path: root/newlib/libc/sys/go32/fixpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/sys/go32/fixpath.c')
-rw-r--r--newlib/libc/sys/go32/fixpath.c155
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 00000000000..e7d61fddd1a
--- /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(&regs, &regs);
+ 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(&regs, &regs);
+ 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