
/*
 *
 * Description
 *	Read an OFF object data file.
 *
 * Output
 *
 * Input
 *	Obj		Pointer to object structure in which to store data.
 *	FileName	Name of file to be read.
 *
 * Diagnostics
 *	Returns 0 if successful, -1 if unsuccessful for any reason.
 *
 * Author
 *	Randi J. Rost
 *	Digital Equipment Corp.
 *	Workstation Systems Engineering
 *	Palo Alto, CA
 *
 * History
 *	17-Nov-86	Created
 *
 */

#include <stdio.h>
#include "off.h"

#define	MAX_OBJ_DIRS		10
#define DEFAULT_DATA_BLK	100

static	char		ObjDir[MAX_OBJ_DIRS][OFF_BIGSTR];
static	int		NumObjDirs = 0;
static	int		firsttime = 1;
static	OFFProperty	**pProp;

OFFReadObj(Obj, FileName)
    OFFObjDesc	 *Obj;			/* Object data structure to fill out */
    char	 *FileName;		/* File to be opened and read */

    {
    FILE	*ObjFile;
    char	Line[OFF_BIGSTR];
    char	Key[OFF_BIGSTR];
    char	Remainder[OFF_BIGSTR];
    char	Directory[OFF_BIGSTR];
    char	Path[OFF_BIGSTR];
    char	TmpString[OFF_BIGSTR];
    char	*index(), *getenv();
    int		i;
    int		status = 0;
    char	*comment = "comment";
    char	*nl = "nl";


/*  If this is the first time, parse the object search path  */
    if (firsttime)
	status = ParseObjPath();

/*  Punt if too many directories in OBJ_PATH  */
    if (status < 0)
	{
	fprintf(stderr,"OFFReadObj: too many (> %d) directories in OBJ_PATH\n",
		MAX_OBJ_DIRS);
	return(-1);
	}

/*  See if filename has a leading pathname component  */
    Directory[0] = '\0';
    for (i = strlen(FileName) - 1; i >= 0; i--)
	if (FileName[i] == '/') break;
    if (i >= 0)
	{
	strncpy(Directory, FileName, i + 1);
	Directory[i+1] = '\0';
	}

/*  First try opening the file as passed to us  */
    ObjFile = fopen(FileName,"r");

/*  If that doesn't work, try each directory in search path  */
    if (ObjFile == NULL)
	{ 
	for (i = 0; i < NumObjDirs; i++)
	    {
	    strcpy(Path, ObjDir[i]);
	    strcat(Path, FileName);
	    ObjFile = fopen(Path, "r");
	    if (ObjFile != NULL)
		{
		strcpy(TmpString, ObjDir[i]);
		strcat(TmpString, Directory);
		strcpy(Directory, TmpString);
		break;
		}
	    }
	}

/*  If the file isn't found in any of the search directories, punt  */
    if (ObjFile == NULL)
	{
	fprintf(stderr, "OFFReadObj:  %s not found\n", FileName);
	return(-1);
	}

/*  Initialize fields in object structure  */
    pProp = &(Obj->FirstProp);
    Obj->FirstProp = NULL;

/*  Read lines from the header file  */
    while((fgets(Line, OFF_BIGSTR - 1, ObjFile)) != NULL) 
	{
    /*  Get the first token  */
	if (Line[0] == '\n')
	    status = AddProperty(nl, NULL, NULL);
	else if (Line[0] == '#')
	    status = AddProperty(comment, Line, NULL);
	else
	    {
	    SplitLine(Line, Key, Remainder);
	    status = AddProperty(Key, Remainder, Directory);
	    }
	if (status != 0)
	    {
	    fprintf(stderr, "OFFReadObj: problem parsing line\n");
	    fprintf(stderr, "\t>>>%s\n", Line);
	    return(-1);
	    }
	}

    fclose(ObjFile);
    return(0);
    }



static SplitLine(str, part1, remainder)
    char *str, *part1, *remainder;

    {
    int    i, p1, p2;

/*  If first character is '#' for a comment, we're done  */
    if (str[0] == '#')
	{
	strcpy(part1, "#");
	strcpy(remainder, &(str[1]));
	return;
	}

/*  Position p1 to first non-separator character  */
/*  Blanks, tabs, commas are separators */
    p1 = 0;	
    while ((str[p1] == ' ' ) || (str[p1] == '\t') || (str[p1] == ',')) p1++;

/*  Position p2 to first separator character after p1  */
    p2 = p1;
    while ((str[p2] != ' ') && (str[p2] != '\t') && (str[p2] != '\0') &&
	   (str[p2] != ',') && (str[p2] != '\n')) p2++;

/*  Copy what's between p1 and p2 to part1  */
    for (i = p1; i < p2; i++)
	part1[i - p1] = str[i];
    part1[i - p1] = '\0';

/*  Position p2 to next non-separator character  */
    while ((str[p2] == ' ' ) || (str[p2] == '\t') || (str[p2] == ',')) p2++;
    i = 0;
    while ((str[p2] != '\0') && (str[p2] != '\n') && (str[p2] != '\0'))
	remainder[i++] = str[p2++];
    remainder[i] = '\0';
    }

