/* abspath.c (emx+gcc) -- Copyright (c) 1992-1996 by Eberhard Mattes */

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#ifdef __EMX__
#include <alloca.h>
#endif

static char _fngetdrive (const char *src)
{
  if (src[0] >= 'A' && src[0] <= 'Z' && src[1] == ':')
    return src[0];
  else if (src[0] >= 'a' && src[0] <= 'z' && src[1] == ':')
    return src[0]-'a'+'A';
  else
    return 0;
}

static char *_fnslashify (char *name)
{
  char *p;

  p = name;
  while (*p != 0)
    if (*p == '\\')
      *p++ = '/';
    else
      ++p;
  return name;
}

#define FALSE   0
#define TRUE    1
#define IS_PATH_DELIM(c) ((c)=='\\' || (c)=='/')

int _abspath (char *dst, const char *src, int size)
{
  char drive, dir[261], src_drive, *s, *p;
  int i, j, rel, server, trail;

  s = alloca (strlen (src) + 1);
  strcpy (s, src);
  src_drive = _fngetdrive (s);
  if (src_drive == 0)
    drive = 0;
  else
    {
      drive = src_drive;
      s += 2;
    }
  dir[0] = 0; rel = FALSE; server = FALSE; trail = FALSE;
  if (IS_PATH_DELIM (*s))
    {
      ++s;
      if (IS_PATH_DELIM (*s))
        {
          ++s; server = TRUE;
        }
    }
  else if (getcwd (dir, 260) != NULL)
    _fnslashify (dir);
  else
    {
      dir[0] = 0;
      rel = TRUE;
    }
  while (*s != 0)
    {
      if (s[0] == '.' && (IS_PATH_DELIM (s[1]) || s[1] == 0))
        ++s;
      else if (s[0] == '.' && s[1] == '.' && (IS_PATH_DELIM (s[2]) || 
                                              s[2] == 0))
        {
          s += 2;

          p = strrchr (dir, '/');
          if (p == NULL)
            p = strrchr (dir, '\\');
          else
            --p;
          if (p == NULL)
            p = dir;
          else
            --p;

          if (p == dir)
            strcpy (dir, "..");
          else
            p[-1] = 0;
        }
      else
        {
          i = strlen (dir);
          if (i < sizeof (dir) - 1)
            dir[i++] = '/';
          while (*s != 0)
            {
              if (IS_PATH_DELIM (*s))
                break;
              else
                {
                  if (i < sizeof (dir) - 1)
                    dir[i++] = *s;
                  ++s;
                }
            }
          dir[i] = 0;
        }
      if (*s != 0)
        {
          ++s;
          if (*s == 0)
            trail = 1;
        }
    }
  i = 0;
  if (i+1 < size && (src_drive != 0 || !server))
    {
      dst[i++] = drive;
      dst[i++] = ':';
    }
  if (i < size && server && src_drive == 0)
    dst[i++] = '/';
  if (i < size && !rel && dir[0] != '/')
    dst[i++] = '/';
  j = 0;
  if (rel && dir[j] == '/')
    ++j;
  while (i < size && dir[j] != 0)
    dst[i++] = dir[j++];
  if (trail && i < size && (i == 0 || dst[i-1] != '/'))
    dst[i++] = '/';
  if (i >= size)
    {
      dir[size-1] = 0;
      errno = ERANGE;
      return -1;
    }
  dst[i] = 0;
  return 0;
}
