PTBKPORT.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright (C) 1993-96 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

#include "porttool.h"
#include "port.h"


/* define line types returned from GetNextLine */
#define VALID_LINE 0
#define COMMENT_LINE 1
#define EOF_LINE 2

#define CARRIAGE_RETURN 13
#define LINE_FEED 10

/* define worker functions for this module */
int WINAPI GetNextLine (char *, int, char *, char *, BOOL *);
int WINAPI NextLineLength (char *, char *, int);
BOOL WINAPI BkFilePortThread (LPBKPORTFILESTRUCT);
void WINAPI DateTimeStamp (char *);



/* function creates a background porting thread */
HANDLE WINAPI StartBkPortThread (LPBKPORTFILESTRUCT lpBkPort)
{
DWORD id;

/* create thread with initial structure */
return (lpBkPort->hThread = CreateThread ((LPSECURITY_ATTRIBUTES)NULL,
4096,
(LPTHREAD_START_ROUTINE)BkFilePortThread,
(LPVOID)lpBkPort,
0,
&id));
}


/* independent thread function that performs background file porting */
BOOL WINAPI BkFilePortThread (
LPBKPORTFILESTRUCT lpBkPort)
{
HANDLEhEvents[nBKPORTEVENTS];
HANDLEhFile;
OFSTRUCTof;
DWORDnFileSize;
DWORD nBytes;
HANDLEhFileBuffer;
char*lpFile, *lpFilePtr;
WORDwComplete, wIssues = 0;
int nLines = 0;
BOOLbCommentOn;
HANDLEhLine;
HANDLEhToken, hIssue, hSuggest, hHelp;
RESULTrIssue;
char*lpLine;
charszHeader[MAX_PATH], szToken[50], szIssue[50], szdt[50],
szSuggest[50], szHelp[50], szHelpFile[50], szEOL[50], szNL[5];


/* adjust our priority to below normal */
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_BELOW_NORMAL);

/* attach our thread input to the parent thread so we can post messages directly */
AttachThreadInput (GetCurrentThreadId (),
GetWindowThreadProcessId (lpBkPort->hDlg, NULL),
TRUE);

/* load file comment strings */
LoadString (GetModuleHandle (NULL), IDS_BKPORTNEWLINE, szNL, 5);
LoadString (GetModuleHandle (NULL), IDS_BKPORTHEADER, szHeader, MAX_PATH);
LoadString (GetModuleHandle (NULL), IDS_BKPORTTOKEN, szToken, 50);
LoadString (GetModuleHandle (NULL), IDS_BKPORTISSUE, szIssue, 50);
LoadString (GetModuleHandle (NULL), IDS_BKPORTSUGGEST, szSuggest, 50);
LoadString (GetModuleHandle (NULL), IDS_BKPORTHELP, szHelp, 50);
LoadString (GetModuleHandle (NULL), IDS_BKPORTHELPFILE, szHelpFile, 50);
LoadString (GetModuleHandle (NULL), IDS_BKPORTEOL, szEOL, 50);

/* initialize wait events for communication between threads */
if (!CreateEvents (hEvents, lpBkPort))
return FALSE;

/* open file for porting and read into buffer */
if ((int)(hFile = (HANDLE)OpenFile (lpBkPort->szFilePath, &of, OF_READWRITE)) == -1)
{
DestroyEvents (hEvents);
return FALSE;
}

/* global allocate buffer for file */
if (!(hFileBuffer = GlobalAlloc (GPTR, (nFileSize = GetFileSize (hFile, NULL))+1)) ||
!(lpFile = (char *)GlobalLock (hFileBuffer)))
{
CloseHandle (hFile);
DestroyEvents (hEvents);
return FALSE;
}

/* allocate initial line buffer of reasonable size */
hLine = GlobalAlloc (GMEM_MOVEABLE, 1024);

