#ifndef	LINT
char lib_replace[] =
	"@(#) lib/replace.c V1.3 Copyright Julian H. Stacey 89-10-04\n" ;
#endif
/* Symmetric implements char as signed char,
	hence the use of unsigned chars in some places,
	else a byte in a file such as 0xFF gets erroneously treated as EOF */

/* only valid way to use this file is by calling replace(),
	which does all necessary initialisations for you, to ensure this
	usage is enforced, all other procedures are declared static*/
/* ----------------------------------------------------------------------- */
/* temporary file name	*/
#ifdef	MSDOS	/* { */
/* temporary file in msdos laptop ram root drive */
#define	TMP_NAME	"/reXXXXXX.tmp"		
#else		/* } { */
/* temporary file for unix not possible in root directory */
#define	TMP_NAME	"/tmp/replace.XXXXXX"
#endif		/* } */
static	char	gbl_tmp_name[sizeof(TMP_NAME)+1] ; /* temporary file name	*/
/* ----------------------------------------------------------------------- */
#include	<stdio.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#ifdef ns32000	/* { */
#define BSD
#endif		/* } */
#ifdef	BSD
#include	<sys/file.h>
#include	<sys/signal.h>
#else
#include	<signal.h>
#endif
#ifndef	BSD	/* { */
#include	<fcntl.h>
#endif		/* } */
#include	"ms_exe.h"
/* ----------------------------------------------------------------------- */
typedef	int		FD ;
#define	FD_UNSET	-1
typedef	char		FLAG ;
#ifdef	MSDOS	/* { */
	typedef int	CKSUM ;
#endif		/* } */
#ifdef	ns32000	/* { */
	typedef	short	CKSUM ;
#endif		/* } */
/* ----------------------------------------------------------------------- */
#ifdef	MSDOS
#define MAXBUF	20000
			/* if MAXBUF = 30000, MSC compiler generating for
			small model produces a binary
			that complains not enough room for environment */
#else
#define MAXBUF	50000
#endif
/* ----------------------------------------------------------------------- */
extern	char **ARGV ;
extern	syntax() ;
extern	char *strcpy() ;
extern	char *mktemp() ;
extern	char *malloc() ;
/* ----------------------------------------------------------------------- */
/* output/tmpfile variables	*/
static unsigned char	gbl_out_buf[MAXBUF] ;
static unsigned char	*gbl_out_buf_p ;	/* where to write next char */

/* input file variables	*/
static unsigned char	gbl_in_buf[MAXBUF] ;
static unsigned char	*gbl_in_buf_next_p ;
static unsigned char	*gbl_in_buf_end_p ;
					/* address of byte beyond buffer */
/* ----------------------------------------------------------------------- */
/* MSDOS .EXE Checksum to be written back:
					I dont know how msdos works out
					checksum, so i subtract
					each input word from the original
					checksum, and add each output word back
					to the original checksum */
static CKSUM	gbl_orig_cksum ;	/* checksum msdos file originally
					contains calculated by msdos linker */
static CKSUM	gbl_input_data_cksum ;	/*sum of words input from data segment*/
static CKSUM	gbl_output_data_cksum ;	/*sum of words output to data segment */
static CKSUM	gbl_input_tmp_cksum ;	/* byte/word buffering on input */
static CKSUM	gbl_output_tmp_cksum ;	/* byte/word buffering on output */
/* ----------------------------------------------------------------------- */
static	long	gbl_in_count ;	/* read seek counter from start of file, used
					for checksum calculation, and 
					will be used to obviate
					redundant reads writes combinations */
static	long	gbl_out_count ; /* write seek counter from start of file, used
					for checksum calculation, and 
					will be used to obviate
					redundant writes combinations */
static	FD	gbl_tmp_fd ;
static	FD	gbl_orig_fd ;
static	FLAG	gbl_cksum_f ;
static	FLAG	gbl_binary_f ;
/* ----------------------------------------------------------------------- */
/* variables set (& possibly used by replace()) and used by buf_flush(),
	not passed as a parameter to buf_flush() for efficiency,
	because of the high number of times buf_flush() will be called */
