/*
 * @DEC_COPYRIGHT@
 */
/*
 * HISTORY
 * Revision 1.2  1995/03/09  21:50:32  bourquard
 * port to NT
 *
 *
 * Revision 1.1  90/01/01  00:00:00  devrcs
 * Initial load into Alpha pool
 * 
 * Revision 1.2  91/12/30  12:48:20  devbld
 * Initial load of project
 * 
 */
/*
 * 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.
 */

/*
 *
 *	dxdiff
 *
 *	filestuff.c - file handling code
 *
 *	Author:	Laurence P. G. Cable
 *
 *	Created : 25th April 1988
 *
 *
 *	Description
 *	-----------
 *
 *
 *	Modification History
 *	------------ -------
 *	
 */

static char sccsid[] = "@(#)filestuff.c	1.11	17:45:20 2/21/89";


#include	<sys/types.h>

#ifdef WIN32
#define stat    _stat
#define off_t   _off_t
typedef char    *caddr_t;
#define O_RDONLY _O_RDONLY
#endif WIN32

#include	<sys/stat.h>

#ifndef WIN32
#include	<sys/file.h>
#else
#define close 	_close
#define read 	_read
#include <windows.h>
#endif WIN32

#include <X11/Xlib.h>
#include <Xm/Xm.h>
#ifdef I18N_MULTIBYTE
#include <DXm/DECspecific.h>
#endif /* I18N_MULTIBYTE */

#include "y.tab.h"
#include "filestuff.h"
#include "parsediff.h"
#include "alloc.h"
#include "arglists.h"
#include "differencebox.h"
#ifdef WIN32
#include <fcntl.h>
#endif

#define	FormPointer(base, offset, ptrtype) ptrtype((char *)(base) + offset)

extern  void XmTextSetHighlight();

/********************** Public Routines ************************/


#ifdef WIN32
/********************************
 *
 *	   err_sys
 *
 ********************************/
 void err_sys(char *msg)
 {
 	HANDLE hStderr;
 	DWORD ErrMsgLen, n_write;
 	LPVOID lpvMessage;

 	hStderr = GetStdHandle(STD_ERROR_HANDLE);
 	WriteFile( hStderr, msg, lstrlen(msg), &n_write, NULL);
 	WriteFile( hStderr, "\n", 2*sizeof(TCHAR), &n_write, NULL);
 	ErrMsgLen = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
 							   NULL,
							   GetLastError(),
							   MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
							   (LPSTR) &lpvMessage,
							   0,
							   NULL);
	WriteFile(hStderr, lpvMessage, ErrMsgLen, &n_write, NULL);
	return;
}
#endif WIN32


/********************************
 *
 *	InitializeHighLightInfo
 *
 ********************************/