/* allocate local memory segments for porttool RESULT strings */
if (!(rIssue.lpszToken = LocalLock (hToken = LocalAlloc (LHND, MAXTOKENLEN))) ||
!(rIssue.lpszHelpStr = LocalLock (hHelp = LocalAlloc (LHND, MAXHELPLEN))) ||
!(rIssue.lpszIssue = LocalLock (hIssue = LocalAlloc (LHND, MAXISSUELEN))) ||
!(rIssue.lpszSuggest = LocalLock (hSuggest = LocalAlloc (LHND, MAXSUGGESTLEN))))
{
CloseHandle (hFile);
GlobalUnlock (lpFile);
GlobalFree (hFileBuffer);
DestroyEvents (hEvents);
GlobalFree (hLine);
return FALSE;
}

/* read entire file into buffer and zero terminate */
ReadFile (hFile, lpFile, nFileSize, &nBytes, NULL);
lpFile[nFileSize] = 0;
lpFilePtr = lpFile;

/* if bytes read not equal to size of file, abort */
if (nBytes != nFileSize)
{
CloseHandle (hFile);
GlobalUnlock (lpFile);
GlobalFree (hFileBuffer);
DestroyEvents (hEvents);
GlobalFree (hLine);
return FALSE;
}

/* reset file to size zero before beginning porting */
SetFilePointer (hFile, 0, NULL, FILE_BEGIN);
SetEndOfFile (hFile);
WriteFile (hFile, szHeader, strlen (szHeader), &nBytes, NULL);
WriteFile (hFile, lpBkPort->szFile, strlen (lpBkPort->szFile), &nBytes, NULL);
WriteFile (hFile, szEOL, strlen (szEOL), &nBytes, NULL);
WriteFile (hFile, szNL, strlen (szNL), &nBytes, NULL);

