/**********************************************************************
 * Menu_File manipulation module
 *
 * $Author: probe $
 * $Source: /afs/sipb.mit.edu/project/sipb-athena/repository/src/olh/libmenu/menu_file.c,v $
 * $Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/olh/libmenu/menu_file.c,v 1.1 1993/10/12 05:46:00 probe Exp $
 *
 * Copyright (c) 1990, Massachusetts Institute of Technology
 **********************************************************************/

#ifndef lint
#ifndef SABER
static char rcsid_menu_file_c[] = "$Header: /afs/sipb.mit.edu/project/sipb-athena/repository/src/olh/libmenu/menu_file.c,v 1.1 1993/10/12 05:46:00 probe Exp $";
#endif
#endif

#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include <memory.h>
#include <menu.h>

extern int errno;
extern Menu **menus_loaded;

/****************************************************************
 * menu_file_save
 *
 * Arguments:
 *    m -- (Menu *) to save
 *    filename -- (char *) where to save
 *
 * Returns: (long) error status
 ****************************************************************/

long
menu_file_save(m, filename)
     Menu *m;
     char *filename;
{
  FILE *fp;
  MenuEntry *e, *estop;
  register EntryField *f, *fstop;

  if ((fp = fopen(filename, "w")) == NULL) return((long) errno);

  estop = m->entry + m->size;
  for(e = m->entry; e < estop; e++) {
    fstop = e->field + e->size;
    for(f = e->field; f < fstop; f++)
      fprintf(fp, "%-15s %s\n", f->name, f->value);
    fprintf(fp, "\n");
  }
  if (fclose(fp) == EOF) return((long) errno);
  return(0L);
}

/*
 * WARNING: next two functions mangle strings passed to them.
 * They are for internal use by menu_file_load only.
 */

char *
_get_field_name(s)
     char *s;
{
  register char *p;
  char *i;

  for (p = s; *p != '\0' && !isspace(*p); p++)
    if (isupper(*p)) *p = tolower(*p);
  *p = '\0';
  i = in_word_set(s,p-s);
  if (i == NULL) {
    i = NewString(s);
    strcpy(i,s);
  }
  return(i);
}

char *
_get_field_value(s)
     char *s;
{
  register char *p;

  while (*s != '\0' && isspace(*s)) s++;
  for (p = s+strlen(s); isspace(*(p-1)); p--);
  *p = '\0';
  return(s);
}

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

long
menu_file_load(filename, mp)
     char *filename;
     Menu **mp;
{
  FILE *fp;
  int i = 0;
  char buf[1024], *name, *value;
  long code;

  /* Load configuration menu if necessary */
  if (!menus_loaded) {
    code = menu_init(NULL);
    if (code) return(code);
  }
  /* See if menu 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)->size = 0;
  if ((fp = fopen(filename, "r")) == NULL) return((long) errno);

  buf[0] = '\0';
  for(i=0 ;; i++) {		/* break loop with goto */
    /* find beginning of node */
    while(!isalpha(buf[0]))
      if (fgets(buf, 1024, fp) == 0) goto MENU_FILE_LOAD_DONE;

    /* allocate new node */
    if ((*mp)->size == 0) {
      (*mp)->n_alloc = ENT_A_SIZE;
      (*mp)->entry = NewArray(MenuEntry, (*mp)->n_alloc);
    }
    else {
      if ((*mp)->size == (*mp)->n_alloc) {
	/* time to reallocate... */
	(*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);
    }
    (*mp)->entry[i].size = 0;

    /* fill in fields */
    while(isalpha(buf[0])) {
      name = _get_field_name(buf);
      value = _get_field_value(buf + strlen(name) + 1);
      if (code = field_set(&((*mp)->entry[i]), name, value))
	return(code);		/* XXX memory leak */
      if (fgets(buf, 1024, fp) == 0) goto MENU_FILE_LOAD_DONE;
    }
  }

MENU_FILE_LOAD_DONE:
  (*mp)->file = filename;
  (void) 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);
}
