/**********************************************************************
 * Dirhook_File manipulation module
 *
 * $Author: miki $
 * $Source: /afs/sipb.mit.edu/project/sipb-athena/repository/src/olh/libmenu/dirhook_file.c,v $
 * $Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/olh/libmenu/dirhook_file.c,v 1.2 1993/05/03 14:00:10 miki Exp $
 *
 * Copyright (c) 1990, Massachusetts Institute of Technology
 **********************************************************************/

#ifndef lint
#ifndef SABER
static char rcsid_dirhook_file_c[] = "$Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/olh/libmenu/dirhook_file.c,v 1.2 1993/05/03 14:00:10 miki Exp $";
#endif
#endif

#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/param.h>
#ifdef SYSV
#include <dirent.h>
#else
#include <sys/dir.h>		/* XXX for AIX: <dirent.h> */
#endif
#include <memory.h>
#include <menu.h>

extern int errno;
extern Menu **menus_loaded;

/********/
char *
dirhook_type_translate(s)
     char *s;
{
  if (strcmp(s, "directory") == 0) return("DIRHOOK");
  if (strcmp(s, "entry") == 0) return("DOCUMENT"); /* olcspeak */
  if (strcmp(s, "plain_text") == 0) return("DOCUMENT"); /* infospeak */

  return(s);
}

/****************************************************************
 * dirhook_file_load
 *
 * Arguments:
 *    filename -- (char *) where to load from
 *    mp -- (Menu **) returns loaded dirhook
 *
 * Returns: (long) error status
 ****************************************************************/

long
dirhook_file_load(filename, mp)
     char *filename;
     Menu **mp;
{
  FILE *fp;
  int i, n;
  char buf[MAXPATHLEN], buf2[MAXPATHLEN];
  long code;
  char *index_fields[5];
  char *s;

  /* Load configuration menu if necessary */
  if (!menus_loaded) {
    code = menu_init(NULL);
    if (code) return(code);
  }
  /* See if dirhook has already been loaded */
  for(i=0; menus_loaded[i] != NULL; i++) {
    if (strcmp(menus_loaded[i]->file, filename) == 0) {
      *mp = menus_loaded[i];
      return(0L);
    }
  }
  
  *mp = New(Menu);
  if (!*mp) return((long) errno);
  (*mp)->n_alloc = MENU_A_SIZE;
  (*mp)->entry = NewArray(MenuEntry, (*mp)->n_alloc);
  (*mp)->entry->size = 0;
  (*mp)->size = 1;
  field_set((*mp)->entry, TYPE, "DIRHOOK");
  field_set((*mp)->entry, FILE_FORMAT, "DIRHOOK");
  field_set((*mp)->entry, NODE_LABEL, filename);
  field_set((*mp)->entry, FILE_LOCATION, filename);

  /* Open index file.  Lines of form
   * type:label:file_location (relative):formatter:maintainer
   */
  strcpy(buf2, filename);
  strcat(buf2, "/.index");
  if ((fp = fopen(buf2, "r")) == NULL) {
    if (errno == ENOENT) {
      directory_load_entries(filename, mp);
    } else {
      return((long) errno);
    }
  } else {
    buf[0] = '\0';

    /*  FIELD-READING LOOP  */
    for (i=1; fgets(buf, MAXPATHLEN, fp); i++) {

      /* allocate new node */
      if ((*mp)->size == (*mp)->n_alloc) {
	/* time to realloc.. */
	(*mp)->n_alloc += ENT_A_SIZE;
	(*mp)->entry = ResizeArray(MenuEntry, (*mp)->entry, (*mp)->n_alloc);
      }
      (*mp)->size++;
      if (!(*mp)->entry) {
	(*mp)->size = 0;
	return((long) errno);	/* XXX memory leak */
      }
      (*mp)->entry[i].size = 0;

      /* Remove trailing whitespace */
      for(s = buf+strlen(buf)-1; isspace(*s); s--) *s = '\0';

      /* fill in fields */
      /* XXX handle low-memory situation */

      n = break_colons(buf, index_fields);
      if (n < 2) {		/* ignore blank lines */
	((*mp)->size)--;
	continue;
      }
      field_set(nth_entry(*mp, i), TYPE,
		dirhook_type_translate(index_fields[0]));
      if (strcmp(index_fields[0],"directory") == 0)
	field_set(nth_entry(*mp, i), FILE_FORMAT, "DIRHOOK");
      field_set(nth_entry(*mp, i), NODE_LABEL, index_fields[1]);

      /* Translate relative filename to absolute pathname */
      strcpy(buf2, filename);
      strcat(buf2, "/");
      strcat(buf2, index_fields[2]);
      field_set(nth_entry(*mp, i), FILE_LOCATION, buf2);
      field_set(nth_entry(*mp, i), NODE_ID, index_fields[2]);

      if (n>3) field_set(nth_entry(*mp, i), FORMATTER, index_fields[3]);
      if (n>4) field_set(nth_entry(*mp, i), MAINTAINER, index_fields[4]);
    }
  }
  (*mp)->file = NewString(filename);
  if (!(*mp)->file) return((long) errno); /* XXX free menu */
  strcpy((*mp)->file, filename);
  if (fp) fclose(fp);		/* read-only needs no err check */

  /* Put in cache of loaded menus */
  for(i=0; menus_loaded[i] != NULL; i++);
  menus_loaded = ResizeArray(Menu *, menus_loaded, i+2);
  if (!menus_loaded) return((long) errno);
  menus_loaded[i] = *mp;
  menus_loaded[i+1] = NULL;
  return(0L);
}

