#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "obj.h"

extern char *progname;
extern char *magicfile;	/* name of current magic file */
extern int debug, nmagic;
extern FILE *efopen();
extern struct magic magic[];
extern char execbuffer[];    /* buffer to execute */
extern long obj_type;
static int magindex;
static char warnbuf[80];

/*
 * softmagic - lookup one file in database 
 * (already read from /etc/magic by apprentice.c).
 * Passed the name and FILE * of one file to be typed.
 */

int softmagic(char *buf)
 {
	magindex = 0;
	if (match(buf))
		return 1;

	return 0;
 }

/*
 * go through the whole list, stopping if you find a match.
 * Be sure to process every continuation of this match.
 */

int match(char *s)
 {
	while (magindex < nmagic) {
		/* if main entry matches, print it... */
		if (mcheck(s, &magic[magindex])) {
			mprint(&magic[magindex],s);
			/* and any continuations that match */
			while (magic[magindex+1].contflag &&
				magindex < nmagic) {
				++magindex;
				if (mcheck(s, &magic[magindex])){
					(void) putchar(' ');
					mprint(&magic[magindex],s);
				}
			}
			return 1;		/* all through */
		} else {
			/* main entry didn't match, flush its continuations */
			while (magic[magindex+1].contflag &&
				magindex < nmagic) {
				++magindex;
			}
		}
		++magindex;			/* on to the next */
	}
	return 0;				/* no match at all */
 }

void mprint(struct magic *m, char *s)
 {
	register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
	char *pp, *strchr();

	switch (m->type) 
	  {
	    case OBJ_BYTE:
		 (void) sprintf(execbuffer, m->desc, p->b);
		 break;
	case OBJ_SHORT:
		(void) sprintf(execbuffer, m->desc, p->h);
		break;
	case OBJ_LONG:
		(void) sprintf(execbuffer, m->desc, p->l);
		break;
	case OBJ_STRING:
		if ((pp=strchr(p->s, '\n')) != NULL)
			*pp = '\0';
		(void) sprintf(execbuffer, m->desc, p->s);
		break;
//	default:
//		sprintf(warnbuf, "invalid m->type (%d) in mprint()", m->type);
//		warning(warnbuf, "");
	}
 }

int mcheck(char *s, struct magic *m)
 {
	register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
	register long l = m->value.l;
	register long v;

	switch (m->type) 
     {
   	 case OBJ_BYTE:     v = p->b;             break;
	    case OBJ_SHORT: 	 v = p->h;             break;
	    case OBJ_LONG: 	 v = p->l;             break;
	    case OBJ_STRING:
		    l = 0;
		/* What we want here is:
		 * v = strncmp(m->value.s, p->s, m->vallen);
		 * but ignoring any nulls.  bcmp doesn't give -/+/0
		 * and isn't universally available anyway.
		 */
		{
			register unsigned char *a = (unsigned char*)m->value.s;
			register unsigned char *b = (unsigned char*)p->s;
			register int len = m->vallen;

			while (--len >= 0)
				if ((v = *b++ - *a++) != 0)
					break;
		}
		break;
	default:
//		sprintf(warnbuf, "invalid type %d in mcheck()", m->type);
//		warning(warnbuf, "");
		return 0;
	}

	switch (m->reln) {
	case '=':
		return v == l;
	case '>':
		return v > l;
	case '<':
		return v < l;
	case '&':
		return v & l;
	default:
		sprintf(warnbuf, "mcheck: can't happen: invalid relation %d", m->reln);
		warning(warnbuf, "");
		return 0;
	}
 }