static	char	*gbl_in_buf_base_p ;	
static	unsigned gbl_remove_u, gbl_relace_u ;
static	int	gbl_occur_max_i ;
static	char	gbl_fill_c ;
static	char	*gbl_replace_p ;
/* ----------------------------------------------------------------------- */
/* strings used more than once */
static	char	gbl_txt_nowrite[] =	"Write error on %s file.\n" ;
static	char	gbl_txt_temp[] =	"temporary" ;
static	char	gbl_txt_abort[] =	", Aborting.\n" ;
static	char	gbl_txt_close[] =	"close" ;
static	char	gbl_txt_lseek[] =	"lseek" ;
static	char	gbl_txt_signal[] =	"signal" ;
/* ----------------------------------------------------------------------- */
static proc_failed(str)
	char	*str ;
	{
	fprintf(stderr,"%s: failed %s%s",*ARGV,str,gbl_txt_abort) ;
	perror(*ARGV) ;
	exit(1) ;
	}
/* ----------------------------------------------------------------------- */
/* 8 & 16 bit arithmetic simulator for larger machines */
#ifdef MSDOS	/* { was msdos , worked ok */
#define s_add(int_a,int_b,width) (int_a + int_b)
#else		/* } { */
	static int
s_add(int_a,int_b,bits)	/* signed 8 or 16 bit addition */
	int int_a, int_b ;	/* must not be passed values outside the scope
					of signed 8/16 bit values,
					but does not matter if compiler
					implements them as longs */
	int	bits ;
	{
	long				/* some hosts may treat ints as 8/16,
						& longs as 32, so stay safe
						with longs */
		long_a, long_b, tmp, max, min ;

	max = (( 1L << (bits - 1)) - 1L ) ;	/* ex 4 bit system 2^3-1 = 7 */
	min = (-( 1L << (bits - 1)) ) ;		/* ex 4 bit system -2^3 = -8 */
	long_a = int_a ;
	long_b = int_b ;
	tmp = long_a + long_b ;
	/* to understand the next bit, draw a circle with +7 down to 0 and
		further round to -8 marked on it */
	if ( tmp > max ) tmp -= (1L << bits) ; /* ex: 14 > 7 +14 - +16 = -2 */
	else if ( tmp < min ) tmp += (1L << bits) ; /* ex: -10 < -8+16+-10=+6 */
	return(tmp) ;
	}
#endif	/* } */
/* ----------------------------------------------------------------------- */
	static
clean_from_sig()
	{
	fprintf(stderr,"%s: Aborted on interrupt.\n",*ARGV);
	my_unlink() ;
	exit(1) ;
	}
/* ----------------------------------------------------------------------- */
	static int
in_c()
	{
	int	amount ;

	amount = read( gbl_orig_fd,  (char *)gbl_in_buf, (int)MAXBUF ) ;
	if ( amount <= 0 ) return( EOF ) ;
	gbl_in_buf_next_p = gbl_in_buf ;
	gbl_in_buf_end_p = gbl_in_buf + amount ;
	return( (int)*gbl_in_buf_next_p++ ) ;
	}
#define my_getchar()	(( gbl_in_buf_next_p < gbl_in_buf_end_p ) ? \
				(int)*gbl_in_buf_next_p++ : in_c())
/* ----------------------------------------------------------------------- */
#define my_putchar(c) 	{ *gbl_out_buf_p++ = c ; if (gbl_out_buf_p >= \
				&gbl_out_buf[MAXBUF-1] ) my_flush() ; }
	static
