#ifdef	ournix
#include "ournix.h"
#endif
char sccsID[] = "@(#) overlay.c V1.14 Copyright Julian H. Stacey, Munich, May 1989.\n";

/* See manual for explanation */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef	MSDOS	/* { */
#include <fcntl.h>
#endif		/* } */
#include <fcntl.h>


char	*output_name = (char *)0 ;
struct stat	stat_buf ;

typedef	int	FD ;
typedef	char	FLAG ;
FD	fd ;
FLAG	silent = 0 ;
FLAG	force = 0 ;
FLAG	f_brother = 0 ;

#ifdef scs	/* { */
extern char *mktemp() ;
#define TMP_NAME "ovXXXXXX"
#else		/* }{ */
#include <unistd.h>
#ifdef MSDOS	/* { */
#define TMP_NAME "ovXXXXXX"
#else		/* }{ */
#define TMP_NAME "overlay.XXXXXX"
#endif		/* } */
#endif		/* } */
#include <sys/param.h>	/* for MAXPATHLEN */
char	tmp_name[MAXPATHLEN] ;		/* temporary file name */

char txt_complain[] = "%s: Cannot open %s.\n";
unsigned	current_line = 1 ;
#define	LINE_LN	1000

FILE	*fp_1, *fp_2 ;
FILE	*fp_out ;
char	**ARGV ;

char a_out_array[LINE_LN] ;
char *p_out_array = a_out_array ;

#undef 		USE_STRCHR
#if ( vax || i386 || MSDOS ) /* { */
#define		USE_STRCHR
#endif		/* } */

#ifdef	USE_STRCHR	/* { */
	extern	char *strchr() ;
#define	index(s,c)	strchr(s,c)
#else		/* } { */
	extern	char *index() ;
#endif		/* } */

	/* ---------------------------------------------------- */

char *get_line(fp,where,max_length)
	FILE	*fp ;
	register char *where ;
	register int max_length ; /* max. size of array including null */
	{
	register int ch ;

	max_length-- ; /* allow for \n */
	while (((ch = getc(fp)) != EOF) && ((char)ch != '\n'))
		{
		if (--max_length <= 0 )
			{
			fprintf(stderr,"%s: Error line %d too long.\n",
				*ARGV, current_line);
			exit(-1);
			}
		*where++ = (char)ch ;
		}
	if ((char)ch == '\n') *where++ = '\n' ;
	*where = '\0' ;
	return(where);
	}

void cleanup()
	{
	(void) unlink(tmp_name) ;
	}

void brother()	/* Allow for brother that does a single pixel down shift when
			doing italic bold underlines */
	{
	register int	count ;
	/* spaces to right perforation */
#define	XX	100	/* 100 for elite (small) 84 for pica (big) */
#define	YY	40
	for ( count = XX ; count-- ; putchar(' ') ) ;
	/* down one pixel each underscore, till brother is stable */
	for ( count = YY ; count-- ; )
		{ putchar('_') ; putchar('\b') ; }
	/* back space to left margin */
	for ( count = XX ; count-- ; putchar('\b') ) ;
	}

void my_putc(ch,where)
	char	ch ;
	FILE	*where ;
	{
	if (silent) return ;
	*p_out_array++ = ch ;
	if (p_out_array - a_out_array > LINE_LN - 5)
		{
		*p_out_array = '\0' ;
		fprintf(stderr,
			"%s: Aborting, Output line too long.\n%s\n",*ARGV,
			a_out_array) ;
		exit(1) ;
		}
	if (ch == '\n')
		{
		*p_out_array++ = '\0' ;
		if (f_brother && (index(a_out_array,'_') != (char *)0))
			brother() ;
		fprintf(where,"%s",a_out_array) ;
		/*
		for (p_out_array = a_out_array; (ch = *p_out_array++) != '\0'; )
			(void)fputc((int)ch,where) ;
			*/
		p_out_array = a_out_array ;
		}
	}