#ifdef caca
OFFPrintObjPath()

    {
    int		i;

/*  If this is the first time, parse the object search path  */
    if (firsttime)
	i = ParseObjPath();

/*  Punt if too many directories in OBJ_PATH  */
    if (i < 0)
	{
	fprintf(stderr,
	    "PrintObjPath: too many (> %d) directories in OBJ_PATH\n",
		MAX_OBJ_DIRS);
	return(-1);
	}

/*  Print out all directories in the object search path  */
    for (i = 0; i < NumObjDirs; i++)
	printf("%s ", ObjDir[i]);
    printf("\n");

    return(0);
    }
#endif

static ParseObjPath()

    {
    char	*str;
    int		i, j, len;

    firsttime = 0;
    str = getenv("OBJ_PATH");
    len = (str == NULL) ? 0 : strlen(str);
    for (i = 0; i < len; i++)
	{
	while ((str[i] == ' ') || (str[i] == '\t')) i++;
	j = i;
	while ((str[j] != ' ') && (str[j] != '\t') && (j < strlen(str)))
	    j++;
	strncpy(ObjDir[NumObjDirs], &(str[i]), j - i);
	ObjDir[NumObjDirs][j - i] = '/';
	ObjDir[NumObjDirs][j - i + 1] = '\0';
	if (strcmp(ObjDir[NumObjDirs], "./") != 0)
	    glob(ObjDir[NumObjDirs++]);  /* ignore directory "." in path */
	i = j;
	if (NumObjDirs > MAX_OBJ_DIRS)
	    return(-1);
	}

    return(0);
    }


#include <pwd.h>
#include <ctype.h>

static glob(string)
    char	*string;

    {
    struct	passwd	*p, *getpwname();
    char	str1[160], str2[160];
    char	*pstr;
    char	*getenv();

   
/*  If first character is '~', expand it  */
    if (string[0] == '~')

	{

	strcpy(str1, string);

    /*  ~/... means use home directory  */
	if (string[1] == '/')
	    {
	    strcpy(string, getenv("HOME"));
	    strcat(string, &(str1[1]));
	    }

    /*  ~whatever/... means use whatever's home directory  */
	else
	    {
	    pstr = index(str1, '/');
	    strncpy(str2, &(string[1]), pstr - str1 - 1);
	    str2[pstr - str1 - 1] = 0;
	    p = getpwnam(str2);
	    strcpy(string, p->pw_dir);
	    strcat(string, pstr);
	    }

	}

    }