InitializeHighLightInfo(filep, head, tail, number, whichfile)
	FileInfoPtr filep;
	EdcPtr	     head,
		     tail;
	int	     number;
	WhichFile    whichfile;
{
#ifdef I18N_MULTIBYTE
	int i18n_cc     = 0;    /* I18N character count */
	char *cp;
	register char  *top;
#else
	register char		  *cp,*top;
#endif /* I18N_MULTIBYTE */
	register EdcPtr		  edcp;
	register HighLightInfoPtr hlp;
	register unsigned int	  nsoff;
	register unsigned int	  hloff;
	int		  	  n;
	Boolean			  isleft;

	if (head == (EdcPtr)NULL) {
		return;	/* no diffs ?? */
	}

	if (isleft = (whichfile == LeftFile)) {
		hloff = XtOffset(EdcPtr, highl);
		nsoff = XtOffset(EdcPtr, ns1);
	} else {
		hloff = XtOffset(EdcPtr, highr);
		nsoff = XtOffset(EdcPtr, ns2);
	}


	if (number <= 0) {		/* we dont know - so find out */
		for (n = 0, edcp = head; edcp != tail->next; n++, edcp = edcp->next)
		;
		number = n;
	}

	if (filep->hlp != (HighLightInfoPtr)NULL)
		XtFree((char *)filep->hlp);

	if ((filep->hlp = hlp =
	     (HighLightInfoPtr)XtMalloc(number * sizeof (HighLightInfo))) == 
	     (HighLightInfoPtr)NULL) {	/* error */
		return;
	}

	filep->dlhead = (ForwardEdcPtr)head;
	filep->dltail = (ForwardEdcPtr)tail;

	for (edcp = head, n = 1, cp = filep->data,
	     top = filep->data + filep->filesize; edcp !=  tail->next && cp < top;
	     hlp++, edcp = edcp->next) {
#ifdef	USESECONDARYSELECTION
		if ((edcp->et == EAppend && isleft) ||
		    (edcp->et == EDelete && !isleft))
			hlp->mode = XmHIGHLIGHT_SECONDARY_SELECTED;
		else
			hlp->mode = XmHIGHLIGHT_SELECTED;
#else
		hlp->mode = XmHIGHLIGHT_SELECTED;
#endif

		*FormPointer(edcp, hloff, (HighLightInfoPtr *)) = hlp;

		number = (*FormPointer(edcp, nsoff, (NumberSequencePtr *)))->numbers[0];
		while (n < number && cp < top) {
#ifdef I18N_MULTIBYTE
			/* hlp->left represents character position. Hence we
			   have to calculate number of characters contained in
			   cp using mblen(). The character count is stored in
			   i18n_cc.
			*/
			while (*cp != '\n' && cp < top)
			{
				cp = cp + mblen(cp, MB_LEN_MAX);
				i18n_cc++;
			}
			cp = cp + mblen(cp, MB_LEN_MAX);
			i18n_cc++;
			n++;
 		}
		hlp->left = (XmTextPosition)i18n_cc;
#else
			while (*cp++ != '\n' && cp < top)
			;
			n++;
		}

		hlp->left = (XmTextPosition)(cp - filep->data);
#endif /* I18N_MULTIBYTE */
		number = (*FormPointer(edcp, nsoff, (NumberSequencePtr *)))->numbers[1];

		while (n <= number && cp < top) {
#ifdef I18N_MULTIBYTE
			/* hlp->right represents character position. Hence we
			   have to calculate number of characters contained in
			   cp using mblen(). The character count is stored in
			   i18n_cc.
			*/
			while (*cp != '\n' && cp < top){
				cp = cp + mblen(cp, MB_LEN_MAX);
				i18n_cc++;
			}
			cp = cp + mblen(cp, MB_LEN_MAX);
			i18n_cc++;
			n++;
		}
		 
		hlp->right = (XmTextPosition)i18n_cc;
#else
			while (*cp++ != '\n' && cp < top)
			;
			n++;
		}

		hlp->right = (XmTextPosition)(cp /* - 1 */ - filep->data);
#endif /* I18N_MULTIBYTE */
	}
}






/********************************
 *
 *	FreeFile
 *
 ********************************/


FreeFile(filep)
	FileInfoPtr filep;
{
	register EdcPtr	p,head,tail;
	unsigned char	mask;
	unsigned int	hloff;
	

	if (filep->data != (char *)NULL)
		XtFree(filep->data);

	head = (EdcPtr)filep->dlhead;
	tail = (EdcPtr)filep->dltail;

	if (head) {
		if (head->highl == filep->hlp) {
			mask = ~HIGHLEFT;
			hloff = XtOffset(EdcPtr, highl);
		} else {
			mask = ~HIGHRIGHT;
			hloff = XtOffset(EdcPtr, highr);
		}

		for (p = head; p != tail->next; p = p->next) {
			p->common.flags &= mask;
			*FormPointer(p, hloff, (HighLightInfoPtr *)) = 
				(HighLightInfoPtr)NULL;
		}
	}
		
	if (filep->hlp != (HighLightInfoPtr)NULL)
		XtFree((char *)filep->hlp);

	XtFree((char *)filep);
}


/********************************
 *
 *	LoadNewFile
 *
 ********************************/

