ReactOS 0.4.15-dev-7788-g1ad9096
more.c File Reference
#include <stdio.h>
#include <stdlib.h>
#include <windef.h>
#include <winbase.h>
#include <winnt.h>
#include <winnls.h>
#include <winreg.h>
#include <winuser.h>
#include <conutils.h>
#include <strsafe.h>
#include "resource.h"
Include dependency graph for more.c:

Go to the source code of this file.

Macros

#define FLAG_HELP   (1 << 0)
 
#define FLAG_E   (1 << 1)
 
#define FLAG_C   (1 << 2)
 
#define FLAG_P   (1 << 3)
 
#define FLAG_S   (1 << 4)
 
#define FLAG_Tn   (1 << 5)
 
#define FLAG_PLUSn   (1 << 6)
 
#define PROMPT_PERCENT   (1 << 0)
 
#define PROMPT_LINE_AT   (1 << 1)
 
#define PROMPT_OPTIONS   (1 << 2)
 
#define PROMPT_LINES   (1 << 3)
 
#define IS_TEXT_UNKNOWN_FLAGS_MASK   ((7 << 13) | (1 << 11))
 
#define FileCacheBufferSize   4096
 

Enumerations

enum  ENCODING {
  ENCODING_ANSI = 0 , ENCODING_UTF16LE = 1 , ENCODING_UTF16BE = 2 , ENCODING_UTF8 = 3 ,
  ENCODING_AUTO = -1 , ENCODING_ANSI = 0 , ENCODING_UTF16LE = 1 , ENCODING_UTF16BE = 2 ,
  ENCODING_UTF8 = 3 , ENCODING_UTF8BOM = 4 , ENCODING_ANSI = 0 , ENCODING_UTF16LE = 1 ,
  ENCODING_UTF16BE = 2 , ENCODING_UTF8 = 3 , ENCODING_ANSI = 1 , ENCODING_UTF8 ,
  ENCODING_UTF16LE , ENCODING_UTF16BE
}
 

Functions

static BOOL IsBlankLine (IN PCWCH line, IN DWORD cch)
 
static BOOL __stdcall MorePagerLine (IN OUT PCON_PAGER Pager, IN PCWCH line, IN DWORD cch)
 
static BOOL __stdcall PagePrompt (PCON_PAGER Pager, DWORD Done, DWORD Total)
 
static BOOL IsDataUnicode (IN PVOID Buffer, IN DWORD BufferSize, OUT ENCODING *Encoding OPTIONAL, OUT PDWORD SkipBytes OPTIONAL)
 
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)
 
static VOID LoadRegistrySettings (HKEY hKeyRoot)
 
static BOOL IsFlag (PCWSTR param)
 
static BOOL ParseArgument (PCWSTR arg, BOOL *pbHasFiles)
 
static BOOL ParseMoreVariable (BOOL *pbHasFiles)
 
int wmain (int argc, WCHAR *argv[])
 

Variables

DWORD dwFileSize
 
DWORD dwSumReadBytes
 
DWORD dwSumReadChars
 
HANDLE hFile = INVALID_HANDLE_VALUE
 
HANDLE hStdIn
 
HANDLE hStdOut
 
HANDLE hKeyboard
 
BOOL bEnableExtensions = TRUE
 
static DWORD s_dwFlags = 0
 
static LONG s_nTabWidth = 8
 
static DWORD s_nNextLineNo = 0
 
static BOOL s_bPrevLineIsBlank = FALSE
 
static WORD s_fPrompt = 0
 
static BOOL s_bDoNextFile = FALSE
 

Macro Definition Documentation

◆ FileCacheBufferSize

#define FileCacheBufferSize   4096

◆ FLAG_C

#define FLAG_C   (1 << 2)

Definition at line 58 of file more.c.

◆ FLAG_E

#define FLAG_E   (1 << 1)

Definition at line 57 of file more.c.

◆ FLAG_HELP

#define FLAG_HELP   (1 << 0)

Definition at line 56 of file more.c.

