/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred."
 *
 */
/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*
 * Copyright  (c) 1985 AT&T
 *      All Rights Reserved
 */

#ident	"$Header: odftread.c 1.2 89/10/10 $@(#)vm.oh:src/oh/odftread.c	1.5"

#include <stdio.h>
#include <ctype.h>
#include <malloc.h>
#include "tsys.h"
#include "typetab.h"
#include "optabdefs.h"
#include "detabdefs.h"
#include "retcds.h"
#include "mio.h"
#include "terror.h"

/* This function reads the External Object Detection Function Table,
 * or "oddfoot" as it is known in conversation.
 * If the oddfoot exists, then it replaces the internal oddfoot.
 *
 * The structure of the external oddfoot is:
 *
 * [LINUM] OBJTYPE DEFAULT-ODI DEFAULT-MASK FUNCTION-TYPE [ARGUMENTS]
 * where:
 * LINUM is an optional decimal line number that is ignored.
 * OBJTYPE is the internal OTS name of the object.
 * DEFAULT-ODI is a string of default Object Dependent Information
 * DEFAULT-MASK is a hex number to be or'ed in with the object's mask.
 * FUNCTION-TYPE is an integer, one of:
 *	 	F_INT (4)	 Detect by internal detection function.
 *		F_SHELL (5)	 Detect by forking a process with a shell
 *		F_EXEC	(6)	 Detect by forking a process
 *		F_PARTS (7)	 Detect by part names
 *		F_DPARTS (8) Detect by the existance of parts
 *      F_MAGIC (9)  Detect by magic numbers 
 * ARGUMENTS are possible arguments to the function being called:
 *		F_INT	argument is a hex number,telling which internal function should
 *				be used.
 *		F_SHELL and F_EXEC, argument is a string, indicating a path.
 *		F_PARTS and F_DPARTS do not need arguments
 *		F_MAGIC a list of pairs of numbers.  The first number of each pair
 *				is an offset, the second is a byte value.  Numbers may be in
 *				hex, octal, or decimal according to the normal conventions
 *				(0xnumber, 0number, or number).
 *				For example: 0x01 033 0x02 041.  There is a limit of MAXMAGIC
 *				magic pairs.
 */

char	*calloc();
char	*expand();

static bool	Already_read = FALSE;	/* only do it once */

static long	Normal_mag_offset[] = {0L, 1L, -1L};

/* magic number info */
static long	O1[] = {0L, 2047L, -1L};
static long	O2[] = {0L, 1L, -1L};
static long	O3[] = {0L, 1L, -1L};
static long	O4[] = {0L, 1L, -1L};
static long	O5[] = {0L, 1L, -1L};
static long	O6[] = {0L, 1L, -1L};

static char	B1[] = {5, 2 }; 
static char	B2[] = {1, 0150 }; 
static char	B3[] = {1, 0151 }; 
static char	B4[] = {1, 0160 }; 
static char	B5[] = {1, 1061 }; 
static char	B6[] = {1, 015 };

extern struct odft_entry Detab[MAXODFT];

struct odft_entry FMLI_detab[MAXODFT] = {
	{ "MDIRECTORY",	"",		0,	8, 	0, NULL, NULL,	NULL },
	{ "DIRECTORY",	"",		0,	8,  	0, NULL, NULL,	NULL },
	{ "MENU",	"",		0,	7,	0, NULL, NULL,	NULL },
	{ "FORM",	"",		0,	7, 	0, NULL, NULL,	NULL },
	{ "TEXT",	"",		0,	7, 	0, NULL, NULL,	NULL },
	{ "STRUCT_1.0",	"",		0,	7, 	0, NULL, NULL,	NULL },
	{ "UCALC_1.0",	"",		0,	7, 	0, NULL, NULL,	NULL },
	{ "MAIL_OUT",	"",		0,	4,	10,NULL, NULL,	NULL },
	{ "MAIL_IN",	"",		0,	4,	9, NULL, NULL, 	NULL },
	{ "ASCII",	"",		0,	4,	0, NULL, NULL, 	NULL },
	{ "XED_5.208",	"",		0,	9,	0, NULL, O1,	B1 },
	{ "EXECUTABLE",	"TYPE=3B20",	0,	9,	0, NULL, O2,	B2  },
	{ "EXECUTABLE",	"TYPE=3B20",	0,	9,	0, NULL, O3,	B3  },
	{ "EXECUTABLE",	"TYPE=3B5/3B2",	0,	9,	0, NULL, O4,	B4  },
	{ "EXECUTABLE",	"TYPE=3B5/3B2",	0,	9,	0, NULL, O5,	B5  },
	{ "EXECUTABLE",	"TYPE=Z80",	0,	9,	0, NULL, O6,	B6  },
	{ "TRANSFER",	"",		0,	4,	3, NULL, NULL, 	NULL },
	{ "ASCII",	"",	 	0,	4,	1, NULL, NULL, 	NULL },
	{ "UNKNOWN",	"TYPE=COREDUMP",4000,	4,	4, NULL, NULL, 	NULL },
	{ "UNKNOWN",	"TYPE=ARCHIVE",	0,	4,	5, NULL, NULL, 	NULL },
	{ "ASCII",	"",		200,	4,	6, NULL, NULL, 	NULL },
	{ "XED_5.208",	"",	 	200,	4,	7, NULL, NULL, 	NULL },
	{ "UNKNOWN",	"",		0,	4,	8, NULL, NULL, 	NULL },
	{ "",		"",		0,	0,	0, NULL, NULL, 	NULL }
};