my_flush()
	{
	register int	amount ;
	/* create temporary file */
	if (gbl_tmp_fd < 0 )
		{
		/* Open temp file if necessary - if buffer is big enough,
			temp file creation is never done, (thats why its
			done here, and not earlier) */
		if ( ( gbl_tmp_fd = open( gbl_tmp_name,
#ifdef	MSDOS	/* { */
				O_BINARY |
#endif	/* } */
				O_CREAT | O_TRUNC | O_RDWR, 0200 ) ) < 0 )
			{
			fprintf( stderr, "%s: Cannot create %s file '%s'\n",
						*ARGV,
						gbl_txt_temp, gbl_tmp_name ) ;
			fprintf(stderr,"%s", gbl_txt_abort) ;
			exit(1) ;
			}
		}
	amount = gbl_out_buf_p - gbl_out_buf ;
	if ( write( gbl_tmp_fd, (char *)gbl_out_buf, amount ) != amount )
		{
		fprintf( stderr, gbl_txt_nowrite, gbl_txt_temp ) ;
		my_unlink() ;
		fprintf(stderr,"%s", gbl_txt_abort) ;
		exit(1) ;
		}
	gbl_out_buf_p = gbl_out_buf ;
	}
/* ----------------------------------------------------------------------- */
	static int
getc_via_cksum()
	{
	register int	byte ;

	byte = my_getchar() ;
	if (gbl_cksum_f)
		{ /* memorise msdos checksum in passing */
		if ((gbl_in_count % 2) == 0)	/* first (=high) byte of word */
			gbl_input_tmp_cksum = 0xFF00 & (byte << 8 ) ;
		else	{ /* trailing low byte */
			gbl_input_tmp_cksum |= 0xFF & byte ;
			if (gbl_in_count > MS_EXE_OVERLAY_LO)
				gbl_input_data_cksum =
					s_add(gbl_input_data_cksum,
						gbl_input_tmp_cksum,16) ;
			else if (gbl_in_count == MS_CKSUM_LO)
				gbl_orig_cksum = -gbl_input_tmp_cksum ;
			}
		}
	/* if (gbl_binary_f) */  gbl_in_count++ ;
	return(byte) ;
	}

	static
putchar_via_cksum(byte)
	char	byte ;
	{
	register char	fast_byte ;
	my_putchar(fast_byte = byte) ;
	if (gbl_cksum_f)
		{
		if (gbl_out_count > MS_EXE_OVERLAY_LO)
			{
			/* add data from checksum */
			if (gbl_out_count % 2)
				gbl_output_tmp_cksum = 0xFF00 & 
					(fast_byte << 8 ) ;
			else	{
				gbl_output_tmp_cksum |= 0xFF & fast_byte ;
				gbl_output_data_cksum =
					s_add(gbl_output_data_cksum,
						gbl_output_tmp_cksum, 16) ;
				}
			}
		gbl_out_count++ ;
		}
	}
/* ----------------------------------------------------------------------- */
	static
sig_ign()
	{
	if (signal( SIGINT, SIG_IGN) < 0) proc_failed(gbl_txt_signal ) ;
	}
	static
my_unlink()
	{
	if ( gbl_tmp_fd >= 0)
		{
		sig_ign() ;
		if (close(gbl_tmp_fd)) proc_failed(gbl_txt_close );
		if (unlink( gbl_tmp_name ) < 0 ) proc_failed("unlink") ;
		gbl_tmp_fd = FD_UNSET ;
		(void) signal(SIGINT,SIG_DFL) ;
		}
	}
	static 
name_off_screen(name)
	char	*name ;
	{
	register int	i, j ;

	i = strlen( name) ;
	for ( j = i ; j-- ; ) (void)putchar( '\b') ;
	for ( j = i ; j-- ; ) (void)putchar( ' ') ;
	for ( j = i ; j-- ; ) (void)putchar( '\b') ;
	}
/* JJ ----------------------------------------------------------------------- */
	static
