📄 textmgr.c
字号:
/*** TXTMGR.C - Text manager for multi-line editing
*
* GLOBAL
* LoadBuf Load a file into a buffer
* FreeBuf Free a buffer
* NewBuf Create a new (blank) buffer
*
* S_LinesInBuf LinesInBuf() routine
* S_CbGetLineBuf CbGetLineBuf() routine
* S_ReplaceLineBuf ReplaceLineBuf() routine
* S_InsertLineBuf InsertLineBuf() routine
* S_InsertBufInBuf InsertBufInBuf() routine
* S_DeleteLinesBuf DeleteLinesBuf() routine
*
* LOCAL
* CbFindLineBuf Find a specified line in a buffer
* InsSpace Insert space into a buffer
* GrowBuf Increase the size of a buffer
*
* DESCRIPTION
*
* This module manages the program source and contains all functions
* that operate directly on the source.
*
* The source buffer is maintained in a single Global Heap Segment. It
* may be larger than 64k. Because of this, linear addresses (32 bit) are
* used. The linear addresses are converted to segmented addresses when
* actually accessing the buffer.
*
* The format of the source buffer is:
*
* +-----------+-----//-----+-----------+-----//-----+
* | WORD len0 | len0 BYTES | WORD len1 | len1 BYTES |
* +-----------+-----//-----+-----------+-----//-----+
*
* +------+-----//-----+---------+
* ... | lenN | lenN BYTES | WORD -1 |
* +------+-----//-----+---------+
*
*/
/*------------------------- Include Files -------------------------*/
#include <version.h>
/* Next, include COW's interface headers */
#include <cw/version.h>
#include <cw/windows.h>
#include <cw/edityp.h>
#include <uiext.h>
#include <..\hd\edit.h>
#ifndef UIINT_H
#include <uiint.h>
#endif
#ifndef HEAP_H
#include <heap.h>
#endif
#ifndef QBIMSGS_H
#include <qbimsgs.h>
#endif
extern char szNull[];
char *pszNull = szNull;
/*-------------------------- Local Macros --------------------------*/
/* Returns TRUE if the fhd is allocated, zero if it is un-allocated */
#define ALLOCEDFHD(fhd) (fhd.hData != 0)
/* Dereferences a fhd and returns a far pointer to the data */
#define MAKELONG(l, h) ((long)(((unsigned)(l)) | ((unsigned long)((unsigned)(h))) << 16))
#define DEREFFHD(fhd) ((char far *) MAKELONG(0, GETSEG(fhd.hData)))
/*----------------------- Forward References -----------------------*/
LOCAL WORD NEAR PASCAL CbFindLineBuf(PBUFINFO, DWORD, WORD, DWORD *);
LOCAL DWORD NEAR PASCAL InsSpace(PBUFINFO, WORD, DWORD);
LOCAL BOOL NEAR PASCAL GrowBuf(PBUFINFO, DWORD);
/*------------------- Global and Local Variables -------------------*/
/* The EDITMGR requires a number of routines to get its work done; it
** does a call back into the application (us) to update the text buffer.
** Such routines as InsertLineBuf(), DeleteLinesBuf(), etc. are among
** these required call-back routines.
*/
/* These are the buffers that acually manage the data and the information
** that is associated with the data
*/
LOCAL BUFINFO rgbufinfo[CBUFINFO];
/*------------------ S_LinesInBuf() ------------------*/
/*** LinesInBuf - How many lines in VAP's buffer?
*
* SYNOPSIS
* cln = LinesInBuf(idVap)
*
* ENTRY
* idVap ID of VAP which owns buffer
*
* RETURNS
* Number of lines currently in buffer
*
* DESCRIPTION
* Examines the .cln field in the BUFINFO structure to determine
* the number of lines currently in the buffer.
*
* NOTES
* Required by EDITMGR
*
*/
GLOBAL WORD FAR PASCAL
S_LinesInBuf(PBUFINFO pbufinfo)
{
DbChkPBufInfo(pbufinfo);
DbAssert(ALLOCEDFHD(pbufinfo->fhd));
return(pbufinfo->cln - 1);
}
/*--------------------------- FreeBuf() ---------------------------*/
/*** FreeBuf - Free a buffer
*
* SYNOPSIS
* FreeBuf(pbufinfo)
*
* ENTRY
* pbufinfo pointer to BUFINFO of buffer
* to deallocate
*
* RETURNS
* None
*
* DESCRIPTION
* Release the memory associated with this buffer.
*
* NOTES
*/
GLOBAL VOID FAR PASCAL
FreeBuf(PBUFINFO pbufinfo)
{
DbChkPBufInfo(pbufinfo);
if (ALLOCEDFHD(pbufinfo->fhd))
{
FhdDealloc(&pbufinfo->fhd);
}
}
/*------------------------ CbFindLineBuf() ------------------------*/
/*** CbFindLineBuf() - Find a line in a buffer
*
* SYNOPSIS
* cb = CbFindLineBuf(pbufinfo, obBase, oln, pobLine)
*
* ENTRY
* pbufinfo Pointer to a BUFINFO structure
* obBase 32-bit pointer to start of buffer
* oln Line number to find
* pobLine Pointer to DWORD (return value)
*
* RETURNS
* Number of bytes in line found
* Also returns 32-bit pointer to line found through pobLine
*
* Note that the "pointer" points to the actual text, NOT the WORD
* length preceding the text.
*
* DESCRIPTION
* Basically a higher-level routine for CbFindLine(); most of
* the work is done there. Uses and updates the cache (.olnCache
* and .obCache fields) from the BUFINFO structure.
*
*/
LOCAL WORD NEAR PASCAL
CbFindLineBuf(PBUFINFO pbufinfo, DWORD obBase, WORD oln, DWORD *pobLine)
{
WORD cb;
WORD olnCache;
*pobLine = obBase;
/* If the requested line is farther along in the file than the
** line last cached, we can save a lot of time by skipping to
** the cached (known) line.
*/
olnCache = pbufinfo->olnCache;
pbufinfo->olnCache = oln;
if (oln >= olnCache)
{
*pobLine += pbufinfo->obCache;
oln -= olnCache;
}
/* Find the line in the buffer. pobLine as passed in to CbFindLine()
** "points to" the WORD length preceding some line; on exit, it will
** "point to" the actual text of the line found.
*/
cb = CbFindLine(pobLine, oln);
/* Update the cache information for this BUFINFO.
*/
pbufinfo->obCache = *pobLine - sizeof(WORD) - obBase;
return(cb);
}
/*--------------------------- InsSpace() ---------------------------*/
/*** InsSpace - Insert space into a buffer
*
* SYNOPSIS
* obNewSpace = InsSpace(pbufinfo, oln, cbAdd)
*
* ENTRY
* pbufinfo Pointer to a BUFINFO structure
* oln Line number within buffer
* cbAdd Number of bytes to add
*
* RETURNS
* 32-bit pointer to start of vacated region (relative
* to begining of memory block)
*
* -OR-
*
* 0L if the buffer could not accomodate the additional space
*
* DESCRIPTION
* This routine will make space in the source buffer for a line of text.
* The space will be made BEFORE oln. The source is moved down from
* oln to the end of source.
*
* NOTES
*/
LOCAL DWORD NEAR PASCAL
InsSpace(PBUFINFO pbufinfo, WORD oln, DWORD cbAdd)
{
DWORD obSrc;
DWORD obBase;
DWORD cbMove;
/* If adding the requested number of bytes would grow the buffer
** beyond its current maximum size, try to make the buffer larger.
** If this fails, return 0L.
*/
if (pbufinfo->obNext + cbAdd + 1 > pbufinfo->cb)
{
if (!GrowBuf(pbufinfo, cbAdd))
return(0L);
}
/* Lock the buffer down and find the offset (32-bit pointer) of
** the indicated line.
*/
DbHeapMoveOff();
obBase = LinearAddr(DEREFFHD(pbufinfo->fhd));
if (oln < pbufinfo->cln) /* If within range... */
{
CbFindLineBuf(pbufinfo, obBase, oln, &obSrc);
obSrc -= sizeof(WORD); /* Move back to WORD length */
cbMove = pbufinfo->obNext - (obSrc - obBase) + 1;
BigMoveDown(obSrc + cbAdd, obSrc, cbMove);
}
else /* Add to end of file */
obSrc = obBase + pbufinfo->obNext;
pbufinfo->obNext += cbAdd;
pbufinfo->olnCache = 0xFFFF; /* Destroy cache information */
DbHeapMoveOn();
return(obSrc - obBase);
}
/*--------------------------- GrowBuf() ---------------------------*/
/*** GrowBuf - Increase the size of a buffer
*
* SYNOPSIS
* fStatus = GrowBuf(pbufinfo, cbAdd)
*
* ENTRY
* pbufinfo Pointer to BUFINFO
* cbAdd Number of bytes to increase size by
*
* RETURNS
* TRUE if buffer could be grown; FALSE if not
*
* DESCRIPTION
* Call the SBMGR to reallocate the buffer, rounding the new size
* to be an even multiple of CBSRCBLK.
*
* NOTES
*/
LOCAL BOOL NEAR PASCAL
GrowBuf(PBUFINFO pbufinfo, DWORD cbAdd)
{
DWORD cbNeeded;
DWORD cbRequested;
cbRequested = cbNeeded = pbufinfo->cb + cbAdd + 1;
cbRequested += CBSRCBLK - 1;
cbRequested &= ~(CBSRCBLK - 1);
// Try the alloc with the extra space
if (FhdRealloc(&(pbufinfo->fhd), cbRequested))
{
pbufinfo->cb = cbRequested;
return(TRUE);
}
// Ok, now try it with just the amount that we need
if (FhdRealloc(&(pbufinfo->fhd), cbNeeded)) {
pbufinfo->cb = cbNeeded;
return(TRUE);
}
// Unable to get the needed amount of memory, fail
SetUiErrOm();
return(FALSE);
}
/*---------------- S_CbGetLineBuf() ----------------*/
/*** S_CbGetLineBuf - Fetch a line of text from a buffer
*
* SYNOPSIS
* cb = S_CbGetLineBuf(idVap, oln, cbMax, pBuf)
*
* ENTRY
* idVap ID of VAP whose buffer this concerns
* oln Line number to fetch
* cbMax Maximum number of characters to place in buffer
* pBuf Buffer to place text in
*
* RETURNS
* Number of characters placed in buffer (excluding terminating zero)
*
* DESCRIPTION
* This routine gets the specified line of text even it is the current
* line. This is used when the ld buffer has been modified and the line
* needs to be refreshed.
*
* NOTES
* Required by EDITMGR
*
* M00SWAP NPCORE
*/
GLOBAL WORD FAR PASCAL
S_CbGetLineBuf(PBUFINFO pbufinfo, WORD oln, WORD cbMax, char *pBuf)
{
REG2 WORD cb;
DWORD obSrc;
DbChkPBufInfo(pbufinfo);
DbAssert(ALLOCEDFHD(pbufinfo->fhd));
/* Ignore first line of buffer -- it contains the filename.
*/
oln++;
if (oln < pbufinfo->cln)
{
DbHeapMoveOff();
cb = CbFindLineBuf(pbufinfo, LinearAddr(DEREFFHD(pbufinfo->fhd)), oln, &obSrc);
cb = min(cb, cbMax);
fmemcpy((char far *)pBuf, SegAddr(obSrc), cb);
DbHeapMoveOn();
}
else
cb = 0;
pBuf[cb] = '\0';
return(cb);
}
/*-------------- S_ReplaceLineBuf() --------------*/
/*** S_ReplaceLineBuf - Replace a line in a buffer
*
* SYNOPSIS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -