reactos/sdk/lib/conutils/pager.c

692 lines
20 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Console Utilities Library
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Console/terminal paging functionality.
* COPYRIGHT: Copyright 2017-2021 Hermes Belusca-Maito
* Copyright 2021 Katayama Hirofumi MZ
*/
/**
* @file pager.c
* @ingroup ConUtils
*
* @brief Console/terminal paging functionality.
**/
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
#define UNICODE
#define _UNICODE
#include <windef.h>
#include <winbase.h>
// #include <winnls.h>
#include <wincon.h> // Console APIs (only if kernel32 support included)
#include <winnls.h> // for WideCharToMultiByte
#include <strsafe.h>
#include "conutils.h"
#include "stream.h"
#include "screen.h"
#include "pager.h"
// Temporary HACK
#define CON_STREAM_WRITE ConStreamWrite
#define CP_SHIFTJIS 932 // Japanese Shift-JIS
#define CP_HANGUL 949 // Korean Hangul/Wansung
#define CP_JOHAB 1361 // Korean Johab
#define CP_GB2312 936 // Chinese Simplified (GB2312)
#define CP_BIG5 950 // Chinese Traditional (Big5)
/* IsFarEastCP(CodePage) */
#define IsCJKCodePage(CodePage) \
((CodePage) == CP_SHIFTJIS || (CodePage) == CP_HANGUL || \
/* (CodePage) == CP_JOHAB || */ \
(CodePage) == CP_BIG5 || (CodePage) == CP_GB2312)
static inline INT
GetWidthOfCharCJK(
IN UINT nCodePage,
IN WCHAR ch)
{
INT ret = WideCharToMultiByte(nCodePage, 0, &ch, 1, NULL, 0, NULL, NULL);
if (ret == 0)
ret = 1;
else if (ret > 2)
ret = 2;
return ret;
}
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/**
* @brief Retrieves a new text line, or continue fetching the current one.
*
* @remark Manages setting Pager's CurrentLine, ichCurr, iEndLine, and the
* line cache (CachedLine, cchCachedLine). Other functions must not
* modify these values.
**/
static BOOL
GetNextLine(
IN OUT PCON_PAGER Pager,
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
IN PCTCH TextBuff,
IN SIZE_T cch)
{
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
SIZE_T ich = Pager->ich;
SIZE_T ichStart;
SIZE_T cchLine;
BOOL bCacheLine;
Pager->ichCurr = 0;
Pager->iEndLine = 0;
/*
* If we already had an existing line, then we can safely start a new one
* and getting rid of any current cached line. Otherwise, we don't have
* a current line and we may be caching a new one, in which case, continue
* caching it until it becomes complete.
*/
// INVESTIGATE: Do that only if (ichStart >= iEndLine) ??
if (Pager->CurrentLine)
{
// ASSERT(Pager->CurrentLine == Pager->CachedLine);
if (Pager->CachedLine)
{
HeapFree(GetProcessHeap(), 0, (PVOID)Pager->CachedLine);
Pager->CachedLine = NULL;
Pager->cchCachedLine = 0;
}
Pager->CurrentLine = NULL;
}
/* Nothing else to read if we are past the end of the buffer */
if (ich >= cch)
{
/* If we have a pending cached line, terminate it now */
if (Pager->CachedLine)
goto TerminateLine;
/* Otherwise, bail out */
return FALSE;
}
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Start a new line, or continue an existing one */
ichStart = ich;
/* Find where this line ends, looking for a NEWLINE character.
* (NOTE: We cannot use strchr because the buffer is not NULL-terminated) */
for (; ich < cch; ++ich)
{
if (TextBuff[ich] == TEXT('\n'))
{
++ich;
break;
}
}
Pager->ich = ich;
cchLine = (ich - ichStart);
//
// FIXME: Impose a maximum string limit when the line is cached, in order
// not to potentially grow memory indefinitely. When the limit is reached,
// terminate the line.
//
/*
* If we have stopped because we have exhausted the text buffer
* and we have not found an end-of-line character, this may mean
* that the text line spans across different text buffers. If we
* have been told so, cache this line: we will complete it during
* the next call(s) and only then, display it.
* Otherwise, consider the line to be terminated now.
*/
bCacheLine = ((Pager->dwFlags & CON_PAGER_CACHE_INCOMPLETE_LINE) &&
(ich >= cch) && (TextBuff[ich - 1] != TEXT('\n')));
/* Allocate, or re-allocate, the cached line buffer */
if (bCacheLine && !Pager->CachedLine)
{
/* We start caching, allocate the cached line buffer */
Pager->CachedLine = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
cchLine * sizeof(TCHAR));
Pager->cchCachedLine = 0;
if (!Pager->CachedLine)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
}
else if (Pager->CachedLine)
{
/* We continue caching, re-allocate the cached line buffer */
PVOID ptr = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
(PVOID)Pager->CachedLine,
(Pager->cchCachedLine + cchLine) * sizeof(TCHAR));
if (!ptr)
{
HeapFree(GetProcessHeap(), 0, (PVOID)Pager->CachedLine);
Pager->CachedLine = NULL;
Pager->cchCachedLine = 0;
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
Pager->CachedLine = ptr;
}
if (Pager->CachedLine)
{
/* Copy/append the text to the cached line buffer */
RtlCopyMemory((PVOID)&Pager->CachedLine[Pager->cchCachedLine],
&TextBuff[ichStart],
cchLine * sizeof(TCHAR));
Pager->cchCachedLine += cchLine;
}
if (bCacheLine)
{
/* The line is currently incomplete, don't proceed further for now */
return FALSE;
}
TerminateLine:
/* The line should be complete now. If we have an existing cached line,
* it has been completed by appending the remaining text to it. */
/* We are starting a new line */
Pager->ichCurr = 0;
if (Pager->CachedLine)
{
Pager->iEndLine = Pager->cchCachedLine;
Pager->CurrentLine = Pager->CachedLine;
}
else
{
Pager->iEndLine = cchLine;
Pager->CurrentLine = &TextBuff[ichStart];
}
/* Increase only when we have got a NEWLINE */
if ((Pager->iEndLine > 0) && (Pager->CurrentLine[Pager->iEndLine - 1] == TEXT('\n')))
Pager->lineno++;
return TRUE;
}
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/**
* @brief Does the main paging work: fetching text lines and displaying them.
**/
static BOOL
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
ConPagerWorker(
IN PCON_PAGER Pager,
IN PCTCH TextBuff,
IN DWORD cch)
{
const DWORD PageColumns = Pager->PageColumns;
const DWORD ScrollRows = Pager->ScrollRows;
BOOL bFinitePaging = ((PageColumns > 0) && (Pager->PageRows > 0));
LONG nTabWidth = Pager->nTabWidth;
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
PCTCH Line;
SIZE_T ich;
SIZE_T ichStart;
SIZE_T iEndLine;
DWORD iColumn = Pager->iColumn;
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
UINT nCodePage = GetConsoleOutputCP();
BOOL IsCJK = IsCJKCodePage(nCodePage);
UINT nWidthOfChar = 1;
BOOL IsDoubleWidthCharTrailing = FALSE;
/* Normalize the tab width: if negative or too large,
* cap it to the number of columns. */
if (PageColumns > 0) // if (bFinitePaging)
{
if (nTabWidth < 0)
nTabWidth = PageColumns - 1;
else
nTabWidth = min(nTabWidth, PageColumns - 1);
}
else
{
/* If no column width is known, default to 8 spaces if the
* original value is negative; otherwise keep the current one. */
if (nTabWidth < 0)
nTabWidth = 8;
}
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Continue displaying the previous line, if any, or start a new one */
Line = Pager->CurrentLine;
ichStart = Pager->ichCurr;
iEndLine = Pager->iEndLine;
ProcessLine:
/* Stop now if we have displayed more page lines than requested */
if (bFinitePaging && (Pager->iLine >= ScrollRows))
goto End;
if (!Line || (ichStart >= iEndLine))
{
/* Start a new line */
if (!GetNextLine(Pager, TextBuff, cch))
goto End;
Line = Pager->CurrentLine;
ichStart = Pager->ichCurr;
iEndLine = Pager->iEndLine;
}
else
{
/* Continue displaying the current line */
}
// ASSERT(Line && ((ichStart < iEndLine) || (ichStart == iEndLine && iEndLine == 0)));
/* Determine whether this line segment (from the current position till the end) should be displayed */
Pager->iColumn = iColumn;
if (Pager->PagerLine && Pager->PagerLine(Pager, &Line[ichStart], iEndLine - ichStart))
{
iColumn = Pager->iColumn;
/* Done with this line; start a new one */
Pager->nSpacePending = 0; // And reset any pending space.
ichStart = iEndLine;
goto ProcessLine;
}
// else: Continue displaying the line.
/* Print out any pending TAB expansion */
if (Pager->nSpacePending > 0)
{
ExpandTab:
while (Pager->nSpacePending > 0)
{
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Print filling spaces */
CON_STREAM_WRITE(Pager->Screen->Stream, TEXT(" "), 1);
--(Pager->nSpacePending);
++iColumn;
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Check whether we are going across the column */
if ((PageColumns > 0) && (iColumn % PageColumns == 0))
{
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
// Pager->nSpacePending = 0; // <-- This is the mode of most text editors...
/* Reposition the cursor to the next line, first column */
if (!bFinitePaging || (PageColumns < Pager->Screen->csbi.dwSize.X))
CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
Pager->iLine++;
/* Restart at the character */
// ASSERT(ichStart == ich);
goto ProcessLine;
}
}
}
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Find, within this line segment (starting from its
* beginning), until where we can print to the page. */
for (ich = ichStart; ich < iEndLine; ++ich)
{
/* NEWLINE character */
if (Line[ich] == TEXT('\n'))
{
/* We should stop now */
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
// ASSERT(ich == iEndLine - 1);
break;
}
/* TAB character */
if (Line[ich] == TEXT('\t') &&
(Pager->dwFlags & CON_PAGER_EXPAND_TABS))
{
/* We should stop now */
break;
}
/* FORM-FEED character */
if (Line[ich] == TEXT('\f') &&
(Pager->dwFlags & CON_PAGER_EXPAND_FF))
{
/* We should stop now */
break;
}
/* Other character - Handle double-width for CJK */
if (IsCJK)
nWidthOfChar = GetWidthOfCharCJK(nCodePage, Line[ich]);
/* Care about CJK character presentation only when outputting
* to a device where the number of columns is known. */
if ((PageColumns > 0) && IsCJK)
{
IsDoubleWidthCharTrailing = (nWidthOfChar == 2) &&
((iColumn + 1) % PageColumns == 0);
if (IsDoubleWidthCharTrailing)
{
/* Reserve this character for the next line */
++iColumn; // Count a blank instead.
/* We should stop now */
break;
}
}
iColumn += nWidthOfChar;
/* Check whether we are going across the column */
if ((PageColumns > 0) && (iColumn % PageColumns == 0))
{
++ich;
break;
}
}
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Output the pending line segment */
if (ich - ichStart > 0)
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
CON_STREAM_WRITE(Pager->Screen->Stream, &Line[ichStart], ich - ichStart);
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Have we finished the line segment? */
if (ich >= iEndLine)
{
/* Restart at the character */
ichStart = ich;
goto ProcessLine;
}
/* Handle special characters */
/* NEWLINE character */
if (Line[ich] == TEXT('\n'))
{
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
// ASSERT(ich == iEndLine - 1);
/* Reposition the cursor to the next line, first column */
CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
Pager->iLine++;
iColumn = 0;
/* Done with this line; start a new one */
Pager->nSpacePending = 0; // And reset any pending space.
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
ichStart = iEndLine;
goto ProcessLine;
}
/* TAB character */
if (Line[ich] == TEXT('\t') &&
(Pager->dwFlags & CON_PAGER_EXPAND_TABS))
{
/* Perform TAB expansion, unless the tab width is zero */
if (nTabWidth == 0)
{
ichStart = ++ich;
goto ProcessLine;
}
ichStart = ++ich;
/* Reset the number of spaces needed to develop this TAB character */
Pager->nSpacePending = nTabWidth - (iColumn % nTabWidth);
goto ExpandTab;
}
/* FORM-FEED character */
if (Line[ich] == TEXT('\f') &&
(Pager->dwFlags & CON_PAGER_EXPAND_FF))
{
if (bFinitePaging)
{
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Clear until the end of the page */
while (Pager->iLine < ScrollRows)
{
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Call the user paging function in order to know
* whether we need to output the blank lines. */
Pager->iColumn = iColumn;
if (Pager->PagerLine && Pager->PagerLine(Pager, TEXT("\n"), 1))
{
/* Only one blank line displayed, that counts in the line count */
Pager->iLine++;
break;
}
else
{
CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
Pager->iLine++;
}
}
}
else
{
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Just output a FORM-FEED and a NEWLINE */
CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\f\n"), 2);
Pager->iLine++;
}
iColumn = 0;
Pager->nSpacePending = 0; // And reset any pending space.
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Skip and restart past the character */
ichStart = ++ich;
goto ProcessLine;
}
/* If we output a double-width character that goes across the column,
* fill with blank and display the character on the next line. */
if (IsDoubleWidthCharTrailing)
{
IsDoubleWidthCharTrailing = FALSE; // Reset the flag.
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
CON_STREAM_WRITE(Pager->Screen->Stream, TEXT(" "), 1);
/* Fall back below */
}
/* Are we wrapping the line? */
if ((PageColumns > 0) && (iColumn % PageColumns == 0))
{
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Reposition the cursor to the next line, first column */
if (!bFinitePaging || (PageColumns < Pager->Screen->csbi.dwSize.X))
CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
Pager->iLine++;
}
/* Restart at the character */
ichStart = ich;
goto ProcessLine;
End:
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/*
* We are exiting, either because we displayed all the required lines
* (iLine >= ScrollRows), or, because we don't have more data to display.
*/
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
Pager->ichCurr = ichStart;
Pager->iColumn = iColumn;
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
// INVESTIGATE: Can we get rid of CurrentLine here? // if (ichStart >= iEndLine) ...
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Return TRUE if we displayed all the required lines; FALSE otherwise */
if (bFinitePaging && (Pager->iLine >= ScrollRows))
{
Pager->iLine = 0; /* Reset the count of lines being printed */
return TRUE;
}
else
{
return FALSE;
}
}
/**
* @name ConWritePaging
* Pages the contents of a user-specified character buffer on the screen.
*
* @param[in] Pager
* Pager object that describes where the paged output is issued.
*
* @param[in] PagePrompt
* A user-specific callback, called when a page has been displayed.
*
* @param[in] StartPaging
* Set to TRUE for initializing the paging operation; FALSE during paging.
*
* @param[in] szStr
* Pointer to the character buffer whose contents are to be paged.
*
* @param[in] len
* Length of the character buffer pointed by @p szStr, specified
* in number of characters.
*
* @return
* TRUE when all the contents of the character buffer has been displayed;
* FALSE if the paging operation has been stopped (controlled via @p PagePrompt).
**/
BOOL
ConWritePaging(
IN PCON_PAGER Pager,
IN PAGE_PROMPT PagePrompt,
IN BOOL StartPaging,
IN PCTCH szStr,
IN DWORD len)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
BOOL bIsConsole;
/* Parameters validation */
if (!Pager)
return FALSE;
/* Get the size of the visual screen that can be printed to */
bIsConsole = ConGetScreenInfo(Pager->Screen, &csbi);
if (bIsConsole)
{
/* Calculate the console screen extent */
Pager->PageColumns = csbi.dwSize.X;
Pager->PageRows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
}
else
{
/* We assume it's a file handle */
Pager->PageColumns = 0;
Pager->PageRows = 0;
}
if (StartPaging)
{
if (bIsConsole && (Pager->PageRows >= 2))
{
/* Reset to display one page by default */
Pager->ScrollRows = Pager->PageRows - 1;
}
else
{
/* File output, or single line: all lines are displayed at once; reset to a default value */
Pager->ScrollRows = 0;
}
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Reset the internal data buffer */
Pager->CachedLine = NULL;
Pager->cchCachedLine = 0;
/* Reset the paging state */
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
Pager->CurrentLine = NULL;
Pager->ichCurr = 0;
Pager->iEndLine = 0;
Pager->nSpacePending = 0;
Pager->iColumn = 0;
Pager->iLine = 0;
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
Pager->lineno = 0;
}
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Reset the reading index in the user-provided source buffer */
Pager->ich = 0;
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
/* Run the pager even when the user-provided source buffer is
* empty, in case we need to flush any remaining cached line. */
if (!Pager->CachedLine)
{
/* No cached line, bail out now */
if (len == 0 || szStr == NULL)
return TRUE;
}
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
while (ConPagerWorker(Pager, szStr, len))
{
/* Prompt the user only when we display to a console and the screen
* is not too small: at least one line for the actual paged text and
* one line for the prompt. */
if (bIsConsole && (Pager->PageRows >= 2))
{
/* Reset to display one page by default */
Pager->ScrollRows = Pager->PageRows - 1;
/* Prompt the user; give him some values for statistics */
[CONUTILS:PAGER][MORE] Implement text line caching + fix some bugs. - Implement caching of individual (newline-separated) text lines; this behaviour can be enabled with a flag (enabled by MORE): CON_PAGER_CACHE_INCOMPLETE_LINE. This feature is necessary when reading a text file, whose text lines may span across two or more successive temporary read buffers, and is required for correctly determining whether the lines being read are blank and may be squeezed. - When squeezing blank lines, the blank-line check must be done for each line segment corresponding to the screen line (and following) that need to be displayed. This matches the behaviour of MS MORE.COM. - Fix the IsBlankLine() check to not consider FORM-FEEDs as being blank characters: This is necessary for correctly handling FORM-FEED expansion. Also note that MS MORE.COM only checks for spaces and TABs, so we are slightly overdoing these checks (considering other types of whitespace). - Get rid of ConCallPagerLine() and the intermediate CON_PAGER_DONT_OUTPUT state flag that were used repeatedly for each and every small line chunks. Instead, call directly the user-specified 'PagerLine' callback when we are about to start treating the next line segment to be displayed (see comment above). - Fix the exit return condition of ConPagerWorker(): it should return TRUE whenever we displayed all the required lines, and FALSE otherwise. Otherwise, the previous (buggy) condition on the data being read from the text file, may lead to the prompt not showing when a screenful of text has been displayed, if it happened that the current text buffer becomes empty at the same time (even if, overall, the text file hasn't been fully displayed). - In MorePagerLine(), when we encounter for the first time a blank line that will be squeezed with other successive ones, display a single blank line. But for that, just display one space and a newline: this single space is especially needed in order to force line wrapping when the ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN console modes are enabled. Otherwise the cursor remains at the previous line (without wrapping), and just outputting one newline will not make it move past 2 lines as one would naively expect.
2021-06-29 02:08:38 +08:00
// FIXME: Doesn't reflect what's currently being displayed.
if (!PagePrompt(Pager, Pager->ich, len))
return FALSE;
}
/* If we display to a console, recalculate its screen extent
* in case the user has redimensioned it during the prompt. */
if (bIsConsole && ConGetScreenInfo(Pager->Screen, &csbi))
{
Pager->PageColumns = csbi.dwSize.X;
Pager->PageRows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
}
}
return TRUE;
}
BOOL
ConPutsPaging(
IN PCON_PAGER Pager,
IN PAGE_PROMPT PagePrompt,
IN BOOL StartPaging,
IN PCTSTR szStr)
{
DWORD len;
/* Return if no string has been given */
if (szStr == NULL)
return TRUE;
len = wcslen(szStr);
return ConWritePaging(Pager, PagePrompt, StartPaging, szStr, len);
}
BOOL
ConResPagingEx(
IN PCON_PAGER Pager,
IN PAGE_PROMPT PagePrompt,
IN BOOL StartPaging,
IN HINSTANCE hInstance OPTIONAL,
IN UINT uID)
{
INT Len;
PCWSTR szStr = NULL;
Len = K32LoadStringW(hInstance, uID, (PWSTR)&szStr, 0);
if (szStr && Len)
return ConWritePaging(Pager, PagePrompt, StartPaging, szStr, Len);
else
return TRUE;
}
BOOL
ConResPaging(
IN PCON_PAGER Pager,
IN PAGE_PROMPT PagePrompt,
IN BOOL StartPaging,
IN UINT uID)
{
return ConResPagingEx(Pager, PagePrompt, StartPaging,
NULL /*GetModuleHandleW(NULL)*/, uID);
}
/* EOF */