buf_flush(P_buf_count_u, P_found_u)
/* Flushes initial portion, then pad portion, then extension portion.
   Code outside this routine must copy every byte received 
   into array beginnnig at *gbl_in_buf_base_p 
	+-----------------------------------------------+
   In:	| REMOVE_______________________ | EXTENSION____	|
	+-----------------------------------------------+
   Out:	| REPLACE______________	| PAD__	| EXTENSION____	|
	+-----------------------------------------------+	*/
	unsigned	P_buf_count_u ;
	unsigned	P_found_u ;
	{
	register unsigned	L_out_u ;
	register char 		*L_out_p ;
	register FLAG		L_do_swap_f ;

#ifdef	DEBUG	/* { */
	printf("%s %s%d %s%d\n", "debug buf_flush: ",
		"|P_buf_count_u:", P_buf_count_u, "|P_found_u:"	P_found_u ) ;
#endif		/* } */

	if (P_buf_count_u == 0) return ;	/* erroneous call */
	/* flush initial portion (same length as replace in diagram above) */
	if (L_do_swap_f = ((P_buf_count_u >= gbl_remove_u) && 
		!((P_found_u > gbl_occur_max_i) && (gbl_occur_max_i != -1))	) )
		{	/* do a replacement */
		L_out_p = gbl_replace_p ;
		L_out_u = gbl_relace_u ;
		}
	else	{	/* only partial match, flush input stream */
		L_out_p = gbl_in_buf_base_p  ;
		L_out_u = P_buf_count_u ;
		}
	while(L_out_u--) putchar_via_cksum(*L_out_p++) ;

	if (P_buf_count_u <= gbl_relace_u) return ;

	/* flush padding portion */
	L_out_p = gbl_in_buf_base_p + gbl_relace_u ;
	L_out_u = (P_buf_count_u > gbl_remove_u) ? 
		gbl_remove_u - gbl_relace_u : P_buf_count_u - gbl_relace_u ;
	while(L_out_u--)
		{
		if (gbl_binary_f)
			putchar_via_cksum((L_do_swap_f) ?
				gbl_fill_c : *L_out_p++);
		else	{
			if (!L_do_swap_f) /* discard */ L_out_p++ ;
			else putchar_via_cksum(*L_out_p++) ;
			}
		}
	if (P_buf_count_u <= gbl_remove_u) return ;

	/* flush extension portion */
	L_out_u = P_buf_count_u - gbl_remove_u ;
	while(L_out_u--) 
		putchar_via_cksum((L_do_swap_f) ? gbl_fill_c : *L_out_p++);
	}

/* ----------------------------------------------------------------------- */
/* Replace strings in a file, returns 0 if dont care how many occurences done,
   else returns (number requested - number replaced); exit(1) on any error */
	int
