windows-nt/Source/XPSP1/NT/sdktools/mep/extens/justify/justify.c
2020-09-26 16:20:57 +08:00

533 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#define EXT_ID "justify ver 2.02 "##__DATE__##" "##__TIME__
/*
** Justify Z extension
**
** History:
** 12-Sep-1988 mz Made WhenLoaded match declaration
** 01-Sep-1988 Corrected hang when flush-justifying a line with no
** spaces.
** 14-Aug-1988 Corrected right-justification on non-column-1 based
** lines. Corrected justification over multiple
** paragraphs.
** 30-Mar-1988 Extracted from "myext".
**
*/
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "ext.h"
#ifndef TRUE
#define TRUE -1
#define FALSE 0
#endif
void pascal near DumpLine (char far *, PFILE, COL, COL, LINE, char far *, int);
int pascal near NextLine (char far *, PFILE, LINE, LINE far *, int far *);
flagType pascal near isterm (char);
void pascal near _stat (char *);
#ifdef DEBUG
void pascal near debend (flagType);
void pascal near debhex (long);
void pascal near debmsg (char far *);
#else
#define debend(x)
#define debhex(x)
#define debmsg(x)
#endif
flagType just2space = TRUE;
int justwidth = 79;
/*************************************************************************
**
** justify
** justify paragraph(s)
**
** NOARG: Justify between columns 0 and 78, from the current line to
** blank line.
** NULLARG: Justify between current column and 78, from the current line to
** blank line.
** LINEARG: Justify between current column and 78, the specified lines.
** "STREAMARG": Justify between specified columns from current line to blank.
** (handled by boxarg)
** BOXARG: justify between specified columns the specified rows
** TEXTARG: Justify between columns 0 and 78, from the current line to
** blank line, prepending each resulting line with the textarg.
*/
flagType pascal EXTERNAL
justify (
CMDDATA argData,
ARG far *pArg,
flagType fMeta
)
{
int cbLine; /* length of line just read */
char inbuf[512]; /* input buffer */
PFILE pFile; /* file handle */
char far *pText; /* pointer to prepending text */
COL x1; /* justify to left column */
COL x2; /* justify to right columne */
LINE y1; /* start line */
LINE y2; /* end line */
LINE yOut; /* output line */
//
// Unreferenced parameters
//
(void)argData;
_stat(EXT_ID);
switch (pArg->argType) {
case NOARG: /* justify paragraph */
x1 = 0; /* between cols 0... */
x2 = justwidth; /* ...and 79 */
y1 = pArg->arg.noarg.y; /* current line... */
y2 = -1; /* ...to blank line*/
pText = 0; /* there is no text */
break;
case NULLARG: /* justify indented */
x1 = pArg->arg.nullarg.x; /* between cur col... */
x2 = justwidth; /* ...and 79 */
y1 = pArg->arg.nullarg.y; /* current line... */
y2 = -1; /* ...to blank line*/
pText = 0; /* there is no text */
break;
case LINEARG: /* justify line range */
x1 = 0; /* between cols 0... */
x2 = justwidth; /* ...and 79 */
y1 = pArg->arg.linearg.yStart; /* and range of lines */
y2 = pArg->arg.linearg.yEnd;
pText = 0; /* there is no text */
break;
case BOXARG: /* justify box */
x1 = pArg->arg.boxarg.xLeft; /* from left corner... */
x2 = pArg->arg.boxarg.xRight; /* ...to right */
y1 = pArg->arg.boxarg.yTop; /* from top... */
y2 = pArg->arg.boxarg.yBottom; /* ...to bottom */
pText = 0; /* there is no text */
break;
case TEXTARG: /* justify & prepend */
x1 = 0; /* between 0... */
x2 = justwidth; /* ...and 79 */
y1 = pArg->arg.textarg.y; /* current line... */
y2 = -1; /* ...to blank line */
pText = pArg->arg.textarg.pText; /* there IS text */
break;
}
pFile = FileNameToHandle ("", "");
if (y1 == y2) /* if same line, then */
y2 = -1; /* just to blank line */
if (x1 == x2) /* if same column */
x2 = justwidth; /* then just to default */
if (x2 < x1) { /* if bas-ackwards */
x1 = 0; /* revert to default */
x2 = justwidth;
}
/*
** while we can get data within the specified limits, format each new line
** and output back to the file.
*/
inbuf[0] = 0;
yOut = y1;
while (NextLine(inbuf,pFile,y1,&y2,&cbLine)) {
/*
** if the line was blank, NextLine returned TRUE becase we're formating a
** range of text. This means we've reached the end of one paragraph. We dump
** the text collected so far (if any), and then a blank line.
*/
if (cbLine == 0) {
if (inbuf[0]) {
DumpLine(inbuf,pFile,x1,x2,yOut++,pText,0);
y1++;
if (y2 != (LINE)-1)
y2++;
}
DumpLine("",pFile,x1,x2,yOut++,pText,0);/* dump blank line */
y1++;
if (y2 != (LINE)-1)
y2++;
}
else
/*
** inbuf contains the data collected so far for output. Output one newly
** formated line at a time until the contents of inbuf are narrower than
** our output columns.
*/
while ((COL)strlen(inbuf) > (x2-x1)) { /* while data to output */
DumpLine(inbuf,pFile,x1,x2,yOut++,pText,fMeta);
y1++; /* line moves with insert*/
if (y2 != (LINE)-1)
y2++;
}
}
/*
** Dump any partial last line. Then if we were formatting to a blank line,
** dump out one of those too.;
*/
if (inbuf[0])
DumpLine (inbuf,pFile,x1,x2,yOut++,pText,0); /* dump last line */
if (y2 == -1)
DumpLine (NULL,pFile,x1,x2,yOut++,pText,0); /* dump blank line */
return TRUE;
/* end justify */}
/*** NextLine - Get next line from file
*
* Get next line from file, remove leading and trailing spaces, and append
* it to the input buffer. Each line is deleted from the file as it is
* read in. This means that the target terminator, (*py2), is decremented
* by one for each line read in.
*
* Input:
* pBuf = pointer to input buffer
* pFile = file pointer
* y1 = line # to read
* py2 = pointer to line # to stop at (updated)
* pcbLine = pointer to place to put the count of bytes read
*
* Output:
* Returns TRUE on a line being read & more reformatting should occurr.
*
*************************************************************************/
int pascal near NextLine (
char far *pBuf, /* input buffer */
PFILE pFile, /* file pointer */
LINE y1, /* line # to read */
LINE far *py2, /* line # to stop at */
int far *pcbLine /* loc to place bytes read*/
) {
flagType fRet = TRUE;
char far *pT; /* working pointer */
char workbuf[512]; /* working buffer */
*pcbLine = 0;
workbuf[0] = 0;
/*
** If asked for line that is not in file, we're done.
*/
if (y1 >= FileLength(pFile))
return FALSE;
/*
** if current line past range, (and range is not "-1"), then we're done.
*/
if ((*py2 != (LINE)-1) && (y1 > *py2))
return FALSE;
/*
** Get the next line in the file & remove it.
*/
*pcbLine = GetLine(y1, workbuf, pFile);
DelLine(pFile, y1, y1);
if (*py2 == 0)
fRet = FALSE;
else if (*py2 != (LINE)-1)
(*py2)--;
/*
** If the line is blank, and the range is "-1", we're done.
*/
if (!*pcbLine && (*py2 == -1))
return FALSE;
/*
** strip leading spaces in newly input line
*/
pT = workbuf; /* point into line */
while (*pT == ' ')
pT++; /* skip leading spaces */
/*
** If existing buffer is non-empty, append a space & set pointer to end
*/
if (strlen(pBuf)) { /* if non-null string */
pBuf += strlen(pBuf); /* point to null */
*pBuf++ = ' '; /* append space */
if (isterm(*(pBuf-2))) /* if sentence term... */
*pBuf++ = ' '; /* append another */
}
/*
** append new line, but compress multiple spaces into one
*/
while (*pT) { /* copy line over */
if (isterm(*pT)) /* if sentence term... */
if (*(pT+1) == ' ') { /* ...space */
*pBuf++ = *pT++; /* copy period */
*pBuf++ = *pT; /* copy space */
}
if ((*pBuf++ = *pT++) == ' ' ) /* copy a char */
while (*pT == ' ') pT++; /* skip multiple spaces */
}
if (*(pBuf-1) == ' ') /* if a trailing space */
pBuf--; /* remove it */
*pBuf = 0;
return fRet;
/* end NextLine */}
/*** DumpLine - Dump one line of text to the file
*
* Dump one line of text to the file. Prepend any required text or spaces,
* and perform word break/cut at right hand column.
*
* Input:
* pBuf = Pointer to the buffer containing data to output. If NULL, pText
* will not be prepended to output text.
* pFile
* x1
* x2
* yOut
* pText
* fFlush
*
* Output:
* Returns .....
*
* Exceptions:
*
* Notes:
*
*************************************************************************/
void pascal near DumpLine (
char far *pBuf, /* data to output */
PFILE pFile, /* file to output to */
COL x1, /* left-hand column */
COL x2, /* right-hand column */
LINE yOut, /* line to output to */
char far *pText, /* text to prepend */
int fFlush /* flush both sides */
) {
int i;
char far *pT;
char far *pT2;
char workbuf[512]; /* working buffer */
char flushbuf[512]; /* working buffer */
char fSpace; /* space seen flag */
/*
** Start by prepending any text, and then filling out to the left hand column
** to justify to.
*/
workbuf[0] = 0; /* start with null */
if (pText && pBuf)
strcpy(workbuf,pText); /* if starting with text*/
i = strlen(workbuf); /* length of line-so-far*/
while (i++ < x1)
strcat(workbuf," "); /* fill out with spaces */
/*
** Append the data to be output, and then starting at the right column, scan
** back for a space to break at. If one is not found before the left hand
** column, then break at the right hand column. Copy any line left over back
** to the passed in buffer
*/
if (pBuf) {
strcat(workbuf,pBuf); /* get total line */
*pBuf = 0; /* empty input buffer */
}
if ((COL)strlen(workbuf) > x2) { /* if we need to cut */
pT = &workbuf[x2]; /* point at potential cut*/
while ((pT > (char far *)&workbuf[0]) && (*pT != ' ')) pT--; /* back up to space*/
if (pT <= (char far *)&workbuf[x1]) { /* if none found in range*/
if (pBuf)
strcpy(pBuf,&workbuf[x2]); /* copy remainder of line*/
workbuf[x2] = 0; /* and terminate this one*/
}
else {
while (*++pT == ' '); /* Skip leading spaces */
if (pBuf)
strcpy(pBuf,pT); /* copy remainder of line*/
*pT = 0; /* and terminate this one*/
}
}
/*
** This code is invoked when the user wants to justify both right and left
** sides of his text. We determine how many spaces we need to add, and scan
** through and add one space to each run of spaces until we've added enough
*/
if (fFlush) { /* right & left justify?*/
if ((LONG_PTR) (pT = workbuf + strlen(workbuf) - 1) > 0)
while (*pT == ' ')
*pT-- = 0;
if (strchr(workbuf,' ')) {
while ((i = x2 - strlen(workbuf)) > 0) {/* count of spaces to add */
strcpy(flushbuf,workbuf); /* start with unmodified*/
pT = workbuf + x1;
pT2 = flushbuf + x1; /* skip fixed part */
fSpace = FALSE; /* assume no spaces */
while (*pT) { /* while data to copy */
if ((*pT == ' ') && i) { /* time to insert a space*/
fSpace = TRUE; /* we've seen a space */
*pT2++ = ' ';
i--;
while (*pT == ' ')
*pT2++ = *pT++; /* copy run of spaces */
}
if (*pT)
*pT2++ = *pT++; /* copy line */
else if (!fSpace)
break; /* no embedded spaces */
}
*pT2 = 0;
strcpy(workbuf,flushbuf); /* copy back */
if (!fSpace)
break;
}
}
}
CopyLine ((PFILE) NULL, pFile, yOut, yOut, yOut); /* create new line */
PutLine (yOut, workbuf, pFile); /* output line */
/* end DumpLine */}
/*************************************************************************
**
** isterm
** returns true/false based on the character being a sentence terminator:
** one of '.', '?', '!'. Also, always returns false if just2space is off.
*/
flagType pascal near isterm(
char c /* character to test */
)
{
return (flagType)(just2space && ((c == '.') || (c == '!') || (c == '?')));
/* end isterm */}
/*
** switch communication table to Z
*/
struct swiDesc swiTable[] = {
{ "just2space", toPIF(just2space), SWI_BOOLEAN },
{ "justwidth", toPIF(justwidth), SWI_NUMERIC | RADIX10 },
{0, 0, 0}
};
/*
** command communication table to Z
*/
struct cmdDesc cmdTable[] = {
{ "justify", justify, 0, MODIFIES | NOARG | NULLARG | LINEARG | BOXARG | TEXTARG },
{0, 0, 0}
};
/*
** WhenLoaded
** Executed when these extensions get loaded. Identify self & assign keys.
*/
void EXTERNAL WhenLoaded () {
PSWI pwidth;
_stat(EXT_ID);
SetKey ("justify","alt+b");
if (pwidth = FindSwitch("rmargin"))
justwidth = *pwidth->act.ival;
}
/*************************************************************************
**
** stat - display status line message
**
** Purpose:
** Places extension name and message on the status line
**
** Entry:
** pszFcn - Pointer to string to be prepended.
**
** Exit:
** none
**
** Exceptions:
** none
**
*/
void pascal near _stat (
char *pszFcn /* function name */
) {
buffer buf; /* message buffer */
strcpy(buf,"justify: "); /* start with name */
#ifdef DEBUG
if (strlen(pszFcn) > 71) {
pszFcn+= strlen(pszFcn) - 68;
strcat (buf, "...");
}
#endif
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));
/* 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) {
_stat (strcat (debstring, " Press a key..."));
ReadChar ();
}
debstring[0] = 0;
/* end debend */}
#endif