◆ FLAG_P

#define FLAG_P   (1 << 3)

Definition at line 59 of file more.c.

◆ FLAG_PLUSn

#define FLAG_PLUSn   (1 << 6)

Definition at line 62 of file more.c.

◆ FLAG_S

#define FLAG_S   (1 << 4)

Definition at line 60 of file more.c.

◆ FLAG_Tn

#define FLAG_Tn   (1 << 5)

Definition at line 61 of file more.c.

◆ IS_TEXT_UNKNOWN_FLAGS_MASK

#define IS_TEXT_UNKNOWN_FLAGS_MASK   ((7 << 13) | (1 << 11))

◆ PROMPT_LINE_AT

#define PROMPT_LINE_AT   (1 << 1)

Definition at line 66 of file more.c.

◆ PROMPT_LINES

#define PROMPT_LINES   (1 << 3)

Definition at line 68 of file more.c.

◆ PROMPT_OPTIONS

#define PROMPT_OPTIONS   (1 << 2)

Definition at line 67 of file more.c.

◆ PROMPT_PERCENT

#define PROMPT_PERCENT   (1 << 0)

Definition at line 65 of file more.c.

Enumeration Type Documentation

◆ ENCODING

Enumerator
ENCODING_ANSI 
ENCODING_UTF16LE 
ENCODING_UTF16BE 
ENCODING_UTF8 
ENCODING_AUTO 
ENCODING_ANSI 
ENCODING_UTF16LE 
ENCODING_UTF16BE 
ENCODING_UTF8 
ENCODING_UTF8BOM 
ENCODING_ANSI 
ENCODING_UTF16LE 
ENCODING_UTF16BE 
ENCODING_UTF8 
ENCODING_ANSI 
ENCODING_UTF8 
ENCODING_UTF16LE 
ENCODING_UTF16BE 

Definition at line 491 of file more.c.

492{
493 ENCODING_ANSI = 0,
496 ENCODING_UTF8 = 3
497} ENCODING;
ENCODING
Definition: more.c:492
@ ENCODING_UTF16BE
Definition: more.c:495
@ ENCODING_UTF8
Definition: more.c:496
@ ENCODING_UTF16LE
Definition: more.c:494
@ ENCODING_ANSI
Definition: more.c:493

Function Documentation

◆ FileGetString()

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 
)
static

Definition at line 652 of file more.c.

661{
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}
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define GetProcessHeap()
Definition: compat.h:736
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define HeapAlloc
Definition: compat.h:733
#define HeapReAlloc
Definition: compat.h:734
#define HeapFree(x, y, z)
Definition: compat.h:735
#define MultiByteToWideChar
Definition: compat.h:110
UINT WINAPI DECLSPEC_HOTPATCH GetConsoleCP(VOID)
Definition: console.c:2391
@ Success
Definition: eventcreate.c:712
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLenum GLsizei len
Definition: glext.h:6722
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
#define LOBYTE(W)
Definition: jmemdos.c:487
#define HIBYTE(W)
Definition: jmemdos.c:486
_In_ HANDLE hFile
Definition: mswsock.h:90
unsigned int UINT
Definition: ndis.h:50
PVOID pBuffer
#define CP_UTF8
Definition: nls.h:20
uint16_t * PWSTR
Definition: typedefs.h:56
#define MAKEWORD(a, b)
Definition: typedefs.h:248
int32_t INT
Definition: typedefs.h:58
uint16_t * PWCHAR
Definition: typedefs.h:56
__wchar_t WCHAR
Definition: xmlstorage.h:180

Referenced by wmain().

◆ IsBlankLine()

static BOOL IsBlankLine ( IN PCWCH  line,
IN DWORD  cch 
)
static

