/*++

Copyright (c) 1993  Microsoft Corporation

Module Name:

    log.c

Abstract:

    This file implements the access to the postmortem log file.

Author:

    Wesley Witt (wesw) 1-May-1993

Environment:

    User Mode

--*/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <commdlg.h>
#include <direct.h>

#include "drwatson.h"
#include "proto.h"
#include "messages.h"
#include "resource.h"

//
// global variables for this module
//
static HANDLE  hFile = NULL;
static HANDLE  hLogProtect = NULL;
static DWORD   dwStartingPos = 0;


void
lprintf(DWORD dwFormatId, ...)

/*++

Routine Description:

    This is function is a printf style function for printing messages
    in a message file.

Arguments:

    dwFormatId    - format id in the message file
    ...           - var args

Return Value:

    None.

--*/

{
    char        buf[1024];
    DWORD       dwCount;
    va_list     args;

    va_start( args, dwFormatId );

    dwCount = FormatMessage(
                FORMAT_MESSAGE_FROM_HMODULE,
                NULL,
                dwFormatId,
                0, // GetUserDefaultLangID(),
                buf,
                sizeof(buf),
                &args
                );

    Assert( dwCount != 0 );

    WriteFile( hFile, buf, dwCount, &dwCount, NULL );

    return;
}

void
lprintfs(char *format, ...)

/*++

Routine Description:

    This is function is a printf replacement that writes the output to
    the DrWatson log file.

Arguments:

    format        - print format
    ...           - var args

Return Value:

    None.

--*/

{
    char    buf[1024];
    DWORD   cb;

    va_list arg_ptr;
    va_start(arg_ptr, format);
    cb = _vsnprintf(buf, sizeof(buf), format, arg_ptr);
    Assert( hFile != NULL );
    WriteFile( hFile, buf, cb, &cb, NULL );
    return;
}

void
OpenLogFile( char *szFileName, BOOL fAppend, BOOL fVisual )

/*++

Routine Description:

    Opens the DrWatson logfile for reading & writting.

Arguments:

    szFileName    - logfile name
    fAppend       - append the new data to the end of the file or
                    create a new file
    fVisual       - visual notification

Return Value:

    None.

--*/

{
    char   szName[1024];

    GetAppName( szName, sizeof(szName) );
    strcat( szName, "LogProtect" );

    hLogProtect = OpenSemaphore( SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, FALSE, szName);
    if (hLogProtect == NULL) {
        hLogProtect = CreateSemaphore( NULL, 0, 1, szName );
        Assert( hLogProtect != NULL );
    }
    else {
        WaitForSingleObject( hLogProtect, INFINITE );
    }

openagain:
    hFile = CreateFile( szFileName,
                        GENERIC_WRITE | GENERIC_READ,
                        FILE_SHARE_READ,
                        NULL,
                        fAppend ? OPEN_EXISTING : CREATE_ALWAYS,
                        FILE_ATTRIBUTE_ATOMIC_WRITE,
                        NULL
                      );

    if (fAppend) {
        if (hFile == INVALID_HANDLE_VALUE) {
            //
            // file does not exist, so lets create a new file
            //
            hFile = CreateFile( szFileName,
                                GENERIC_WRITE | GENERIC_READ,
                                FILE_SHARE_READ,
                                NULL,
                                CREATE_NEW,
                                FILE_ATTRIBUTE_ATOMIC_WRITE,
                                NULL
                              );
            if (hFile == INVALID_HANDLE_VALUE) {
                if (fVisual) {
                    NonFatalError( LoadRcString(IDS_INVALID_LOGFILE) );
                    _getcwd( szFileName, MAX_PATH );
                    if (!BrowseForDirectory( szFileName )) {
                        FatalError( LoadRcString(IDS_CANT_OPEN_LOGFILE) );
                    }
                    MakeLogFileName( szFileName );
                    goto openagain;
                }
                else {
                    ExitProcess( 1 );
                }
            }

            //
            // write the file banner
            //
            lprintfs( "\r\n" );
            lprintf( MSG_BANNER );
            lprintfs( "\r\n" );
        }

        SetFilePointer( hFile, 0, 0, FILE_END );
    }
    else {
        //
        // write the file banner
        //
        lprintfs( "\r\n" );
        lprintf( MSG_BANNER );
        lprintfs( "\r\n" );
    }

    Assert( hFile != INVALID_HANDLE_VALUE );

    dwStartingPos = SetFilePointer( hFile, 0, NULL, FILE_CURRENT );

    return;
}

void
CloseLogFile( void )

/*++

Routine Description:

    Closes the DrWatson logfile & releases the semaphore that
    protects it.

Arguments:

    None.

Return Value:

    None.

--*/

{
    CloseHandle( hFile );
    ReleaseSemaphore( hLogProtect, 1, NULL );
    CloseHandle( hLogProtect );
}

char *
GetLogFileData( PDWORD pdwLogFileDataSize )

/*++

Routine Description:

    Reads in all of the logfile data that has been written since it was
    opened.  The data is placed into a buffer allocated by this function.
    The caller is responsible for freeing the memory.

Arguments:

    pdwLogFileDataSize     -  pointer to a dword that contains the size
                              in bytes of the data that is read.

Return Value:

    Valid character pointer to the logfile data

    NULL - could not read the data.

--*/

{
    DWORD   dwCurrPos;
    char    *p;
    DWORD   size;


    dwCurrPos = SetFilePointer( hFile, 0, NULL, FILE_CURRENT );

    *pdwLogFileDataSize = 0;
    size = dwCurrPos - dwStartingPos;

    p = (char *) malloc( size );
    if (p == NULL) {
        return NULL;
    }

    SetFilePointer( hFile, dwStartingPos, NULL, FILE_BEGIN );

    if (!ReadFile( hFile, p, size, &size, NULL )) {
        free( p );
        p = NULL;
        size = 0;
    }

    SetFilePointer( hFile, dwCurrPos, NULL, FILE_BEGIN );

    *pdwLogFileDataSize = size;

    return p;
}

void
MakeLogFileName( char *szName )

/*++

Routine Description:

    Concatinates the base logfile name on to the string passed in.

Arguments:

    szName                 -  buffer for the logfile name.

Return Value:

    None.

--*/

{
    strcat( szName, "\\drwtsn32.log" );
}
