/*
 * @DEC_COPYRIGHT@
 */
/*
 * HISTORY
 * $Log: binary.c,v $
 * Revision 1.2  1995/03/09  21:40:29  bourquard
 * port to NT
 *
 * Revision 1.1.2.2  1994/04/08  19:02:22  Susan_Ng
 * 	contains code to check whether a file is a binary file or not
 * 	[1994/03/31  22:15:16  Susan_Ng]
 *
 * $EndLog$
 */
#ifndef lint
static char *rcsid = "@(#)$RCSfile: binary.c,v $ $Revision: 1.2 $ (DEC) $Date: 1995/03/09 21:40:29 $";
#endif
/*
 * Copyright 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
 * 
 *                         All Rights Reserved
 * 
 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */
/*
 *
 *	FACILITY: 
 *		dxdiff
 *
 *	MODULE: 
 *		binary.c - the main body!
 *
 *	AUTHOR:
 *
 *
 *	ABSTRACT:
 *		This file contains code to determine whether a file is a
 *		binary file or a plain ascii file.
 *		This code was taken from the "diff" utility; file diffdir.c.
 *		The function CheckForBinaryFile() is same as function ascii()
 *		as in diffdir. Only the name has been changed.
 *
 *	MODIFICATION HISTORY:
 *
 */
 
#include <stdio.h>
#include <sys/stat.h>
#ifdef WIN32
#include <X11/xfuncs.h>
#define lseek 	_lseek
#define read	_read
#endif WIN32
#include "dxdiff_proto.h"	/* Function proto's */

#define MAGIC	"/etc/magic"

int ascii_bsd PROTO ((int f));


int CheckForBinaryFile
/*
 * Function: checks to see if file is ascii
 *
 * Inputs: f - file descriptor of file to check
 *
 * Outputs: returns 1 for binary and 0 for ascii.
 *          **** I think this is reversed --
 *          **** returns 0 for binary and 1 for ascii.
 *          **** Deb Bourquard 1/17/95
 *
 * Notes: This function was called ascii in diff. 
 *
 *     Severely hacked for WIN32 on NT -- just returns 1 (ascii).
 */
  
#ifdef DXDIFF_PROTO	/* prototypes */
	(int f)
#else			/* no prototypes */
	(f)
	int f;
#endif			/* end ifdef DXDIFF_PROTO */
{
	char buf[BUFSIZ], cmpbuf[BUFSIZ], s1[BUFSIZ], msg[BUFSIZ];
	char type[40], svalue[40], *tmp;
	FILE *fd;
	long int prevoff, offset;
	long unsigned nvalue;

#ifndef WIN32
	if ((fd = fopen(MAGIC,"r")) == NULL) {
		fprintf(stderr,"Can not open %s file\n",MAGIC);
		return(1);
	}
	prevoff = -1;
	while ((fgets(buf,BUFSIZ,fd)) != NULL) {
		if (!iswdigit((wint_t)buf[0]))
			continue;
		sscanf(buf,"%s %s %s %s",s1,type,svalue,msg);
		offset = strtoul(s1,&tmp,0);
		if (strcmp("short",type) != 0 &&
		    strcmp("long",type) != 0 &&
		    strcmp("byte",type) != 0 )
			continue;
		nvalue = strtoul(svalue, NULL, 0);
		if (offset != prevoff) {
			lseek(f, offset, 0);
			bzero(cmpbuf, BUFSIZ);
			read(f, cmpbuf, BUFSIZ);
			prevoff = offset;
		}
		if (strcmp("short",type) == 0) {
			if (nvalue != (long)(*(unsigned short *) cmpbuf))
				continue;
		} else if (strcmp("long",type) == 0) {
			if (nvalue != (*(long *) cmpbuf))
				continue;
		} else if (nvalue != (long)(*(unsigned char *) cmpbuf))
			continue;
		(void) fclose(fd);
		return(0);
	}
	(void) fclose(fd);
	/* At this point it looks like the file might be "ASCII",
	 * but there are "string"-type entries in /etc/magic which
	 * identify binary files too, but the string-type entries are
	 * skipped above.  The file(1) command also knows about binary
	 * files that are not in /etc/magic, but file(1) returns strings
	 * which may be internationalized, so we can't depend on those
	 * message strings.
	 *
	 * Therefore, for now, lets fall back to the old reliable method
	 * of checking if files are a.out files, or contain non-text
	 * characters.
	 */
#endif WIN32

	return(ascii_bsd(f));
}

#ifndef WIN32
#include <a.out.h>
#endif WIN32
#ifdef	multimax
#define	BADMAG(X) (X.f_magic != NS32GMAGIC && X.f_magic != NS32SMAGIC)
#endif	/* multimax */
#if     defined(mips) || defined(__alpha)
#define	BADMAG(X) (!(ISCOFF(X.f_magic)))
#endif	/* mips or alpha */
#if	defined(i386) || defined (PS2)
#define BADMAG(X) ((X.f_magic != I386MAGIC) && (X.f_magic != COFF386MAGIC))
#endif  /* i386 || PS2 */


int
ascii_bsd
/*
 * Function: check to see if file is an a.out type file
 *
 * Inputs: f - file descriptor of file to check
 *
 * Outputs: returns 1 for binary and 0 for ascii
 *
 * Notes:  This function is the same as in diff.
 */
#ifdef DXDIFF_PROTO	/* prototypes */
	(int f)
#else			/* no prototypes */
	(f)
	int f;
#endif			/* end ifdef DXDIFF_PROTO */
{
#ifndef WIN32    
	char buf[BUFSIZ];
	register int cnt;
	register int c;
	register char *cp;

	lseek(f, (long)0, 0);
	cnt = read(f, buf, BUFSIZ);
	if (cnt >= sizeof (struct filehdr)) {
		struct filehdr hdr;
		hdr = *(struct filehdr *)buf;
		if (!BADMAG(hdr))
			return (0);
	}
	cp = buf;
	while (cnt > 0)
	{
		c = mblen(cp, cnt);
		if (!(c & 0377))
			return(0);			/* GA001 */
		if ((c < 0) && (cnt >= MB_LEN_MAX))
			return(0) ;	/* Invalid multi-byte character */
		else if (c < 0)
			break ;		/* Not binary */
		else if (c == 0)
			cnt--, cp++ ;
		else
		{
			cnt -= c ;
			cp  += c ;
		}
	}
	return (1);
#else 
    return (1);             /* it's ASCII */
#endif WIN32
}