int
directory_load_entries_compar(e1, e2)
     MenuEntry *e1, *e2;
{
  return(strcmp(field_value(e1, NODE_LABEL), field_value(e2, NODE_LABEL)));
}

long
directory_load_entries(filename, mp)
     char *filename;
     Menu **mp;
{
  DIR *dirp;
#ifndef SYSV
  struct direct *dp;
#else
  struct dirent *dp;
#endif
  struct stat sbuf;
  MenuEntry *e;
  char buf[MAXPATHLEN];
  register char *s;

  dirp = opendir(filename);
  if (!dirp) return((long) errno);

  while(dp = readdir(dirp)) {
    /* ignore files beginning with . or #, ending with ~ */
#ifndef SYSV
    if (dp->d_name[0] == '.' || dp->d_name[0] == '#'
	|| dp->d_name[dp->d_namlen-1] == '~') continue;
#else
    if (dp->d_name[0] == '.' || dp->d_name[0] == '#'
       || dp->d_name[0] == '~') continue;
#endif
    /* Form full pathname, get stats */
    strcpy(buf, filename);
    strcat(buf, "/");
    strcat(buf, dp->d_name);
    if (stat(buf, &sbuf)) continue; /* ignore files that won't stat */

    resizemenu(*mp, (*mp)->size + 1);
    e = nth_entry((*mp), (*mp)->size - 1);

    if (sbuf.st_mode & S_IFDIR) {
      field_set(e, TYPE, "DIRHOOK");
      field_set(e, FILE_FORMAT, "DIRHOOK");
    } else {
      field_set(e, TYPE, "DOCUMENT");
      field_set(e, FILE_FORMAT, "plain_text");
    }
    field_set(e, NODE_ID, dp->d_name);
    field_set(e, FILE_LOCATION, buf);

    /* make label be filename w/o underscores */
    strcpy(buf, dp->d_name);
    for (s = buf; *s != '\0'; s++)
      if (*s == '_') *s = ' ';
    field_set(e, NODE_LABEL, buf);

    /* Add modify date */
    sprintf(buf, "%ld", sbuf.st_mtime);
    field_set(e, MODIFY_DATE, buf);
  }
  closedir(dirp);

  /* sort so that most recently modified comes first */
  qsort(nth_entry(*mp, 1), (*mp)->size - 1, sizeof(MenuEntry),
	directory_load_entries_compar);

  return(0L);
}