Definition at line 77 of file more.c.

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}
unsigned short WORD
Definition: ntddk_ex.h:93
#define C1_SPACE
Definition: unicode.h:34
#define C1_BLANK
Definition: unicode.h:37
BOOL WINAPI GetStringTypeW(DWORD type, LPCWSTR src, INT count, LPWORD chartype)
Definition: lang.c:1709
static DWORD DWORD void LPSTR DWORD cch
Definition: str.c:202
#define L(x)
Definition: ntvdm.h:50
Definition: parser.c:49
#define CT_CTYPE1
Definition: winnls.h:237

Referenced by MorePagerLine().

◆ IsDataUnicode()

static BOOL IsDataUnicode ( IN PVOID  Buffer,
IN DWORD  BufferSize,
OUT ENCODING *Encoding  OPTIONAL,
OUT PDWORD SkipBytes  OPTIONAL 
)
static

Definition at line 500 of file more.c.

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}
struct test_data Tests[]
Definition: bufpool.h:45
BOOL WINAPI IsTextUnicode(IN CONST VOID *lpv, IN INT iSize, IN OUT LPINT lpiResult OPTIONAL)
Definition: unicode.c:27
#define IS_TEXT_UNKNOWN_FLAGS_MASK
BYTE * PBYTE
Definition: pedump.c:66
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
#define IS_TEXT_UNICODE_ILLEGAL_CHARS
Definition: winnt_old.h:894
#define IS_TEXT_UNICODE_UNICODE_MASK
Definition: winnt_old.h:898
#define IS_TEXT_UNICODE_NOT_ASCII_MASK
Definition: winnt_old.h:901
#define IS_TEXT_UNICODE_NULL_BYTES
Definition: winnt_old.h:897
#define IS_TEXT_UNICODE_REVERSE_MASK
Definition: winnt_old.h:899
#define IS_TEXT_UNICODE_REVERSE_SIGNATURE
Definition: winnt_old.h:893
#define IS_TEXT_UNICODE_NOT_UNICODE_MASK
Definition: winnt_old.h:900
#define IS_TEXT_UNICODE_SIGNATURE
Definition: winnt_old.h:892
_Must_inspect_result_ _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS SkipBytes
Definition: mmfuncs.h:227

Referenced by wmain().

◆ IsFlag()

static BOOL IsFlag ( PCWSTR  param)
static

Definition at line 807 of file more.c.

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}
GLfloat param
Definition: glext.h:5796
_Check_return_ long __cdecl wcstol(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
#define pch(ap)
Definition: match.c:418
const uint16_t * PCWSTR
Definition: typedefs.h:57

Referenced by ParseArgument(), and wmain().

◆ LoadRegistrySettings()

static VOID LoadRegistrySettings ( HKEY  hKeyRoot)
static

Definition at line 767 of file more.c.

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)
801 }
802 // else, use the default setting set globally.
803
805}
#define RegCloseKey(hKey)
Definition: registry.h:49
#define ERROR_SUCCESS
Definition: deptool.c:10
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3362
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4132
FxAutoRegKey hKey
_Check_return_ _CRTIMP long __cdecl _wtol(_In_z_ const wchar_t *_Str)
#define C_ASSERT(e)
Definition: intsafe.h:73
#define REG_SZ
Definition: layer.c:22
BOOL bEnableExtensions
Definition: more.c:53
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
DWORD * PDWORD
Definition: pedump.c:68
long LONG
Definition: pedump.c:60
#define REG_DWORD
Definition: sdbapi.c:596

Referenced by wmain().

◆ MorePagerLine()

static BOOL __stdcall MorePagerLine ( IN OUT PCON_PAGER  Pager,
IN PCWCH  line,
IN DWORD  cch 
)
static

Definition at line 106 of file more.c.

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 {
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}
#define TEXT(s)
Definition: k32.h:26
static BOOL s_bPrevLineIsBlank
Definition: more.c:73
static BOOL IsBlankLine(IN PCWCH line, IN DWORD cch)
Definition: more.c:77
#define FLAG_S
Definition: more.c:60
#define FLAG_PLUSn
Definition: more.c:62
static DWORD s_nNextLineNo
Definition: more.c:72
static DWORD s_dwFlags
Definition: more.c:70
INT ConStreamWrite(IN PCON_STREAM Stream, IN PCTCH szStr, IN DWORD len)
Definition: outstream.c:398