FileInfoPtr
LoadNewFile(file)
	char		*file;
{
	extern int	     errno;
	register FileInfoPtr filep;
#ifdef I18N_MULTIBYTE
	int i18n_cc = 0; /* I18N Character Count */
	char 		     *cp;
	register char        *ocp,*top;
#else
	register char	     *cp,*ocp,*top;
#endif /* I18N_MULTIBYTE */
#ifndef WIN32
	struct stat	     statbuf;
#else
    HANDLE	     hFile;
	LPOFSTRUCT	 fileBuf;
#endif WIN32
	int		     fd;
	register int	     t;
	
	if ((filep = (FileInfoPtr)XtMalloc(sizeof (FileInfo))) ==
	    (FileInfoPtr)NULL)	{	/* error */
		return filep;
	}

	filep->data = (char *)NULL;
	filep->hlp = (HighLightInfoPtr)NULL;

	filep->path = file;
	filep->filesize = filep->widestline = filep->modtime =
	filep->numlines = 0;

	filep->dlhead = filep->dltail = (ForwardEdcPtr)NULL;

#ifndef WIN32
    if (stat(file, &statbuf) == -1) {	/* error */
		perror("bad stat(2) in LoadNewFile");
		return (FileInfoPtr)NULL;
	}

	filep->filesize = statbuf.st_size;
	filep->modtime = statbuf.st_mtime;
#else
    if ( (hFile = CreateFile( file, 
    					    GENERIC_READ, 
    					    FILE_SHARE_READ, 
    					    NULL, 
    					    OPEN_EXISTING, 
    					    FILE_ATTRIBUTE_NORMAL, 
    					    NULL)) 
    			!= INVALID_HANDLE_VALUE)
		{
	    if ( (filep->filesize = GetFileSize(hFile, NULL))
		           == -1)
		    err_sys("GetFileSize failed in LoadNewFile\n");
	    if (!CloseHandle(hFile))
	        err_sys("Couldn't CloseHandle in LoadNewFile\n");
    	/* Note that we don't fill in the filep->modtime field.
	 	 * It's not used, so no harm should befall us.
	 	 */
		}
	else
	    perror("couldn't open %s\n", file);
#endif WIN32
	if ((filep->data = cp = XtMalloc(filep->filesize + 1)) == (char *)NULL) {
		return (FileInfoPtr)NULL;
	}

	cp[filep->filesize] = '\0';

#ifdef WIN32
	/* Deb:  possible compiler bug:  couldn't get it to recognize O_BINARY
	 * or _O_BINARY; had to resort to searching fcntl.h and hardwiring
	 * 0x8000 
	 */
	fd = _open(file,  O_RDONLY | 0x8000 );
	if (fd == -1 )	{

    /* Deb:  The code below should have worked but is apparently a C++ compiler
	 * bug
	 */
#else 
	if ((fd = open(file, O_RDONLY)) == -1) {	 error */
#endif WIN32
		perror("bad open(2)in LoadNewFile");
		return (FileInfoPtr)NULL;
	}

	if (read(fd, cp, filep->filesize) != filep->filesize) {
			perror("bad read(2) in LoadNewFile");
			XtFree(filep->data);
			close(fd);
			return (FileInfoPtr)NULL;
	}
	close(fd);

#ifdef I18N_MULTIBYTE
	for (i18n_cc = 0, top = cp + filep->filesize; cp < top;)
	{
		cp = cp + mblen(cp, MB_LEN_MAX);
		i18n_cc++;
		if (*cp == '\n') {
			filep->numlines++;
			if (i18n_cc - 2 > (int)(filep->widestline))
				filep->widestline = i18n_cc - 2;
			i18n_cc = 0;
		}
	}
#else
	for (top = (cp = ocp = filep->data) + filep->filesize; cp < top;)
		if (*cp++ == '\n') {
			filep->numlines++;
			if ((t = cp - ocp - 2) > (int)(filep->widestline))
				filep->widestline = t;
			ocp = cp;
		}
#endif /* I18N_MULTIBYTE */

	if (*(cp - 1) != '\n') {	/* incomplete last line */
			filep->numlines++;
#ifdef I18N_MULTIBYTE
			if (i18n_cc > (int)(filep->widestline))
				filep->widestline = i18n_cc;
#else
			if ((t = cp - ocp) > (int)(filep->widestline))
				filep->widestline = t;
#endif /* I18N_MULTIBYTE */
	}

	return filep;
}
