/*** mhutil - utilities for the help extension for the Microsoft Editor
*
*   Copyright <C> 1988, Microsoft Corporation
*
* Revision History (most recent first):
*
*	01-Dec-1988 ln	Cleanup & dislog help
*	28-Sep-1988 ln	Correct GrabWord return value
*	02-Sep-1988 ln	Make all data inited. Add info in debug vers.
*   []	16-May-1988	Extracted from mehelp.c
*
*************************************************************************/
#include <string.h>			/* string functions		*/
#include <malloc.h>
#include "mh.h" 			/* help extension include file	*/



/************************************************************************
**
** procArgs
**
** Purpose:
**  decode arguments passed into extension into commonly used variables.
**
** Entry:
**  pArg	= pointer to arg structure, courtesy of Z
**
** Exit:
**  returns pArg->argType. Global variables updated.
*/
int pascal near procArgs (pArg)
ARG far *pArg;				/* argument data		*/
{
buf[0] = 0;
pArgWord = pArgText = 0;
rnArg.flFirst.col = rnArg.flLast.col = 0;
rnArg.flFirst.lin = rnArg.flLast.lin = 0;
cArg = 0;

opendefault ();
pFileCur = FileNameToHandle ("", "");	/* get current file handle	*/
fnCur[0] = 0;
GetEditorObject(RQ_FILE_NAME,0,fnCur);	/* get filename 		*/
fnExtCur = strchr (fnCur, '.'); 	/* and pointer to extension	*/

switch (pArg->argType) {
    case NOARG:             /* <function> only, no arg  */
    cArg     = 0;
    pArgText = NULL;
	break;

    case NULLARG:			/* <arg><function>		*/
	cArg = pArg->arg.nullarg.cArg;	/* get <arg> count		*/
	GrabWord ();			/* get argtext and argword	*/
	break;

    case STREAMARG:			/* <arg>line movement<function> */
	cArg = pArg->arg.streamarg.cArg;/* get <arg> count		*/
	rnArg.flFirst.col = pArg->arg.streamarg.xStart;
	rnArg.flLast.col  = pArg->arg.streamarg.xEnd;
	rnArg.flFirst.lin = pArg->arg.streamarg.yStart;
	if (GetLine(rnArg.flFirst.lin, buf, pFileCur) > rnArg.flFirst.col) {
	    pArgText = &buf[rnArg.flFirst.col];  /* point at word		 */
	    buf[rnArg.flLast.col] = 0;		 /* terminate string		 */
	    }
	break;

    case TEXTARG:			/* <arg> text <function>	*/
	cArg = pArg->arg.textarg.cArg;	/* get <arg> count		*/
	pArgText = pArg->arg.textarg.pText;
	break;
    }
return pArg->argType;
/* end procArgs */}

/************************************************************************
**
** GrabWord - Grab the word under the editor cursor
**
** Purpose:
**  grabs the word underneath the cursor for context sensitive help look-up.
**
** Entry:
**  none
**
** Returns:
**  nothing. pArgWord points to word, if it was parsed.
*/
void pascal near GrabWord () {

pArgText = pArgWord = 0;
pFileCur = FileNameToHandle ("", "");	   /* get current file handle	   */
GetTextCursor (&rnArg.flFirst.col, &rnArg.flFirst.lin);
if (GetLine(rnArg.flFirst.lin, buf, pFileCur)) {	   /* get line			   */
    pArgText = &buf[rnArg.flFirst.col]; 		/* point at word	*/
    while (!wordSepar((int)*pArgText))
	pArgText++;			/* search for end		*/
    *pArgText = 0;			/* and terminate		*/
    pArgWord = pArgText = &buf[rnArg.flFirst.col];	/* point at word		*/
    while ((pArgWord > &buf[0]) && !wordSepar ((int)*(pArgWord-1)))
	pArgWord--;
    }
/* end GrabWord */}

/*** appTitle - Append help file title to buffer
*
*  Read in the title of a help file and append it to a buffer.
*
* Input:
*  fpDest	- far pointer to destination of string
*  ncInit	- Any nc of file to get title for
*
* Output:
*  Returns
*
*************************************************************************/
void pascal near appTitle (
char far *pDest,
nc	ncInit
) {
/*
** first, point to end of string to append to
*/
while (*pDest)
    pDest++;
/*
** Start by getting the info on the file referenced, so that we can get the
** ncInit for that file.
*/
if (!HelpGetInfo (ncInit, &hInfoCur, sizeof(hInfoCur))) {
    ncInit = NCINIT(&hInfoCur);
/*
** Find the context string, and read the topic. Then just read the first
** line into the destination
*/
    ncInit = HelpNc ("h.title",ncInit);
    if (ncInit.cn && (fReadNc(ncInit))) {
    pDest += HelpGetLine (1, BUFLEN, pDest, pTopic);
	*pDest = 0;
	free (pTopic);
	pTopic = NULL;
	}
/*
** If no title was found, then just place the help file name there.
*/
    else
	strcpy (pDest, HFNAME(&hInfoCur));
    }
/*
** If we couldn't even get the info, then punt...
*/
else
    strcpy (pDest, "** unknown **");
/* end appTitle */}