extern int Vflag;

int
odftread()
{
	if (Already_read)
		return(0);
	Already_read = TRUE;
	if (!Vflag) {
		/*
		 * table is hard-coded for "FACE" FMLI 
		 */
		register int i;

		for (i = 0; i < MAXODFT && FMLI_detab[i].objtype[0] != '\0';i++)
			Detab[i] = FMLI_detab[i];
		Detab[i].objtype[0] = '\0';
	}
	else {
		register int i, moffset;
		char *p, *q, buf[PATHSIZ];
		char *b;
		char	*tmpstr;
		FILE *fp;
		int offset = 0, magic;
		long magic_offset[MAXMAGIC+1];
		char magic_bytes[MAXMAGIC];
		char	*get_skip();
		char	*tab_parse();
		long	tab_long();

		p = expand("$OASYS/info/OH/externals/detect.tab");
		fp = fopen(p, "r");
		free(p);
		if (fp == NULL)
			fatal(MISSING, "detect.tab");
		tmpstr = NULL;
		while (get_skip(buf, PATHSIZ, fp) != NULL) {
			/* flush optional line number */
			for (b = buf; *b == '\t' || isdigit(*b); b++)
				;
			b = tab_parse(&tmpstr, b);
			strncpy(Detab[offset].objtype, tmpstr, OTYPESIZ);
			if (b) {
				char	*unbackslash();

				b = tab_parse(&Detab[offset].defodi, b);
				p = unbackslash(Detab[offset].defodi);
				if (p[0] == '"')
					memshift(p, p + 1, strlen(p));
				p += strlen(p) - 1;
				if (p[0] == '"')
					p[0] = '\0';
			}
			Detab[offset].defmask = tab_long(&b, 16);
			if (b && *b)
				Detab[offset].func_type = tab_long(&b, 16);
			else {
#ifdef _DEBUG
				_debug(stderr, "BAD ODFT '%s'\n", Detab[offset].objtype);
#endif
				error(MUNGED, "heuristics table");
				continue;
			}
			switch (Detab[offset].func_type) {
			case F_INT:
				Detab[offset].intern_func = tab_long(&b, 0);
				break;
			case F_SHELL:
			case F_EXEC:
				b = tab_parse(&tmpstr, b);
				Detab[offset].extern_func = tmpstr;
				tmpstr = NULL;
				break;
			case F_PARTS:
			case F_DPARTS:
				break;
			case F_MAGIC:
				p = b;
				magic = 0;
				while (*p && magic < MAXMAGIC) {
					moffset = strtol(p, &q, 0);
					if (p == q)  /* strtol failed */
						break;
					p = q;
					while (*q && isspace(*q))
						q++;
					if (*q == '"') {
						q++;
						while (*q && *q != '"' && magic < MAXMAGIC-1) {
							magic_bytes[magic] = *q;
							magic_offset[magic] = moffset++;
							magic++;
							q++;
						}
						if (*q)
							q++;
					} else {
						magic_offset[magic] = moffset;
						magic_bytes[magic] = (char) strtol(p,&q,0);
						if (p == q) {
							p = '\0';
							break;
						} else
							p = q;
						magic++;
					}
				}
				if (magic == 0) {
#ifdef _DEBUG
					_debug(stderr, "BAD ODFT '%s' MAGIC: %s\n", Detab[offset].objtype, q);
#endif
					error(MUNGED, "heuristics magic number");
					continue;
				}
				magic_offset[magic] = -1L;

				/* for efficiency, the most common magic number
				 * case, 0, 1, -1, is coded up.
				 */

				if (magic == 2 && magic_offset[0] == 0L &&
					magic_offset[1] == 1L) {
					Detab[offset].magic_offset = &(Normal_mag_offset[0]);
				}
				else {
					Detab[offset].magic_offset = (long *)calloc(magic+1, sizeof(long));
					for (i = 0; i < magic+1; i++)
						Detab[offset].magic_offset[i] = magic_offset[i];
				}
				Detab[offset].magic_bytes = calloc(magic, sizeof(char));
				for (i = 0; i < magic; i++)
					Detab[offset].magic_bytes[i] = magic_bytes[i];
				break;
			default:
#ifdef _DEBUG
				_debug(stderr, "ODFT '%s' BAD FUNCTION: %d\n", Detab[offset].objtype, Detab[offset].func_type);
#endif
				error(MUNGED, "heuristics table function");
				continue;
			}
			offset++;
		}
		fclose(fp);
		Detab[offset].objtype[0] = '\0';
		if (tmpstr)
			free(tmpstr);
	}
	return(0);
}
