ReactOS  0.4.15-dev-3440-g915569a
more.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS More Command
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Displays text stream from STDIN or from an arbitrary number
5  * of files to STDOUT, with screen capabilities (more than CAT,
6  * but less than LESS ^^).
7  * COPYRIGHT: Copyright 1999 Paolo Pantaleo
8  * Copyright 2003 Timothy Schepens
9  * Copyright 2016-2021 Hermes Belusca-Maito
10  * Copyright 2021 Katayama Hirofumi MZ
11  */
12 /*
13  * MORE.C - external command.
14  *
15  * clone from 4nt more command
16  *
17  * 26 Sep 1999 - Paolo Pantaleo <paolopan@freemail.it>
18  * started
19  *
20  * Oct 2003 - Timothy Schepens <tischepe at fastmail dot fm>
21  * use window size instead of buffer size.
22  */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 
27 #include <windef.h>
28 #include <winbase.h>
29 #include <winnt.h>
30 #include <winnls.h>
31 #include <winreg.h>
32 #include <winuser.h>
33 
34 #include <conutils.h>
35 #include <strsafe.h>
36 
37 #include "resource.h"
38 
39 /* PagePrompt statistics for the current file */
40 DWORD dwFileSize; // In bytes
42 // The average number of bytes per character is equal to
43 // dwSumReadBytes / dwSumReadChars. Note that dwSumReadChars
44 // will never be == 0 when ConWritePaging (and possibly PagePrompt)
45 // is called.
46 
47 /* Handles for file and console */
51 
52 /* Enable/Disable extensions */
53 BOOL bEnableExtensions = TRUE; // FIXME: By default, it should be FALSE.
54 
55 /* Parser flags */
56 #define FLAG_HELP (1 << 0)
57 #define FLAG_E (1 << 1)
58 #define FLAG_C (1 << 2)
59 #define FLAG_P (1 << 3)
60 #define FLAG_S (1 << 4)
61 #define FLAG_Tn (1 << 5)
62 #define FLAG_PLUSn (1 << 6)
63 
64 /* Prompt flags */
65 #define PROMPT_PERCENT (1 << 0)
66 #define PROMPT_LINE_AT (1 << 1)
67 #define PROMPT_OPTIONS (1 << 2)
68 #define PROMPT_LINES (1 << 3)
69 
70 static DWORD s_dwFlags = 0;
71 static LONG s_nTabWidth = 8;
72 static DWORD s_nNextLineNo = 0;
74 static WORD s_fPrompt = 0;
76 
78 {
79  DWORD ich;
80  WORD wType;
81  for (ich = 0; ich < cch; ++ich)
82  {
83  /*
84  * Explicitly exclude FORM-FEED from the check,
85  * so that the pager can handle it.
86  */
87  if (line[ich] == L'\f')
88  return FALSE;
89 
90  /*
91  * Otherwise do the extended blanks check.
92  * Note that MS MORE.COM only checks for spaces (\x20) and TABs (\x09).
93  * See http://archives.miloush.net/michkap/archive/2007/06/11/3230072.html
94  * for more information.
95  */
96  wType = 0;
97  GetStringTypeW(CT_CTYPE1, &line[ich], 1, &wType);
98  if (!(wType & (C1_BLANK | C1_SPACE)))
99  return FALSE;
100  }
101  return TRUE;
102 }
103 
104 static BOOL
105 __stdcall
107  IN OUT PCON_PAGER Pager,
108  IN PCWCH line,
109  IN DWORD cch)
110 {
111  if (s_dwFlags & FLAG_PLUSn) /* Skip lines */
112  {
113  if (Pager->lineno < s_nNextLineNo)
114  {
116  return TRUE; /* Handled */
117  }
118  s_dwFlags &= ~FLAG_PLUSn;
119  }
120 
121  if (s_dwFlags & FLAG_S) /* Shrink blank lines */
122  {
123  if (IsBlankLine(line, cch))
124  {
125  if (s_bPrevLineIsBlank)
126  return TRUE; /* Handled */
127 
128  /*
129  * Display a single blank line, independently of the actual size
130  * of the current line, by displaying just one space: this is
131  * especially needed in order to force line wrapping when the
132  * ENABLE_VIRTUAL_TERMINAL_PROCESSING or DISABLE_NEWLINE_AUTO_RETURN
133  * console modes are enabled.
134  * Then, reposition the cursor to the next line, first column.
135  */
136  if (Pager->PageColumns > 0)
137  ConStreamWrite(Pager->Screen->Stream, TEXT(" "), 1);
138  ConStreamWrite(Pager->Screen->Stream, TEXT("\n"), 1);
139  Pager->iLine++;
140  Pager->iColumn = 0;
141 
143  s_nNextLineNo = 0;
144 
145  return TRUE; /* Handled */
146  }
147  else
148  {
150  }
151  }
152 
153  s_nNextLineNo = 0;
154  /* Not handled, let the pager do the default action */
155  return FALSE;
156 }
157 
158 static BOOL
159 __stdcall
160 PagePrompt(PCON_PAGER Pager, DWORD Done, DWORD Total)
161 {
163  HANDLE hOutput = ConStreamGetOSHandle(Pager->Screen->Stream);
165  COORD orgCursorPosition;
166  DWORD dwMode;
167 
168  KEY_EVENT_RECORD KeyEvent;
169  BOOL fCtrl;
170  DWORD nLines;
171  WCHAR chSubCommand = 0;
172 
173  /* Prompt strings (small size since the prompt should
174  * hold ideally on one <= 80-character line) */
175  static WCHAR StrPercent[80] = L"";
176  static WCHAR StrLineAt[80] = L"";
177  static WCHAR StrOptions[80] = L"";
178  static WCHAR StrLines[80] = L"";
179 
180  WCHAR szPercent[80] = L"";
181  WCHAR szLineAt[80] = L"";
182 
183  /* Load the prompt strings */
184  if (!*StrPercent)
185  K32LoadStringW(NULL, IDS_CONTINUE_PERCENT, StrPercent, ARRAYSIZE(StrPercent));
186  if (!*StrLineAt)
187  K32LoadStringW(NULL, IDS_CONTINUE_LINE_AT, StrLineAt, ARRAYSIZE(StrLineAt));
188  if (!*StrOptions)
189  K32LoadStringW(NULL, IDS_CONTINUE_OPTIONS, StrOptions, ARRAYSIZE(StrOptions));
190  if (!*StrLines)
191  K32LoadStringW(NULL, IDS_CONTINUE_LINES, StrLines, ARRAYSIZE(StrLines));
192 
193  /*
194  * Check whether the pager is prompting, but we have actually finished
195  * to display a given file, or no data is present in STDIN anymore.
196  * In this case, skip the prompt altogether. The only exception is when
197  * we are displaying other files.
198  */
199  // TODO: Implement!
200 
201 Restart:
202  nLines = 0;
203 
204  /* Do not show the progress percentage when STDIN is being displayed */
205  if (s_fPrompt & PROMPT_PERCENT) // && (hFile != hStdIn)
206  {
207  /*
208  * The progress percentage is evaluated as follows.
209  * So far we have read a total of 'dwSumReadBytes' bytes from the file.
210  * Amongst those is the latest read chunk of 'dwReadBytes' bytes, to which
211  * correspond a number of 'dwReadChars' characters with which we have called
212  * ConWritePaging who called PagePrompt. We then have: Total == dwReadChars.
213  * During this ConWritePaging call the PagePrompt was called after 'Done'
214  * number of characters over 'Total'.
215  * It should be noted that for 'dwSumReadBytes' number of bytes read it
216  * *roughly* corresponds 'dwSumReadChars' number of characters. This is
217  * because there may be some failures happening during the conversion of
218  * the bytes read to the character string for a given encoding.
219  * Therefore the number of characters displayed on screen is equal to:
220  * dwSumReadChars - Total + Done ,
221  * but the best corresponding approximed number of bytes would be:
222  * dwSumReadBytes - (Total - Done) * (dwSumReadBytes / dwSumReadChars) ,
223  * where the ratio is the average number of bytes per character.
224  * The percentage is then computed relative to the total file size.
225  */
226  DWORD dwPercent = (dwSumReadBytes - (Total - Done) *
228  StringCchPrintfW(szPercent, ARRAYSIZE(szPercent), StrPercent, dwPercent);
229  }
231  {
232  StringCchPrintfW(szLineAt, ARRAYSIZE(szLineAt), StrLineAt, Pager->lineno);
233  }
234 
235  /* Suitably format and display the prompt */
238  (s_fPrompt & PROMPT_LINE_AT ? szLineAt : L""),
239  (s_fPrompt & PROMPT_OPTIONS ? StrOptions : L""),
240  (s_fPrompt & PROMPT_LINES ? StrLines : L""));
241 
242  /* Reset the prompt to a default state */
244 
245  /* RemoveBreakHandler */
247  /* ConInDisable */
248  GetConsoleMode(hInput, &dwMode);
249  dwMode &= ~ENABLE_PROCESSED_INPUT;
250  SetConsoleMode(hInput, dwMode);
251 
252  // FIXME: Does not support TTY yet!
253  ConGetScreenInfo(Pager->Screen, &csbi);
254  orgCursorPosition = csbi.dwCursorPosition;
255  for (;;)
256  {
257  INPUT_RECORD ir = {0};
258  DWORD dwRead;
259  WCHAR ch;
260 
261  do
262  {
263  ReadConsoleInput(hInput, &ir, 1, &dwRead);
264  }
265  while ((ir.EventType != KEY_EVENT) || (!ir.Event.KeyEvent.bKeyDown));
266 
267  /* Got our key */
268  KeyEvent = ir.Event.KeyEvent;
269 
270  /* Ignore any unsupported keyboard press */
271  if ((KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
272  (KeyEvent.wVirtualKeyCode == VK_MENU) ||
273  (KeyEvent.wVirtualKeyCode == VK_CONTROL))
274  {
275  continue;
276  }
277 
278  /* Ctrl key is pressed? */
279  fCtrl = !!(KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED));
280 
281  /* Ctrl+C or Ctrl+Esc? */
282  if (fCtrl && ((KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
283  (KeyEvent.wVirtualKeyCode == L'C')))
284  {
285  chSubCommand = 0;
286  break;
287  }
288 
289  /* If extended features are unavailable, or no
290  * pending commands, don't do more processing. */
291  if (!(s_dwFlags & FLAG_E) || (chSubCommand == 0))
292  break;
293 
294  ch = KeyEvent.uChar.UnicodeChar;
295  if (L'0' <= ch && ch <= L'9')
296  {
297  nLines *= 10;
298  nLines += ch - L'0';
299  ConStreamWrite(Pager->Screen->Stream, &ch, 1);
300  continue;
301  }
302  else if (KeyEvent.wVirtualKeyCode == VK_RETURN)
303  {
304  /* Validate the line number */
305  break;
306  }
307  else if (KeyEvent.wVirtualKeyCode == VK_ESCAPE)
308  {
309  /* Cancel the current command */
310  chSubCommand = 0;
311  break;
312  }
313  else if (KeyEvent.wVirtualKeyCode == VK_BACK)
314  {
315  if (nLines != 0)
316  nLines /= 10;
317 
318  /* Erase the current character */
319  ConGetScreenInfo(Pager->Screen, &csbi);
320  if ( (csbi.dwCursorPosition.Y > orgCursorPosition.Y) ||
321  ((csbi.dwCursorPosition.Y == orgCursorPosition.Y) &&
322  (csbi.dwCursorPosition.X > orgCursorPosition.X)) )
323  {
324  if (csbi.dwCursorPosition.X > 0)
325  {
326  csbi.dwCursorPosition.X = csbi.dwCursorPosition.X - 1;
327  }
328  else if (csbi.dwCursorPosition.Y > 0)
329  {
330  csbi.dwCursorPosition.Y = csbi.dwCursorPosition.Y - 1;
331  csbi.dwCursorPosition.X = (csbi.dwSize.X ? csbi.dwSize.X - 1 : 0);
332  }
333 
335 
336  ch = L' ';
337  ConStreamWrite(Pager->Screen->Stream, &ch, 1);
339  }
340 
341  continue;
342  }
343  }
344 
345  /* AddBreakHandler */
347  /* ConInEnable */
348  GetConsoleMode(hInput, &dwMode);
349  dwMode |= ENABLE_PROCESSED_INPUT;
350  SetConsoleMode(hInput, dwMode);
351 
352  /* Refresh the screen information, as the console may have been
353  * redimensioned. Update also the default number of lines to scroll. */
354  ConGetScreenInfo(Pager->Screen, &csbi);
355  Pager->ScrollRows = csbi.srWindow.Bottom - csbi.srWindow.Top;
356 
357  /*
358  * Erase the full line where the cursor is, and move
359  * the cursor back to the beginning of the line.
360  */
361  ConClearLine(Pager->Screen->Stream);
362 
363  /* Ctrl+C or Ctrl+Esc: Control Break */
364  if (fCtrl && ((KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
365  (KeyEvent.wVirtualKeyCode == L'C')))
366  {
367  /* We break, output a newline */
368  WCHAR ch = L'\n';
369  ConStreamWrite(Pager->Screen->Stream, &ch, 1);
370  return FALSE;
371  }
372 
373  switch (chSubCommand)
374  {
375  case L'P':
376  {
377  /* If we don't display other lines, just restart the prompt */
378  if (nLines == 0)
379  {
380  chSubCommand = 0;
381  goto Restart;
382  }
383  /* Otherwise tell the pager to display them */
384  Pager->ScrollRows = nLines;
385  return TRUE;
386  }
387  case L'S':
388  {
390  s_nNextLineNo = Pager->lineno + nLines;
391  /* Use the default Pager->ScrollRows value */
392  return TRUE;
393  }
394  default:
395  chSubCommand = 0;
396  break;
397  }
398 
399  /* If extended features are available */
400  if (s_dwFlags & FLAG_E)
401  {
402  /* Ignore any key presses if Ctrl is pressed */
403  if (fCtrl)
404  {
405  chSubCommand = 0;
406  goto Restart;
407  }
408 
409  /* 'Q': Quit */
410  if (KeyEvent.wVirtualKeyCode == L'Q')
411  {
412  /* We break, output a newline */
413  WCHAR ch = L'\n';
414  ConStreamWrite(Pager->Screen->Stream, &ch, 1);
415  return FALSE;
416  }
417 
418  /* 'F': Next file */
419  if (KeyEvent.wVirtualKeyCode == L'F')
420  {
422  return FALSE;
423  }
424 
425  /* '?': Show Options */
426  if (KeyEvent.uChar.UnicodeChar == L'?')
427  {
429  goto Restart;
430  }
431 
432  /* [Enter] key: Display one line */
433  if (KeyEvent.wVirtualKeyCode == VK_RETURN)
434  {
435  Pager->ScrollRows = 1;
436  return TRUE;
437  }
438 
439  /* [Space] key: Display one page */
440  if (KeyEvent.wVirtualKeyCode == VK_SPACE)
441  {
442  if (s_dwFlags & FLAG_C)
443  {
444  /* Clear the screen */
445  ConClearScreen(Pager->Screen);
446  }
447  /* Use the default Pager->ScrollRows value */
448  return TRUE;
449  }
450 
451  /* 'P': Display n lines */
452  if (KeyEvent.wVirtualKeyCode == L'P')
453  {
455  chSubCommand = L'P';
456  goto Restart;
457  }
458 
459  /* 'S': Skip n lines */
460  if (KeyEvent.wVirtualKeyCode == L'S')
461  {
463  chSubCommand = L'S';
464  goto Restart;
465  }
466 
467  /* '=': Show current line number */
468  if (KeyEvent.uChar.UnicodeChar == L'=')
469  {
471  goto Restart;
472  }
473 
474  chSubCommand = 0;
475  goto Restart;
476  }
477  else
478  {
479  /* Extended features are unavailable: display one page */
480  /* Use the default Pager->ScrollRows value */
481  return TRUE;
482  }
483 }
484 
485 /*
486  * See base/applications/cmdutils/clip/clip.c!IsDataUnicode()
487  * and base/applications/notepad/text.c!ReadText() for more details.
488  * Also some good code example can be found at:
489  * https://github.com/AutoIt/text-encoding-detect
490  */
491 typedef enum
492 {
497 } ENCODING;
498 
499 static BOOL
501  IN PVOID Buffer,
503  OUT ENCODING* Encoding OPTIONAL,
505 {
506  PBYTE pBytes = Buffer;
507  ENCODING encFile = ENCODING_ANSI;
508  DWORD dwPos = 0;
509 
510  /*
511  * See http://archives.miloush.net/michkap/archive/2007/04/22/2239345.html
512  * for more details about the algorithm and the pitfalls behind it.
513  * Of course it would be actually great to make a nice function that
514  * would work, once and for all, and put it into a library.
515  */
516 
517  /* Look for Byte Order Marks */
518  if ((BufferSize >= 2) && (pBytes[0] == 0xFF) && (pBytes[1] == 0xFE))
519  {
520  encFile = ENCODING_UTF16LE;
521  dwPos = 2;
522  }
523  else if ((BufferSize >= 2) && (pBytes[0] == 0xFE) && (pBytes[1] == 0xFF))
524  {
525  encFile = ENCODING_UTF16BE;
526  dwPos = 2;
527  }
528  else if ((BufferSize >= 3) && (pBytes[0] == 0xEF) && (pBytes[1] == 0xBB) && (pBytes[2] == 0xBF))
529  {
530  encFile = ENCODING_UTF8;
531  dwPos = 3;
532  }
533  else
534  {
535  /*
536  * Try using statistical analysis. Do not rely on the return value of
537  * IsTextUnicode as we can get FALSE even if the text is in UTF-16 BE
538  * (i.e. we have some of the IS_TEXT_UNICODE_REVERSE_MASK bits set).
539  * Instead, set all the tests we want to perform, then just check
540  * the passed tests and try to deduce the string properties.
541  */
542 
543 /*
544  * This mask contains the 3 highest bits from IS_TEXT_UNICODE_NOT_ASCII_MASK
545  * and the 1st highest bit from IS_TEXT_UNICODE_NOT_UNICODE_MASK.
546  */
547 #define IS_TEXT_UNKNOWN_FLAGS_MASK ((7 << 13) | (1 << 11))
548 
549  /* Flag out the unknown flags here, the passed tests will not have them either */
554  INT Results;
555 
557  Results = Tests;
558 
559  /*
560  * As the IS_TEXT_UNICODE_NULL_BYTES or IS_TEXT_UNICODE_ILLEGAL_CHARS
561  * flags are expected to be potentially present in the result without
562  * modifying our expectations, filter them out now.
563  */
565 
566  /*
567  * NOTE: The flags IS_TEXT_UNICODE_ASCII16 and
568  * IS_TEXT_UNICODE_REVERSE_ASCII16 are not reliable.
569  *
570  * NOTE2: Check for potential "bush hid the facts" effect by also
571  * checking the original results (in 'Tests') for the absence of
572  * the IS_TEXT_UNICODE_NULL_BYTES flag, as we may presumably expect
573  * that in UTF-16 text there will be at some point some NULL bytes.
574  * If not, fall back to ANSI. This shows the limitations of using the
575  * IsTextUnicode API to perform such tests, and the usage of a more
576  * improved encoding detection algorithm would be really welcome.
577  */
578  if (!(Results & IS_TEXT_UNICODE_NOT_UNICODE_MASK) &&
579  !(Results & IS_TEXT_UNICODE_REVERSE_MASK) &&
580  (Results & IS_TEXT_UNICODE_UNICODE_MASK) &&
582  {
583  encFile = ENCODING_UTF16LE;
584  dwPos = (Results & IS_TEXT_UNICODE_SIGNATURE) ? 2 : 0;
585  }
586  else
587  if (!(Results & IS_TEXT_UNICODE_NOT_UNICODE_MASK) &&
588  !(Results & IS_TEXT_UNICODE_UNICODE_MASK) &&
589  (Results & IS_TEXT_UNICODE_REVERSE_MASK) &&
591  {
592  encFile = ENCODING_UTF16BE;
593  dwPos = (Results & IS_TEXT_UNICODE_REVERSE_SIGNATURE) ? 2 : 0;
594  }
595  else
596  {
597  /*
598  * Either 'Results' has neither of those masks set, as it can be
599  * the case for UTF-8 text (or ANSI), or it has both as can be the
600  * case when analysing pure binary data chunk. This is therefore
601  * invalid and we fall back to ANSI encoding.
602  * FIXME: In case of failure, assume ANSI (as long as we do not have
603  * correct tests for UTF8, otherwise we should do them, and at the
604  * very end, assume ANSI).
605  */
606  encFile = ENCODING_ANSI; // ENCODING_UTF8;
607  dwPos = 0;
608  }
609  }
610 
611  if (Encoding)
612  *Encoding = encFile;
613  if (SkipBytes)
614  *SkipBytes = dwPos;
615 
616  return (encFile != ENCODING_ANSI);
617 }
618 
619 /*
620  * Adapted from base/shell/cmd/misc.c!FileGetString(), but with correct
621  * text encoding support. Also please note that similar code should be
622  * also used in the CMD.EXE 'TYPE' command.
623  * Contrary to CMD's FileGetString() we do not stop at new-lines.
624  *
625  * Read text data from a file and convert it from a given encoding to UTF-16.
626  *
627  * IN OUT PVOID pCacheBuffer and IN DWORD CacheBufferLength :
628  * Implementation detail so that the function uses an external user-provided
629  * buffer to store the data temporarily read from the file. The function
630  * could have used an internal buffer instead. The length is in number of bytes.
631  *
632  * IN OUT PWSTR* pBuffer and IN OUT PDWORD pnBufferLength :
633  * Reallocated buffer containing the string data converted to UTF-16.
634  * In input, contains a pointer to the original buffer and its length.
635  * In output, contains a pointer to the reallocated buffer and its length.
636  * The length is in number of characters.
637  *
638  * At first call to this function, pBuffer can be set to NULL, in which case
639  * when the function returns the pointer will point to a valid buffer.
640  * After the last call to this function, free the pBuffer pointer with:
641  * HeapFree(GetProcessHeap(), 0, *pBuffer);
642  *
643  * If Encoding is set to ENCODING_UTF16LE or ENCODING_UTF16BE, since we are
644  * compiled in UNICODE, no extra conversion is performed and therefore
645  * pBuffer is unused (remains unallocated) and one can directly use the
646  * contents of pCacheBuffer as it is expected to contain valid UTF-16 text.
647  *
648  * OUT PDWORD pdwReadBytes : Number of bytes read from the file (optional).
649  * OUT PDWORD pdwReadChars : Corresponding number of characters read (optional).
650  */
651 static BOOL
653  IN HANDLE hFile,
654  IN ENCODING Encoding,
655  IN OUT PVOID pCacheBuffer,
656  IN DWORD CacheBufferLength,
657  IN OUT PWCHAR* pBuffer,
658  IN OUT PDWORD pnBufferLength,
659  OUT PDWORD pdwReadBytes OPTIONAL,
660  OUT PDWORD pdwReadChars OPTIONAL)
661 {
662  BOOL Success;
663  UINT CodePage = (UINT)-1;
664  DWORD dwReadBytes;
665  INT len;
666 
667  // ASSERT(pCacheBuffer && (CacheBufferLength > 0));
668  // ASSERT(CacheBufferLength % 2 == 0); // Cache buffer length MUST BE even!
669  // ASSERT(pBuffer && pnBufferLength);
670 
671  /* Always reset the retrieved number of bytes/characters */
672  if (pdwReadBytes) *pdwReadBytes = 0;
673  if (pdwReadChars) *pdwReadChars = 0;
674 
675  Success = ReadFile(hFile, pCacheBuffer, CacheBufferLength, &dwReadBytes, NULL);
676  if (!Success || dwReadBytes == 0)
677  return FALSE;
678 
679  if (pdwReadBytes) *pdwReadBytes = dwReadBytes;
680 
681  if ((Encoding == ENCODING_ANSI) || (Encoding == ENCODING_UTF8))
682  {
683  /* Conversion is needed */
684 
685  if (Encoding == ENCODING_ANSI)
686  CodePage = GetConsoleCP(); // CP_ACP; // FIXME: Cache GetConsoleCP() value.
687  else // if (Encoding == ENCODING_UTF8)
688  CodePage = CP_UTF8;
689 
690  /* Retrieve the needed buffer size */
691  len = MultiByteToWideChar(CodePage, 0, pCacheBuffer, dwReadBytes,
692  NULL, 0);
693  if (len == 0)
694  {
695  /* Failure, bail out */
696  return FALSE;
697  }
698 
699  /* Initialize the conversion buffer if needed... */
700  if (*pBuffer == NULL)
701  {
702  *pnBufferLength = len;
703  *pBuffer = HeapAlloc(GetProcessHeap(), 0, *pnBufferLength * sizeof(WCHAR));
704  if (*pBuffer == NULL)
705  {
706  // *pBuffer = NULL;
707  *pnBufferLength = 0;
708  // WARN("DEBUG: Cannot allocate memory for *pBuffer!\n");
709  // ConErrFormatMessage(GetLastError());
710  return FALSE;
711  }
712  }
713  /* ... or reallocate only if the new length is greater than the old one */
714  else if (len > *pnBufferLength)
715  {
716  PWSTR OldBuffer = *pBuffer;
717 
718  *pnBufferLength = len;
719  *pBuffer = HeapReAlloc(GetProcessHeap(), 0, *pBuffer, *pnBufferLength * sizeof(WCHAR));
720  if (*pBuffer == NULL)
721  {
722  /* Do not leak old buffer */
723  HeapFree(GetProcessHeap(), 0, OldBuffer);
724  // *pBuffer = NULL;
725  *pnBufferLength = 0;
726  // WARN("DEBUG: Cannot reallocate memory for *pBuffer!\n");
727  // ConErrFormatMessage(GetLastError());
728  return FALSE;
729  }
730  }
731 
732  /* Now perform the conversion proper */
733  len = MultiByteToWideChar(CodePage, 0, pCacheBuffer, dwReadBytes,
734  *pBuffer, len);
735  dwReadBytes = len;
736  }
737  else
738  {
739  /*
740  * No conversion needed, just convert from big to little endian if needed.
741  * pBuffer and pnBufferLength are left untouched and pCacheBuffer can be
742  * directly used.
743  */
744  PWCHAR pWChars = pCacheBuffer;
745  DWORD i;
746 
747  dwReadBytes /= sizeof(WCHAR);
748 
749  if (Encoding == ENCODING_UTF16BE)
750  {
751  for (i = 0; i < dwReadBytes; i++)
752  {
753  /* Equivalent to RtlUshortByteSwap: reverse high/low bytes */
754  pWChars[i] = MAKEWORD(HIBYTE(pWChars[i]), LOBYTE(pWChars[i]));
755  }
756  }
757  // else if (Encoding == ENCODING_UTF16LE), we are good, nothing to do.
758  }
759 
760  /* Return the number of characters (dwReadBytes is converted) */
761  if (pdwReadChars) *pdwReadChars = dwReadBytes;
762 
763  return TRUE;
764 }
765 
766 static VOID
768 {
769  LONG lRet;
770  HKEY hKey;
771  DWORD dwType, len;
772  /*
773  * Buffer big enough to hold the string L"4294967295",
774  * corresponding to the literal 0xFFFFFFFF (MAXULONG) in decimal.
775  */
776  WCHAR Buffer[sizeof("4294967295")];
777  C_ASSERT(sizeof(Buffer) >= sizeof(DWORD));
778 
779  lRet = RegOpenKeyExW(hKeyRoot,
780  L"Software\\Microsoft\\Command Processor",
781  0,
783  &hKey);
784  if (lRet != ERROR_SUCCESS)
785  return;
786 
787  len = sizeof(Buffer);
788  lRet = RegQueryValueExW(hKey,
789  L"EnableExtensions",
790  NULL,
791  &dwType,
792  (PBYTE)&Buffer,
793  &len);
794  if (lRet == ERROR_SUCCESS)
795  {
796  /* Overwrite the default setting */
797  if (dwType == REG_DWORD)
799  else if (dwType == REG_SZ)
800  bEnableExtensions = (_wtol((PWSTR)Buffer) == 1);
801  }
802  // else, use the default setting set globally.
803 
804  RegCloseKey(hKey);
805 }
806 
808 {
809  PCWSTR pch;
810  PWCHAR endptr;
811 
812  if (param[0] == L'/')
813  return TRUE;
814 
815  if (param[0] == L'+')
816  {
817  pch = param + 1;
818  if (*pch)
819  {
820  (void)wcstol(pch, &endptr, 10);
821  return (*endptr == 0);
822  }
823  }
824  return FALSE;
825 }
826 
827 static BOOL ParseArgument(PCWSTR arg, BOOL* pbHasFiles)
828 {
829  PWCHAR endptr;
830 
831  if (arg[0] == L'/')
832  {
833  switch (towupper(arg[1]))
834  {
835  case L'?':
836  if (arg[2] == 0)
837  {
838  s_dwFlags |= FLAG_HELP;
839  return TRUE;
840  }
841  break;
842  case L'E':
843  if (arg[2] == 0)
844  {
845  s_dwFlags |= FLAG_E;
846  return TRUE;
847  }
848  break;
849  case L'C':
850  if (arg[2] == 0)
851  {
852  s_dwFlags |= FLAG_C;
853  return TRUE;
854  }
855  break;
856  case L'P':
857  if (arg[2] == 0)
858  {
859  s_dwFlags |= FLAG_P;
860  return TRUE;
861  }
862  break;
863  case L'S':
864  if (arg[2] == 0)
865  {
866  s_dwFlags |= FLAG_S;
867  return TRUE;
868  }
869  break;
870  case L'T':
871  if (arg[2] != 0)
872  {
873  s_dwFlags |= FLAG_Tn;
874  s_nTabWidth = wcstol(&arg[2], &endptr, 10);
875  if (*endptr == 0)
876  return TRUE;
877  }
878  break;
879  default:
880  break;
881  }
882  }
883  else if (arg[0] == L'+')
884  {
885  if (arg[1] != 0)
886  {
888  s_nNextLineNo = wcstol(&arg[1], &endptr, 10) + 1;
889  if (*endptr == 0)
890  return TRUE;
891  }
892  }
893 
894  if (IsFlag(arg))
895  {
897  return FALSE;
898  }
899  else
900  {
901  *pbHasFiles = TRUE;
902  }
903 
904  return TRUE;
905 }
906 
907 static BOOL ParseMoreVariable(BOOL* pbHasFiles)
908 {
909  BOOL ret = TRUE;
910  PWSTR psz;
911  PWCHAR pch;
912  DWORD cch;
913 
914  cch = GetEnvironmentVariableW(L"MORE", NULL, 0);
915  if (cch == 0)
916  return TRUE;
917 
918  psz = (PWSTR)malloc((cch + 1) * sizeof(WCHAR));
919  if (!psz)
920  return TRUE;
921 
922  if (!GetEnvironmentVariableW(L"MORE", psz, cch + 1))
923  {
924  free(psz);
925  return TRUE;
926  }
927 
928  for (pch = wcstok(psz, L" "); pch; pch = wcstok(NULL, L" "))
929  {
930  ret = ParseArgument(pch, pbHasFiles);
931  if (!ret)
932  break;
933  }
934 
935  free(psz);
936  return ret;
937 }
938 
939 // INT CommandMore(LPTSTR cmd, LPTSTR param)
940 int wmain(int argc, WCHAR* argv[])
941 {
942  // FIXME this stuff!
944  CON_PAGER Pager = {&Screen, 0};
945 
946  int i;
947 
948  BOOL bRet, bContinue;
949 
950  ENCODING Encoding;
951  DWORD SkipBytes = 0;
952  BOOL HasFiles;
953 
954 #define FileCacheBufferSize 4096
955  PVOID FileCacheBuffer = NULL;
957  DWORD StringBufferLength = 0;
958  DWORD dwReadBytes = 0, dwReadChars = 0;
959 
960  TCHAR szFullPath[MAX_PATH];
961 
964 
965  /* Initialize the Console Standard Streams */
969 
970  /*
971  * Bad usage (too much options) or we use the /? switch.
972  * Display help for the MORE command.
973  */
974  if (argc > 1 && wcscmp(argv[1], L"/?") == 0)
975  {
977  return 0;
978  }
979 
980  /* Load the registry settings */
983  if (bEnableExtensions)
984  s_dwFlags |= FLAG_E;
985 
986  // NOTE: We might try to duplicate the ConOut for read access... ?
989  OPEN_EXISTING, 0, NULL);
992 
993  FileCacheBuffer = HeapAlloc(GetProcessHeap(), 0, FileCacheBufferSize);
994  if (!FileCacheBuffer)
995  {
996  ConPuts(StdErr, L"Error: no memory\n");
998  return 1;
999  }
1000 
1001  /* First, load the "MORE" environment variable and parse it,
1002  * then parse the command-line parameters. */
1003  HasFiles = FALSE;
1004  if (!ParseMoreVariable(&HasFiles))
1005  return 1;
1006  for (i = 1; i < argc; i++)
1007  {
1008  if (!ParseArgument(argv[i], &HasFiles))
1009  return 1;
1010  }
1011 
1012  if (s_dwFlags & FLAG_HELP)
1013  {
1015  return 0;
1016  }
1017 
1018  Pager.PagerLine = MorePagerLine;
1020  if (s_dwFlags & FLAG_P)
1021  Pager.dwFlags |= CON_PAGER_EXPAND_FF;
1022  Pager.nTabWidth = s_nTabWidth;
1023 
1024  /* Special case where we run 'MORE' without any argument: we use STDIN */
1025  if (!HasFiles)
1026  {
1027  /*
1028  * Assign STDIN handle to hFile so that the page prompt function will
1029  * know the data comes from STDIN, and will take different actions.
1030  */
1031  hFile = hStdIn;
1032 
1033  /* Update the statistics for PagePrompt */
1034  dwFileSize = 0;
1036 
1037  /* We suppose we read text from the file */
1038 
1039  /* For STDIN we always suppose we are in ANSI mode */
1040  // SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
1041  Encoding = ENCODING_ANSI; // ENCODING_UTF8;
1042 
1043  /* Start paging */
1044  bContinue = ConWritePaging(&Pager, PagePrompt, TRUE, NULL, 0);
1045  if (!bContinue)
1046  goto Quit;
1047 
1048  do
1049  {
1050  bRet = FileGetString(hFile, Encoding,
1051  FileCacheBuffer, FileCacheBufferSize,
1052  &StringBuffer, &StringBufferLength,
1053  &dwReadBytes, &dwReadChars);
1054  if (!bRet || dwReadBytes == 0 || dwReadChars == 0)
1055  {
1056  /* We failed at reading the file, bail out */
1057  break;
1058  }
1059 
1060  /* Update the statistics for PagePrompt */
1061  dwSumReadBytes += dwReadBytes;
1062  dwSumReadChars += dwReadChars;
1063 
1064  bContinue = ConWritePaging(&Pager, PagePrompt, FALSE,
1065  StringBuffer, dwReadChars);
1066  /* If we Ctrl-C/Ctrl-Break, stop everything */
1067  if (!bContinue)
1068  break;
1069  }
1070  while (bRet && dwReadBytes > 0);
1071 
1072  /* Flush any cached pager buffers */
1073  if (bContinue)
1074  bContinue = ConWritePaging(&Pager, PagePrompt, FALSE, NULL, 0);
1075 
1076  goto Quit;
1077  }
1078 
1079  /* We have files: read them and output them to STDOUT */
1080  for (i = 1; i < argc; i++)
1081  {
1082  if (IsFlag(argv[i]))
1083  continue;
1084 
1085  GetFullPathNameW(argv[i], ARRAYSIZE(szFullPath), szFullPath, NULL);
1086  hFile = CreateFileW(szFullPath,
1087  GENERIC_READ,
1089  NULL,
1090  OPEN_EXISTING,
1091  0, // FILE_ATTRIBUTE_NORMAL,
1092  NULL);
1093  if (hFile == INVALID_HANDLE_VALUE)
1094  {
1095  ConResPrintf(StdErr, IDS_FILE_ACCESS, szFullPath);
1096  goto Quit;
1097  }
1098 
1099  /* We currently do not support files too big */
1102  {
1103  ConPuts(StdErr, L"ERROR: Invalid file size!\n");
1104  CloseHandle(hFile);
1105  continue;
1106  }
1107 
1108  /* We suppose we read text from the file */
1109 
1110  /* Check whether the file is UNICODE and retrieve its encoding */
1112  bRet = ReadFile(hFile, FileCacheBuffer, FileCacheBufferSize, &dwReadBytes, NULL);
1113  IsDataUnicode(FileCacheBuffer, dwReadBytes, &Encoding, &SkipBytes);
1115 
1116  /* Reset state for paging */
1117  s_nNextLineNo = 0;
1120  s_bDoNextFile = FALSE;
1121 
1122  /* Update the statistics for PagePrompt */
1124 
1125  /* Start paging */
1126  bContinue = ConWritePaging(&Pager, PagePrompt, TRUE, NULL, 0);
1127  if (!bContinue)
1128  {
1129  /* We stop displaying this file */
1130  CloseHandle(hFile);
1131  if (s_bDoNextFile)
1132  {
1133  /* Bail out and continue with the other files */
1134  continue;
1135  }
1136 
1137  /* We Ctrl-C/Ctrl-Break, stop everything */
1138  goto Quit;
1139  }
1140 
1141  do
1142  {
1143  bRet = FileGetString(hFile, Encoding,
1144  FileCacheBuffer, FileCacheBufferSize,
1145  &StringBuffer, &StringBufferLength,
1146  &dwReadBytes, &dwReadChars);
1147  if (!bRet || dwReadBytes == 0 || dwReadChars == 0)
1148  {
1149  /*
1150  * We failed at reading the file, bail out
1151  * and continue with the other files.
1152  */
1153  break;
1154  }
1155 
1156  /* Update the statistics for PagePrompt */
1157  dwSumReadBytes += dwReadBytes;
1158  dwSumReadChars += dwReadChars;
1159 
1160  if ((Encoding == ENCODING_UTF16LE) || (Encoding == ENCODING_UTF16BE))
1161  {
1162  bContinue = ConWritePaging(&Pager, PagePrompt, FALSE,
1163  FileCacheBuffer, dwReadChars);
1164  }
1165  else
1166  {
1167  bContinue = ConWritePaging(&Pager, PagePrompt, FALSE,
1168  StringBuffer, dwReadChars);
1169  }
1170  if (!bContinue)
1171  {
1172  /* We stop displaying this file */
1173  break;
1174  }
1175  }
1176  while (bRet && dwReadBytes > 0);
1177 
1178  /* Flush any cached pager buffers */
1179  if (bContinue)
1180  bContinue = ConWritePaging(&Pager, PagePrompt, FALSE, NULL, 0);
1181 
1182  CloseHandle(hFile);
1183 
1184  /* Check whether we should stop displaying this file */
1185  if (!bContinue)
1186  {
1187  if (s_bDoNextFile)
1188  {
1189  /* Bail out and continue with the other files */
1190  continue;
1191  }
1192 
1193  /* We Ctrl-C/Ctrl-Break, stop everything */
1194  goto Quit;
1195  }
1196  }
1197 
1198 Quit:
1200  HeapFree(GetProcessHeap(), 0, FileCacheBuffer);
1202  return 0;
1203 }
1204 
1205 /* EOF */
PCON_STREAM Stream
Definition: screen.h:43
#define FLAG_HELP
Definition: more.c:56
CONST WCHAR * PCWCH
Definition: ntbasedef.h:411
#define IDS_CONTINUE_OPTIONS
Definition: resource.h:10
static int argc
Definition: ServiceArgs.c:12
#define FLAG_Tn
Definition: more.c:61
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
#define CloseHandle
Definition: compat.h:598
WCHAR UnicodeChar
Definition: wincon.h:245
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define ERROR_SUCCESS
Definition: deptool.c:10
#define LOBYTE(W)
Definition: jmemdos.c:487
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
static WORD s_fPrompt
Definition: more.c:74
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
#define MAKEWORD(a, b)
Definition: typedefs.h:248
#define TRUE
Definition: types.h:120
uint16_t * PWSTR
Definition: typedefs.h:56
DWORD dwSumReadBytes
Definition: more.c:41
#define HKEY_CURRENT_USER
Definition: winreg.h:11
#define free
Definition: debug_ros.c:5
#define C1_BLANK
Definition: unicode.h:37
#define FLAG_S
Definition: more.c:60
BOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode)
Definition: console.c:1571
DWORD dwFileSize
Definition: more.c:40
#define IS_TEXT_UNICODE_NOT_ASCII_MASK
Definition: winnt_old.h:935
static const WCHAR szPercent[]
Definition: varformat.c:393
_Check_return_ _CRTIMP wchar_t *__cdecl wcstok(_Inout_opt_z_ wchar_t *_Str, _In_z_ const wchar_t *_Delim)
DWORD dwControlKeyState
Definition: wincon.h:248
#define HIBYTE(W)
Definition: jmemdos.c:486
#define PROMPT_LINE_AT
Definition: more.c:66
VOID ConClearLine(IN PCON_STREAM Stream)
Definition: outstream.c:1483
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define PROMPT_OPTIONS
Definition: more.c:67
#define INVALID_HANDLE_VALUE
Definition: compat.h:590
BOOL WINAPI FlushConsoleInputBuffer(IN HANDLE hConsoleInput)
Definition: console.c:217
#define FileCacheBufferSize
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1105
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:200
#define IS_TEXT_UNKNOWN_FLAGS_MASK
INT WINAPI K32LoadStringW(IN HINSTANCE hInstance OPTIONAL, IN UINT uID, OUT LPWSTR lpBuffer, IN INT nBufferMax)
Definition: utils.c:173
static BOOL ParseMoreVariable(BOOL *pbHasFiles)
Definition: more.c:907
#define IDS_USAGE
Definition: resource.h:3
#define IDS_BAD_FLAG
Definition: resource.h:4
#define INVALID_FILE_SIZE
Definition: winbase.h:545
_Check_return_ long __cdecl wcstol(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
#define VK_MENU
Definition: winuser.h:2184
static BOOL s_bPrevLineIsBlank
Definition: more.c:73
#define FILE_BEGIN
Definition: compat.h:620
uint16_t * PWCHAR
Definition: typedefs.h:56
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define CON_PAGER_EXPAND_TABS
Definition: pager.h:40
#define argv
Definition: mplay32.c:18
#define VK_ESCAPE
Definition: winuser.h:2194
int32_t INT
Definition: typedefs.h:58
#define VK_RETURN
Definition: winuser.h:2181
#define pch(ap)
Definition: match.c:418
#define FILE_SHARE_READ
Definition: compat.h:136
#define FLAG_PLUSn
Definition: more.c:62
#define IS_TEXT_UNICODE_SIGNATURE
Definition: winnt_old.h:926
WORD wVirtualKeyCode
Definition: wincon.h:242
union _KEY_EVENT_RECORD::@3205 uChar
void ConPuts(FILE *fp, LPCWSTR psz)
Definition: fc.c:16
#define FLAG_P
Definition: more.c:59
PCON_SCREEN Screen
Definition: pager.h:48
#define FLAG_E
Definition: more.c:57
LONG nTabWidth
Definition: pager.h:55
#define L(x)
Definition: ntvdm.h:50
DWORD dwFlags
Definition: pager.h:54
#define CP_UTF8
Definition: nls.h:20
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
#define ReadConsoleInput
Definition: wincon.h:778
long LONG
Definition: pedump.c:60
#define FLAG_C
Definition: more.c:58
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode)
Definition: console.c:1608
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add)
Definition: console.c:2111
#define GENERIC_WRITE
Definition: nt_native.h:90
HANDLE hStdOut
Definition: more.c:49
#define KEY_EVENT
Definition: wincon.h:128
#define PROMPT_LINES
Definition: more.c:68
#define VK_SHIFT
Definition: winuser.h:2182
PVOID pBuffer
BOOL WINAPI SetConsoleCursorPosition(IN HANDLE hConsoleOutput, IN COORD dwCursorPosition)
Definition: console.c:638
INT ConStreamWrite(IN PCON_STREAM Stream, IN PCTCH szStr, IN DWORD len)
Definition: outstream.c:398
Definition: parser.c:48
Definition: bufpool.h:45
#define C_ASSERT(e)
Definition: intsafe.h:73
UINT WINAPI DECLSPEC_HOTPATCH GetConsoleCP(VOID)
Definition: console.c:2393
void ConResPuts(FILE *fp, UINT nID)
Definition: fc.c:27
#define STD_INPUT_HANDLE
Definition: winbase.h:264
_Must_inspect_result_ _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS SkipBytes
Definition: mmfuncs.h:226
#define OPEN_EXISTING
Definition: compat.h:634
ULONG X
Definition: bl.h:1340
CON_PAGER_LINE_FN PagerLine
Definition: pager.h:53
HANDLE ConStreamGetOSHandle(IN PCON_STREAM Stream)
Definition: stream.c:240
#define IS_TEXT_UNICODE_REVERSE_SIGNATURE
Definition: winnt_old.h:927
char TCHAR
Definition: xmlstorage.h:189
BOOL ConStreamInit(OUT PCON_STREAM Stream, IN PVOID Handle, IN CON_STREAM_MODE Mode, IN UINT CacheCodePage OPTIONAL)
Definition: stream.c:185
#define CON_PAGER_EXPAND_FF
Definition: pager.h:41
static BOOL IsDataUnicode(IN PVOID Buffer, IN DWORD BufferSize, OUT ENCODING *Encoding OPTIONAL, OUT PDWORD SkipBytes OPTIONAL)
Definition: more.c:500
void ConResPrintf(FILE *fp, UINT nID,...)
Definition: fc.c:33
BOOL WINAPI IsTextUnicode(IN CONST VOID *lpv, IN INT iSize, IN OUT LPINT lpiResult OPTIONAL)
Definition: unicode.c:27
#define GetProcessHeap()
Definition: compat.h:595
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
SHORT Bottom
Definition: blue.h:35
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4120
__wchar_t WCHAR
Definition: xmlstorage.h:180
BOOL WINAPI GetStringTypeW(DWORD type, LPCWSTR src, INT count, LPWORD chartype)
Definition: lang.c:1703
static BOOL s_bDoNextFile
Definition: more.c:75
#define STD_ERROR_HANDLE
Definition: winbase.h:266
GLfloat param
Definition: glext.h:5796
#define MAX_PATH
Definition: compat.h:34
static BOOL IsFlag(PCWSTR param)
Definition: more.c:807
KEY_EVENT_RECORD KeyEvent
Definition: wincon.h:275
unsigned short WORD
Definition: ntddk_ex.h:93
static BOOL IsBlankLine(IN PCWCH line, IN DWORD cch)
Definition: more.c:77
unsigned long DWORD
Definition: ntddk_ex.h:95
#define IDS_CONTINUE_PERCENT
Definition: resource.h:8
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
Definition: fileinfo.c:331
#define __stdcall
Definition: typedefs.h:25
static BOOL FileGetString(IN HANDLE hFile, IN ENCODING Encoding, IN OUT PVOID pCacheBuffer, IN DWORD CacheBufferLength, IN OUT PWCHAR *pBuffer, IN OUT PDWORD pnBufferLength, OUT PDWORD pdwReadBytes OPTIONAL, OUT PDWORD pdwReadChars OPTIONAL)
Definition: more.c:652
SHORT Top
Definition: blue.h:33
#define CT_CTYPE1
Definition: winnls.h:237
#define IDS_CONTINUE_LINES
Definition: resource.h:11
#define INVALID_CP
Definition: stream.h:53
static DWORD s_dwFlags
Definition: more.c:70
int ret
int wmain(int argc, WCHAR *argv[])
Definition: more.c:940
#define LEFT_CTRL_PRESSED
Definition: wincon.h:140
static BOOL ParseArgument(PCWSTR arg, BOOL *pbHasFiles)
Definition: more.c:827
BOOL ConStreamSetOSHandle(IN PCON_STREAM Stream, IN HANDLE Handle)
Definition: stream.c:263
DWORD ScrollRows
Definition: pager.h:56
GLenum GLsizei len
Definition: glext.h:6722
#define GENERIC_READ
Definition: compat.h:135
#define STD_OUTPUT_HANDLE
Definition: winbase.h:265
VOID ConClearScreen(IN PCON_SCREEN Screen)
Definition: screen.c:131
static VOID LoadRegistrySettings(HKEY hKeyRoot)
Definition: more.c:767
#define VK_BACK
Definition: winuser.h:2178
_In_ HANDLE hFile
Definition: mswsock.h:90
static DWORD s_nNextLineNo
Definition: more.c:72
Definition: bl.h:1338
#define IS_TEXT_UNICODE_ILLEGAL_CHARS
Definition: winnt_old.h:928
static LONG s_nTabWidth
Definition: more.c:71
#define CON_PAGER_CACHE_INCOMPLETE_LINE
Definition: pager.h:43
DWORD dwSumReadChars
Definition: more.c:41
#define ENABLE_PROCESSED_INPUT
Definition: wincon.h:78
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
ENCODING
Definition: more.c:491
HANDLE hStdIn
Definition: more.c:49
#define TEXT(s)
Definition: k32.h:26
BOOL bEnableExtensions
Definition: more.c:53
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
FxAutoRegKey hKey
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define HeapReAlloc
Definition: compat.h:593
STRSAFEAPI StringCchPrintfW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:530
DWORD lineno
Definition: pager.h:70
union _INPUT_RECORD::@3206 Event
#define ReadFile(a, b, c, d, e)
Definition: compat.h:601
unsigned int UINT
Definition: ndis.h:50
_Check_return_ _CRTIMP long __cdecl _wtol(_In_z_ const wchar_t *_Str)
#define NULL
Definition: types.h:112
#define VK_SPACE
Definition: winuser.h:2199
DWORD * PDWORD
Definition: pedump.c:68
#define MultiByteToWideChar
Definition: compat.h:110
#define VK_CONTROL
Definition: winuser.h:2183
WORD EventType
Definition: wincon.h:273
#define CreateFileW
Definition: compat.h:600
#define StdOut
Definition: fc.c:14
#define IDS_CONTINUE_LINE_AT
Definition: resource.h:9
#define OUT
Definition: typedefs.h:40
#define IS_TEXT_UNICODE_REVERSE_MASK
Definition: winnt_old.h:933
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3356
#define IDS_FILE_ACCESS
Definition: resource.h:5
Definition: console.h:34
#define malloc
Definition: debug_ros.c:4
#define C1_SPACE
Definition: unicode.h:34
HANDLE hKeyboard
Definition: more.c:50
#define RIGHT_CTRL_PRESSED
Definition: wincon.h:139
#define IDS_CONTINUE_PROMPT
Definition: resource.h:7
#define towupper(c)
Definition: wctype.h:99
static BOOL __stdcall MorePagerLine(IN OUT PCON_PAGER Pager, IN PCWCH line, IN DWORD cch)
Definition: more.c:106
#define PROMPT_PERCENT
Definition: more.c:65
IN PCTCH IN DWORD cch
Definition: pager.h:36
#define GetEnvironmentVariableW(x, y, z)
Definition: compat.h:614
ULONG Y
Definition: bl.h:1341
#define REG_DWORD
Definition: sdbapi.c:596
#define IS_TEXT_UNICODE_NULL_BYTES
Definition: winnt_old.h:931
WCHAR StringBuffer[156]
Definition: ldrinit.c:41
BYTE * PBYTE
Definition: pedump.c:66
#define IS_TEXT_UNICODE_UNICODE_MASK
Definition: winnt_old.h:932
#define HeapFree(x, y, z)
Definition: compat.h:594
struct test_data Tests[]
#define RegCloseKey(hKey)
Definition: registry.h:40
#define SetFilePointer
Definition: compat.h:602
#define StdIn
Definition: stream.h:81
INT __cdecl ConResMsgPrintf(IN PCON_STREAM Stream, IN DWORD dwFlags, IN UINT uID,...)
Definition: outstream.c:1461
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:251
#define IS_TEXT_UNICODE_NOT_UNICODE_MASK
Definition: winnt_old.h:934
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define StdErr
Definition: fc.c:15
#define REG_SZ
Definition: layer.c:22
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68