home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windoware
/
WINDOWARE_1_6.iso
/
source
/
wzun11sr
/
status.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-18
|
22KB
|
668 lines
/* Status.c -- the status module of WizUnzip
* Robert Heath. 1991.
*/
#include <sys\types.h>
#include <sys\stat.h>
#include <time.h>
#include <windows.h>
#include <string.h>
#include <ctype.h>
#include <io.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include "wizunzip.h"
#include "unzip.h"
#define STATUS_INCREMENT 512 /* incremental status data size */
#define MAX_H_CHARS 160 /* max horizontal chars. */
#define MAX_INDEX_ENTRIES 16 /* Message Window index max entries */
#define MAX_BUFFER_SIZE 0xffffL /* max Message Buffer size. Must fit
* within one memory segment! */
#define MAX_TEXTOUT_COUNT 0x7fffL /* max no. bytes TextOut() accepts */
#define STDIO_BUF_SIZE (FILNAMSIZ+LONG_FORM_FNAME_INX) /* buffer size during printf or fprintf */
static short yClient; /* height of client area */
static short yChar; /* height of typical char. */
static short nVscrollPos = 0; /* scroll position of mesg. window */
static short nNumLines = 0; /* number of lines in buffer */
static short nVscrollMax; /* max scroll position of mesg. window */
static DWORD dwStatusSize = 0L; /* status data size */
static DWORD dwBufferSize = 0L; /* Status buffer size. Never
exceeds MAX_BUFFER_SIZE */
static HANDLE hGlobalStatus; /* global mesg. handle */
static DWORD dwMsgWinIndex[MAX_INDEX_ENTRIES]; /* max index entries */
static short nIndexEntries; /* no. active index entries, with
MAX_INDEX_ENTRIES as its max.
When set to 0, it's time to
re-index.*/
static short nLinesPerEntry; /* lines per index entry */
/* displayed when buffer shouldn't grow or can't grow */
static char CLEARING_MSG[] =
"Clearing Messages window to make room for more information.";
static struct KeyEntry {
WORD wVirtKey;
BOOL bCntl;
int iMessage;
WORD wRequest;
} KeyTable[] = {
/* vertical scroll control
*/
{VK_HOME, TRUE, WM_VSCROLL, SB_TOP },
{VK_END, TRUE, WM_VSCROLL, SB_BOTTOM },
{VK_PRIOR, FALSE, WM_VSCROLL, SB_PAGEUP },
{VK_NEXT, FALSE, WM_VSCROLL, SB_PAGEDOWN },
{VK_UP, FALSE, WM_VSCROLL, SB_LINEUP },
{VK_DOWN, FALSE, WM_VSCROLL, SB_LINEDOWN },
/* horizontal scroll control
*/
{VK_HOME, FALSE, WM_HSCROLL, SB_TOP },
{VK_END, FALSE, WM_HSCROLL, SB_BOTTOM },
{VK_PRIOR, TRUE, WM_HSCROLL, SB_PAGEUP },
{VK_NEXT, TRUE, WM_HSCROLL, SB_PAGEDOWN },
{VK_LEFT, FALSE, WM_HSCROLL, SB_LINEUP },
{VK_RIGHT, FALSE, WM_HSCROLL, SB_LINEDOWN },
} ;
#define NUMKEYS (sizeof(KeyTable)/sizeof(struct KeyEntry))
/* Forward Refs
*/
static void FreeStatusLog(void);
/* Globals
*/
BOOL bRealTimeMsgUpdate = TRUE; /* update messages window in real-time.
* Reset by callers when update can be
* be deferred.
*/
/* Clears status buffer. Frees buffer.
*/
static void FreeStatusLog(void)
{
if (hGlobalStatus)
{
GlobalFree(hGlobalStatus);
hGlobalStatus = NULL;
}
dwStatusSize = 0L; /* status data size */
dwBufferSize = 0L; /* status buffer size */
nNumLines = 0; /* number of lines in buffer */
nVscrollMax = 1;
SetScrollRange(hWndStatus, SB_VERT, 0, 1, FALSE);
nVscrollPos = 0;
SetScrollPos(hWndStatus, SB_VERT, nVscrollPos, TRUE);
}
/* Update Message Window Position is called after adding
* a number of lines to the message window without updating it.
* The function invalidates then updates the window.
*/
void UpdateMsgWndPos(void)
{
nVscrollPos = max(0,(nNumLines-MessageWinLines+1)); /* set position to next to last line */
SetScrollPos(hWndStatus, SB_VERT, nVscrollPos, TRUE);
InvalidateRect(hWndStatus, NULL, TRUE);
UpdateWindow(hWndStatus);
}
/* Add message line (or part of a line) to the global status buffer
* that is the contents of the Message Window.
* Assumes that global data is unlocked when called.
*/
void WriteStringToMsgWin(PSTR String, BOOL bUpdate)
{
WriteBufferToMsgWin(String, strlen(String), bUpdate);
}
/* Add message buffer (maybe part of a line) to the global status buffer
* that is the contents of the Message Window.
* Assumes that global data is unlocked when called.
*/
void WriteBufferToMsgWin(LPSTR buffer, int nBufferLen, BOOL bUpdate)
{
LPSTR lpC; /* pointer into buffer */
HANDLE hGlobalStatusTmp;
LPSTR lpGlobalBuffer; /* pointer into global buffer */
DWORD dwNewSize = dwStatusSize + (DWORD)nBufferLen;
int nIncrLines = 0; /* incremental lines in buffer */
int nIncompleteExistingLine = 0; /* add -1 if incomplete existing last line */
int nIncompleteAddedLine = 0; /* add +1 if incomplete added last line */
DWORD dwRequestedSize; /* Size needed to hold all data. Can't
practically exceeded MAX_BUFFER_SIZE.*/
if (!nBufferLen) /* if no data */
return; /* just beat it */
/* count LF's in buffer to later add to total */
for (lpC = buffer; lpC != NULL && (lpC - buffer) < nBufferLen; )
{
/* use memchr() for speed (?) considerations */
if (lpC = _fmemchr(lpC, '\n', (size_t)(nBufferLen - (lpC - buffer))))
{
nIncrLines++; /* tally line found */
lpC++; /* point beyond LF for next pass */
}
}
if (dwNewSize > dwBufferSize) /* if won't fit or 1st time */
{
/* Round up if necessary to nearest whole increment
*/
dwRequestedSize = ((dwNewSize + STATUS_INCREMENT - 1) /
STATUS_INCREMENT) * STATUS_INCREMENT;
if (hGlobalStatus) /* if buffer exists, realloc */
{
if (dwRequestedSize <= MAX_BUFFER_SIZE &&
(hGlobalStatusTmp = GlobalReAlloc(hGlobalStatus,
dwRequestedSize, GMEM_MOVEABLE)))
{
/* successful re-allocation */
hGlobalStatus = hGlobalStatusTmp;
dwBufferSize = dwRequestedSize;
}
else /* re-allocation failed, make last-ditch attempt! */
{
FreeStatusLog(); /* free own buffers */
MessageBox (hMainWnd, CLEARING_MSG,
"Note", MB_ICONINFORMATION | MB_OK);
WriteBufferToMsgWin(buffer, nBufferLen, bUpdate);
return;
}
}
else /* 1st time */
{
if (hGlobalStatus = GlobalAlloc(GMEM_MOVEABLE,
dwRequestedSize))
{
dwBufferSize = dwRequestedSize; /* save it */
}
else /* 1st allocation failed! */
{
WinAssert(hGlobalStatus); /* DEBUG */
return;
}
}
}
/* should be easy copy of data from here */
lpGlobalBuffer = GlobalLock(hGlobalStatus);
if (lpGlobalBuffer)
{
/* Account for partial lines existing and being added.
*/
if (dwStatusSize &&
lpGlobalBuffer[dwStatusSize-1] != '\n')
nIncompleteExistingLine-- ; /* subtract 1 */
if (buffer[nBufferLen-1] != '\n') /* nBufferLen guaranteed >0 */
nIncompleteAddedLine++ ; /* add 1 */
/* copy data into global buffer */
if (nBufferLen) /* map to ANSI; if 0 don't copy; 0 means 65K */
{
OemToAnsiBuff(buffer, &lpGlobalBuffer[dwStatusSize], nBufferLen);
}
/* bump no. lines accounting for incomplete lines */
nNumLines += (nIncrLines+nIncompleteExistingLine+nIncompleteAddedLine);
dwStatusSize = dwNewSize; /* new data size counting end null */
GlobalUnlock(hGlobalStatus);
nVscrollMax = max(1, nNumLines + 2 - yClient/yChar);
SetScrollRange(hWndStatus, SB_VERT, 0, nVscrollMax, FALSE);
nIndexEntries = 0; /* re-index whenever more data is added */
if (bUpdate) /* if requested to update message box */
{
nVscrollPos = max(0,(nNumLines-MessageWinLines+1)); /* set position to next to last line */
SetScrollPos(hWndStatus, SB_VERT, nVscrollPos, TRUE);
InvalidateRect(hWndStatus, NULL, TRUE);
UpdateWindow(hWndStatus);
}
}
else
{
WinAssert(lpGlobalBuffer); /* DEBUG */
}
}
long FAR PASCAL StatusProc (HWND hWnd, unsigned iMessage, WORD wParam, LONG lParam)
{
static short xClient ; /* size of client area */
HDC hDC; /* device context */
TEXTMETRIC tm; /* text metric structure */
PAINTSTRUCT ps;
#ifdef OLD_WAY
RECT rect;
#endif
struct KeyEntry *pKE; /* pointer to key entry */
LPSTR lpStatusBuffer; /* pointer to global mesg. buffer */
int nMenuItemCount; /* no. items in System menu before deleting separators */
BOOL bCntl; /* control shift pressed ? */
static short xChar;
static short nHscrollMax;
static short nHscrollPos;
static short nMaxWidth; /* in pixels */
short nVscrollInc;
short nHscrollInc;
short i, x, y, nPaintBeg, nPaintEnd;
HMENU hSysMenu; /* this guy's system menu */
switch (iMessage) {
case WM_CREATE:
#ifdef NEEDME
wStatusItem = LOWORD((LONG)(((LPCREATESTRUCT)lParam)->lpCreateParams));
#endif
hDC = GetDC(hWnd); /* get device context */
hOldFont = SelectObject ( hDC, hFixedFont);
GetTextMetrics(hDC, &tm);
ReleaseDC(hWnd, hDC);
xChar = tm.tmAveCharWidth;
yChar = tm.tmHeight + tm.tmExternalLeading;
nMaxWidth = MAX_H_CHARS * xChar;
nVscrollPos = 0; /* reset position to 0 */
nVscrollMax = max(1,nNumLines);
SetScrollRange(hWnd, SB_VERT, 0, nVscrollMax, FALSE);
SetScrollPos(hWnd, SB_VERT, 0, TRUE);
hSysMenu = GetSystemMenu(hWnd, FALSE);
DeleteMenu(hSysMenu, SC_SIZE, MF_BYCOMMAND); /* delete menu item */
DeleteMenu(hSysMenu, SC_MOVE, MF_BYCOMMAND); /* delete menu item */
DeleteMenu(hSysMenu, SC_CLOSE, MF_BYCOMMAND); /* delete menu item */
DeleteMenu(hSysMenu, SC_TASKLIST, MF_BYCOMMAND); /* delete menu item */
/* walk thru menu and delete all separator bars
*/
for (nMenuItemCount = GetMenuItemCount(hMenu);
nMenuItemCount ; nMenuItemCount--)
{
if (GetMenuState(hSysMenu, nMenuItemCount-1, MF_BYPOSITION) & MF_SEPARATOR)
{
DeleteMenu(hSysMenu, nMenuItemCount-1, MF_BYPOSITION);
}
}
return 0;
case WM_SIZE:
xClient = LOWORD(lParam);/* x size of client area */
yClient = HIWORD(lParam);/* y size of client area */
nVscrollMax = max(1, nNumLines + 2 - yClient/yChar);
nVscrollPos = min(nVscrollPos, nVscrollMax);
SetScrollRange(hWnd, SB_VERT, 0, nVscrollMax, FALSE);
SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE);
nHscrollMax = max(0, 2 + (nMaxWidth - xClient) / xChar);
nHscrollPos = min(nHscrollPos, nHscrollMax);
SetScrollRange(hWnd, SB_HORZ, 0, nHscrollMax, FALSE);
SetScrollPos(hWnd, SB_HORZ, nHscrollPos, TRUE);
return 0;
case WM_SYSCOMMAND:
switch ((wParam & 0xFFF0)) { /* decode parameter type */
case SC_RESTORE: /* alert parent */
PostMessage(hMainWnd, WM_COMMAND,
IDM_RESTORE_STATUS, 0L);
break;
case SC_MAXIMIZE:
PostMessage(hMainWnd, WM_COMMAND,
IDM_MAX_STATUS, 0L);
break;
default:
return (DefWindowProc(hWnd, iMessage, wParam, lParam));
}
break;
case WM_COMMAND:
switch (wParam) { /* decode parameter type */
case IDM_CLEAR_STATUS:
FreeStatusLog(); /* free log contents */
InvalidateRect(hWndStatus, NULL, TRUE);
break;
default:
break;
}
break;
case WM_VSCROLL: /* scroll bar action on list box */
switch (wParam) { /* decode parameter type */
case SB_TOP:
nVscrollInc = -nVscrollPos;
break;
case SB_BOTTOM:
nVscrollInc = nVscrollMax - nVscrollPos;
break;
case SB_LINEUP:
nVscrollInc = -1;
break;
case SB_LINEDOWN:
nVscrollInc = 1;
break;
case SB_PAGEUP:
nVscrollInc = min(-1, -yClient/yChar);
break;
case SB_PAGEDOWN:
nVscrollInc = max(1, yClient/yChar);
break;
case SB_THUMBPOSITION:
nVscrollInc = LOWORD(lParam) - nVscrollPos;
break;
default: /* END_SCROLL comes thru here */
nVscrollInc = 0;
} /* bottom of scroll-decoding switch */
if (nVscrollInc = max(-nVscrollPos,
min(nVscrollInc, nVscrollMax - nVscrollPos)))
{
nVscrollPos += nVscrollInc;
ScrollWindow(hWnd, 0, -yChar * nVscrollInc, NULL, NULL);
SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE);
UpdateWindow(hWnd);
}
return 0;
case WM_HSCROLL: /* scroll bar action on list box */
switch (wParam) { /* decode parameter type */
case SB_TOP:
nHscrollInc = -nHscrollPos;
break;
case SB_BOTTOM:
nHscrollInc = nHscrollMax - nHscrollPos;
break;
case SB_LINEUP:
nHscrollInc = -1;
break;
case SB_LINEDOWN:
nHscrollInc = 1;
break;
case SB_PAGEUP:
nHscrollInc = -8;
break;
case SB_PAGEDOWN:
nHscrollInc = 8;
break;
case SB_THUMBPOSITION:
nHscrollInc = LOWORD(lParam) - nHscrollPos;
break;
default:
#ifdef CATCHING_END_SCROLL
nHscrollInc = 0;
#else
return (DefWindowProc(hWnd, iMessage, wParam, lParam));
#endif
} /* bottom of scroll-decoding switch */
if (nHscrollInc = max(-nHscrollPos,
min(nHscrollInc, nHscrollMax - nHscrollPos)))
{
nHscrollPos += nHscrollInc;
ScrollWindow(hWnd, -xChar * nHscrollInc, 0, NULL, NULL);
SetScrollPos(hWnd, SB_HORZ, nHscrollPos, TRUE);
}
return 0;
case WM_KEYDOWN:
bCntl = (BOOL)(GetKeyState(VK_CONTROL) < 0 ? TRUE : FALSE);
for (i = 0, pKE = KeyTable; i < NUMKEYS; i++, pKE++)
{
if (wParam == pKE->wVirtKey && bCntl == pKE->bCntl)
{
SendMessage(hWnd, pKE->iMessage, pKE->wRequest, 0L);
break;
}
}
break;
case WM_PAINT:
if (!hGlobalStatus) /* if nothing to paint */
{
return (DefWindowProc(hWnd, iMessage, wParam, lParam)); /* exit */
}
{
REGISTER LPSTR lpC; /* current char */
LPSTR lpCtemp; /* address of next '\n' in buffer */
LPSTR lpStartC; /* paint starting character */
LPSTR lpBegLine; /* beginning of current line */
HANDLE hNewHandle;
DWORD dwLineLen; /* length of current line */
short nLinesSinceLastEntry; /* lines since last entry */
DWORD dwSearchLen; /* length for _fmemchr() to search */
lpStartC = NULL; /* paint starting character */
lpStatusBuffer = GlobalLock(hGlobalStatus);
WinAssert(lpStatusBuffer); /* DEBUG */
hDC = BeginPaint(hWnd, &ps);
WinAssert(hDC); /* DEBUG */
hNewHandle = SelectObject ( hDC, hFixedFont);
WinAssert(hNewHandle); /* DEBUG */
nPaintBeg = max(0, nVscrollPos+ps.rcPaint.top/yChar -1);
nPaintEnd = min(nNumLines, nVscrollPos + ps.rcPaint.bottom/yChar);
if (nPaintBeg >= nPaintEnd) /* if no painting to do ... */
{
EndPaint(hWnd, &ps); /* just exit */
GlobalUnlock(hGlobalStatus); /* unlock memory */
return 0;
}
if (!nIndexEntries) /* re-index whenever more data is added */
{
/* Round up to make lines_per_entry encompass all
* possible lines in buffer.
*/
nLinesPerEntry = (nNumLines+MAX_INDEX_ENTRIES-1) / MAX_INDEX_ENTRIES;
if (!nLinesPerEntry) /* if zero */
nLinesPerEntry++; /* set to 1 as minimum */
/* Count lines from beginning of buffer to:
* 1) mark beginning of paint sequence (lpStartC) and
* 2) periodically save buffer index in MsgWinIndex[] table.
*/
for (lpC = lpStatusBuffer, i = 0, nLinesSinceLastEntry = 0;
(DWORD)(lpC - lpStatusBuffer) < dwStatusSize ; i++)
{
/* We are at the 1st character position in the line */
if (i == nPaintBeg) /* Starting point for paint ? */
lpStartC = lpC; /* If so, mark starting point */
/* Entry time ? */
if (!nLinesSinceLastEntry++ &&
nIndexEntries < MAX_INDEX_ENTRIES)
{
dwMsgWinIndex[nIndexEntries] =
(DWORD)(lpC - lpStatusBuffer); /* save index */
nIndexEntries++;
}
if (nLinesSinceLastEntry >= nLinesPerEntry)
nLinesSinceLastEntry = 0;
/* Use _fmemchr() to find next LF.
* It's probably optimized for searches.
*/
dwSearchLen = dwStatusSize -
(DWORD)(lpC - lpStatusBuffer);
if ((lpCtemp = _fmemchr(lpC, '\n', (size_t)dwSearchLen)))
lpC = ++lpCtemp; /* use next char as beg of line */
else /* else use lpC with incremented value */
lpC += dwSearchLen;
} /* bottom of still-counting-lines loop */
WinAssert(lpStartC); /* DEBUG */
lpC = lpStartC; /* restore starting point */
WinAssert((DWORD)lpC >= (DWORD)lpStatusBuffer && /* DEBUG */
(DWORD)lpC < (DWORD)&lpStatusBuffer[dwStatusSize]);
} /* bottom of need-to-build-index block */
else /* index is still valid */
{
short nIndexEntry; /* work backwards! */
/* Find index of line number which is equal to or just
* below the starting line to paint. Work backwards
* thru the table. Here, "i" is the line no. corresponding
* to the current table index.
*/
for (nIndexEntry = nIndexEntries - 1,
i = nIndexEntry * nLinesPerEntry;
nIndexEntry >= 0 &&
nPaintBeg < i ;
nIndexEntry--, i -= nLinesPerEntry )
;
WinAssert(nIndexEntry >= 0); /* DEBUG */
WinAssert(i <= nPaintBeg); /* DEBUG */
/* OK, we've got a head start on the search.
* Start checking characters from the position found
* in the index table.
*/
for (lpC = &lpStatusBuffer[dwMsgWinIndex[nIndexEntry]];
i < nPaintBeg &&
#ifndef NEW_WAY
(DWORD)(lpC - lpStatusBuffer) < dwStatusSize;
#else
((DWORD)lpC - (DWORD)lpStatusBuffer) < dwStatusSize;
#endif
i++)
{
/* Find length of current line. Use _fmemchr() to
* find next LF.
*/
dwSearchLen = dwStatusSize -
(DWORD)(lpC - lpStatusBuffer);
if ((lpCtemp = _fmemchr(lpC, '\n', (size_t)dwSearchLen)) != NULL)
lpC = ++lpCtemp; /* point to next char. past '\n' */
else /* If search fails, pretend LF exists, go past it. */
lpC += dwSearchLen;
}
} /* bottom of index-is-still-valid block. */
/* At this point we've got the buffer address, lpC, for the 1st
* line at which we begin painting, nPaintBeg.
*/
for (i = nPaintBeg;
i < nPaintEnd &&
#ifndef NEW_WAY
(DWORD)(lpC - lpStatusBuffer) >= 0L &&
(DWORD)(lpC - lpStatusBuffer) < dwStatusSize ;
#else
((DWORD)lpC - (DWORD)lpStatusBuffer) >= 0L &&
((DWORD)lpC - (DWORD)lpStatusBuffer) < dwStatusSize ;
#endif
i++)
{
lpBegLine = lpC;
/* Find length of current line. Use _fmemchr() to find next LF.
*/
dwSearchLen = dwStatusSize - (DWORD)(lpC - lpStatusBuffer);
if ((lpCtemp = _fmemchr(lpC, '\n', (size_t)dwSearchLen)) == NULL)
{
/* If search fails, pretend we found LF, we won't
* display it anyway.
*/
lpCtemp = lpC + dwSearchLen;
}
WinAssert((DWORD)lpCtemp >= (DWORD)lpBegLine); /* should be non-negative */
WinAssert((DWORD)lpCtemp >= (DWORD)lpStatusBuffer && /* DEBUG */
(DWORD)lpCtemp <= (DWORD)&lpStatusBuffer[dwStatusSize]);
x = xChar * (1 - nHscrollPos);
y = yChar * (1 - nVscrollPos + i);
dwLineLen = (DWORD)(lpCtemp - lpBegLine);/* calc length*/
if (dwLineLen && lpBegLine[dwLineLen-1] == '\r')
dwLineLen--; /* don't display '\r' */
/* may be displaying long lines if binary file */
if (dwLineLen > MAX_TEXTOUT_COUNT)
dwLineLen = MAX_TEXTOUT_COUNT;
TabbedTextOut(hDC, x, y, lpBegLine, (int)dwLineLen, 0, NULL, 0);
lpC = ++lpCtemp; /* point to next char. past '\n' */
}
EndPaint(hWnd, &ps);
GlobalUnlock(hGlobalStatus); /* unlock memory */
return 0;
}
return (DefWindowProc(hWnd, iMessage, wParam, lParam));
break;
case WM_CLOSE: /* message: close the window */
DestroyWindow(hWnd); /* close the mesg. window */
break;
case WM_DESTROY:
FreeStatusLog();
break;
default:
return (DefWindowProc(hWnd, iMessage, wParam, lParam));
}
return 0L;
}
/* Printf buffers the current output and counts the number of lines
* within it. It makes sure there is enough space in the global
* buffer, then copies the buffered data to the global buffer.
* It then triggers a repaint of the status buffer.
*/
int _FAR_ _cdecl printf(const char _FAR_ *format, ...)
{
va_list argptr;
int LinesInBuffer = 0;
HANDLE hMemory;
PSTR psBuffer;
va_start(argptr, format);
hMemory = LocalAlloc(LMEM_MOVEABLE, STDIO_BUF_SIZE);
WinAssert(hMemory);
if (!hMemory)
{
return 0;
}
psBuffer = (PSTR)LocalLock(hMemory);
WinAssert(psBuffer); /* DEBUG */
vsprintf(psBuffer, format, argptr);
va_end(argptr);
WinAssert(strlen(psBuffer) < STDIO_BUF_SIZE); /* raise STDIO_BUF_SIZE ? */
WriteStringToMsgWin(psBuffer, bRealTimeMsgUpdate);
LocalUnlock(hMemory); /* unlock it to Windows */
LocalFree(hMemory); /* Returns it to Windows */
return 0;
}
/* fprintf clone for code in unzip.c, etc.
*/
int _FAR_ _cdecl fprintf(FILE _FAR_ *file, const char _FAR_ *format, ...)
{
va_list argptr;
int LinesInBuffer = 0;
HANDLE hMemory;
PSTR psBuffer;
va_start(argptr, format);
hMemory = LocalAlloc(LMEM_MOVEABLE, STDIO_BUF_SIZE);
WinAssert(hMemory);
if (!hMemory)
{
return 0;
}
psBuffer = (PSTR)LocalLock(hMemory);
WinAssert(psBuffer); /* DEBUG */
vsprintf(psBuffer, format, argptr);
va_end(argptr);
WinAssert(strlen(psBuffer) < STDIO_BUF_SIZE); /* raise STDIO_BUF_SIZE ? */
WriteStringToMsgWin(psBuffer, bRealTimeMsgUpdate);
LocalUnlock(hMemory); /* unlock it to Windows */
LocalFree(hMemory); /* Returns it to Windows */
}
void _FAR_ _cdecl perror(const char _FAR_ *parm1)
{
printf(parm1);
}