while (TRUE)
{
/* wait 1ms for either abort or status events to signal */
switch (WaitForMultipleObjects (nBKPORTEVENTS, hEvents, FALSE, 1))
{
case BKPORT_ABORT:
{
charszAbort[MAX_PATH];

/* create time and date */
DateTimeStamp (szdt);

/* write header line */
WriteFile (hFile, szHeader, strlen (szHeader), &nBytes, NULL);
WriteFile (hFile, szdt, strlen (szdt), &nBytes, NULL);
WriteFile (hFile, szEOL, strlen (szEOL), &nBytes, NULL);
WriteFile (hFile, szNL, strlen (szNL), &nBytes, NULL);

/* load abort string and write to file */
LoadString (GetModuleHandle (NULL),
IDS_BKPORTABORT,
szAbort,
MAX_PATH);
WriteFile (hFile, szAbort, strlen (szAbort), (LPDWORD)&nBytes, NULL);

/* write rest of file to disk */
WriteFile (hFile,
(VOID *)lpFilePtr,
(nFileSize - (lpFilePtr-lpFile)),
(LPDWORD)&nBytes,
NULL);

/* clean up */
CloseHandle (hFile);
GlobalUnlock (lpFile);
GlobalFree (hFileBuffer);
GlobalFree (hLine);
DestroyEvents (hEvents);

/* free RESULT strings */
LocalUnlock (hToken); LocalFree (hToken);
LocalUnlock (hHelp); LocalFree (hHelp);
LocalUnlock (hIssue); LocalFree (hIssue);
LocalUnlock (hSuggest); LocalFree (hSuggest);

/* exit thread */
return FALSE;
}
break;

case BKPORT_STATUS:
/* post message to parent thread with status info */
PostMessage (lpBkPort->hDlg,
UM_STATUSUPDATE,
MAKELONG (wIssues, wComplete),
nLines);
break;

case WAIT_TIMEOUT:
/* if we timed out ignore */
break;

default:
/* anything else is an error */
ErrorNotify (lpBkPort->hDlg, GetLastError ());
goto DONE;
break;
}

/* reset line buffer */
GlobalReAlloc (hLine,
NextLineLength (lpFilePtr, lpFile, nFileSize),
GMEM_MOVEABLE);
lpLine = (char *)GlobalLock (hLine);
*lpLine = 0;

/* get next line from file buffer */
switch (GetNextLine (lpFile, nFileSize, lpFilePtr, lpLine, &bCommentOn))
{
/* check valid strings for porting issues */
case VALID_LINE:
/* initialize rIssue string lengths */
*(WORD *)rIssue.lpszToken = MAXTOKENLEN;
*(WORD *)rIssue.lpszHelpStr = MAXHELPLEN;
*(WORD *)rIssue.lpszIssue = MAXISSUELEN;
*(WORD *)rIssue.lpszSuggest = MAXSUGGESTLEN;

if (CheckString (lpLine, lpBkPort->dwPTFlags, &rIssue))
{
/* create time and date */
DateTimeStamp (szdt);

/* write header line */
WriteFile (hFile, szNL, strlen (szNL), &nBytes, NULL);
WriteFile (hFile, szHeader, strlen (szHeader), &nBytes, NULL);
WriteFile (hFile, szdt, strlen (szdt), &nBytes, NULL);
WriteFile (hFile, szEOL, strlen (szEOL), &nBytes, NULL);

/* write token line */
WriteFile (hFile, szToken, strlen (szToken), &nBytes, NULL);
WriteFile (hFile,
rIssue.lpszToken,
strlen (rIssue.lpszToken),
&nBytes,
NULL);
WriteFile (hFile, szEOL, strlen (szEOL), &nBytes, NULL);

/* write issue line */
WriteFile (hFile, szIssue, strlen (szIssue), &nBytes, NULL);
WriteFile (hFile,
rIssue.lpszIssue,
strlen (rIssue.lpszIssue),
&nBytes,
NULL);
WriteFile (hFile, szEOL, strlen (szEOL), &nBytes, NULL);

/* if suggestion */
if (*(rIssue.lpszSuggest))
{
WriteFile (hFile, szSuggest, strlen (szSuggest), &nBytes, NULL);
WriteFile (hFile,
rIssue.lpszSuggest,
strlen (rIssue.lpszSuggest),
&nBytes,
NULL);
WriteFile (hFile, szEOL, strlen (szEOL), &nBytes, NULL);
}

/* if help string */
if (*(rIssue.lpszSuggest))
{
WriteFile (hFile, szHelp, strlen (szHelp), &nBytes, NULL);
WriteFile (hFile,
rIssue.lpszHelpStr,
strlen (rIssue.lpszHelpStr),
&nBytes,
NULL);
WriteFile (hFile, szHelpFile, strlen (szHelpFile), &nBytes, NULL);
WriteFile (hFile, szEOL, strlen (szEOL), &nBytes, NULL);
}

wIssues++;
}

case COMMENT_LINE:
/* write line to file whether comment or not */
WriteFile (hFile, lpLine, strlen (lpLine), &nBytes, NULL);
break;

case EOF_LINE:
if (*lpLine)
WriteFile (hFile, lpLine, strlen (lpLine), &nBytes, NULL);
goto DONE;
break;
}

/* unlock line buffer */
GlobalUnlock (hLine);

/* update status counts */
lpFilePtr += strlen (lpLine);
nLines++;
wComplete = (WORD)(((lpFilePtr-lpFile)*100)/nFileSize);
}

DONE:
/* clean up */
CloseHandle (hFile);
GlobalUnlock (lpFile);
GlobalFree (hFileBuffer);
GlobalFree (hLine);
DestroyEvents (hEvents);

/* free RESULT strings */
LocalUnlock (hToken); LocalFree (hToken);
LocalUnlock (hHelp); LocalFree (hHelp);
LocalUnlock (hIssue); LocalFree (hIssue);
LocalUnlock (hSuggest); LocalFree (hSuggest);

/* send message to parent that thread is dead */
PostMessage (lpBkPort->hDlg,
UM_THREADCOMPLETE,
(WPARAM)lpBkPort->hThread,
0);

/* exit thread */
return TRUE;
}