int main(argc, argv)
	int	argc ;
	char	**argv;
	{
	char		*name_1, *name_2 ;
	char		line_1[LINE_LN], line_2[LINE_LN] ;
	char		*p_1, *p_2, c_1, c_2 , *rslt_1, *rslt_2 ;
	unsigned	out_line = 0, out_char = 0 ;
	unsigned	current_char = 1 ;
	register int	ch ;

	ARGV = argv ;
	fp_out = stdout ;
#ifdef	VSL	/* { */
#include	"../../include/vsl.h"
#endif		/* } */
	strcpy(tmp_name,TMP_NAME) ;
	for (argc--, argv++ ; argc > 0 ; argv++ )
		{
		if(**argv != '-') break /* no more parameters */ ;
		argc-- ;
		switch(*++*argv)
			{
			/* option detect */
			case 'o': /* syntax:"overlay -o out in1 in2"
					functionality: like -o flag of cc
					only outputs to file if no error */
				if (argc-- == 0)
					{
					fprintf(stderr,
					 "%s: -o must have a parameter.\n",
						*ARGV);
					exit(-1);
					}
				output_name = *++argv ;
				break ;
			case 's':	/* silent, no normal output,
					just returns error output & status */
				silent = 1 ;
				break ;
			case 'f':	/* force output.
					(normally -o only produces output
					if there is no everlay error) */
				force = 1 ;
				break ;
			case 'b':	/* bad brother printer */
				f_brother = 1 ;
				break ;
			default:
				fprintf(stderr, "%s: Unknown flag %c\n",
					*ARGV, **argv);
				break;
			}
		}

	/* finished taking parameters */
	if ((argc == 0) || (argc > 2))
		{
		fprintf(stderr,"%s: Error, must specify 1 or 2 input files.\n",
			*ARGV);
		exit(-1);
		}
	if (silent && force)
		{
		fprintf(stderr,"%s: Error -s & -f cannot be used together.\n",
			*ARGV);
		exit(-1);
		}

	name_1 = *argv++ ;
	if ( ( fp_1 = fopen(name_1, "r")) == (FILE *)0 )
		{
		fprintf(stderr, txt_complain, *ARGV ,name_1);
		exit(-1);
		}
	if(argc == 1)
		{
		name_2 = "\0" ;
		fp_2 = stdin ;
		}
	else	{
		name_2 = *argv++ ;
		if ( ( fp_2 = fopen(name_2, "r")) == (FILE *)0 )
			{
			fprintf(stderr, txt_complain, *ARGV ,name_2);
			exit(-1);
			}
		}
	if (output_name != (char *)0 )
		{
		if (mktemp(tmp_name) == (char *)0)
			{
			fprintf(stderr,"%s: cant mktemp %s.\n",*ARGV,tmp_name);
			exit(-1) ;
			}

		/* Mask signals */
		(void)signal(SIGINT,	(void *)&cleanup) ;
#ifndef MSDOS		/* { */
		(void)signal(SIGALRM,	(void *)&cleanup) ;
		(void)signal(SIGHUP,	(void *)&cleanup) ;
		(void)signal(SIGQUIT,	(void *)&cleanup) ;
		(void)signal(SIGILL,	(void *)&cleanup) ;
		(void)signal(SIGIOT,	(void *)&cleanup) ;
		(void)signal(SIGEMT,	(void *)&cleanup) ;
		(void)signal(SIGFPE,	(void *)&cleanup) ;
		(void)signal(SIGBUS,	(void *)&cleanup) ;
		(void)signal(SIGSEGV,	(void *)&cleanup) ;
		(void)signal(SIGTERM,	(void *)&cleanup) ;
#ifdef BSD4_2		/* { */
		(void)signal(SIGTSTP,	(void *)&cleanup) ;
#endif			/* } */
#endif			/* } */

		/* create temp file */
		fd =
#ifdef	MSDOS	/* { */
		open
#else	/* MSDOS } { */
		creat
#endif		/* !MSDOS } */
			( tmp_name,
#ifdef	MSDOS	/* { */
			O_WRONLY | O_CREAT , S_IREAD | S_IWRITE
#else	/* MSDOS } { */
			0644
#endif		/* !MSDOS } */
						) ;
		(void) close(fd) ;

		if (( fp_out = fopen(tmp_name, "r+")) == (FILE *)0 )
			{
			fprintf(stderr, txt_complain, *ARGV, tmp_name);
			exit(-1);
			}
		}

	rslt_1 = get_line(fp_1,line_1,LINE_LN) ;
	rslt_2 = get_line(fp_2,line_2,LINE_LN) ;
	while ( (rslt_1 != line_1) || (rslt_2 != line_2) )
		{ /* new lines */
		p_1 = line_1 ; p_2 = line_2 ; current_char = 0 ;
		c_1 = *p_1 ; c_2 = *p_2 ;
		while ( ( c_1 != '\0' ) || ( c_2 != '\0' ) )
			{
			current_char++ ;
			/* warning the order of the following ifs is important*/
			if (c_1 == '\0')	my_putc(c_2,fp_out) ;
			else if (c_2 == '\0')	my_putc(c_1,fp_out) ;

			else if (c_1 == '\n')	my_putc(c_2,fp_out) ;
			else if (c_2 == '\n')	my_putc(c_1,fp_out) ;

			else if (c_1 == c_2)	my_putc(c_1,fp_out) ;

			else if (c_1 == ' ')	my_putc(c_2,fp_out) ;
			else if (c_2 == ' ')	my_putc(c_1,fp_out) ;

			/* tab handling is not ideal, a bit of a cludge,
				but better than nothing */
			/* '\t' should be dealt with before '_' */
			else if (c_1 == '\t')
				{ 
				my_putc(c_2,fp_out) ;
				my_putc('\t',fp_out) ;
				}
			else if (c_2 == '\t')
				{ 
				my_putc(c_1,fp_out) ;
				my_putc('\t',fp_out) ;
				}

			else if (c_1 == '_')
				{
				my_putc('_',fp_out) ;
				my_putc('\b',fp_out) ;
				my_putc(c_2,fp_out) ;
				}
			else if (c_2 == '_')
				{ if (!silent)
				my_putc('_',fp_out) ;
				my_putc('\b',fp_out) ;
				my_putc(c_1,fp_out) ;
				}

			else	{
#define	BELL	((char)7 /* bell*/ )
				my_putc(BELL,fp_out) ;
				if (out_line == 0)
					{
					out_line = current_line ;
					out_char = current_char ;
					}
				}
			if ( c_1 != '\0' ) c_1 = *++p_1 ;
			if ( c_2 != '\0' ) c_2 = *++p_2 ;
			}
		current_line++ ;
		rslt_1 = get_line(fp_1,line_1,LINE_LN) ;
		rslt_2 = get_line(fp_2,line_2,LINE_LN) ;
		}
	if (out_line) fprintf(stderr,
		"%s: Error 1st conflicting character at line %d char %d.\n",
		*ARGV, out_line,(int)out_char);
	(void)fclose(fp_1);
	(void)fclose(fp_2);
	if (output_name == (char *)0 )
		{	/* output to stdout, whether overlay collision or not */
		if (!silent)
			{
			rewind(fp_out) ;
			while ((ch = getc(fp_out)) != EOF) putchar(ch) ;
			}
		(void) fclose(fp_out) ;
		(void) unlink(tmp_name) ;
		}
	else	{	/* output to a file only if no overlay collision */
		if ((out_line && !force) || silent)
			{ /* overlay collision */
			(void) fclose(fp_out) ;
			(void) unlink(tmp_name) ;
			}
		else	{ /* no overlay collision */
			if ( (*output_name == '-' ) /* stdout */
#ifdef	unix	/* { */
				|| ((stat(output_name, &stat_buf) == 0) &&
					(stat_buf.st_nlink > 1) )
#endif		/* } */
				)
				{ /* stdout or linked file so overwrite */
				rewind(fp_out) ;
				if (*output_name != '-' )
					fp_1 = fopen(output_name,"w");
					else fp_1 = stdout ;
				while ((ch = getc(fp_out)) != EOF)
					(void)fputc(ch,fp_1) ;
				(void) fclose(fp_out) ;
				(void) fclose(fp_1) ;
				(void) unlink(tmp_name) ;
				}
			else (void)rename(tmp_name, output_name) ;
			}
		}
	exit((int)out_line);
	}