replace(P_name_p, P_remove_p, P_replace_p, P_extra_u, P_fill_c,
		P_occur_max_i, P_exact_f, P_binary_f, P_cksum_f, P_verbose_f )
	char		*P_name_p ;	/* file name */
	char		*P_remove_p ;	/* string to be removed */
	char		*P_replace_p ; 	/* string to be added */
	unsigned	P_extra_u ;	/* up to so many trailing extra chars
					possibly occuring, to be removed
					or converted to fill chars */
	char		P_fill_c ;	/* fill/pad character */
	int		P_occur_max_i ;	/* occurences:
						-1 == any no, 0==none (ie it is
						an error if !=0), 1==1 */
	FLAG 		P_exact_f ;	/* err exit if P_occur_max_i != no of
						occurences detected */
	FLAG		P_binary_f ;	/* 0==text, 1 == binary */
 	FLAG		P_cksum_f ;	/* 0==no ms_checksums, else 1 */
	FLAG 		P_verbose_f ;	/* announce file name */
	{
	register int	L_byte_i ;	/* current byte from input file */
	register char	*L_in_buf_p ;
	register unsigned L_buf_count_u ;	/* input count (increments on a
						character basis till a full
						match is detected) */
	register char	*L_scan_p ;	/* I/O pointer */

	int	L_length_i	;
	FLAG	L_write_fail_f = 0 ;
	unsigned L_found_u = 0 ;	/* no of strings found */
	unsigned L_max_u ;
	CKSUM	L_new_cksum ;
	char	L_cksum_buf[2] ;
	/* ------------------------------------------------------------------ */
#ifdef	DEBUG	/* { */
	printf("%s%s%s\n%s%s%s%s\n%s%u%s%c%s%d\n%s%c%s%c%s%c%s%c\n",
		"debug replace ",
		"|P_name_p:", P_name_p,
		"|P_remove_p:", P_remove_p,
		"|P_replace_p:", P_replace_p,
		"|P_extra_u:", P_extra_u,
		"|P_fill_c:", P_fill_c,
		"|P_occur_max_i:", P_occur_max_i,
		"|P_exact_f:", P_exact_f + '0',
		"|P_binary_f:", P_binary_f + '0',
		"|P_cksum_f:", P_cksum_f + '0',
		"|P_verbose_f:", P_verbose_f + '0') ;
#endif		/* } */
	gbl_cksum_f = P_cksum_f ;	/* export for other procedures */
	gbl_binary_f = P_binary_f ;	/* export for other procedures */

	/* check parameters */
	if (	( P_name_p == (char *)0 ) || ( *P_name_p == '\0' ) ||
		( P_remove_p == (char *)0 ) || ( *P_remove_p == '\0' )
		)	{ syntax() ; proc_failed("parameters"); }
	if ( (gbl_replace_p = P_replace_p) == (char *)0)	gbl_replace_p = "\0" ;
	if ( (gbl_occur_max_i = P_occur_max_i) < -1)	proc_failed("occurence count");
	if ((gbl_occur_max_i == -1) && P_exact_f)		{ syntax() ; exit(1) ; }
	gbl_remove_u = strlen( (char *)P_remove_p ) ;
	gbl_relace_u = strlen( (char *)gbl_replace_p ) ;
	/* check for replacement string too long */
	if ( ( gbl_relace_u > gbl_remove_u ) && gbl_binary_f )
		{
		*(gbl_replace_p + gbl_remove_u ) = '\0' ;
		fprintf( stderr,
	"%s: Warning: %s is binary, so replacement string truncated to %s\n",
			*ARGV, P_name_p, gbl_replace_p ) ;
		gbl_relace_u = gbl_remove_u ;
		}
	if (P_cksum_f && !gbl_binary_f) { syntax() ; exit(1) ; }
	/* determine number of pad characters to append after replacement
		string to remove tail of old string */
	gbl_fill_c = P_fill_c ;
	L_max_u = gbl_remove_u + P_extra_u ;
	/* ------------------------------------------------------------------ */
	/* PREPARE TEMPORARY FILE AND POINTERS */
	if ( (gbl_orig_fd = open(P_name_p,
#ifdef	MSDOS	/* { */
			O_BINARY |
#endif	/* } */
			( (!gbl_binary_f) ? O_RDONLY :
			O_RDWR /* fixed size so lseek will be sufficient later*/
			) ) ) < 0 )
		{
		fprintf( stderr, "%s: Cannot open %s\n", *ARGV, P_name_p);
#include "replace.h"
		return(REPLACE_FAIL) ;
		}
	/* copy (and change) data from P_name_p to gbl_tmp_name (or buffer) */
	if (P_verbose_f) { printf( "%s", P_name_p ) ; (void)fflush( stdout) ; }
	/* orig_to_tmp */
	gbl_tmp_fd = FD_UNSET ;	/* unset, may not need to be created */
	/* mktemp manual says the caller gets changed from XXXXXX,
		we call it once for each file, so use of strcpy protects
		original XXXXXX for subsequent invocations. */
	(void) strcpy(gbl_tmp_name,TMP_NAME);
	(void) mktemp(gbl_tmp_name) ;
	/* initialise buffers */
	gbl_in_buf_next_p = gbl_in_buf ;
	gbl_in_buf_end_p = gbl_in_buf ;
	gbl_out_buf_p = gbl_out_buf ;
	if ((gbl_in_buf_base_p = malloc(L_max_u)) == (char *)0)
		{
		fprintf(stderr,
			"%s: Couldnt allocate space pad memory%s",
			*ARGV, gbl_txt_abort ) ;
		perror(*ARGV) ;
		exit(1) ;
		}
	if (gbl_cksum_f)
		{
		gbl_input_data_cksum = gbl_output_data_cksum = (CKSUM)0 ;
		gbl_in_count = gbl_out_count = 0L ;
		}
	/* ------------------------------------------------------------------ */
	/* START SCANNING INPUT - this section within these brackets can
		conceptually be read seperately as a smaller unit than the total
		procedure, in order to aid comprehension.	*/
	{
#define	INIT_BUF	{				\
			L_buf_count_u = 0 ;		\
			L_scan_p = P_remove_p ;		\
			L_in_buf_p = gbl_in_buf_base_p ;	\
			}
	INIT_BUF
	if (signal( SIGINT, clean_from_sig) < 0 ) proc_failed(gbl_txt_signal ) ;
	while(1){
		if ( (L_byte_i = getc_via_cksum() ) == EOF)
			{
			buf_flush(L_buf_count_u, L_found_u ) ;
			break ;
			}
		L_byte_i &= 0xFF ;
		if ( gbl_cksum_f && (gbl_in_count <= (MS_EXE_OVERLAY_LO + 1)))
			{
			putchar_via_cksum((char)L_byte_i) ;
			continue ;
			}
		/* Cant do a a putchar if already detected enough occurences,
			because we want to scan input stream to detect an 
			unexpectedly high number of input occurences */
		*L_in_buf_p++ = L_byte_i ;
		if ((++L_buf_count_u > gbl_remove_u) || 
			(*L_scan_p++ == L_byte_i))
				/* access *L_scan_p after detect_f to avoid
				incrementing when not needed (MMU might
				interrupt if we go over end) */
			{ /* possible partial, full, or extended match,
				(including full or extended match not to be
				changed but merely noted) */
			if (L_buf_count_u == gbl_remove_u)
				{ /* matching string in 'P_name_p' and
					'P_remove_p' */
				if ((++L_found_u > gbl_occur_max_i) && 
					P_exact_f)
					{
					fprintf(stderr,
				"%s: Error %d occurences in %s",
						*ARGV, L_found_u, P_name_p,
						gbl_txt_abort ) ;
					my_unlink() ;
					exit(1) ;
					}
				}
			if (L_buf_count_u == L_max_u) 
				{
				buf_flush(L_buf_count_u, L_found_u ) ;
				INIT_BUF
				}
			}
		else	{	/* no recognisable match, flush 
				Note if single char in input buffer, we avoid
				calling flush with its time consuming 9 
				parameters for each byte in the file!	*/
			if (L_buf_count_u == 1) 
				/* For effeciency, avoid calling
					buf_flush(L_buf_count_u, L_found_u ) ;
					on failing to match with first character
					in match string */
				putchar_via_cksum((char)L_byte_i) ; 
				else buf_flush(L_buf_count_u, L_found_u ) ;
			INIT_BUF
			}
		}
	(void) free(gbl_in_buf_base_p) ;
	}
	/* ------------------------------------------------------------------ */

	/* look for odd bytes at end (not belonging to an input word) */
	if (gbl_cksum_f && (--gbl_in_count > MS_EXE_OVERLAY_LO) &&
						((gbl_in_count % 2) == 0))
		/* lone high byte in data segment */
		gbl_input_data_cksum = s_add(gbl_input_data_cksum,
						gbl_input_tmp_cksum ,16);
	if ((gbl_occur_max_i != -1) && (gbl_occur_max_i != L_found_u))
		fprintf(stderr,
			"%s: Warning: in %s, %d requested, %d detected.\n",
			*ARGV, P_name_p, gbl_occur_max_i, (int)L_found_u ) ;
	/* ------------------------------------------------------------------ */
	/* RE OPEN ORIGINAL PRIOR TO RETURNING DATA */
	sig_ign() ;
	if ((gbl_binary_f) && (lseek( gbl_orig_fd, (off_t)0, 0 ) < 0) )
		proc_failed(gbl_txt_lseek ) ;
	else	{
		if (close(gbl_orig_fd)) proc_failed(gbl_txt_close ) ;
		/* if in text mode we may want to shorten the file,
			so gbl_orig_fd can not be opened just once as
			read+write, as read & writes wont shorten file,
			spare bytes will hang around unchanged at end of file */
		if ((gbl_orig_fd = open( P_name_p,
#ifdef	MSDOS	/* { */
			O_BINARY |
#endif	/* } */
			O_WRONLY | O_CREAT | O_TRUNC, 0200 ) ) < 0 )
			{
			fprintf( stderr, "%s: Cannot recreate '%s' %s %s%s",
				*ARGV, P_name_p,
				",data lost (unless file was",
				"previously write protected)",
				gbl_txt_abort
				) ;
			my_unlink() ;
			exit(1) ;
			}
		}
	/* ------------------------------------------------------------------ */
	/* WRITE DATA TO ORIGINAL FILE */
	if (gbl_tmp_fd >= 0)
		{
		if (lseek( gbl_tmp_fd, (off_t)0, 0 ) < 0) proc_failed(gbl_txt_lseek ) ;
		/* go back to beginning */
		while ( ( L_length_i = read( gbl_tmp_fd, (char *) gbl_in_buf,
			(int)MAXBUF ) ) > 0 )
			if ( write( gbl_orig_fd, (char *)gbl_in_buf,
				L_length_i ) != L_length_i )
				{
				L_write_fail_f = 1 ;
				break ;
				}
		(void) close(gbl_tmp_fd) ;
		}
	/* remaining buffer */
	L_length_i = gbl_out_buf_p - gbl_out_buf ;
	if ( L_length_i && (write( gbl_orig_fd, (char *)gbl_out_buf, 
		L_length_i ) != L_length_i )) L_write_fail_f = 1;
	if ( L_write_fail_f )
		{
		fprintf( stderr, gbl_txt_nowrite, "source" ) ;
		fprintf( stderr, "%s",gbl_txt_abort ) ;
		my_unlink() ;
		exit(1) ;
		}
	/* ------------------------------------------------------------------ */
	/* OVERLAY NEW MSDOS .EXE CHECKSUM */
	if (gbl_cksum_f)
		{
		if ((--gbl_out_count > MS_EXE_OVERLAY_LO) &&
			((gbl_out_count % 2) == 0))
			/* lone high byte with no matching low byte */
			gbl_output_data_cksum = s_add(gbl_output_data_cksum,
				gbl_output_tmp_cksum, 16) ;
#ifdef	MSDOS	/* { */
#define	L_SET	0
#endif		/* } */
		if ( (lseek(gbl_orig_fd,(off_t)MS_CKSUM_HI,L_SET) ) < 0 )
			proc_failed(gbl_txt_lseek );
		L_new_cksum = gbl_orig_cksum ;
		L_new_cksum = s_add(L_new_cksum, -gbl_input_data_cksum, 16);
		L_new_cksum = s_add(L_new_cksum, gbl_output_data_cksum, 16);
		L_new_cksum = -L_new_cksum ;
		L_cksum_buf[0] = ( L_new_cksum & 0xFF00 ) >> 8 ;
		L_cksum_buf[1] = L_new_cksum & 0xFF ;
		if (write(gbl_orig_fd,(char *)L_cksum_buf,2) != 2 )
			proc_failed("write");
		}
	if (close(gbl_orig_fd)) proc_failed(gbl_txt_close ) ;
	my_unlink() ;
	if (P_verbose_f) name_off_screen(P_name_p) ;
	return( (P_exact_f) ? (gbl_occur_max_i - L_found_u) : 0) ;
	}

