/**********************************************************************
 * File: HostfileIO.c        Problem file and hostfile reader / writer*
 *  Version 1.0       Author: WB Norton  Merit Computer Network       *
 *  Modification History:                                             *
 *  written 5/18/89   Bill Norton, Merit Computer Network             *
 *  08/09/89 - Allow Spaces in parm lists for Appletalk argv   @wbn1 *
 *             We do this by substituting paren enclosed spaces       *
 *             with 0x01 - our white separator                        *
 *  12/03/90 - Split apart files - This is NOW InetRover Hostfileio.c *
 *  12/11/90 - Use malloc for each record-now just static array of ptr*
 *	       Call ReadNodeFile each cycle, and if we take care of   *
 *	       re-reading hostfile if things have changed	      *
 **********************************************************************/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "Hostfileio.h"
#include "../Ctools/ctools.h"

struct NodeType NodeList[MAXNODES];
int NumNodes;
long NodeListLastModified;

/*********************************************************/
/*#define DEBUG 1	/*   */
/*********************************************************/
#ifdef STANDALONE
char hostfile[100];
char *DefaultPingkyDir=".";

main()
{
char *pingkydir,*getenv();
struct NodeType *Nodes;

    if ((pingkydir=getenv("PINGKYDIR"))==NULL) pingkydir=DefaultPingkyDir;
    strcat(pingkydir,"/");
    strcpy(hostfile,pingkydir); strcat(hostfile,"hostfile");
   while( 1 == 1 ) {
   	Nodes=ReadNodeFile(hostfile);
   }
   printf("There are %d net work nodes in file %s\n",NumNodes,hostfile);
   PrintNodes(Nodes);
}
#endif

/*****************************************************************************
 * ReadNodeFile:  Read the list of nodes we are responsible for.       @bev  *
 *****************************************************************************/
struct NodeType *ReadNodeFile(file)  /* Read and Store hostfile NodeArray */
char *file;		/* Filename to read these from */
{
FILE *stream;
char buffer[MAXLINE];
int Error=FALSE, virgin=TRUE;
int i,j,k,line;
 
	if ( !(FileChanged( file, &NodeListLastModified )) ) return(NodeList);

	if ( virgin ) {
		for( i=0; i<MAXNODES; i++ )
			NodeList[i].NodeName = NULL;
		virgin=FALSE;
   	}
   	else {
		for( i=0; i<MAXNODES && NodeList[i].NodeName != NULL; i++ ) {
			free( NodeList[i].NodeName );
			NodeList[i].NodeName = NULL;
		}
	}

	/* Open File and process a record at a time.  Malloc, and assign ptrs */

	if ((stream=fopen(file,"r")) == NULL)
		syserr("fopen hostfile: ");
	for( i=0,line=0; 	/* FOR EACH LINE IN NODE FILE */
		( (fgets(buffer,sizeof(buffer),stream) != NULL) && 
							( i < MAXNODES ) );
					line++ ) {
		if (Error==TRUE) { 
			printf("%s Error in line %d of hostfile - IGNORED\n",
					NodeList[i].NodeName,line);
			free(NodeList[i].NodeName); /* free memory */
		}
		Error=TRUE;	/* Assume a bad line */
		if (buffer[0]=='#') { Error=FALSE; continue; } /* COMMENT */
		if ( (NodeList[i].NodeName =
				(char *) malloc(strlen(buffer)+2)) == NULL )
					panic("malloc failed in ReadNode");
		strcpy( NodeList[i].NodeName , buffer );
		if ( ( NodeList[i].NodeName =
			strtok(NodeList[i].NodeName," \t\n")) == NULL )
				 { Error=FALSE;  continue; }
      		if ( (NodeList[i].UniqueID=strtok(NULL," \t\n")) == NULL ) 
			continue; 
      		if ( (NodeList[i].Helpfilename=strtok(NULL," \t\n")) == NULL ) 
			continue; 

		/* PULL OFF TESTS to be performed on this Node */

		Error=FALSE;
		for(j=0; 	/* FOR EACH TEST ON THIS LINE */
			( ( NodeList[i].Test[j].argv[0] = strtok(NULL," \t\n")) 
				!= NULL); j++) {
			if ( j >= MAXTESTS ) {
				sprintf(buffer, "ReadNodeFile: Too many Tests (MAX=%d) on line %d of config file\n",MAXTESTS,line);	
				Log( buffer, NULL );
				panic(buffer);
      			}
		}
				/* SPLIT TESTS INTO ARGV LIST */
      		for(j=j-1; j>=0; j-- )  {
			NodeList[i].Test[j].argv[0] = 
			      strtok(NodeList[i].Test[j].argv[0],"()");
			for(k=1; 
				(k<MAXARGS)&&((NodeList[i].Test[j].argv[k] =
					strtok(NULL,"()")) != NULL); 
			k++) {
				if ( k>=MAXARGS ) {
					sprintf(buffer,"ReadNodeFile: Too many arguments (MAX=%d) on line %d of config file\n",MAXARGS,line);
				Log( buffer, NULL );
					panic(buffer);
				}
			}
		}
		i++;		/** Yea! We have a valid line **/
	}
	fclose(stream);
	if ( i == MAXNODES ) {
		sprintf(buffer,"ERROR!!!! MAXNODES (%d) reached!!!\n",i);
		Log( buffer, NULL );
		fprintf(stderr,buffer );
	}
	NumNodes=i;
#ifdef DEBUG
 	PrintNodes(NodeList);
#endif
	return(NodeList);
}
   
void PrintNodes(Node)
struct NodeType *Node;
{
int i,j,k;

   for(i=0; Node[i].NodeName!=NULL; i++) {
      printf("%d %s Node [%s] uses Help: %s & Protos ",i,
           Node[i].NodeName,Node[i].UniqueID,Node[i].Helpfilename); 
      for(j=0; (( Node[i].Test[j].argv[0] != NULL ) && (j<MAXTESTS)); j++) {
            printf(" %s(",Node[i].Test[j].argv[0]);
            for(k=1; (( Node[i].Test[j].argv[k] != NULL) && (k<MAXARGS)) ; k++)
                printf("%d=%s,",k,Node[i].Test[j].argv[k]);
           if (k!=1) printf("%c",8);
           printf(")");
      }
      printf("\n");
   }
}