Referenced by wmain().

◆ PagePrompt()

static BOOL __stdcall PagePrompt ( PCON_PAGER  Pager,
DWORD  Done,
DWORD  Total 
)
static

Definition at line 160 of file more.c.

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
201Restart:
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}
#define IDS_CONTINUE_OPTIONS
Definition: resource.h:10
#define IDS_CONTINUE_LINES
Definition: resource.h:11
#define IDS_CONTINUE_LINE_AT
Definition: resource.h:9
#define IDS_CONTINUE_PROMPT
Definition: resource.h:7
#define IDS_CONTINUE_PERCENT
Definition: resource.h:8
BOOL WINAPI SetConsoleCursorPosition(IN HANDLE hConsoleOutput, IN COORD dwCursorPosition)
Definition: console.c:641
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
BOOL WINAPI GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode)
Definition: console.c:1569
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode)
Definition: console.c:1606
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add)
Definition: console.c:2109
static const WCHAR szPercent[]
Definition: varformat.c:393
#define PROMPT_PERCENT
Definition: more.c:65
DWORD dwSumReadBytes
Definition: more.c:41
#define PROMPT_LINE_AT
Definition: more.c:66
#define PROMPT_LINES
Definition: more.c:68
DWORD dwFileSize
Definition: more.c:40
#define PROMPT_OPTIONS
Definition: more.c:67
#define FLAG_C
Definition: more.c:58
DWORD dwSumReadChars
Definition: more.c:41
#define FLAG_E
Definition: more.c:57
static BOOL s_bDoNextFile
Definition: more.c:75
static WORD s_fPrompt
Definition: more.c:74
INT __cdecl ConResMsgPrintf(IN PCON_STREAM Stream, IN DWORD dwFlags, IN UINT uID,...)
Definition: outstream.c:1461
VOID ConClearLine(IN PCON_STREAM Stream)
Definition: outstream.c:1483
@ Restart
Definition: sacdrv.h:269
BOOL ConGetScreenInfo(IN PCON_SCREEN Screen, OUT PCONSOLE_SCREEN_BUFFER_INFO pcsbi)
Definition: screen.c:73
VOID ConClearScreen(IN PCON_SCREEN Screen)
Definition: screen.c:131
HANDLE ConStreamGetOSHandle(IN PCON_STREAM Stream)
Definition: stream.c:240
#define StdIn
Definition: stream.h:81
INT WINAPI K32LoadStringW(IN HINSTANCE hInstance OPTIONAL, IN UINT uID, OUT LPWSTR lpBuffer, IN INT nBufferMax)
Definition: utils.c:173
STRSAFEAPI StringCchPrintfW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:530
DWORD lineno
Definition: pager.h:70
DWORD ScrollRows
Definition: pager.h:56
PCON_SCREEN Screen
Definition: pager.h:48
PCON_STREAM Stream
Definition: screen.h:43
Definition: bl.h:1338
ULONG Y
Definition: bl.h:1340
ULONG X
Definition: bl.h:1339
union _INPUT_RECORD::@3287 Event
WORD EventType
Definition: wincon.h:273
KEY_EVENT_RECORD KeyEvent
Definition: wincon.h:275
DWORD dwControlKeyState
Definition: wincon.h:248
WORD wVirtualKeyCode
Definition: wincon.h:242
union _KEY_EVENT_RECORD::@3286 uChar
WCHAR UnicodeChar
Definition: wincon.h:245
SHORT Y
Definition: blue.h:27
SHORT X
Definition: blue.h:26
SHORT Top
Definition: blue.h:33
SHORT Bottom
Definition: blue.h:35
#define LEFT_CTRL_PRESSED
Definition: wincon.h:140
#define ReadConsoleInput
Definition: wincon.h:778
#define KEY_EVENT
Definition: wincon.h:128
#define RIGHT_CTRL_PRESSED
Definition: wincon.h:139
#define ENABLE_PROCESSED_INPUT
Definition: wincon.h:78
#define VK_SPACE
Definition: winuser.h:2219
#define VK_CONTROL
Definition: winuser.h:2203
#define VK_RETURN
Definition: winuser.h:2201
#define VK_BACK
Definition: winuser.h:2198
#define VK_SHIFT
Definition: winuser.h:2202
#define VK_ESCAPE
Definition: winuser.h:2214
#define VK_MENU
Definition: winuser.h:2204

