home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Inside Multimedia 1995 July
/
IMM0795.ISO
/
share
/
os2
/
pmfract
/
src
/
smplhelp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-24
|
29KB
|
836 lines
/*--------------------------------------------------------
SMPLHELP.C -- a Simple Help Displayer system
This DLL system is used to display a simple help window
to go along with a main application window of choice.
Interface is through three functions, only one of which
is required to be called:
SimpleHelpInit (HAB hab); // optional one-time initialization
SimpleHelpExit (void); // optional clean-up call
SimpleHelp (HAB hab, etc.); // Required call to display
// a given text resource.
Help text is stored as user resources in the callers EXE file.
The type and ID of these user resources is passed to SimpleHelp,
which causes the help window to be created if it does not
exist and the described text to be displayed.
Completed 12/26/89 Code by Donald P. Egen
(but much inspired from a variety of sources)
Version 1.01 01/02/90 DPE
Add a little paranoia code at initialization,
and do a better job of handling the
WinRegisterWindowDestroy processing.
Version 1.2 09/03/90 DPE
Do the reformatting as a subthread.
This improves responsiveness on very
large texts being displayed.
Version 1.3 09/30/90 DPE
Support the OS/2 1.2 Scroll bar
thumb size (SBM_SETTHUMBSIZE).
10/16/90 DPE
SHORTS are negative half the time!!!
(ARRRGGHH!!)
Version 1.4 03/17/91 DPE
Fix running off the end of the input
segment if the last line ends with a CR/LF
but there is no EOF character.
(ARRRGHH!! again)
--------------------------------------------------------*/
#define INCL_WIN
#define INCL_GPI
#define INCL_DOS
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "smplhelp.hh"
#include "smplhelp.h"
#define SYSVAL(x) ( (USHORT) WinQuerySysValue(HWND_DESKTOP, x) )
HMODULE hmodHelp = (HMODULE) 0;
HMODULE hmodHelpLast = (HMODULE) 0, hmodHelpNew = (HMODULE) 0;
USHORT idTypeLast = 0, idNameLast = 0, idTypeNew = 0, idNameNew = 0;
HWND hwndScroll ;
HWND hwndHelpFrame = (HWND) 0, hwndHelp = (HWND) 0;
HWND hwndCaller = (HWND) 0;
TID tidReformat = 0;
BOOL flReformatAgain = FALSE;
ULONG semReformat = 0L;
SHORT sThreadStack[STACKSIZE];
ULONG semWindowPS = 0L;
volatile BOOL flReformatStop = FALSE;
PCHAR pResource, pFormat ;
SEL selResource, selFormat;
SHORT cxClient, cyClient, cxChar, cyChar, cyDesc, cyLines,
sScrollPos, sNumLines, sScrollMax ;
ULONG ulResourceSize ;
BOOL fInitOnce = FALSE, fInitWnd = FALSE;
CHAR szClientClass [10] ;
CHAR szTitleBarHelp [20] ;
CHAR szWorking[15];
CHAR szBadAttach[35];
ULONG flFrameFlags = FCF_TITLEBAR | FCF_SYSMENU |
FCF_SIZEBORDER | FCF_MINMAX |
FCF_SHELLPOSITION | FCF_NOMOVEWITHOWNER |
FCF_VERTSCROLL | FCF_ICON |
FCF_MENU | FCF_ACCELTABLE ;
MRESULT EXPENTRY HelpWndProc (HWND, USHORT, MPARAM, MPARAM) ;
MRESULT CALLBACK HelpAboutProc(HWND hDlg, USHORT msg, MPARAM mp1, MPARAM mp2);
static void HelpReformat(void);
static void OneTimeInit (HAB hab)
{
if (!fInitOnce)
{ /* one per process init - get strings, register class */
WinLoadString (hab, hmodHelp, IDS_CLASS,
sizeof szClientClass, szClientClass);
WinLoadString (hab, hmodHelp, IDS_TITLE,
sizeof szTitleBarHelp, szTitleBarHelp) ;
WinLoadString (hab, hmodHelp, IDS_WORKING,
sizeof szWorking, szWorking);
WinLoadString (hab, hmodHelp, IDS_BADATTACH,
sizeof szBadAttach, szBadAttach);
WinRegisterClass (hab, szClientClass, HelpWndProc, CS_SIZEREDRAW, 0) ;
fInitOnce = TRUE;
}
}
VOID CALLBACK SimpleHelpInit (HAB hab)
{ /* Externalize the One Time Init function */
OneTimeInit (hab);
}
VOID CALLBACK SimpleHelp (HAB hab, HWND hwndUser, PSZ achUser,
HMODULE hmodUser, USHORT idType, USHORT idName)
{
/*
This function is the primary interface to the Simple Help System.
It is assumed to be called from a user Client Window Proc.
We do what is necessary to get us up and the focus of attention,
and ready to display the requested help text.
On return from this function, the Simple Help window is an independent
top-level window in the same thread as the original caller.
We can be recalled to change the help text even if we are already
open. This allows a user routine to have possibly multiple submenu
entries in his "Help" menu, and the text displayed here can be
switched by the Help menu in the original window.
*/
CHAR szTitleText [40];
SWP swpFrame;
USHORT cxScreen, cyScreen, cyIcon, cxMe, cyMe, xMe, yMe;
/* do the One Time Initialization if it has not been done already */
OneTimeInit(hab);
if (!fInitWnd)
{ /* if we don't have a window at the moment, create an empty one */
hwndHelpFrame = WinCreateStdWindow (HWND_DESKTOP, 0,
&flFrameFlags, szClientClass, NULL,
0L, hmodHelp, ID_RESOURCE, &hwndHelp) ;
cxScreen = SYSVAL(SV_CXSCREEN);
cyScreen = SYSVAL(SV_CYSCREEN);
cyIcon = SYSVAL(SV_CYICON);
cxMe = cxScreen / 3;
cyMe = cyScreen - 2 * cyIcon;
xMe = cxScreen - cxMe;
yMe = 2 * cyIcon;
WinSetWindowPos (hwndHelpFrame, HWND_TOP,
xMe, yMe, cxMe, cyMe,
SWP_ACTIVATE | SWP_ZORDER | SWP_MOVE | SWP_SIZE | SWP_SHOW);
/* now put the window up */
WinShowWindow(hwndHelpFrame, TRUE);
fInitWnd = TRUE;
}
/* Register so that that we get called when our caller goes away */
if (hwndCaller != hwndUser)
{ /* our caller changed. Unregister the previous caller */
if (hwndCaller != (HWND) 0)
WinRegisterWindowDestroy (hwndCaller, FALSE);
/* now register the new guy */
hwndCaller = hwndUser;
WinRegisterWindowDestroy (hwndCaller, TRUE);
}
/* If we are minimized, restore and activate us */
WinQueryWindowPos (hwndHelpFrame, &swpFrame);
if ( (swpFrame.fs & SWP_MINIMIZE) && (!(swpFrame.fs & SWP_MAXIMIZE)) )
{
WinSetWindowPos (hwndHelpFrame, HWND_TOP,
0, 0, 0, 0,
SWP_RESTORE | SWP_ACTIVATE | SWP_ZORDER);
}
else /* just activate and bring us to the top */
{
WinSetWindowPos (hwndHelpFrame, HWND_TOP,
0, 0, 0, 0,
SWP_ACTIVATE | SWP_ZORDER);
}
/* set up the title bar by concatenating the resource string with the
user's argument string. The idea is to create "Help for <ZXCVBNM>" */
strcpy(szTitleText, szTitleBarHelp);
strcat(szTitleText, achUser);
WinSetWindowText (hwndHelpFrame, szTitleText);
/* now display the text resource requested */
WinSendMsg (hwndHelp, WM_NEW_TEXT, MPFROM2SHORT(hmodUser, 0),
MPFROM2SHORT(idType, idName) );
}
VOID CALLBACK SimpleHelpExit (void)
{ /* if we are still active, close us down */
if (fInitWnd)
WinSendMsg (hwndHelp, WM_CLOSE, 0L, 0L);
}
static void ReFormat (HWND hwnd)
{
USHORT rc;
CHAR szErrorMessage[35];
if (tidReformat)
{ /* already active, queue for another try */
flReformatStop = TRUE;
flReformatAgain = TRUE;
return;
}
/* fire up the sub thread */
DosSemSet((HSEM) &semReformat);
flReformatAgain = FALSE;
flReformatStop = FALSE;
WinEnableWindow (hwndScroll, FALSE);
rc = DosCreateThread (HelpReformat, &tidReformat,
(PBYTE) &sThreadStack[STACKSIZE]);
if (rc == 0)
/* chap down the priority */
rc = DosSetPrty(PRTYS_THREAD, PRTYC_NOCHANGE, -5, tidReformat);
else
{ /* clean up */
DosSemClear((HSEM) &semReformat);
tidReformat = 0;
}
if (rc != 0)
{ /* report the bad news */
sprintf(szErrorMessage, szBadAttach, rc);
WinMessageBox (HWND_DESKTOP, hwnd,
(PSZ) szErrorMessage, (PSZ) szClientClass,
ID_EMESSAGEBOX,
MB_OK | MB_ICONASTERISK | MB_APPLMODAL);
}
}
MRESULT EXPENTRY HelpWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
{
HPS hps ;
POINTL ptl;
SHORT sLineLength, sLine, sScrollInc, sPaintBeg, sPaintEnd;
RECTL rclInvalid ;
PCHAR outp;
SHORT cxNew, cyNew;
switch (msg)
{
case WM_CREATE:
/*-----------------------------------------
Prime the pump by allocating an initial dummy
resource segment
-----------------------------------------*/
DosAllocSeg (25, &selResource, SEG_NONSHARED);
ulResourceSize = 20L;
pResource = MAKEP (selResource, 0) ;
*pResource = AEOF; /* set EOF at front of segment */
/*-----------------------------------------------
Allocate a segment for formatting the text into.
Note: Zero length means Max length (65536 bytyes)
-----------------------------------------------*/
DosAllocSeg(0, &selFormat, SEG_NONSHARED) ;
pFormat = MAKEP (selFormat, 0) ;
/*----------------------
Query character size
----------------------*/
{
FONTMETRICS fm ;
hps = WinGetPS (hwnd) ;
GpiQueryFontMetrics (hps, (LONG) sizeof fm, &fm) ;
cxChar = (SHORT) fm.lAveCharWidth ;
cyChar = (SHORT) fm.lMaxBaselineExt ;
cyDesc = (SHORT) fm.lMaxDescender ;
WinReleasePS (hps) ;
}
/*------------------------------------------
Get scroll bar handle while the getting is good
------------------------------------------*/
hwndScroll = WinWindowFromID (
WinQueryWindow (hwnd, QW_PARENT, FALSE),
FID_VERTSCROLL) ;
/*------------------------------------------
Get the client window size from the CREATESTRUCT
------------------------------------------*/
{
PCREATESTRUCT pcrst = (PCREATESTRUCT) PVOIDFROMMP (mp2);
cxClient = pcrst->cx;
cyClient = pcrst->cy;
cyLines = cyClient / cyChar;
}
return 0 ;
case WM_NEW_TEXT:
/* switch to a new incoming text resource */
/* free the old resource segment */
/* we must wait for the subthread if it is running */
if (tidReformat)
{
flReformatStop = TRUE;
DosSemWait ((HSEM) &semReformat, SEM_INDEFINITE_WAIT);
}
DosFreeSeg (selResource);
hmodHelpLast = hmodHelpNew;
idTypeLast = idTypeNew;
idNameLast = idNameNew;
/*-----------------------------------------
Load the resource, get size and address
-----------------------------------------*/
DosGetResource ( hmodHelpNew = (HMODULE) SHORT1FROMMP(mp1),
idTypeNew = SHORT1FROMMP(mp2),
idNameNew = SHORT2FROMMP(mp2),
&selResource) ;
DosSizeSeg (selResource, &ulResourceSize) ;
pResource = MAKEP (selResource, 0) ;
/* Reformat to initial state. */
/* If we waited at the top of this message,
this will enter queued state, and we will restart
when we process the WM_SUB_DONE message
(which should be in the message queue by now). */
ReFormat(hwnd);
/* force an entire screen update */
WinInvalidateRect (hwnd, NULL, FALSE);
return 0 ;
case WM_SUB_DONE:
/* Reformatting is complete.
If there is another reformat queued, start it.
Else, clean up and schedule repaint */
tidReformat = 0;
flReformatStop = FALSE;
if (flReformatAgain)
{ /* fire up again */
flReformatAgain = FALSE;
ReFormat(hwnd);
return 0;
}
/* fix up the scroll bar */
sScrollMax = max (0, sNumLines - cyLines) ;
sScrollPos = min (0, sScrollMax) ;
WinSendMsg (hwndScroll, SBM_SETSCROLLBAR,
MPFROM2SHORT (sScrollPos, 0),
MPFROM2SHORT (0, sScrollMax)) ;
WinSendMsg (hwndScroll, SBM_SETTHUMBSIZE,
MPFROM2SHORT(cyLines, sNumLines), 0L);
WinEnableWindow (hwndScroll, sScrollMax ? TRUE : FALSE) ;
/* trigger screen update */
WinInvalidateRect (hwnd, NULL, FALSE);
return 0;
case WM_SIZE:
/*
if we are getting minimized, then the new window
sizes will both be zeros.
If so, ignore the message.
If the "New" values are the same as the old values,
also ignore the message.
*/
cxNew = SHORT1FROMMP (mp2) ;
cyNew = SHORT2FROMMP (mp2) ;
if ( (cxNew == 0) && (cyNew == 0) )
/* being minimized */
return 0;
if ( (cxNew == cxClient) && (cyNew == cyClient) )
return 0;
/* nope, must handle the real change in window size */
cxClient = cxNew;
cyClient = cyNew;
cyLines = cyClient / cyChar;
/* reformat everything to the new size */
ReFormat(hwnd);
WinInvalidateRect (hwnd, NULL, FALSE);
return 0 ;
case WM_CHAR:
if (CHARMSG(&msg)->fs & KC_KEYUP)
break;
if (CHARMSG(&msg)->fs & KC_VIRTUALKEY)
{
if (CHARMSG(&msg)->fs & KC_CTRL)
{
switch(CHARMSG(&msg)->vkey)
{ /* Note: Cntl- optional for Top/Bottom movement */
case VK_HOME:
return WinSendMsg (hwnd, WM_VSCROLL,
MPFROMSHORT(1), MPFROM2SHORT(0, SB_SLIDERPOSITION));
case VK_END:
return WinSendMsg (hwnd, WM_VSCROLL,
MPFROMSHORT(1), MPFROM2SHORT(sNumLines - 1, SB_SLIDERPOSITION));
}
break;
}
switch (CHARMSG(&msg)->vkey)
{ /* Note: Home/End don't need Cntl- for vert movement */
case VK_HOME:
return WinSendMsg (hwnd, WM_VSCROLL,
MPFROMSHORT(1), MPFROM2SHORT(0, SB_SLIDERPOSITION));
case VK_END:
return WinSendMsg (hwnd, WM_VSCROLL,
MPFROMSHORT(1), MPFROM2SHORT(sNumLines - 1, SB_SLIDERPOSITION));
case VK_UP:
case VK_DOWN:
case VK_PAGEUP:
case VK_PAGEDOWN:
return WinSendMsg (hwndScroll, msg, mp1, mp2) ;
}
}
break ;
case WM_VSCROLL:
switch (SHORT2FROMMP (mp2))
{
case SB_LINEUP:
sScrollInc = -1 ;
break ;
case SB_LINEDOWN:
sScrollInc = 1 ;
break ;
case SB_PAGEUP:
sScrollInc = min (-1, -cyLines) ;
break ;
case SB_PAGEDOWN:
sScrollInc = max (1, cyLines) ;
break ;
case SB_SLIDERTRACK:
case SB_SLIDERPOSITION:
sScrollInc = SHORT1FROMMP (mp2) - sScrollPos;
break ;
default:
sScrollInc = 0 ;
break ;
}
sScrollInc = max (-sScrollPos,
min (sScrollInc, sScrollMax - sScrollPos)) ;
if (sScrollInc != 0) ;
{
sScrollPos += sScrollInc ;
WinScrollWindow (hwnd, 0, cyChar * sScrollInc,
NULL, NULL, (HRGN) 0, NULL, SW_INVALIDATERGN) ;
if (SHORT2FROMMP(mp2) != SB_SLIDERTRACK)
WinSendMsg (hwndScroll, SBM_SETPOS,
MPFROMSHORT (sScrollPos), NULL) ;
WinUpdateWindow (hwnd) ;
}
return 0 ;
case WM_SYSCOLORCHANGE:
/* Global color change. Trigger Paint to handle it */
WinInvalidateRect (hwnd, NULL, FALSE);
return 0;
case WM_COMMAND:
switch (COMMANDMSG(&msg)->cmd) {
case IDM_ABOUT:
{
HWND hwndAbout;
USHORT rc;
/*
The following kludge is required because of APAR PJ00398.
If ICON static controls in a dialog resource are compiled
into a DLL, it will not load and will cause the entire
dialog box to not display. ICON resources will not load
into dialog boxes which are in DLLs. The ICON, dialog box,
and the calling code are all in the same DLL.
*/
hwndAbout = WinLoadDlg (HWND_DESKTOP, hwnd, /* load em up */
HelpAboutProc, hmodHelp, IDD_ABOUT, NULL);
/* fix the ICON */
WinSendMsg (WinWindowFromID (hwndAbout, IDC_MYICON),
SM_SETHANDLE,
MPFROMLONG( (LONG) WinSendMsg (hwndHelpFrame,
WM_QUERYICON, 0L, 0L) ),
0L);
rc = WinProcessDlg(hwndAbout); /* do the dialog box */
WinDestroyWindow (hwndAbout); /* then zilch it */
}
return 0;
case IDM_RESTORE:
/* flip-flop between current and last displayed
help text. This allows flip-flop between
"Help for <ZXCVBNM>" and "Help for Help" */
WinPostMsg (hwnd, WM_NEW_TEXT,
MPFROM2SHORT(hmodHelpLast, 0),
MPFROM2SHORT(idTypeLast, idNameLast) );
return 0;
default: return 0;
}
break;
case WM_HELP:
WinPostMsg (hwnd, WM_NEW_TEXT,
MPFROM2SHORT(hmodHelp, 0),
MPFROM2SHORT(IDT_TEXT, IDT_HELPONHELP) );
return 0 ;
case WM_PAINT:
/* It's showtime, folks */
/* synchronize with the subthread if it is active */
DosSemRequest ((HSEM) &semWindowPS, SEM_INDEFINITE_WAIT);
hps = WinBeginPaint (hwnd, NULL, &rclInvalid) ;
/* set the foreground and background colors to the
system color values SYSCLR_HELPTEXT and
SYSCLR_HELPBACKGROUND, respectively. */
GpiCreateLogColorTable (hps, LCOL_RESET, LCOLF_RGB,
0L, 0L, NULL);
GpiSetColor (hps, WinQuerySysColor (HWND_DESKTOP,
SYSCLR_HELPTEXT, 0L) );
WinFillRect (hps, &rclInvalid,
WinQuerySysColor (HWND_DESKTOP,
SYSCLR_HELPBACKGROUND, 0L) );
if (tidReformat)
{ /* reformat is active.
put out a "Working..." message */
WinQueryWindowRect(hwnd, &rclInvalid);
WinDrawText(hps, -1, szWorking, &rclInvalid,
0L, 0L, DT_CENTER | DT_VCENTER | DT_TEXTATTRS);
}
else
{ /* put out the real text */
sPaintBeg = max (0, sScrollPos +
(cyClient - (SHORT) rclInvalid.yTop) / cyChar) ;
sPaintEnd = min (sNumLines, sScrollPos +
(cyClient - (SHORT) rclInvalid.yBottom)
/ cyChar + 1) ;
/* Skip down to the first line to be emitted */
outp = pFormat;
for (sLine = 0; sLine < sPaintBeg; sLine++)
{
outp += strlen(outp) + 1;
}
/* Now draw what changed */
for (sLine = sPaintBeg ; sLine < sPaintEnd ; sLine++)
{
ptl.x = cxChar ;
ptl.y = cyClient - cyChar * (sLine + 1 - sScrollPos)
+ cyDesc ;
sLineLength = strlen (outp);
GpiCharStringAt (hps, &ptl,
(LONG) sLineLength,
outp) ;
outp += sLineLength + 1;
}
/* That's all, folks */
}
WinEndPaint (hps) ;
DosSemClear ((HSEM) &semWindowPS);
return 0 ;
case WM_OTHERWINDOWDESTROYED:
/* if the Other Window Destroyed is our caller, and
we are still around, close us down. */
if ( fInitWnd && (hwndCaller == HWNDFROMMP(mp1)) )
WinSendMsg (hwnd, WM_CLOSE, 0L, 0L);
return 0;
case WM_CLOSE:
/* close us down */
WinRegisterWindowDestroy (hwndCaller, FALSE); /* deregister caller */
WinDestroyWindow (hwndHelpFrame);
return 0;
case WM_DESTROY:
/* if the reformat thread is active, wait for it to finish */
if (tidReformat)
{
flReformatStop = TRUE;
DosSemWait ( (HSEM) &semReformat, SEM_INDEFINITE_WAIT);
tidReformat = 0;
}
DosFreeSeg (selResource) ;
DosFreeSeg (selFormat) ;
hwndHelpFrame = (HWND) 0;
hwndHelp = (HWND) 0;
hwndScroll = (HWND) 0;
hwndCaller = (HWND) 0;
fInitWnd = FALSE;
return 0 ;
}
return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
}
MRESULT CALLBACK HelpAboutProc(HWND hDlg, USHORT msg, MPARAM mp1, MPARAM mp2)
/*
About... dialog procedure
*/
{
switch(msg) {
case WM_COMMAND:
switch(COMMANDMSG(&msg)->cmd) {
case DID_OK: WinDismissDlg(hDlg, TRUE); break;
default: break;
}
break;
default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
}
return FALSE;
}
static void HelpReformat(void)
{
HAB habThread;
HPS hps ;
PCHAR inp, outp, olast, tptr;
POINTL aptlBox[TXTBOX_COUNT];
SHORT sLineLength,
sFormatWidth ;
/* Reformat the Original Resource (Text) lines into
lines that will display at full width in the
current window size. */
habThread = WinInitialize(0);
olast = outp = pFormat;
inp = pResource;
sNumLines = sLineLength = 0;
sFormatWidth = cxClient - 2 * cxChar;
while ( ( ! flReformatStop )
&& ( ( (USHORT) (inp - pResource) ) < (USHORT) ulResourceSize )
&& (*inp != '\0') && (*inp != AEOF) )
{
switch (*inp)
{
case '\r':
inp++;
break;
case '\n':
case '\t': /* white space */
case ' ':
/* Look for line overflow first */
DosSemRequest((HSEM) &semWindowPS, SEM_INDEFINITE_WAIT);
hps = WinGetPS (hwndHelp);
GpiQueryTextBox (hps, (LONG) sLineLength,
(PCH) olast,
TXTBOX_COUNT, aptlBox);
WinReleasePS(hps);
DosSemClear((HSEM) &semWindowPS);
if ((aptlBox[TXTBOX_BOTTOMRIGHT].x -
aptlBox[TXTBOX_BOTTOMLEFT].x) > sFormatWidth)
{
tptr = outp; /* try to backscan for last blank */
while (sLineLength > 0)
{
sLineLength--;
if (*--tptr == ' ') break;
}
if (sLineLength == 0)
{ /* only one word on line, take it */
*outp++ = '\0';
sNumLines++;
olast = outp;
sLineLength = 0;
}
else
{ /* overlay space, term line */
*tptr = '\0';
sNumLines++;
olast = tptr + 1;
*outp++ = ' '; /* deposit blank after remainder */
sLineLength = outp - olast;
}
}
else
{ /* no overflow */
if ( ! ( (outp == olast) && (*inp == '\n') ) )
{
*outp++ = ' '; /* deposit the space */
sLineLength++;
}
}
if (*inp == '\n') /* if it was new line */
{
inp++; /* consume the new line */
/* check special front of */
/* line cases */
if ((USHORT)(inp - pResource) >= (USHORT) ulResourceSize )
/* exit if at end -- no line */
/* exists to be at the front of */
{
break;
}
else
if ((*inp == '#') || (*inp == '\r'))
{
*outp++ = '\0'; /* force new line, double space */
sNumLines++;
*outp++ = ' ';
*outp++ = '\0';
sNumLines++;
olast = outp;
sLineLength = 0;
inp++;
}
else
if (*inp == '\\')
{
*outp++ = '\0'; /* force new line, single space */
sNumLines++;
olast = outp;
sLineLength = 0;
inp++;
}
else
if ( (*inp == ' ') || (*inp == '\t') )
{ /* leading space */
if (sLineLength != 0)
{
*outp++ = '\0'; /* force new line, single space */
sNumLines++;
olast = outp;
}
sLineLength = 1;
*outp++ = ' '; /* and keep the space */
inp++;
}
}
else
inp++; /* just consume the white space */
break;
default:
*outp++ = *inp++; /* deposit the nonblank character */
sLineLength++;
} /* end switch */
} /* end while */
if (*(outp-1) != '\0')
{
*outp++ = '\0'; /* terminate the last line if necessary */
sNumLines++;
}
WinTerminate (habThread);
/* indicate we done */
DosEnterCritSec();
DosSemClear(&semReformat);
WinPostMsg (hwndHelp, WM_SUB_DONE, 0L, 0L);
/* and exit thread */
}