#define TRACE
/*    
	Logging.c	2.16
    	Copyright 1997 Willows Software, Inc. 

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.


For more information about the Willows Twin Libraries.

	http://www.willows.com	

To send email to the maintainer of the Willows Twin Libraries.

	mailto:twin@willows.com 

 */

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

#include "windows.h"

#include "Endian.h"
#include "Log.h"
#include "kerndef.h"
#include "Kernel.h"

/* External prototypes */

#define RL_INIT		0
#define RL_BIN		1
#define RL_ENUM		2
#define RL_API		3

struct RunControl *RunState;
int RunLevel;			/* nesting level of API calls */

void
TWIN_InitLog()
{
    RunLevel = 0;
    RunState = (struct RunControl *) WinMalloc(256 * sizeof(RunState));
    memset((LPSTR)RunState,'\0',256 * sizeof(RunState));
}

WORD	msgnum[] = {
	0x200,		/* mouse move */
	0x20,		/* setcursor  */
	0x82,		/* ncdestroy  */
	0x2,		/* destroy    */
	0x7,		/* setfocus  */
	0x8,		/* killfocus */
	0x113,		/* timermsg  */
	0
};

/* 
 *	tell whether to log a msg
 */
int
LogMSG(WORD wMsg)
{
	int	i;
	for(i=0;msgnum[i];i++) {
		if(msgnum[i] == wMsg)
			return 0;
	}
 	return 1;
}

/*****************************************************************************
 *
 * prints out the message that will be returned from 
 * a call to get/peek message. 
 * This does not limit messages that will be returned on the basis
 * of sendmessage type logging
 * For purpose of logging, this is treated like APIRET, ie. log the
 * return values of an API call.
 *
 ****************************************************************************/
void
LogGetMessage(int type,LPMSG lpMsg,BOOL flag)
{
#ifdef TRACE
 	LPSTR	lpAPI;
	lpAPI = (type == 0)?"GETMESSAGE":"PEEKMESSAGE";
	logstr(LF_APIRET,"API[%lx:%d]: ret %s [hwnd=%x msg=%4.4x w=%x l=%x] %s\n",
		RunState[RunLevel].apinum,RunLevel, lpAPI,
		lpMsg->hwnd,lpMsg->message,lpMsg->wParam,lpMsg->lParam,
		flag?"TRUE":"FALSE");
#endif
}

/*****************************************************************************
 *
 * 	LogAPIcall	which api is being called
 *	LogAPIret	which ax/dx value is being returned 
 *
 ****************************************************************************/

void
LogAPIcall(WORD wSel,WORD wOff,LPSTR lpModName,LPSTR lpProcName)
{
    static long apinum;
    char buffer[80];

    if ( RunState ) {
	if (RunLevel < 255)
	    RunLevel++;
	RunState[RunLevel].apinum = apinum++;
	RunState[RunLevel].module = wSel;
	RunState[RunLevel].ordinal = wOff;

	if (lpProcName == 0) {
	    sprintf(buffer,"module(%x:%x)",wSel,wOff);
	    lpProcName = (LPSTR) buffer;
	}

        RunState[RunLevel].apilog = 1;
	RunState[RunLevel].apistr = lpProcName;

	if(RunState[RunLevel].apilog)
		logstr(LF_APICALL,"API[%lx:%d]: call %s:%s\n",
			RunState[RunLevel].apinum,RunLevel,lpModName,lpProcName);
    }
}

void
LogAPIret(WORD ax,WORD dx,LPSTR lpModName,LPSTR lpProcName)
{
	char buffer[80];

        if(RunState && RunState[RunLevel].apilog) { 
		lpProcName = RunState[RunLevel].apistr;
		if (lpProcName == 0) {
	    		sprintf(buffer,"module(%x:%x)",
				RunState[RunLevel].module,
				RunState[RunLevel].ordinal);
	    		lpProcName = (LPSTR) buffer;
		}

		logstr(LF_APIRET,"API[%lx:%d]: ret  %s ax=%x dx=%x\n",
			RunState[RunLevel].apinum,RunLevel, lpProcName,ax,dx);
	}
	if (RunLevel)
		RunLevel--;
}

/*****************************************************************************
 *
 *	the following pair is the sendmessage/return pair 
 *
 *
 ****************************************************************************/

char *GetTwinMsgCode(HWND,WPARAM);


void
LogSendMsg(int flg,char *lpmsg,HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
#ifdef TRACE
    if ( RunState ) {
	if(LogMSG(wMsg) == 0) {
	    RunState[RunLevel].msglog = 0;
            return;
	}
    
	RunState[RunLevel].msglog = 1;

	logstr(LF_LIBCALL,
	"LIB[%lx:%d]: call %s(hWnd=%.04x,wMsg=%s,wParam=%4.4x,lParam=%lx) %s", 
		RunState[RunLevel].apinum,RunLevel,
		flg?"CallWindowProc":"SendMessage",
		hWnd, GetTwinMsgCode(hWnd,wMsg),wParam,lParam,lpmsg);

	if (wMsg == WM_CONVERT)
	    logstr(LF_LIBCALL," (msg = %4.4x)",((WMCONVERT *)lParam)->uMsg);

	logstr(LF_LIBCALL,"\n");
    }
#endif
}

/* 
 * generalized return...
 * use wMsg as LF_xxx
 * use lParam as return value
 * use wParam as modifier for whether to print, returned by LogMsg...
 */
void
LogReturn(int flg,LPARAM lParam)
{
#ifdef TRACE
    if (RunState) {
	if(RunState[RunLevel].msglog == 0)
		return;

	logstr(LF_LIBRET,"LIB[%lx:%d]: ret  %s returns %lx\n",
			RunState[RunLevel].apinum,RunLevel,
			flg?"CallWindowProc":"SendMessage",	
			lParam);           
    }
#endif
}

/*****************************************************************************
 *
 *	The following is the api logging interface 
 *	NOTE: the expectation is that flag will be LF_API
 *	which controls logging of API parameters
 *
 *
 ****************************************************************************/

void
apistr(long flag, ...)
{
#ifdef TRACE
	va_list args;
	char *fmt;
	char  fmtstr[0x4000];

	if(RunState && RunState[RunLevel].apilog && RunState[RunLevel].apilog) {
		va_start(args, flag);

		/* point to fmt and args... */
		fmt = va_arg(args, char *);
	
		/* print out remainder of message locally */
		vsprintf(fmtstr,fmt,args);

		logstr(flag,"LIB[%lx:%d]: api  %s",
			RunState[RunLevel].apinum,RunLevel,fmtstr);

		va_end(args);
	}
#endif
}

void
intstr(long flag, ...) 
{
#ifdef TRACE
	va_list args;
	char *fmt;
	char  fmtstr[512];

	if(RunState && RunState[RunLevel].apilog) {
		va_start(args, flag);

		/* point to fmt and args... */
		fmt = va_arg(args, char *);
	
		/* print out remainder of message locally */
		vsprintf(fmtstr,fmt,args);

		logstr(flag,"INT[%lx:%d]: %s",
			RunState[RunLevel].apinum,RunLevel,
			fmtstr);

		va_end(args);
	}
#endif
}

void
drvstr(long flag, ...) 
{
#ifdef TRACE
	va_list args;
	char *fmt;
	char *str;
	char  fmtstr[512];

	if(RunState && RunState[RunLevel].apilog) {
		va_start(args, flag);

		/* point to fmt and args... */
		fmt = va_arg(args, char *);
	
		/* print out remainder of message locally */
		vsprintf(fmtstr,fmt,args);

		str = "DRV";
		logstr(flag,"%s[%lx:%d]: %s",
			str,
			RunState[RunLevel].apinum,RunLevel,
			fmtstr);

		va_end(args);
	}
#endif
}