Referenced by ConOutResPaging(), ConPrintfVPaging(), ConPutsPaging(), ConResPaging(), ConResPagingEx(), ConWritePaging(), and wmain().

◆ ParseArgument()

static BOOL ParseArgument ( PCWSTR  arg,
BOOL pbHasFiles 
)
static

Definition at line 827 of file more.c.

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 {
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 {
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}
void ConResPrintf(FILE *fp, UINT nID,...)
Definition: fc.c:33
#define StdErr
Definition: fc.c:15
#define IDS_BAD_FLAG
Definition: resource.h:4
#define FLAG_Tn
Definition: more.c:61
#define FLAG_P
Definition: more.c:59
static LONG s_nTabWidth
Definition: more.c:71
static BOOL IsFlag(PCWSTR param)
Definition: more.c:807
#define FLAG_HELP
Definition: more.c:56
#define towupper(c)
Definition: wctype.h:99

Referenced by ParseMoreVariable(), and wmain().

◆ ParseMoreVariable()

static BOOL ParseMoreVariable ( BOOL pbHasFiles)
static

Definition at line 907 of file more.c.

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}
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define GetEnvironmentVariableW(x, y, z)
Definition: compat.h:755
static BOOL ParseArgument(PCWSTR arg, BOOL *pbHasFiles)
Definition: more.c:827
_Check_return_ _CRTIMP wchar_t *__cdecl wcstok(_Inout_opt_z_ wchar_t *_Str, _In_z_ const wchar_t *_Delim)
int ret

Referenced by wmain().

◆ wmain()

int wmain ( int  argc,
WCHAR argv[] 
)