static int AddProperty(PropName, String, Directory)
    char	*PropName;
    char	*String;
    char	*Directory;

    {
    OFFProperty	*newprop;
    char	str[OFF_BIGSTR], junk[OFF_BIGSTR], remainder[OFF_BIGSTR];
    char	datatype[OFF_BIGSTR];
    char	filename[OFF_BIGSTR];
    long	*iptr;
    short	*hptr;
    float	*fptr;
    double	*dptr;
    char	*ptr;
    int		i, j, k;
    char	*comment = "comment";

    newprop = (OFFProperty *) malloc(sizeof(OFFProperty));
    *pProp = newprop;
    pProp = &(newprop->NextProp);
    newprop->NextProp = NULL;
    newprop->PropData = NULL;
    newprop->PropFileName[0] = '\0';
    newprop->DataFormat[0] = '\0';
    newprop->PropCount = 0;
    PropName[OFF_SMSTR] = '\0';
    strcpy(newprop->PropName, PropName);

/* The following strcmp apparently caused some problems with the MIPS
   compiler...don't know what the problem was, but have altered the code
   some and it seems to work now.  Somehow the value for PropName was
   getting trashed.  Don't ask me.  */
/* fprintf(stderr, "PropName = >%s<\n", PropName); */
    if (strncmp(PropName, comment, strlen(comment) - 1) == 0)
	{
/* fprintf(stderr, "Got a comment!!!\n"); */
	String[strlen(String) - 1] = '\0';
	newprop->PropData = (char *) malloc(strlen(String));
	strcpy(newprop->PropData, String);
	newprop->PropType = OFF_COMMENT_DATA;
	return(0);
	}
/* fprintf(stderr, "PropName = >%s<\n", PropName); */

    if (strcmp(PropName, "nl") == 0)
	{
	newprop->PropData = (char *) malloc(OFF_BIGSTR);
	newprop->PropType = OFF_COMMENT_DATA;
	return(0);
	}

    if (strcmp(PropName, "name") == 0 || strcmp(PropName, "author") == 0 ||
	strcmp(PropName, "type") == 0 || strcmp(PropName, "description") == 0
	|| strcmp(PropName, "copyright") == 0)
	{
	newprop->PropData = (char *) malloc(OFF_BIGSTR);
	strcpy(newprop->PropData, String);
	newprop->PropType = OFF_STANDARD_DATA;
	return(0);
	}

    else
	{
	SplitLine(String, datatype, remainder);
	if (strcmp(datatype, "default") == 0)
		newprop->PropType = OFF_DEFAULT_DATA;
	else if (strcmp(datatype, "generic") == 0)
		newprop->PropType = OFF_GENERIC_DATA;
	else if (strcmp(datatype, "indexed") == 0)
		newprop->PropType = OFF_INDEXED_DATA;
	else if (strcmp(datatype, "indexed_poly") == 0)
		newprop->PropType = OFF_INDEXED_POLY_DATA;
	else
		newprop->PropType = OFF_UNKNOWN_TYPE_DATA;
	strcpy(str, remainder);
	SplitLine(str, newprop->DataFormat, remainder);

	remainder[OFF_SMSTR] = '\0';
	if (newprop->PropType != OFF_DEFAULT_DATA)
	    strcpy(newprop->PropFileName, remainder);

	switch(newprop->PropType)
	    {
	    case OFF_DEFAULT_DATA:
		newprop->PropCount = 1;
		newprop->PropData = (char *) malloc(DEFAULT_DATA_BLK);
		ptr = newprop->PropData;
		for (i = 0; i < strlen(newprop->DataFormat); i++)
		    {
		    switch (newprop->DataFormat[i])
			{
			case 'i':
			     /* Make sure we're aligned on word boundary */
			     ptr += (((int) ptr % 4) == 0) ?
				0 : 4 - (int) ptr % 4;
			     iptr = (long *) ptr;
			     sscanf(remainder, "%d", iptr);
			     ptr += sizeof(long);
			     strcpy(str, remainder);
			     SplitLine(str, junk, remainder);
			     break;
			case 'b':
			     sscanf(remainder, "%d", &j);
			     *ptr++ = (unsigned char) j;
			     strcpy(str, remainder);
			     SplitLine(str, junk, remainder);
			     break;
			case 'd':
			     /* Make sure we're aligned on word boundary */
			     ptr += (((int) ptr % 4) == 0) ?
				0 : 4 - (int) ptr % 4;
			     dptr = (double *) ptr;
			     sscanf(remainder, "%F", dptr);
			     ptr += sizeof(double);
			     strcpy(str, remainder);
			     SplitLine(str, junk, remainder);
			     break;
			case 'h':
			     /* Make sure we're aligned on halfword boundary */
			     ptr += (((int) ptr % 2) == 0) ? 0 : 1;
			     hptr = (short *) ptr;
			     sscanf(remainder, "%hd", hptr);
			     ptr += sizeof(short);
			     strcpy(str, remainder);
			     SplitLine(str, junk, remainder);
			     break;
			case 'f':
			     /* Make sure we're aligned on word boundary */
			     ptr += (((int) ptr % 4) == 0) ?
				0 : 4 - (int) ptr % 4;
			     fptr = (float *) ptr;
			     sscanf(remainder, "%f", fptr);
			     ptr += sizeof(float);
			     strcpy(str, remainder);
			     SplitLine(str, junk, remainder);
			     break;
			case 's':
			     j = 0; k = 0;
			     while (remainder[j] != ' ' && remainder[j] != '\t'
				    && j < strlen(remainder))
				 junk[k++] = remainder[j++];
			     junk[k] = '\0';
			     *((char **) ptr) = (char *) malloc(k + 1);
			     strcpy(*((char **) ptr), junk);
			     ptr += sizeof(char *);
			     strcpy(junk, &(remainder[j]));
			     strcpy(remainder, junk);
			     break;
			default:
			     return(-1);
			} /* switch */
		    } /* for */
		break;

	    case OFF_GENERIC_DATA:
		strcpy(filename, Directory);
		strcat(filename, newprop->PropFileName);
		if ((i = OFFReadGeneric(newprop, filename)) != 0)
		    return(-1);
		break;

	    case OFF_INDEXED_DATA:
		strcpy(filename, Directory);
		strcat(filename, newprop->PropFileName);
		if ((i = OFFReadIndexed(newprop, filename)) != 0)
		    return(-1);
		break;

	    case OFF_INDEXED_POLY_DATA:
		strcpy(filename, Directory);
		strcat(filename, newprop->PropFileName);
		if (OFFReadIndexedPoly(newprop, filename) != 0)
		    return(-1);
		break;

	    default:
		return(-1);
		break;
	    } /* switch */
	}

    return(0);
    }
