/*
 * util.c:
 *
 * Copyright (c) 2000 James McKenzie <james@fishsoup.dhs.org>,
 * All rights reserved.
 *
 */

static char rcsid[] =
    "$Id: util.c,v 1.14 2002/06/23 17:16:39 root Exp root $";

/*
 * $Log: util.c,v $
 * Revision 1.14  2002/06/23 17:16:39  root
 * #
 *
 * Revision 1.13  2001/10/04 18:21:16  root
 * #
 *
 * Revision 1.12  2001/10/04 18:00:36  root
 * #
 *
 * Revision 1.11  2000/12/01 04:42:10  root
 * #
 *
 * Revision 1.10  2000/12/01 04:13:42  root
 * #
 *
 * Revision 1.9  2000/11/23 23:45:19  root
 * #
 *
 * Revision 1.8  2000/10/07 18:30:03  root
 * #
 *
 * Revision 1.7  2000/09/24 01:58:26  root
 * #
 *
 * Revision 1.6  2000/09/24 01:58:21  root
 * #
 *
 * Revision 1.5  2000/09/24 01:46:04  root
 * #
 *
 * Revision 1.4  2000/09/24 01:44:47  root
 * #
 *
 * Revision 1.3  2000/09/19 03:53:27  root
 * #
 *
 */

#include "project.h"
#include "object.h"

#include <sys/time.h>

/*
 *  /abc/def/ghi   -> /abc/def/
 *  /abc/def/ghi/  -> /abc/def/
 */


INTERNAL char *hack_off(const char *path)
{
  char *foo = strdup(path);
  char *ptr = foo;

  if (foo[0] != '/') {
    *foo = 0;
    return foo;
  }

  while (*ptr)
    ptr++;
  ptr--;
  ptr--;

  while (*ptr != '/')
    ptr--;
  ptr++;

  *ptr = 0;


  return foo;
}


INTERNAL char *directory_of(const char *path)
{
  char *foo, *ptr;
  struct stat s;

  ptr = foo = malloc(strlen(path) + 2);
  strcpy(foo, path);

  if (foo[strlen(path) - 1] == '/')
    return foo;

  if (!stat(path, &s)) {
    if (S_ISDIR(s.st_mode)) {
      strcat(foo, "/");
      return foo;
    }
  }


  while (*ptr)
    ptr++;
  ptr--;
  ptr--;

  while (*ptr != '/')
    ptr--;
  ptr++;

  *ptr = 0;


  return foo;
}


BEGIN_OBJECT(Component)
char *c;
END_OBJECT(Component)

static void component_destructor(Component c)
{
  if (!c)
    return;
  if (c->c)
    free(c->c);
  free(c);
}

CREATOR(Component) = (Creator(Component)) Obj_DefaultCreator;
DESTRUCTOR(Component) = (Destructor(Component)) component_destructor;

INTERNAL char *path_tidy(const char *ptr)
{
  int sz = strlen(ptr) + 1;
  char *ref = strdup(ptr);
  char *cptr = NULL;
  Component_list l;
  Component c;
  int i;

  l = CREATE_LIST(Component);

  if (ptr[0] != '/') {
    c = CREATE_OBJ(Component);
    Obj_Insert(l, c, ObjInsertTail);
    c->c = cptr = malloc(sz);
    *cptr = 0;
  }

  while (*ptr) {
    if (*ptr == '/') {
      c = CREATE_OBJ(Component);
      Obj_Insert(l, c, ObjInsertTail);
      c->c = cptr = malloc(sz);
      *cptr = 0;
    } else {
      *(cptr++) = *ptr;
      *cptr = 0;
    }
    ptr++;
  }

/* Double / thing */
  if (l->tail) {
    c = l->tail;
    while (c) {
      if ((c->prev) && (strlen(c->prev->c) == 0)) {
        while (c->prev) {
          Component d = c->prev;
          Obj_Remove(l, d);
          Obj_Delete(d);
        }
      }
      c = c->prev;
    }
  }

/* . */

  c = l->head;
  while (c) {
    Component d = c->next;
    if (!strcmp(c->c, ".")) {
      Obj_Remove(l, c);
      Obj_Delete(c);
    }
    c = d;
  }

/* .. */

  i = 1;
  while (i) {
    c = l->tail;
    i = 0;
    while ((!i) && (c)) {
      if (!strcmp(c->c, "..")) {
        Component d = c->prev;
        if (d) {
          Obj_Remove(l, d);
          Obj_Delete(d);
        }
        Obj_Remove(l, c);
        Obj_Delete(c);
        i++;
      } else {
        c = c->prev;
      }

    }
  }

  if (*ref != '/') {
    *ref = 0;
    c = l->head;
    strcat(ref, c->c);
    Obj_Remove(l, c);
    Obj_Delete(c);
  } else {
    *ref = 0;
  }

  while (l->head) {
    c = l->head;
    strcat(ref, "/");
    strcat(ref, c->c);
    Obj_Remove(l, c);
    Obj_Delete(c);
  }

  return ref;
}

INTERNAL char *de_relativise(const char *file, const char *ibase)
{
  char *ref;
  char *ptr;
  char *base;

  if (file[0] == '/') {
    return (strdup(file));
  }

  base = directory_of(ibase);

  ptr = malloc(2 + strlen(file) + strlen(base));
  strcpy(ptr, base);
  strcat(ptr, file);
  free(base);

  ref = path_tidy(ptr);
  free(ptr);

  return (ref);

}

INTERNAL char *relativise(const char *file, const char *ibase)
{
  char *base = directory_of(ibase);
  char *ptr;

  ptr = path_tidy(base);
  free(base);
  base = ptr;

  //Short circuit simple case
  while ((*file) && (*file == *ptr)) {
    file++;
    ptr++;
  }

  //Ok more complicated
  if (*file != *ptr) {
    int dd = 0;
    while (*ptr) {
      if (*ptr == '/')
        dd++;
      ptr++;
    }

    free(base);

    base = path_tidy(file);

    ptr = (char *) malloc(dd * 3 + strlen(base) + 1);
    *ptr = 0;
    while (dd--) {
      strcat(ptr, "../");
    }
    strcat(ptr, base);
    free(base);

    return ptr;
  }

  free(base);

  base = path_tidy(file);

  return base;

}

INTERNAL int canread(int fd)
{
  fd_set fds;
  struct timeval tv;

  FD_ZERO(&fds);
  FD_SET(fd, &fds);

  bzero(&tv, sizeof(tv));

  if (select(fd + 1, &fds, NULL, NULL, &tv) < 0)
    return 0;

  if (FD_ISSET(fd, &fds))
    return 1;

  return 0;


}