Definition at line 940 of file more.c.

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 */
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)
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,
1089 NULL,
1091 0, // FILE_ATTRIBUTE_NORMAL,
1092 NULL);
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");
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;
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 */
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
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
1198Quit:
1200 HeapFree(GetProcessHeap(), 0, FileCacheBuffer);
1202 return 0;
1203}
static int argc
Definition: ServiceArgs.c:12
#define IDS_USAGE
Definition: resource.h:3
void ConPuts(FILE *fp, LPCWSTR psz)
Definition: fc.c:16
#define StdOut
Definition: fc.c:14
void ConResPuts(FILE *fp, UINT nID)
Definition: fc.c:27
#define IDS_FILE_ACCESS
Definition: resource.h:5
BOOL WINAPI FlushConsoleInputBuffer(IN HANDLE hConsoleInput)
Definition: console.c:220
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:203
@ Screen
Definition: console.h:34
#define CloseHandle
Definition: compat.h:739
#define FILE_BEGIN
Definition: compat.h:761
#define OPEN_EXISTING
Definition: compat.h:775
#define SetFilePointer
Definition: compat.h:743
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define CreateFileW
Definition: compat.h:741
#define FILE_SHARE_READ
Definition: compat.h:136
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
Definition: fileinfo.c:331
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1106
WCHAR StringBuffer[156]
Definition: ldrinit.c:41
static BOOL __stdcall MorePagerLine(IN OUT PCON_PAGER Pager, IN PCWCH line, IN DWORD cch)
Definition: more.c:106
static VOID LoadRegistrySettings(HKEY hKeyRoot)
Definition: more.c:767
static BOOL ParseMoreVariable(BOOL *pbHasFiles)
Definition: more.c:907
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
static BOOL __stdcall PagePrompt(PCON_PAGER Pager, DWORD Done, DWORD Total)
Definition: more.c:160
HANDLE hStdOut
Definition: more.c:49
#define FileCacheBufferSize
HANDLE hStdIn
Definition: more.c:49
HANDLE hKeyboard
Definition: more.c:50
static BOOL IsDataUnicode(IN PVOID Buffer, IN DWORD BufferSize, OUT ENCODING *Encoding OPTIONAL, OUT PDWORD SkipBytes OPTIONAL)
Definition: more.c:500
#define argv
Definition: mplay32.c:18
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define GENERIC_WRITE
Definition: nt_native.h:90
#define CON_PAGER_EXPAND_TABS
Definition: pager.h:40
#define CON_PAGER_CACHE_INCOMPLETE_LINE
Definition: pager.h:43
#define CON_PAGER_EXPAND_FF
Definition: pager.h:41
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
BOOL ConWritePaging(IN PCON_PAGER Pager, IN PAGE_PROMPT PagePrompt, IN BOOL StartPaging, IN PCTCH szStr, IN DWORD len)
Definition: pager.c:549
BOOL ConStreamSetOSHandle(IN PCON_STREAM Stream, IN HANDLE Handle)
Definition: stream.c:263
BOOL ConStreamInit(OUT PCON_STREAM Stream, IN PVOID Handle, IN CON_STREAM_MODE Mode, IN UINT CacheCodePage OPTIONAL)
Definition: stream.c:185
@ UTF8Text
Definition: stream.h:50
#define INVALID_CP
Definition: stream.h:53
DWORD dwFlags
Definition: pager.h:54
LONG nTabWidth
Definition: pager.h:55
CON_PAGER_LINE_FN PagerLine
Definition: pager.h:53
#define STD_OUTPUT_HANDLE
Definition: winbase.h:268
#define STD_INPUT_HANDLE
Definition: winbase.h:267
#define STD_ERROR_HANDLE
Definition: winbase.h:269
#define INVALID_FILE_SIZE
Definition: winbase.h:548
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define HKEY_CURRENT_USER
Definition: winreg.h:11
char TCHAR
Definition: xmlstorage.h:189

Variable Documentation

◆ bEnableExtensions

◆ dwFileSize

◆ dwSumReadBytes

DWORD dwSumReadBytes

Definition at line 41 of file more.c.

Referenced by PagePrompt(), and wmain().

◆ dwSumReadChars

DWORD dwSumReadChars

Definition at line 41 of file more.c.

Referenced by PagePrompt(), and wmain().

◆ hFile

Definition at line 48 of file more.c.

◆ hKeyboard

HANDLE hKeyboard

Definition at line 50 of file more.c.

Referenced by wmain().

◆ hStdIn

HANDLE hStdIn

Definition at line 49 of file more.c.

Referenced by ConsolePager(), doChild(), InputChar(), and wmain().

◆ hStdOut

HANDLE hStdOut

Definition at line 49 of file more.c.

Referenced by ConsolePager(), doChild(), and wmain().

◆ s_bDoNextFile

BOOL s_bDoNextFile = FALSE
static

Definition at line 75 of file more.c.

Referenced by PagePrompt(), and wmain().

◆ s_bPrevLineIsBlank

BOOL s_bPrevLineIsBlank = FALSE
static

Definition at line 73 of file more.c.

Referenced by MorePagerLine(), and wmain().

◆ s_dwFlags

DWORD s_dwFlags = 0
static

Definition at line 70 of file more.c.

Referenced by MorePagerLine(), PagePrompt(), ParseArgument(), and wmain().

◆ s_fPrompt

WORD s_fPrompt = 0
static

Definition at line 74 of file more.c.

Referenced by PagePrompt(), and wmain().

◆ s_nNextLineNo

DWORD s_nNextLineNo = 0
static

Definition at line 72 of file more.c.

Referenced by MorePagerLine(), PagePrompt(), ParseArgument(), and wmain().

◆ s_nTabWidth

LONG s_nTabWidth = 8
static

Definition at line 71 of file more.c.

Referenced by ParseArgument(), and wmain().