void WINAPI DateTimeStamp (
char *lpszDT)
{
SYSTEMTIME dt;
char Buff[10];

/* create time and date stamp */
GetSystemTime (&dt);

//
// On Japanese system change the date display order,
// we should do this right w/ locales eventually.
//
if (PRIMARYLANGID(GetUserDefaultLangID ()) == LANG_JAPANESE) {

strcpy (lpszDT, itoa (dt.wYear, Buff, 10));
strcat (lpszDT, "/");
strcat (lpszDT, itoa (dt.wMonth, Buff, 10));
strcat (lpszDT, "/");
strcat (lpszDT, itoa (dt.wDay, Buff, 10));
} else {
strcpy (lpszDT, itoa (dt.wMonth, Buff, 10));
strcat (lpszDT, "/");
strcat (lpszDT, itoa (dt.wDay, Buff, 10));
strcat (lpszDT, "/");
strcat (lpszDT, itoa (dt.wYear, Buff, 10));
}

strcat (lpszDT, " ");
strcat (lpszDT, itoa (dt.wHour, Buff, 10));
strcat (lpszDT, ":");
strcat (lpszDT, itoa (dt.wMinute, Buff, 10));
}





BOOL WINAPI CreateEvents (
HANDLE *lphEvents,
LPBKPORTFILESTRUCT lpBkPort)
{
char szEvent[MAX_PATH];


LoadString (GetModuleHandle (NULL), IDS_BKPORTABORT, szEvent, MAX_PATH);
strcat (szEvent, lpBkPort->szFile);
if (!(lphEvents[BKPORT_ABORT] = CreateEvent (NULL, TRUE, FALSE, szEvent)))
return FALSE;

LoadString (GetModuleHandle (NULL), IDS_BKPORTSTATUS, szEvent, MAX_PATH);
strcat (szEvent, lpBkPort->szFile);
if (!(lphEvents[BKPORT_STATUS] = CreateEvent (NULL, TRUE, FALSE, szEvent)))
{
CloseHandle (lphEvents[BKPORT_ABORT]);
return FALSE;
}

/* return success */
return TRUE;
}




void WINAPI DestroyEvents (
HANDLE *lphEvents)
{
/* close event handles */
CloseHandle (lphEvents[BKPORT_ABORT]);
CloseHandle (lphEvents[BKPORT_STATUS]);
}




int WINAPI NextLineLength (
char *lpFilePtr,
char *lpFile,
int nFileSize)
{
int nCnt=0;
char *lpf = lpFilePtr;

/* count all characters up to end of file or CR/LF sequence */
while (lpf &&
lpf-lpFile < nFileSize &&
*lpf != CARRIAGE_RETURN &&
*(lpf+1) != LINE_FEED)
{
lpf++;
nCnt++;
}

/* length plus 3 for CR/LF/0 terminator sequence */
return nCnt + 3;
}




int WINAPI GetNextLine (
char *lpFile,
int nFileSize,
char *lpFilePtr,
char *lpLine,
BOOL *bCommentOn)
{
char *lpf = lpFilePtr;
char *lpl = lpLine;

/* copy all characters up to end of file or CR/LF sequence */
while (lpf &&
lpf-lpFile < nFileSize &&
*lpf != CARRIAGE_RETURN &&
*(lpf+1) != LINE_FEED)
*lpl++ = *lpf++;

/* check for end of buffer */
if (lpf-lpFile >= nFileSize)
return EOF_LINE;

/* copy carriage return and line feed to line and terminate */
*lpl++ = *lpf++;
*lpl++ = *lpf++;
*lpl = 0;

/* increment lpl to first non space character in line */
lpl = lpLine;
while (*lpl == ' ')
lpl++;

/* see if single line comments exist */
if (*lpl == '/' &&
*(lpl+1) == '/')
return COMMENT_LINE;

/* see if comments begin */
if (*lpl == '/' &&
*(lpl+1) == '*')
*bCommentOn = TRUE;

/* if comment on, see if it terminates yet */
if (*bCommentOn)
{
lpl = lpLine;
while (*lpl)
{
if (*lpl == '*' &&
*(lpl+1) == '/')
{
*bCommentOn = FALSE;
break;
}
lpl = CharNext(lpl);
}

/* if more text on line, valid line */
while (*lpl)
if (*lpl != '*' &&
*(lpl+1) != '/')
return VALID_LINE;
else
return COMMENT_LINE;
}

/* if haven't returned yet, must be valid line */
return VALID_LINE;
}