ReactOS  0.4.15-dev-3187-ge372f2b
pager.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Console Utilities Library
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Console/terminal paging functionality.
5  * COPYRIGHT: Copyright 2017-2021 Hermes Belusca-Maito
6  * Copyright 2021 Katayama Hirofumi MZ
7  */
8 
16 /* FIXME: Temporary HACK before we cleanly support UNICODE functions */
17 #define UNICODE
18 #define _UNICODE
19 
20 #include <windef.h>
21 #include <winbase.h>
22 // #include <winnls.h>
23 #include <wincon.h> // Console APIs (only if kernel32 support included)
24 #include <winnls.h> // for WideCharToMultiByte
25 #include <strsafe.h>
26 
27 #include "conutils.h"
28 #include "stream.h"
29 #include "screen.h"
30 #include "pager.h"
31 
32 // Temporary HACK
33 #define CON_STREAM_WRITE ConStreamWrite
34 
35 #define CP_SHIFTJIS 932 // Japanese Shift-JIS
36 #define CP_HANGUL 949 // Korean Hangul/Wansung
37 #define CP_JOHAB 1361 // Korean Johab
38 #define CP_GB2312 936 // Chinese Simplified (GB2312)
39 #define CP_BIG5 950 // Chinese Traditional (Big5)
40 
41 /* IsFarEastCP(CodePage) */
42 #define IsCJKCodePage(CodePage) \
43  ((CodePage) == CP_SHIFTJIS || (CodePage) == CP_HANGUL || \
44  /* (CodePage) == CP_JOHAB || */ \
45  (CodePage) == CP_BIG5 || (CodePage) == CP_GB2312)
46 
47 static inline INT
49  IN UINT nCodePage,
50  IN WCHAR ch)
51 {
52  INT ret = WideCharToMultiByte(nCodePage, 0, &ch, 1, NULL, 0, NULL, NULL);
53  if (ret == 0)
54  ret = 1;
55  else if (ret > 2)
56  ret = 2;
57  return ret;
58 }
59 
67 static BOOL
69  IN OUT PCON_PAGER Pager,
70  IN PCTCH TextBuff,
71  IN SIZE_T cch)
72 {
73  SIZE_T ich = Pager->ich;
74  SIZE_T ichStart;
75  SIZE_T cchLine;
76  BOOL bCacheLine;
77 
78  Pager->ichCurr = 0;
79  Pager->iEndLine = 0;
80 
81  /*
82  * If we already had an existing line, then we can safely start a new one
83  * and getting rid of any current cached line. Otherwise, we don't have
84  * a current line and we may be caching a new one, in which case, continue
85  * caching it until it becomes complete.
86  */
87  // INVESTIGATE: Do that only if (ichStart >= iEndLine) ??
88  if (Pager->CurrentLine)
89  {
90  // ASSERT(Pager->CurrentLine == Pager->CachedLine);
91  if (Pager->CachedLine)
92  {
93  HeapFree(GetProcessHeap(), 0, (PVOID)Pager->CachedLine);
94  Pager->CachedLine = NULL;
95  Pager->cchCachedLine = 0;
96  }
97 
98  Pager->CurrentLine = NULL;
99  }
100 
101  /* Nothing else to read if we are past the end of the buffer */
102  if (ich >= cch)
103  {
104  /* If we have a pending cached line, terminate it now */
105  if (Pager->CachedLine)
106  goto TerminateLine;
107 
108  /* Otherwise, bail out */
109  return FALSE;
110  }
111 
112  /* Start a new line, or continue an existing one */
113  ichStart = ich;
114 
115  /* Find where this line ends, looking for a NEWLINE character.
116  * (NOTE: We cannot use strchr because the buffer is not NULL-terminated) */
117  for (; ich < cch; ++ich)
118  {
119  if (TextBuff[ich] == TEXT('\n'))
120  {
121  ++ich;
122  break;
123  }
124  }
125  Pager->ich = ich;
126 
127  cchLine = (ich - ichStart);
128 
129  //
130  // FIXME: Impose a maximum string limit when the line is cached, in order
131  // not to potentially grow memory indefinitely. When the limit is reached,
132  // terminate the line.
133  //
134 
135  /*
136  * If we have stopped because we have exhausted the text buffer
137  * and we have not found an end-of-line character, this may mean
138  * that the text line spans across different text buffers. If we
139  * have been told so, cache this line: we will complete it during
140  * the next call(s) and only then, display it.
141  * Otherwise, consider the line to be terminated now.
142  */
143  bCacheLine = ((Pager->dwFlags & CON_PAGER_CACHE_INCOMPLETE_LINE) &&
144  (ich >= cch) && (TextBuff[ich - 1] != TEXT('\n')));
145 
146  /* Allocate, or re-allocate, the cached line buffer */
147  if (bCacheLine && !Pager->CachedLine)
148  {
149  /* We start caching, allocate the cached line buffer */
150  Pager->CachedLine = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
151  cchLine * sizeof(TCHAR));
152  Pager->cchCachedLine = 0;
153 
154  if (!Pager->CachedLine)
155  {
157  return FALSE;
158  }
159  }
160  else if (Pager->CachedLine)
161  {
162  /* We continue caching, re-allocate the cached line buffer */
164  (PVOID)Pager->CachedLine,
165  (Pager->cchCachedLine + cchLine) * sizeof(TCHAR));
166  if (!ptr)
167  {
168  HeapFree(GetProcessHeap(), 0, (PVOID)Pager->CachedLine);
169  Pager->CachedLine = NULL;
170  Pager->cchCachedLine = 0;
171 
173  return FALSE;
174  }
175  Pager->CachedLine = ptr;
176  }
177  if (Pager->CachedLine)
178  {
179  /* Copy/append the text to the cached line buffer */
180  RtlCopyMemory((PVOID)&Pager->CachedLine[Pager->cchCachedLine],
181  &TextBuff[ichStart],
182  cchLine * sizeof(TCHAR));
183  Pager->cchCachedLine += cchLine;
184  }
185  if (bCacheLine)
186  {
187  /* The line is currently incomplete, don't proceed further for now */
188  return FALSE;
189  }
190 
191 TerminateLine:
192  /* The line should be complete now. If we have an existing cached line,
193  * it has been completed by appending the remaining text to it. */
194 
195  /* We are starting a new line */
196  Pager->ichCurr = 0;
197  if (Pager->CachedLine)
198  {
199  Pager->iEndLine = Pager->cchCachedLine;
200  Pager->CurrentLine = Pager->CachedLine;
201  }
202  else
203  {
204  Pager->iEndLine = cchLine;
205  Pager->CurrentLine = &TextBuff[ichStart];
206  }
207 
208  /* Increase only when we have got a NEWLINE */
209  if ((Pager->iEndLine > 0) && (Pager->CurrentLine[Pager->iEndLine - 1] == TEXT('\n')))
210  Pager->lineno++;
211 
212  return TRUE;
213 }
214 
218 static BOOL
220  IN PCON_PAGER Pager,
221  IN PCTCH TextBuff,
222  IN DWORD cch)
223 {
224  const DWORD PageColumns = Pager->PageColumns;
225  const DWORD ScrollRows = Pager->ScrollRows;
226 
227  BOOL bFinitePaging = ((PageColumns > 0) && (Pager->PageRows > 0));
228  LONG nTabWidth = Pager->nTabWidth;
229 
230  PCTCH Line;
231  SIZE_T ich;
232  SIZE_T ichStart;
233  SIZE_T iEndLine;
234  DWORD iColumn = Pager->iColumn;
235 
236  UINT nCodePage = GetConsoleOutputCP();
237  BOOL IsCJK = IsCJKCodePage(nCodePage);
238  UINT nWidthOfChar = 1;
239  BOOL IsDoubleWidthCharTrailing = FALSE;
240 
241  /* Normalize the tab width: if negative or too large,
242  * cap it to the number of columns. */
243  if (PageColumns > 0) // if (bFinitePaging)
244  {
245  if (nTabWidth < 0)
246  nTabWidth = PageColumns - 1;
247  else
248  nTabWidth = min(nTabWidth, PageColumns - 1);
249  }
250  else
251  {
252  /* If no column width is known, default to 8 spaces if the
253  * original value is negative; otherwise keep the current one. */
254  if (nTabWidth < 0)
255  nTabWidth = 8;
256  }
257 
258 
259  /* Continue displaying the previous line, if any, or start a new one */
260  Line = Pager->CurrentLine;
261  ichStart = Pager->ichCurr;
262  iEndLine = Pager->iEndLine;
263 
264 ProcessLine:
265 
266  /* Stop now if we have displayed more page lines than requested */
267  if (bFinitePaging && (Pager->iLine >= ScrollRows))
268  goto End;
269 
270  if (!Line || (ichStart >= iEndLine))
271  {
272  /* Start a new line */
273  if (!GetNextLine(Pager, TextBuff, cch))
274  goto End;
275 
276  Line = Pager->CurrentLine;
277  ichStart = Pager->ichCurr;
278  iEndLine = Pager->iEndLine;
279  }
280  else
281  {
282  /* Continue displaying the current line */
283  }
284 
285  // ASSERT(Line && ((ichStart < iEndLine) || (ichStart == iEndLine && iEndLine == 0)));
286 
287  /* Determine whether this line segment (from the current position till the end) should be displayed */
288  Pager->iColumn = iColumn;
289  if (Pager->PagerLine && Pager->PagerLine(Pager, &Line[ichStart], iEndLine - ichStart))
290  {
291  iColumn = Pager->iColumn;
292 
293  /* Done with this line; start a new one */
294  Pager->nSpacePending = 0; // And reset any pending space.
295  ichStart = iEndLine;
296  goto ProcessLine;
297  }
298  // else: Continue displaying the line.
299 
300 
301  /* Print out any pending TAB expansion */
302  if (Pager->nSpacePending > 0)
303  {
304 ExpandTab:
305  while (Pager->nSpacePending > 0)
306  {
307  /* Print filling spaces */
308  CON_STREAM_WRITE(Pager->Screen->Stream, TEXT(" "), 1);
309  --(Pager->nSpacePending);
310  ++iColumn;
311 
312  /* Check whether we are going across the column */
313  if ((PageColumns > 0) && (iColumn % PageColumns == 0))
314  {
315  // Pager->nSpacePending = 0; // <-- This is the mode of most text editors...
316 
317  /* Reposition the cursor to the next line, first column */
318  if (!bFinitePaging || (PageColumns < Pager->Screen->csbi.dwSize.X))
319  CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
320 
321  Pager->iLine++;
322 
323  /* Restart at the character */
324  // ASSERT(ichStart == ich);
325  goto ProcessLine;
326  }
327  }
328  }
329 
330 
331  /* Find, within this line segment (starting from its
332  * beginning), until where we can print to the page. */
333  for (ich = ichStart; ich < iEndLine; ++ich)
334  {
335  /* NEWLINE character */
336  if (Line[ich] == TEXT('\n'))
337  {
338  /* We should stop now */
339  // ASSERT(ich == iEndLine - 1);
340  break;
341  }
342 
343  /* TAB character */
344  if (Line[ich] == TEXT('\t') &&
345  (Pager->dwFlags & CON_PAGER_EXPAND_TABS))
346  {
347  /* We should stop now */
348  break;
349  }
350 
351  /* FORM-FEED character */
352  if (Line[ich] == TEXT('\f') &&
353  (Pager->dwFlags & CON_PAGER_EXPAND_FF))
354  {
355  /* We should stop now */
356  break;
357  }
358 
359  /* Other character - Handle double-width for CJK */
360 
361  if (IsCJK)
362  nWidthOfChar = GetWidthOfCharCJK(nCodePage, Line[ich]);
363 
364  /* Care about CJK character presentation only when outputting
365  * to a device where the number of columns is known. */
366  if ((PageColumns > 0) && IsCJK)
367  {
368  IsDoubleWidthCharTrailing = (nWidthOfChar == 2) &&
369  ((iColumn + 1) % PageColumns == 0);
370  if (IsDoubleWidthCharTrailing)
371  {
372  /* Reserve this character for the next line */
373  ++iColumn; // Count a blank instead.
374  /* We should stop now */
375  break;
376  }
377  }
378 
379  iColumn += nWidthOfChar;
380 
381  /* Check whether we are going across the column */
382  if ((PageColumns > 0) && (iColumn % PageColumns == 0))
383  {
384  ++ich;
385  break;
386  }
387  }
388 
389  /* Output the pending line segment */
390  if (ich - ichStart > 0)
391  CON_STREAM_WRITE(Pager->Screen->Stream, &Line[ichStart], ich - ichStart);
392 
393  /* Have we finished the line segment? */
394  if (ich >= iEndLine)
395  {
396  /* Restart at the character */
397  ichStart = ich;
398  goto ProcessLine;
399  }
400 
401  /* Handle special characters */
402 
403  /* NEWLINE character */
404  if (Line[ich] == TEXT('\n'))
405  {
406  // ASSERT(ich == iEndLine - 1);
407 
408  /* Reposition the cursor to the next line, first column */
409  CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
410 
411  Pager->iLine++;
412  iColumn = 0;
413 
414  /* Done with this line; start a new one */
415  Pager->nSpacePending = 0; // And reset any pending space.
416  ichStart = iEndLine;
417  goto ProcessLine;
418  }
419 
420  /* TAB character */
421  if (Line[ich] == TEXT('\t') &&
422  (Pager->dwFlags & CON_PAGER_EXPAND_TABS))
423  {
424  /* Perform TAB expansion, unless the tab width is zero */
425  if (nTabWidth == 0)
426  {
427  ichStart = ++ich;
428  goto ProcessLine;
429  }
430 
431  ichStart = ++ich;
432  /* Reset the number of spaces needed to develop this TAB character */
433  Pager->nSpacePending = nTabWidth - (iColumn % nTabWidth);
434  goto ExpandTab;
435  }
436 
437  /* FORM-FEED character */
438  if (Line[ich] == TEXT('\f') &&
439  (Pager->dwFlags & CON_PAGER_EXPAND_FF))
440  {
441  if (bFinitePaging)
442  {
443  /* Clear until the end of the page */
444  while (Pager->iLine < ScrollRows)
445  {
446  /* Call the user paging function in order to know
447  * whether we need to output the blank lines. */
448  Pager->iColumn = iColumn;
449  if (Pager->PagerLine && Pager->PagerLine(Pager, TEXT("\n"), 1))
450  {
451  /* Only one blank line displayed, that counts in the line count */
452  Pager->iLine++;
453  break;
454  }
455  else
456  {
457  CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
458  Pager->iLine++;
459  }
460  }
461  }
462  else
463  {
464  /* Just output a FORM-FEED and a NEWLINE */
465  CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\f\n"), 2);
466  Pager->iLine++;
467  }
468 
469  iColumn = 0;
470  Pager->nSpacePending = 0; // And reset any pending space.
471 
472  /* Skip and restart past the character */
473  ichStart = ++ich;
474  goto ProcessLine;
475  }
476 
477  /* If we output a double-width character that goes across the column,
478  * fill with blank and display the character on the next line. */
479  if (IsDoubleWidthCharTrailing)
480  {
481  IsDoubleWidthCharTrailing = FALSE; // Reset the flag.
482  CON_STREAM_WRITE(Pager->Screen->Stream, TEXT(" "), 1);
483  /* Fall back below */
484  }
485 
486  /* Are we wrapping the line? */
487  if ((PageColumns > 0) && (iColumn % PageColumns == 0))
488  {
489  /* Reposition the cursor to the next line, first column */
490  if (!bFinitePaging || (PageColumns < Pager->Screen->csbi.dwSize.X))
491  CON_STREAM_WRITE(Pager->Screen->Stream, TEXT("\n"), 1);
492 
493  Pager->iLine++;
494  }
495 
496  /* Restart at the character */
497  ichStart = ich;
498  goto ProcessLine;
499 
500 
501 End:
502  /*
503  * We are exiting, either because we displayed all the required lines
504  * (iLine >= ScrollRows), or, because we don't have more data to display.
505  */
506 
507  Pager->ichCurr = ichStart;
508  Pager->iColumn = iColumn;
509  // INVESTIGATE: Can we get rid of CurrentLine here? // if (ichStart >= iEndLine) ...
510 
511  /* Return TRUE if we displayed all the required lines; FALSE otherwise */
512  if (bFinitePaging && (Pager->iLine >= ScrollRows))
513  {
514  Pager->iLine = 0; /* Reset the count of lines being printed */
515  return TRUE;
516  }
517  else
518  {
519  return FALSE;
520  }
521 }
522 
523 
548 BOOL
550  IN PCON_PAGER Pager,
552  IN BOOL StartPaging,
553  IN PCTCH szStr,
554  IN DWORD len)
555 {
557  BOOL bIsConsole;
558 
559  /* Parameters validation */
560  if (!Pager)
561  return FALSE;
562 
563  /* Get the size of the visual screen that can be printed to */
564  bIsConsole = ConGetScreenInfo(Pager->Screen, &csbi);
565  if (bIsConsole)
566  {
567  /* Calculate the console screen extent */
568  Pager->PageColumns = csbi.dwSize.X;
569  Pager->PageRows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
570  }
571  else
572  {
573  /* We assume it's a file handle */
574  Pager->PageColumns = 0;
575  Pager->PageRows = 0;
576  }
577 
578  if (StartPaging)
579  {
580  if (bIsConsole && (Pager->PageRows >= 2))
581  {
582  /* Reset to display one page by default */
583  Pager->ScrollRows = Pager->PageRows - 1;
584  }
585  else
586  {
587  /* File output, or single line: all lines are displayed at once; reset to a default value */
588  Pager->ScrollRows = 0;
589  }
590 
591  /* Reset the internal data buffer */
592  Pager->CachedLine = NULL;
593  Pager->cchCachedLine = 0;
594 
595  /* Reset the paging state */
596  Pager->CurrentLine = NULL;
597  Pager->ichCurr = 0;
598  Pager->iEndLine = 0;
599  Pager->nSpacePending = 0;
600  Pager->iColumn = 0;
601  Pager->iLine = 0;
602  Pager->lineno = 0;
603  }
604 
605  /* Reset the reading index in the user-provided source buffer */
606  Pager->ich = 0;
607 
608  /* Run the pager even when the user-provided source buffer is
609  * empty, in case we need to flush any remaining cached line. */
610  if (!Pager->CachedLine)
611  {
612  /* No cached line, bail out now */
613  if (len == 0 || szStr == NULL)
614  return TRUE;
615  }
616 
617  while (ConPagerWorker(Pager, szStr, len))
618  {
619  /* Prompt the user only when we display to a console and the screen
620  * is not too small: at least one line for the actual paged text and
621  * one line for the prompt. */
622  if (bIsConsole && (Pager->PageRows >= 2))
623  {
624  /* Reset to display one page by default */
625  Pager->ScrollRows = Pager->PageRows - 1;
626 
627  /* Prompt the user; give him some values for statistics */
628  // FIXME: Doesn't reflect what's currently being displayed.
629  if (!PagePrompt(Pager, Pager->ich, len))
630  return FALSE;
631  }
632 
633  /* If we display to a console, recalculate its screen extent
634  * in case the user has redimensioned it during the prompt. */
635  if (bIsConsole && ConGetScreenInfo(Pager->Screen, &csbi))
636  {
637  Pager->PageColumns = csbi.dwSize.X;
638  Pager->PageRows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
639  }
640  }
641 
642  return TRUE;
643 }
644 
645 BOOL
647  IN PCON_PAGER Pager,
649  IN BOOL StartPaging,
650  IN PCTSTR szStr)
651 {
652  DWORD len;
653 
654  /* Return if no string has been given */
655  if (szStr == NULL)
656  return TRUE;
657 
658  len = wcslen(szStr);
659  return ConWritePaging(Pager, PagePrompt, StartPaging, szStr, len);
660 }
661 
662 BOOL
664  IN PCON_PAGER Pager,
666  IN BOOL StartPaging,
668  IN UINT uID)
669 {
670  INT Len;
671  PCWSTR szStr = NULL;
672 
673  Len = K32LoadStringW(hInstance, uID, (PWSTR)&szStr, 0);
674  if (szStr && Len)
675  return ConWritePaging(Pager, PagePrompt, StartPaging, szStr, Len);
676  else
677  return TRUE;
678 }
679 
680 BOOL
682  IN PCON_PAGER Pager,
684  IN BOOL StartPaging,
685  IN UINT uID)
686 {
687  return ConResPagingEx(Pager, PagePrompt, StartPaging,
688  NULL /*GetModuleHandleW(NULL)*/, uID);
689 }
690 
691 /* EOF */
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define IN
Definition: typedefs.h:39
static BOOL __stdcall PagePrompt(PCON_PAGER Pager, DWORD Done, DWORD Total)
Definition: more.c:160
LPCSTR PCTSTR
Definition: ntbasedef.h:488
#define CON_STREAM_WRITE
Definition: pager.c:33
#define WideCharToMultiByte
Definition: compat.h:111
BOOL ConWritePaging(IN PCON_PAGER Pager, IN PAGE_PROMPT PagePrompt, IN BOOL StartPaging, IN PCTCH szStr, IN DWORD len)
Definition: pager.c:549
BOOL ConGetScreenInfo(IN PCON_SCREEN Screen, OUT PCONSOLE_SCREEN_BUFFER_INFO pcsbi)
Definition: screen.c:73
#define TRUE
Definition: types.h:120
uint16_t * PWSTR
Definition: typedefs.h:56
static BOOL ConPagerWorker(IN PCON_PAGER Pager, IN PCTCH TextBuff, IN DWORD cch)
Does the main paging work: fetching text lines and displaying them.
Definition: pager.c:219
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
BOOL ConResPaging(IN PCON_PAGER Pager, IN PAGE_PROMPT PagePrompt, IN BOOL StartPaging, IN UINT uID)
Definition: pager.c:681
INT WINAPI K32LoadStringW(IN HINSTANCE hInstance OPTIONAL, IN UINT uID, OUT LPWSTR lpBuffer, IN INT nBufferMax)
Definition: utils.c:173
Console/terminal screen management.
#define CON_PAGER_EXPAND_TABS
Definition: pager.h:40
int32_t INT
Definition: typedefs.h:58
LPCCH PCTCH
Definition: ntbasedef.h:486
static INT GetWidthOfCharCJK(IN UINT nCodePage, IN WCHAR ch)
Definition: pager.c:48
struct Line Line
Definition: wdfdevice.h:4081
HINSTANCE hInstance
Definition: charmap.c:20
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
static PVOID ptr
Definition: dispmode.c:27
UINT WINAPI DECLSPEC_HOTPATCH GetConsoleOutputCP(VOID)
Definition: console.c:2453
ULONG X
Definition: bl.h:1340
BOOL(__stdcall * PAGE_PROMPT)(IN PCON_PAGER Pager, IN DWORD Done, IN DWORD Total)
Definition: pager.h:83
static LPTSTR ExpandTab(LPCTSTR line)
Definition: text.h:141
char TCHAR
Definition: xmlstorage.h:189
#define CON_PAGER_EXPAND_FF
Definition: pager.h:41
#define GetProcessHeap()
Definition: compat.h:595
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
SHORT Bottom
Definition: blue.h:35
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned long DWORD
Definition: ntddk_ex.h:95
#define Len
Definition: deflate.h:82
#define SetLastError(x)
Definition: compat.h:611
SHORT Top
Definition: blue.h:33
Definition: ncftp.h:79
int ret
GLenum GLsizei len
Definition: glext.h:6722
#define CON_PAGER_CACHE_INCOMPLETE_LINE
Definition: pager.h:43
BOOL ConPutsPaging(IN PCON_PAGER Pager, IN PAGE_PROMPT PagePrompt, IN BOOL StartPaging, IN PCTSTR szStr)
Definition: pager.c:646
Console/terminal paging functionality.
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define TEXT(s)
Definition: k32.h:26
BOOL ConResPagingEx(IN PCON_PAGER Pager, IN PAGE_PROMPT PagePrompt, IN BOOL StartPaging, IN HINSTANCE hInstance OPTIONAL, IN UINT uID)
Definition: pager.c:663
#define IsCJKCodePage(CodePage)
Definition: pager.c:42
#define HeapReAlloc
Definition: compat.h:593
#define min(a, b)
Definition: monoChain.cc:55
unsigned int UINT
Definition: ndis.h:50
#define NULL
Definition: types.h:112
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define OUT
Definition: typedefs.h:40
Definition: console.h:34
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
IN PCTCH IN DWORD cch
Definition: pager.h:36
static BOOL GetNextLine(IN OUT PCON_PAGER Pager, IN PCTCH TextBuff, IN SIZE_T cch)
Retrieves a new text line, or continue fetching the current one.
Definition: pager.c:68
#define HeapFree(x, y, z)
Definition: compat.h:594
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68