156 lines
3.0 KiB
C
156 lines
3.0 KiB
C
|
/*
|
||
|
(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
|