/*** errstat - display error status message
*
*  In non cw, just display the strings on the status line. In CW, bring up
*  a message box.
*
* Input:
*  sz1		= first error message line
*  sz2		= second. May be NULL.
*
* Output:
*  Returns FALSE
*************************************************************************/
flagType pascal near errstat (
char	*sz1,
char	*sz2
) {
#if defined(PWB)
DoMessageBox (sz1, sz2, NULL, MBOX_OK);
#else
buffer	buf;

strcpy (buf, sz1);
if (sz2) {
    strcat (buf, " ");
    strcat (buf, sz2);
    }
stat (buf);
#endif
return FALSE;
/* end errstat */}

/*** stat - display status line message
*
*  Places extension name and message on the status line
*
* Entry:
*  pszFcn      - Pointer to string to be prepended.
*
* Exit:
*  none
*
*************************************************************************/
void pascal near stat(pszFcn)
char *pszFcn;					/* function name	*/
{
buffer	buf;					/* message buffer	*/

strcpy(buf,"mhelp: ");				/* start with name	*/
if (strlen(pszFcn) > 72) {
    pszFcn+= strlen(pszFcn) - 69;
    strcat (buf, "...");
    }
strcat(buf,pszFcn);				/* append message	*/
DoMessage (buf);				/* display		*/
/* end stat */}

#ifdef DEBUG
buffer	debstring   = {0};
extern	int	delay;			/* message delay		*/

/*** debhex - output long in hex
*
*  Display the value of a long in hex
*
* Input:
*  lval 	= long value
*
* Output:
*  Returns nothing
*
*************************************************************************/
void pascal near debhex (
long	lval
) {
char lbuf[10];

_ultoa (lval, lbuf, 16);
debmsg (lbuf);
/* end debhex */}

/*** debmsg - piece together debug message
*
*  Outputs a the cummulative message formed by successive calls.
*
* Input:
*  psz		= pointer to message part
*
* Output:
*  Returns nothing
*************************************************************************/
void pascal near debmsg (
char far *psz
) {
_stat (strcat (debstring, psz ? psz : "<NULL>" ));
/* end debmsg */}

/*** debend - terminates message accumulation & pauses
*
*  Terminates the message accumulation, displays the final message, and
*  pauses, either for the pause time, or for a keystroke.
*
* Input:
*  fWait	= TRUE => wait for a keystroke
*
* Output:
*  Returns nothing
*
*************************************************************************/
void pascal near debend (
flagType fWait
) {
if (fWait && delay) {
#if defined(PWB)
    DoMessageBox (debstring, NULL, NULL, MBOX_OK);
#else
    _stat (strcat (debstring, " Press a key..."));
    ReadChar ();
#endif
    }
#ifdef OS2
else if (delay)
    DosSleep ((long)delay);
#endif
debstring[0] = 0;
/* end debend */}

/*** _mhassertexit - display assertion message and exit
*
* Input:
*  pszExp	- expression which failed
*  pszFn	- filename containing failure
*  line 	- line number failed at
*
* Output:
*  Doesn't return
*
*************************************************************************/
void pascal near _mhassertexit (
char	*pszExp,
char	*pszFn,
int	line
) {
char lbuf[10];

_ultoa (line, lbuf, 10);
strcpy (buf, pszExp);
strcat (buf, " in ");
strcat (buf, pszFn);
strcat (buf, ": line ");
strcat (buf, lbuf);
errstat ("Help assertion failed", buf);

fExecute ("exit");

/* end _mhassertexit */}

#endif


flagType  pascal  wordSepar (int i) {
    CHAR c = (CHAR)i;
    if (((c >= 'a') && (c <= 'z')) ||
        ((c >= 'A') && (c <= 'Z')) ||
        ((c >= '0') && (c <= '9')) ||
         ( c == '_' )              ||
         ( c == '$' ) ) {
        return FALSE;
    } else {
        return TRUE;
    }
}


char far *  pascal near     xrefCopy (char far *dst, char far *src)
{
    if ( *src ) {
        strcpy( dst, src );
    } else {
        dst[0] = src[0];
        dst[1] = src[1];
        dst[2] = src[2];
    }

    return dst;
}