mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 17:05:46 +00:00
[MORE]: Rewrite almost completely the MORE command, taking advantage of the console pager functionality of the ConUtils library (see CORE-10504 and commit r73024).
- When displaying files, display the percentage of file read so far in the "Continue" prompt. Otherwise (when being piped or feeded from StdIn), just display the "Continue" prompt without percentage. - Try to detect the text file encoding (ANSI, UTF16-BE/BE w/ or w/o BOM; UTF-8 to do!!) before displaying it. See the code for more details. NOTE that the other functionalities of more (being able to scroll one line at a time, other command-line switches, etc...) are still not implemented yet. svn path=/trunk/; revision=73025
This commit is contained in:
parent
eb198b854d
commit
6f5d03b414
25 changed files with 670 additions and 222 deletions
|
@ -1,6 +1,11 @@
|
|||
|
||||
PROJECT(more)
|
||||
|
||||
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
||||
|
||||
add_executable(more more.c more.rc)
|
||||
set_module_type(more win32cui)
|
||||
set_module_type(more win32cui UNICODE)
|
||||
target_link_libraries(more conutils_pager ${PSEH_LIB})
|
||||
add_importlibs(more advapi32 user32 msvcrt kernel32)
|
||||
set_target_properties(more PROPERTIES SUFFIX ".com")
|
||||
add_importlibs(more user32 msvcrt kernel32)
|
||||
add_cd_file(TARGET more DESTINATION reactos/system32 FOR all)
|
||||
|
|
|
@ -9,6 +9,7 @@ BEGIN
|
|||
[Устройство:][Път]Файлово име Файл, чието съдържание да бъде показано.\n\
|
||||
Команда\t\t Команда, чийто изход да бъде показан.\n\n\
|
||||
При въпроса ""-- Продължаване --"" натиснете произволен клавиш, за показаване на следващата страница.\n"
|
||||
IDS_CONTINUE " -- Продължаване (100%) -- "
|
||||
IDS_FILE_ACCESS "Няма достъп до файл %s."
|
||||
IDS_CONTINUE "-- Продължаване --"
|
||||
IDS_CONTINUE_PROGRESS "-- Продължаване (%d%%) --"
|
||||
IDS_FILE_ACCESS "Няма достъп до файл %s.\n"
|
||||
END
|
||||
|
|
|
@ -9,6 +9,7 @@ BEGIN
|
|||
[Unitat:][Ruta]Nom del fitxer Un fitxer, el contingut del qual serà mostrat.\n\
|
||||
Instrucció\t\t Una instrucció, el resultat de la qual serà mostrada.\n\n\
|
||||
Al visualitzar ""-- Continua --"" heu de premer qualsevol tecla per visualitzar la següent pàgina.\n"
|
||||
IDS_CONTINUE " -- Continua (100%) -- "
|
||||
IDS_FILE_ACCESS "No puc accedir al fitxer %s."
|
||||
IDS_CONTINUE "-- Continua --"
|
||||
IDS_CONTINUE_PROGRESS "-- Continua (%d%%) --"
|
||||
IDS_FILE_ACCESS "No puc accedir al fitxer %s.\n"
|
||||
END
|
||||
|
|
|
@ -16,6 +16,7 @@ BEGIN
|
|||
Příkaz\t\t Příkaz, jehož výstup bude zobrazen.\n\n\
|
||||
Při výzvě ""-- Pokračovat --"" lze stisknout libovolnou klávesu\n\
|
||||
pro zobrazení další stránky.\n"
|
||||
IDS_CONTINUE " -- Pokračovat (100%) -- "
|
||||
IDS_FILE_ACCESS "Nelze získat přístup k souboru %s."
|
||||
IDS_CONTINUE "-- Pokračovat --"
|
||||
IDS_CONTINUE_PROGRESS "-- Pokračovat (%d%%) --"
|
||||
IDS_FILE_ACCESS "Nelze získat přístup k souboru %s.\n"
|
||||
END
|
||||
|
|
|
@ -10,6 +10,7 @@ BEGIN
|
|||
Befehl\t\t Ein Befehl, dessen Ausgabe angezeigt werden soll.\n\n\
|
||||
An der Eingabeaufforderung ""-- Fortsetzung --"" kann eine beliebige\n\
|
||||
Taste gedrückt werden, um die nächste Seite anzuzeigen.\n"
|
||||
IDS_CONTINUE " -- Fortsetzung (100%) -- "
|
||||
IDS_FILE_ACCESS "Auf die Datei %s kann nicht zugegriffen werden."
|
||||
IDS_CONTINUE "-- Fortsetzung --"
|
||||
IDS_CONTINUE_PROGRESS "-- Fortsetzung (%d%%) --"
|
||||
IDS_FILE_ACCESS "Auf die Datei %s kann nicht zugegriffen werden.\n"
|
||||
END
|
||||
|
|
|
@ -9,6 +9,7 @@ BEGIN
|
|||
[Δίσκος:][Μονοπάτι]Όνομα αρχείου Το αρχείο, τα δεδομένα του οποίου θα εμφανιστούν.\n\
|
||||
Εντολή\t\t Η εντολή, της οποίας η έξοδος θα εμφανιστεί.\n\n\
|
||||
Στη γραμμή εντολών ""-- Συνέχεια --"" μπορείτε να πατήσετε οποιοδήποτε κουμπί για να δείτε την επόμενη σελίδα.\n"
|
||||
IDS_CONTINUE " -- Συνέχεια (100%) -- "
|
||||
IDS_FILE_ACCESS "Δεν ήταν δυνατή η προσπέλαση του αρχείου %s."
|
||||
IDS_CONTINUE "-- Συνέχεια --"
|
||||
IDS_CONTINUE_PROGRESS "-- Συνέχεια (%d%%) --"
|
||||
IDS_FILE_ACCESS "Δεν ήταν δυνατή η προσπέλαση του αρχείου %s.\n"
|
||||
END
|
||||
|
|
|
@ -9,6 +9,7 @@ BEGIN
|
|||
[Drive:][Path]File name A file, whose content shall be displayed.\n\
|
||||
Command\t\t A command, whose output shall be displayed.\n\n\
|
||||
At the prompt ""-- Continue --"" you can press any key to show the next page.\n"
|
||||
IDS_CONTINUE " -- Continue (100%) -- "
|
||||
IDS_FILE_ACCESS "Cannot access the file %s."
|
||||
IDS_CONTINUE "-- Continue --"
|
||||
IDS_CONTINUE_PROGRESS "-- Continue (%d%%) --"
|
||||
IDS_FILE_ACCESS "Cannot access the file %s.\n"
|
||||
END
|
||||
|
|
|
@ -9,6 +9,7 @@ BEGIN
|
|||
[Unidad:][Ruta]Nombre del archivo Un archivo, cuyo contenido pueda ser mostrado.\n\
|
||||
Comando\t\t Un comando, cuya salida pueda ser mostrada.\n\n\
|
||||
Al visualizar ""-- Continuar --"" presione cualquier tecla para mostrar la siguiente página.\n"
|
||||
IDS_CONTINUE " -- Continuar (100%) -- "
|
||||
IDS_FILE_ACCESS "No se puede acceder al fichero %s."
|
||||
IDS_CONTINUE "-- Continuar --"
|
||||
IDS_CONTINUE_PROGRESS "-- Continuar (%d%%) --"
|
||||
IDS_FILE_ACCESS "No se puede acceder al fichero %s.\n"
|
||||
END
|
||||
|
|
|
@ -9,6 +9,7 @@ BEGIN
|
|||
[Lecteur:][Chemin]Nom du fichier Un fichier, dont le contenu sera affiché.\n\
|
||||
Commande\t\t Une commande, dont la sortie sera affichée.\n\n\
|
||||
À l'invite ""-- Continuer --"" Vous pouvez appuyer sur n'importe quelle touche pour afficher la page suivante.\n"
|
||||
IDS_CONTINUE " -- Continuer (100%) -- "
|
||||
IDS_FILE_ACCESS "Impossible d'accéder au fichier %s."
|
||||
IDS_CONTINUE "-- Continuer --"
|
||||
IDS_CONTINUE_PROGRESS "-- Continuer (%d %%) --"
|
||||
IDS_FILE_ACCESS "Impossible d'accéder au fichier %s.\n"
|
||||
END
|
||||
|
|
|
@ -9,6 +9,7 @@ BEGIN
|
|||
[Drive:][Path]File Il file da visualizzare.\n\
|
||||
Comando\t\t Il comando di cui l'output dev'essere visualizzato.\n\n\
|
||||
Alla richiesta ""-- Continua --"" premere un tasto qualsiasi per visualizzare la pagina successiva.\n"
|
||||
IDS_CONTINUE " -- Continua (100%) -- "
|
||||
IDS_FILE_ACCESS "Impossibile accedere al file %s."
|
||||
IDS_CONTINUE "-- Continua --"
|
||||
IDS_CONTINUE_PROGRESS "-- Continua (%d%%) --"
|
||||
IDS_FILE_ACCESS "Impossibile accedere al file %s.\n"
|
||||
END
|
||||
|
|
|
@ -21,6 +21,7 @@ BEGIN
|
|||
būti atvaizduotas.\n\n\
|
||||
Pasirodžius raginimui ""-- Toliau --"" spauskite bet kurį klavišą, kad\n\
|
||||
pamatytumėte sekantį puslapį.\n"
|
||||
IDS_CONTINUE " -- Toliau (100%) -- "
|
||||
IDS_FILE_ACCESS "Nepavyko atverti bylos %s."
|
||||
IDS_CONTINUE "-- Toliau --"
|
||||
IDS_CONTINUE_PROGRESS "-- Toliau (%d%%) --"
|
||||
IDS_FILE_ACCESS "Nepavyko atverti bylos %s.\n"
|
||||
END
|
||||
|
|
|
@ -9,6 +9,7 @@ BEGIN
|
|||
[Stasjon:][Mappe]Filnavn En fil, Velg innhold som skal vises.\n\
|
||||
Command\t\t En kommando, Velg output som skal vises.\n\n\
|
||||
At the prompt ""-- Fortsett --"" du kan trykke en tast for å vise neste side.\n"
|
||||
IDS_CONTINUE " -- Fortsett (100%) -- "
|
||||
IDS_FILE_ACCESS "Får ikke tilgang til filen %s."
|
||||
IDS_CONTINUE "-- Fortsett --"
|
||||
IDS_CONTINUE_PROGRESS "-- Fortsett (%d%%) --"
|
||||
IDS_FILE_ACCESS "Får ikke tilgang til filen %s.\n"
|
||||
END
|
||||
|
|
|
@ -17,6 +17,7 @@ BEGIN
|
|||
[Napęd:][Ścieżka]Nazwa pliku Plik, którego zawartość ma być wyświetlona.\n\
|
||||
Polecenie\t\t Polecenie, którego wynik ma być wyświetlony.\n\n\
|
||||
Po wyświetleniu ""-- Kontynuuj --"" możesz nacisnąć dowolny klawisz, aby przejść do następnej strony.\n"
|
||||
IDS_CONTINUE " -- Kontynuuj (100%) -- "
|
||||
IDS_FILE_ACCESS "Brak dostępu do pliku: %s."
|
||||
IDS_CONTINUE "-- Kontynuuj --"
|
||||
IDS_CONTINUE_PROGRESS "-- Kontynuuj (%d%%) --"
|
||||
IDS_FILE_ACCESS "Brak dostępu do pliku: %s.\n"
|
||||
END
|
||||
|
|
|
@ -18,6 +18,7 @@ BEGIN
|
|||
Comandă Comanda a cărei ieșire va fi afișată.\n\n\
|
||||
La vederea sugestiei ""-- Continuă --"" veți apăsa o tastă pentru afișarea\n\
|
||||
următoarei pagini.\n"
|
||||
IDS_CONTINUE " -- Continuă (100%) -- "
|
||||
IDS_FILE_ACCESS "Fișierul «%s» nu poate fi accesat!"
|
||||
IDS_CONTINUE "-- Continuă --"
|
||||
IDS_CONTINUE_PROGRESS "-- Continuă (%d%%) --"
|
||||
IDS_FILE_ACCESS "Fișierul «%s» nu poate fi accesat!\n"
|
||||
END
|
||||
|
|
|
@ -17,6 +17,7 @@ BEGIN
|
|||
[диск:][путь]имя_файла Файл, отображаемый по фрагментам.\n\
|
||||
имя_команды Команда, вывод которой отображается на экране.\n\n\
|
||||
При запросе ""-- Продолжить --"" вы можете нажать любую клавишу для отображения следующего экрана.\n"
|
||||
IDS_CONTINUE " -- Продолжить (100%) -- "
|
||||
IDS_FILE_ACCESS "Нет доступа к файлу %s."
|
||||
IDS_CONTINUE "-- Продолжить --"
|
||||
IDS_CONTINUE_PROGRESS "-- Продолжить (%d%%) --"
|
||||
IDS_FILE_ACCESS "Нет доступа к файлу %s.\n"
|
||||
END
|
||||
|
|
|
@ -14,6 +14,7 @@ BEGIN
|
|||
Príkaz\t\t Príkaz, ktorého výstup má byť zobrazený.\n\n\
|
||||
Pri výzve ""-- Pokračujte --"" môžete stlačiť ľubovoľný kláves\n\
|
||||
k zobrazeniu nasledujúcej stránky.\n"
|
||||
IDS_CONTINUE " -- Pokračujte (100%) -- "
|
||||
IDS_FILE_ACCESS "Neviem získať prístup k súboru %s."
|
||||
IDS_CONTINUE "-- Pokračujte --"
|
||||
IDS_CONTINUE_PROGRESS "-- Pokračujte (%d%%) --"
|
||||
IDS_FILE_ACCESS "Neviem získať prístup k súboru %s.\n"
|
||||
END
|
||||
|
|
|
@ -13,6 +13,7 @@ BEGIN
|
|||
[Drive:][Path]File name Nje dokument, përmbajtja e të cilit do të shfaqet.\n\
|
||||
Komandë\t\t Nje komande, nxjerrja e te cilit do të shfaqet.\n\n\
|
||||
At the prompt ""-- Vazhdo --"" ju mund të shtypni çfarëdo butoni për të vazhduar në faqen tjetër.\n"
|
||||
IDS_CONTINUE " -- Vazhdo (100%) -- "
|
||||
IDS_FILE_ACCESS "Nuk mund të aksesoj dokumentin %s."
|
||||
IDS_CONTINUE "-- Vazhdo --"
|
||||
IDS_CONTINUE_PROGRESS "-- Vazhdo (%d%%) --"
|
||||
IDS_FILE_ACCESS "Nuk mund të aksesoj dokumentin %s.\n"
|
||||
END
|
||||
|
|
|
@ -16,6 +16,7 @@ BEGIN
|
|||
[Enhet:][Mapp]Filnamn En fil, Välj innehåll som skall visas.\n\
|
||||
Kommando\t\t Ett kommando, Välj vad som skall visas.\n\n\
|
||||
vid prompten ""-- Fortsätt --"" du kan trycka valfri knapp för att visa nästa sida.\n"
|
||||
IDS_CONTINUE " -- Fortsätt (100%) -- "
|
||||
IDS_FILE_ACCESS "Får inte tillgång till filen %s."
|
||||
IDS_CONTINUE "-- Fortsätt --"
|
||||
IDS_CONTINUE_PROGRESS "-- Fortsätt (%d%%) --"
|
||||
IDS_FILE_ACCESS "Får inte tillgång till filen %s.\n"
|
||||
END
|
||||
|
|
|
@ -11,6 +11,7 @@ BEGIN
|
|||
[Sürücü:][Yol]Kütük adı İçeriği görüntülenecek bir kütük.\n\
|
||||
Komut\t\t Çıkışı görüntülenecek bir komut.\n\n\
|
||||
İstemde ""-- Sürdür --"" ile bir sonraki sayfayı göstermek için rastgele bir düğmeye basabilirsiniz.\n"
|
||||
IDS_CONTINUE " -- Sürdür (%100) -- "
|
||||
IDS_FILE_ACCESS "%s kütüğüne erişilemiyor."
|
||||
IDS_CONTINUE "-- Sürdür --"
|
||||
IDS_CONTINUE_PROGRESS "-- Sürdür (%%%d) --"
|
||||
IDS_FILE_ACCESS "%s kütüğüne erişilemiyor.\n"
|
||||
END
|
||||
|
|
|
@ -17,6 +17,7 @@ BEGIN
|
|||
[Диск:][Шлях]Ім'я_файлу Файл, вмiст якого треба вивести на екран.\n\
|
||||
Command\t\t Команда, результат роботи якої треба вивести на екран.\n\n\
|
||||
На запрошення ""-- Далi --"" Ви можете натиснути будь-яку клавiшу щоб побачити наступну сторiнку.\n"
|
||||
IDS_CONTINUE " -- Далi (100%) -- "
|
||||
IDS_FILE_ACCESS "Не можу отримати доступ до файла %s."
|
||||
IDS_CONTINUE "-- Далi --"
|
||||
IDS_CONTINUE_PROGRESS "-- Далi (%d%%) --"
|
||||
IDS_FILE_ACCESS "Не можу отримати доступ до файла %s.\n"
|
||||
END
|
||||
|
|
|
@ -11,6 +11,7 @@ BEGIN
|
|||
[驱动器:][路径]文件名 一个将要被如此显示内容的文件。\n\
|
||||
命令\t\t 一个输出将要被如此显示的命令。\n\n\
|
||||
在 ""-- 继续 --"" 的提示出现时你可以按任意键来显示下一页。\n"
|
||||
IDS_CONTINUE " -- 继续 (100%) -- "
|
||||
IDS_FILE_ACCESS "无法访问文件 %s。"
|
||||
IDS_CONTINUE "-- 继续 --"
|
||||
IDS_CONTINUE_PROGRESS "-- 继续 (%d%%) --"
|
||||
IDS_FILE_ACCESS "无法访问文件 %s。\n"
|
||||
END
|
||||
|
|
|
@ -11,6 +11,7 @@ BEGIN
|
|||
[磁碟機:][路徑]檔案名 一個將要被如此顯示內容的檔案。\n\
|
||||
命令\t\t 一個輸出將要被如此顯示的命令。\n\n\
|
||||
在 ""-- 繼續 --"" 的提示出現時你可以按任意鍵來顯示下一頁。\n"
|
||||
IDS_CONTINUE " -- 繼續 (100%) -- "
|
||||
IDS_FILE_ACCESS "無法訪問檔案 %s。"
|
||||
IDS_CONTINUE "-- 繼續 --"
|
||||
IDS_CONTINUE_PROGRESS "-- 繼續 (%d%%) --"
|
||||
IDS_FILE_ACCESS "無法訪問檔案 %s。\n"
|
||||
END
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS More Command
|
||||
* FILE: base/applications/cmdutils/more/more.c
|
||||
* PURPOSE: Displays text stream from STDIN or from an arbitrary number
|
||||
* of files to STDOUT, with screen capabilities (more than CAT,
|
||||
* but less than LESS ^^).
|
||||
* PROGRAMMERS: Paolo Pantaleo
|
||||
* Timothy Schepens
|
||||
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
||||
*/
|
||||
/*
|
||||
* MORE.C - external command.
|
||||
*
|
||||
|
@ -5,209 +16,616 @@
|
|||
*
|
||||
* 26 Sep 1999 - Paolo Pantaleo <paolopan@freemail.it>
|
||||
* started
|
||||
*
|
||||
* Oct 2003 - Timothy Schepens <tischepe at fastmail dot fm>
|
||||
* use window size instead of buffer size.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnls.h>
|
||||
#include <winuser.h>
|
||||
#include <wincon.h>
|
||||
|
||||
#include <conutils.h>
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
static TCHAR szCont[128];
|
||||
static DWORD szContLength;
|
||||
static HINSTANCE hApp;
|
||||
/* PagePrompt statistics for the current file */
|
||||
DWORD dwFileSize; // In bytes
|
||||
DWORD dwSumReadBytes, dwSumReadChars;
|
||||
// The average number of bytes per character is equal to
|
||||
// dwSumReadBytes / dwSumReadChars. Note that dwSumReadChars
|
||||
// will never be == 0 when ConWritePaging (and possibly PagePrompt)
|
||||
// is called.
|
||||
|
||||
/*handle for file and console*/
|
||||
HANDLE hStdIn;
|
||||
HANDLE hStdOut;
|
||||
HANDLE hStdErr;
|
||||
/* Handles for file and console */
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
HANDLE hStdIn, hStdOut;
|
||||
HANDLE hKeyboard;
|
||||
|
||||
|
||||
static VOID
|
||||
GetScreenSize (PSHORT maxx, PSHORT maxy)
|
||||
static BOOL
|
||||
__stdcall
|
||||
PagePrompt(PCON_PAGER Pager, DWORD Done, DWORD Total)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
HANDLE hInput = ConStreamGetOSHandle(StdIn);
|
||||
DWORD dwMode;
|
||||
KEY_EVENT_RECORD KeyEvent;
|
||||
|
||||
GetConsoleScreenBufferInfo (hStdOut, &csbi);
|
||||
*maxx = (csbi.srWindow.Right - csbi.srWindow.Left) + 1;
|
||||
*maxy = (csbi.srWindow.Bottom - csbi.srWindow.Top) - 4;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
VOID ConOutPuts (LPTSTR szText)
|
||||
{
|
||||
DWORD dwWritten;
|
||||
|
||||
WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), szText, _tcslen(szText), &dwWritten, NULL);
|
||||
WriteFile (GetStdHandle (STD_OUTPUT_HANDLE), "\n", 1, &dwWritten, NULL);
|
||||
}
|
||||
|
||||
|
||||
static VOID
|
||||
ConInKey (VOID)
|
||||
{
|
||||
INPUT_RECORD ir;
|
||||
DWORD dwRead;
|
||||
|
||||
do
|
||||
{
|
||||
ReadConsoleInput (hKeyboard, &ir, 1, &dwRead);
|
||||
if ((ir.EventType == KEY_EVENT) &&
|
||||
(ir.Event.KeyEvent.bKeyDown == TRUE))
|
||||
return;
|
||||
}
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
|
||||
static VOID
|
||||
WaitForKey (VOID)
|
||||
{
|
||||
DWORD dwWritten;
|
||||
|
||||
WriteFile (hStdErr, szCont , szContLength, &dwWritten, NULL);
|
||||
|
||||
ConInKey();
|
||||
|
||||
WriteFile (hStdErr, _T("\n"), 1, &dwWritten, NULL);
|
||||
|
||||
// FlushConsoleInputBuffer (hConsoleIn);
|
||||
}
|
||||
|
||||
|
||||
//INT CommandMore (LPTSTR cmd, LPTSTR param)
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
SHORT maxx,maxy;
|
||||
SHORT line_count=0,ch_count=0;
|
||||
DWORD i, last;
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||||
TCHAR szFullPath[MAX_PATH];
|
||||
TCHAR szMsg[1024];
|
||||
/*reading/writing buffer*/
|
||||
TCHAR *buff;
|
||||
|
||||
/*bytes written by WriteFile and ReadFile*/
|
||||
DWORD dwRead,dwWritten;
|
||||
|
||||
/*ReadFile() return value*/
|
||||
BOOL bRet;
|
||||
|
||||
|
||||
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
hStdErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
hApp = GetModuleHandle(NULL);
|
||||
|
||||
buff=malloc(4096);
|
||||
if (!buff)
|
||||
{
|
||||
ConOutPuts(_T("Error: no memory"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argc > 1 && _tcsncmp (argv[1], _T("/?"), 2) == 0)
|
||||
{
|
||||
if (LoadString(hApp, IDS_USAGE, buff, 4096 / sizeof(TCHAR)) < (int)(4096 / sizeof(TCHAR)))
|
||||
{
|
||||
CharToOem(buff, buff);
|
||||
ConOutPuts(buff);
|
||||
}
|
||||
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hKeyboard = CreateFile (_T("CONIN$"), GENERIC_READ|GENERIC_WRITE,
|
||||
0,NULL,OPEN_ALWAYS,0,0);
|
||||
|
||||
GetScreenSize(&maxx,&maxy);
|
||||
|
||||
|
||||
|
||||
FlushConsoleInputBuffer (hKeyboard);
|
||||
|
||||
if(argc > 1)
|
||||
{
|
||||
GetFullPathNameA(argv[1], MAX_PATH, szFullPath, NULL);
|
||||
hFile = CreateFile (szFullPath,
|
||||
GENERIC_READ,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (LoadString(hApp, IDS_FILE_ACCESS, szMsg, sizeof(szMsg) / sizeof(TCHAR)) < (int)(sizeof(szMsg) / sizeof(TCHAR)))
|
||||
{
|
||||
_stprintf(buff, szMsg, szFullPath);
|
||||
CharToOem(buff, buff);
|
||||
ConOutPuts(buff);
|
||||
}
|
||||
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hFile = hStdIn;
|
||||
}
|
||||
|
||||
if (!LoadString(hApp, IDS_CONTINUE, szCont, sizeof(szCont) / sizeof(TCHAR)))
|
||||
/*
|
||||
* Just use the simple prompt if the file being displayed is the STDIN,
|
||||
* otherwise use the prompt with progress percentage.
|
||||
*
|
||||
* The progress percentage is evaluated as follows.
|
||||
* So far we have read a total of 'dwSumReadBytes' bytes from the file.
|
||||
* Amongst those is the latest read chunk of 'dwReadBytes' bytes, to which
|
||||
* correspond a number of 'dwReadChars' characters with which we have called
|
||||
* ConWritePaging who called PagePrompt. We then have: Total == dwReadChars.
|
||||
* During this ConWritePaging call the PagePrompt was called after 'Done'
|
||||
* number of characters over 'Total'.
|
||||
* It should be noted that for 'dwSumReadBytes' number of bytes read it
|
||||
* *roughly* corresponds 'dwSumReadChars' number of characters. This is
|
||||
* because there may be some failures happening during the conversion of
|
||||
* the bytes read to the character string for a given encoding.
|
||||
* Therefore the number of characters displayed on screen is equal to:
|
||||
* dwSumReadChars - Total + Done ,
|
||||
* but the best corresponding approximed number of bytes would be:
|
||||
* dwSumReadBytes - (Total - Done) * (dwSumReadBytes / dwSumReadChars) ,
|
||||
* where the ratio is the average number of bytes per character.
|
||||
* The percentage is then computed relative to the total file size.
|
||||
*/
|
||||
if (hFile == hStdIn)
|
||||
{
|
||||
/* Shouldn't happen, so exit */
|
||||
free(buff);
|
||||
ConResPuts(Pager->Screen->Stream, IDS_CONTINUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConResPrintf(Pager->Screen->Stream, IDS_CONTINUE_PROGRESS,
|
||||
// (dwSumReadChars - Total + Done) * 100 / dwFileSize
|
||||
(dwSumReadBytes - (Total - Done) *
|
||||
(dwSumReadBytes / dwSumReadChars)) * 100 / dwFileSize
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Implement prompt read line!
|
||||
|
||||
// FIXME: Does not support TTY yet!
|
||||
|
||||
/* RemoveBreakHandler */
|
||||
SetConsoleCtrlHandler(NULL, TRUE);
|
||||
/* ConInDisable */
|
||||
GetConsoleMode(hInput, &dwMode);
|
||||
dwMode &= ~ENABLE_PROCESSED_INPUT;
|
||||
SetConsoleMode(hInput, dwMode);
|
||||
|
||||
do
|
||||
{
|
||||
// FIXME: Does not support TTY yet!
|
||||
|
||||
// ConInKey(&KeyEvent);
|
||||
INPUT_RECORD ir;
|
||||
DWORD dwRead;
|
||||
do
|
||||
{
|
||||
ReadConsoleInput(hInput, &ir, 1, &dwRead);
|
||||
}
|
||||
while ((ir.EventType != KEY_EVENT) || (!ir.Event.KeyEvent.bKeyDown));
|
||||
|
||||
/* Got our key, return to caller */
|
||||
KeyEvent = ir.Event.KeyEvent;
|
||||
}
|
||||
while ((KeyEvent.wVirtualKeyCode == VK_SHIFT) ||
|
||||
(KeyEvent.wVirtualKeyCode == VK_MENU) ||
|
||||
(KeyEvent.wVirtualKeyCode == VK_CONTROL));
|
||||
|
||||
/* AddBreakHandler */
|
||||
SetConsoleCtrlHandler(NULL, FALSE);
|
||||
/* ConInEnable */
|
||||
GetConsoleMode(hInput, &dwMode);
|
||||
dwMode |= ENABLE_PROCESSED_INPUT;
|
||||
SetConsoleMode(hInput, dwMode);
|
||||
|
||||
/*
|
||||
* Erase the full line where the cursor is, and move
|
||||
* the cursor back to the beginning of the line.
|
||||
*/
|
||||
ConClearLine(Pager->Screen->Stream);
|
||||
|
||||
if ((KeyEvent.wVirtualKeyCode == VK_ESCAPE) ||
|
||||
((KeyEvent.wVirtualKeyCode == L'C') &&
|
||||
(KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))))
|
||||
{
|
||||
/* We break, output a newline */
|
||||
WCHAR ch = L'\n';
|
||||
ConStreamWrite(Pager->Screen->Stream, &ch, 1);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* See base/applications/cmdutils/clip/clip.c!IsDataUnicode()
|
||||
* and base/applications/notepad/text.c!ReadText() for more details.
|
||||
* Also some good code example can be found at:
|
||||
* https://github.com/AutoIt/text-encoding-detect
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ENCODING_ANSI = 0,
|
||||
ENCODING_UTF16LE = 1,
|
||||
ENCODING_UTF16BE = 2,
|
||||
ENCODING_UTF8 = 3
|
||||
} ENCODING;
|
||||
|
||||
static BOOL
|
||||
IsDataUnicode(
|
||||
IN PVOID Buffer,
|
||||
IN DWORD BufferSize,
|
||||
OUT ENCODING* Encoding OPTIONAL,
|
||||
OUT PDWORD SkipBytes OPTIONAL)
|
||||
{
|
||||
PBYTE pBytes = Buffer;
|
||||
ENCODING encFile = ENCODING_ANSI;
|
||||
DWORD dwPos = 0;
|
||||
|
||||
/*
|
||||
* See http://archives.miloush.net/michkap/archive/2007/04/22/2239345.html
|
||||
* for more details about the algorithm and the pitfalls behind it.
|
||||
* Of course it would be actually great to make a nice function that
|
||||
* would work, once and for all, and put it into a library.
|
||||
*/
|
||||
|
||||
/* Look for Byte Order Marks */
|
||||
if ((BufferSize >= 2) && (pBytes[0] == 0xFF) && (pBytes[1] == 0xFE))
|
||||
{
|
||||
encFile = ENCODING_UTF16LE;
|
||||
dwPos = 2;
|
||||
}
|
||||
else if ((BufferSize >= 2) && (pBytes[0] == 0xFE) && (pBytes[1] == 0xFF))
|
||||
{
|
||||
encFile = ENCODING_UTF16BE;
|
||||
dwPos = 2;
|
||||
}
|
||||
else if ((BufferSize >= 3) && (pBytes[0] == 0xEF) && (pBytes[1] == 0xBB) && (pBytes[2] == 0xBF))
|
||||
{
|
||||
encFile = ENCODING_UTF8;
|
||||
dwPos = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Try using statistical analysis. Do not rely on the return value of
|
||||
* IsTextUnicode as we can get FALSE even if the text is in UTF-16 BE
|
||||
* (i.e. we have some of the IS_TEXT_UNICODE_REVERSE_MASK bits set).
|
||||
* Instead, set all the tests we want to perform, then just check
|
||||
* the passed tests and try to deduce the string properties.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This mask contains the 3 highest bits from IS_TEXT_UNICODE_NOT_ASCII_MASK
|
||||
* and the 1st highest bit from IS_TEXT_UNICODE_NOT_UNICODE_MASK.
|
||||
*/
|
||||
#define IS_TEXT_UNKNOWN_FLAGS_MASK ((7 << 13) | (1 << 11))
|
||||
|
||||
/* Flag out the unknown flags here, the passed tests will not have them either */
|
||||
INT Tests = (IS_TEXT_UNICODE_NOT_ASCII_MASK |
|
||||
IS_TEXT_UNICODE_NOT_UNICODE_MASK |
|
||||
IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_UNICODE_MASK)
|
||||
& ~IS_TEXT_UNKNOWN_FLAGS_MASK;
|
||||
INT Results;
|
||||
|
||||
IsTextUnicode(Buffer, BufferSize, &Tests);
|
||||
Results = Tests;
|
||||
|
||||
/*
|
||||
* As the IS_TEXT_UNICODE_NULL_BYTES or IS_TEXT_UNICODE_ILLEGAL_CHARS
|
||||
* flags are expected to be potentially present in the result without
|
||||
* modifying our expectations, filter them out now.
|
||||
*/
|
||||
Results &= ~(IS_TEXT_UNICODE_NULL_BYTES | IS_TEXT_UNICODE_ILLEGAL_CHARS);
|
||||
|
||||
/*
|
||||
* NOTE: The flags IS_TEXT_UNICODE_ASCII16 and
|
||||
* IS_TEXT_UNICODE_REVERSE_ASCII16 are not reliable.
|
||||
*
|
||||
* NOTE2: Check for potential "bush hid the facts" effect by also
|
||||
* checking the original results (in 'Tests') for the absence of
|
||||
* the IS_TEXT_UNICODE_NULL_BYTES flag, as we may presumably expect
|
||||
* that in UTF-16 text there will be at some point some NULL bytes.
|
||||
* If not, fall back to ANSI. This shows the limitations of using the
|
||||
* IsTextUnicode API to perform such tests, and the usage of a more
|
||||
* improved encoding detection algorithm would be really welcome.
|
||||
*/
|
||||
if (!(Results & IS_TEXT_UNICODE_NOT_UNICODE_MASK) &&
|
||||
!(Results & IS_TEXT_UNICODE_REVERSE_MASK) &&
|
||||
(Results & IS_TEXT_UNICODE_UNICODE_MASK) &&
|
||||
(Tests & IS_TEXT_UNICODE_NULL_BYTES))
|
||||
{
|
||||
encFile = ENCODING_UTF16LE;
|
||||
dwPos = (Results & IS_TEXT_UNICODE_SIGNATURE) ? 2 : 0;
|
||||
}
|
||||
else
|
||||
if (!(Results & IS_TEXT_UNICODE_NOT_UNICODE_MASK) &&
|
||||
!(Results & IS_TEXT_UNICODE_UNICODE_MASK) &&
|
||||
(Results & IS_TEXT_UNICODE_REVERSE_MASK) &&
|
||||
(Tests & IS_TEXT_UNICODE_NULL_BYTES))
|
||||
{
|
||||
encFile = ENCODING_UTF16BE;
|
||||
dwPos = (Results & IS_TEXT_UNICODE_REVERSE_SIGNATURE) ? 2 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Either 'Results' has neither of those masks set, as it can be
|
||||
* the case for UTF-8 text (or ANSI), or it has both as can be the
|
||||
* case when analysing pure binary data chunk. This is therefore
|
||||
* invalid and we fall back to ANSI encoding.
|
||||
* FIXME: In case of failure, assume ANSI (as long as we do not have
|
||||
* correct tests for UTF8, otherwise we should do them, and at the
|
||||
* very end, assume ANSI).
|
||||
*/
|
||||
encFile = ENCODING_ANSI; // ENCODING_UTF8;
|
||||
dwPos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (Encoding)
|
||||
*Encoding = encFile;
|
||||
if (SkipBytes)
|
||||
*SkipBytes = dwPos;
|
||||
|
||||
return (encFile != ENCODING_ANSI);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adapted from base/shell/cmd/misc.c!FileGetString(), but with correct
|
||||
* text encoding support. Also please note that similar code should be
|
||||
* also used in the CMD.EXE 'TYPE' command.
|
||||
* Contrary to CMD's FileGetString() we do not stop at new-lines.
|
||||
*
|
||||
* Read text data from a file and convert it from a given encoding to UTF-16.
|
||||
*
|
||||
* IN OUT PVOID pCacheBuffer and IN DWORD CacheBufferLength :
|
||||
* Implementation detail so that the function uses an external user-provided
|
||||
* buffer to store the data temporarily read from the file. The function
|
||||
* could have used an internal buffer instead. The length is in number of bytes.
|
||||
*
|
||||
* IN OUT PWSTR* pBuffer and IN OUT PDWORD pnBufferLength :
|
||||
* Reallocated buffer containing the string data converted to UTF-16.
|
||||
* In input, contains a pointer to the original buffer and its length.
|
||||
* In output, contains a pointer to the reallocated buffer and its length.
|
||||
* The length is in number of characters.
|
||||
*
|
||||
* At first call to this function, pBuffer can be set to NULL, in which case
|
||||
* when the function returns the pointer will point to a valid buffer.
|
||||
* After the last call to this function, free the pBuffer pointer with:
|
||||
* HeapFree(GetProcessHeap(), 0, *pBuffer);
|
||||
*
|
||||
* If Encoding is set to ENCODING_UTF16LE or ENCODING_UTF16BE, since we are
|
||||
* compiled in UNICODE, no extra conversion is performed and therefore
|
||||
* pBuffer is unused (remains unallocated) and one can directly use the
|
||||
* contents of pCacheBuffer as it is expected to contain valid UTF-16 text.
|
||||
*
|
||||
* OUT PDWORD pdwReadBytes : Number of bytes read from the file (optional).
|
||||
* OUT PDWORD pdwReadChars : Corresponding number of characters read (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)
|
||||
{
|
||||
BOOL Success;
|
||||
UINT CodePage = (UINT)-1;
|
||||
DWORD dwReadBytes;
|
||||
INT len;
|
||||
|
||||
// ASSERT(pCacheBuffer && (CacheBufferLength > 0));
|
||||
// ASSERT(CacheBufferLength % 2 == 0); // Cache buffer length MUST BE even!
|
||||
// ASSERT(pBuffer && pnBufferLength);
|
||||
|
||||
/* Always reset the retrieved number of bytes/characters */
|
||||
if (pdwReadBytes) *pdwReadBytes = 0;
|
||||
if (pdwReadChars) *pdwReadChars = 0;
|
||||
|
||||
Success = ReadFile(hFile, pCacheBuffer, CacheBufferLength, &dwReadBytes, NULL);
|
||||
if (!Success || dwReadBytes == 0)
|
||||
return FALSE;
|
||||
|
||||
if (pdwReadBytes) *pdwReadBytes = dwReadBytes;
|
||||
|
||||
if ((Encoding == ENCODING_ANSI) || (Encoding == ENCODING_UTF8))
|
||||
{
|
||||
/* Conversion is needed */
|
||||
|
||||
if (Encoding == ENCODING_ANSI)
|
||||
CodePage = GetConsoleCP(); // CP_ACP; // FIXME: Cache GetConsoleCP() value.
|
||||
else // if (Encoding == ENCODING_UTF8)
|
||||
CodePage = CP_UTF8;
|
||||
|
||||
/* Retrieve the needed buffer size */
|
||||
len = MultiByteToWideChar(CodePage, 0, pCacheBuffer, dwReadBytes,
|
||||
NULL, 0);
|
||||
if (len == 0)
|
||||
{
|
||||
/* Failure, bail out */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Initialize the conversion buffer if needed... */
|
||||
if (*pBuffer == NULL)
|
||||
{
|
||||
*pnBufferLength = len;
|
||||
*pBuffer = HeapAlloc(GetProcessHeap(), 0, *pnBufferLength * sizeof(WCHAR));
|
||||
if (*pBuffer == NULL)
|
||||
{
|
||||
// *pBuffer = NULL;
|
||||
*pnBufferLength = 0;
|
||||
// WARN("DEBUG: Cannot allocate memory for *pBuffer!\n");
|
||||
// ConErrFormatMessage(GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
/* ... or reallocate only if the new length is greater than the old one */
|
||||
else if (len > *pnBufferLength)
|
||||
{
|
||||
PWSTR OldBuffer = *pBuffer;
|
||||
|
||||
*pnBufferLength = len;
|
||||
*pBuffer = HeapReAlloc(GetProcessHeap(), 0, *pBuffer, *pnBufferLength * sizeof(WCHAR));
|
||||
if (*pBuffer == NULL)
|
||||
{
|
||||
/* Do not leak old buffer */
|
||||
HeapFree(GetProcessHeap(), 0, OldBuffer);
|
||||
// *pBuffer = NULL;
|
||||
*pnBufferLength = 0;
|
||||
// WARN("DEBUG: Cannot reallocate memory for *pBuffer!\n");
|
||||
// ConErrFormatMessage(GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now perform the conversion proper */
|
||||
len = MultiByteToWideChar(CodePage, 0, pCacheBuffer, dwReadBytes,
|
||||
*pBuffer, len);
|
||||
dwReadBytes = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* No conversion needed, just convert from big to little endian if needed.
|
||||
* pBuffer and pnBufferLength are left untouched and pCacheBuffer can be
|
||||
* directly used.
|
||||
*/
|
||||
PWCHAR pWChars = pCacheBuffer;
|
||||
DWORD i;
|
||||
|
||||
dwReadBytes /= sizeof(WCHAR);
|
||||
|
||||
if (Encoding == ENCODING_UTF16BE)
|
||||
{
|
||||
for (i = 0; i < dwReadBytes; i++)
|
||||
{
|
||||
/* Equivalent to RtlUshortByteSwap: reverse high/low bytes */
|
||||
pWChars[i] = MAKEWORD(HIBYTE(pWChars[i]), LOBYTE(pWChars[i]));
|
||||
}
|
||||
}
|
||||
// else if (Encoding == ENCODING_UTF16LE), we are good, nothing to do.
|
||||
}
|
||||
|
||||
/* Return the number of characters (dwReadBytes is converted) */
|
||||
if (pdwReadChars) *pdwReadChars = dwReadBytes;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// INT CommandMore(LPTSTR cmd, LPTSTR param)
|
||||
int wmain(int argc, WCHAR* argv[])
|
||||
{
|
||||
// FIXME this stuff!
|
||||
CON_SCREEN Screen = {StdOut};
|
||||
CON_PAGER Pager = {&Screen, 0};
|
||||
|
||||
int i;
|
||||
|
||||
BOOL bRet, bContinue;
|
||||
|
||||
ENCODING Encoding;
|
||||
DWORD SkipBytes = 0;
|
||||
|
||||
#define FileCacheBufferSize 4096
|
||||
PVOID FileCacheBuffer = NULL;
|
||||
PWCHAR StringBuffer = NULL;
|
||||
DWORD StringBufferLength = 0;
|
||||
DWORD dwReadBytes, dwReadChars;
|
||||
|
||||
TCHAR szFullPath[MAX_PATH];
|
||||
|
||||
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
/* Initialize the Console Standard Streams */
|
||||
ConStreamInit(StdIn , GetStdHandle(STD_INPUT_HANDLE) , UTF8Text, INVALID_CP);
|
||||
ConStreamInit(StdOut, GetStdHandle(STD_OUTPUT_HANDLE), UTF8Text, INVALID_CP);
|
||||
ConStreamInit(StdErr, GetStdHandle(STD_ERROR_HANDLE) , UTF8Text, INVALID_CP);
|
||||
|
||||
/*
|
||||
* Bad usage (too much options) or we use the /? switch.
|
||||
* Display help for the MORE command.
|
||||
*/
|
||||
if (argc > 1 && wcscmp(argv[1], L"/?") == 0)
|
||||
{
|
||||
ConResPuts(StdOut, IDS_USAGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// FIXME: Parse all the remaining parameters.
|
||||
// Then the file list can be found at the very end.
|
||||
// FIXME2: Use the PARSER api that can be found in EVENTCREATE.
|
||||
|
||||
// NOTE: We might try to duplicate the ConOut for read access... ?
|
||||
hKeyboard = CreateFileW(L"CONIN$", GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, 0, NULL);
|
||||
FlushConsoleInputBuffer(hKeyboard);
|
||||
ConStreamSetOSHandle(StdIn, hKeyboard);
|
||||
|
||||
|
||||
FileCacheBuffer = HeapAlloc(GetProcessHeap(), 0, FileCacheBufferSize);
|
||||
if (!FileCacheBuffer)
|
||||
{
|
||||
ConPuts(StdErr, L"Error: no memory\n");
|
||||
CloseHandle(hKeyboard);
|
||||
return 1;
|
||||
}
|
||||
szContLength = _tcslen(szCont);
|
||||
|
||||
/* Special case where we run 'MORE' without any argument: we use STDIN */
|
||||
if (argc <= 1)
|
||||
{
|
||||
/*
|
||||
* Assign STDIN handle to hFile so that the page prompt function will
|
||||
* know the data comes from STDIN, and will take different actions.
|
||||
*/
|
||||
hFile = hStdIn;
|
||||
|
||||
/* Update the statistics for PagePrompt */
|
||||
dwFileSize = 0;
|
||||
dwSumReadBytes = dwSumReadChars = 0;
|
||||
|
||||
do
|
||||
{
|
||||
bRet = ReadFile(hFile,buff,4096,&dwRead,NULL);
|
||||
/* We suppose we read text from the file */
|
||||
|
||||
for(last=i=0;i<dwRead && bRet;i++)
|
||||
{
|
||||
ch_count++;
|
||||
if(buff[i] == _T('\n') || ch_count == maxx)
|
||||
{
|
||||
ch_count=0;
|
||||
line_count++;
|
||||
if (line_count == maxy)
|
||||
/* For STDIN we always suppose we are in ANSI mode */
|
||||
// SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
||||
Encoding = ENCODING_ANSI; // ENCODING_UTF8;
|
||||
|
||||
bContinue = ConPutsPaging(&Pager, PagePrompt, TRUE, L"");
|
||||
if (!bContinue)
|
||||
goto Quit;
|
||||
|
||||
do
|
||||
{
|
||||
bRet = FileGetString(hFile, Encoding,
|
||||
FileCacheBuffer, FileCacheBufferSize,
|
||||
&StringBuffer, &StringBufferLength,
|
||||
&dwReadBytes, &dwReadChars);
|
||||
if (!bRet || dwReadBytes == 0 || dwReadChars == 0)
|
||||
{
|
||||
line_count = 0;
|
||||
WriteFile(hStdOut,&buff[last], i-last+1, &dwWritten, NULL);
|
||||
last=i+1;
|
||||
FlushFileBuffers (hStdOut);
|
||||
WaitForKey ();
|
||||
/* We failed at reading the file, bail out */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (last<dwRead && bRet)
|
||||
WriteFile(hStdOut,&buff[last], dwRead-last, &dwWritten, NULL);
|
||||
|
||||
}
|
||||
while(dwRead>0 && bRet);
|
||||
/* Update the statistics for PagePrompt */
|
||||
dwSumReadBytes += dwReadBytes;
|
||||
dwSumReadChars += dwReadChars;
|
||||
|
||||
free (buff);
|
||||
CloseHandle (hKeyboard);
|
||||
if (hFile != hStdIn)
|
||||
CloseHandle (hFile);
|
||||
bContinue = ConWritePaging(&Pager, PagePrompt, FALSE,
|
||||
StringBuffer, dwReadChars);
|
||||
/* If we Ctrl-C/Ctrl-Break, stop everything */
|
||||
if (!bContinue)
|
||||
goto Quit;
|
||||
}
|
||||
while (bRet && dwReadBytes > 0);
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* We have files: read them and output them to STDOUT */
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
GetFullPathNameW(argv[i], ARRAYSIZE(szFullPath), szFullPath, NULL);
|
||||
hFile = CreateFileW(szFullPath,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0, // FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ConResPrintf(StdErr, IDS_FILE_ACCESS, szFullPath);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We currently do not support files too big */
|
||||
dwFileSize = GetFileSize(hFile, NULL);
|
||||
if (dwFileSize == INVALID_FILE_SIZE)
|
||||
{
|
||||
ConPuts(StdErr, L"ERROR: Invalid file size!\n");
|
||||
CloseHandle(hFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We suppose we read text from the file */
|
||||
|
||||
/* Check whether the file is UNICODE and retrieve its encoding */
|
||||
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
||||
bRet = ReadFile(hFile, FileCacheBuffer, FileCacheBufferSize, &dwReadBytes, NULL);
|
||||
IsDataUnicode(FileCacheBuffer, dwReadBytes, &Encoding, &SkipBytes);
|
||||
SetFilePointer(hFile, SkipBytes, NULL, FILE_BEGIN);
|
||||
|
||||
/* Update the statistics for PagePrompt */
|
||||
dwSumReadBytes = dwSumReadChars = 0;
|
||||
|
||||
bContinue = ConPutsPaging(&Pager, PagePrompt, TRUE, L"");
|
||||
if (!bContinue)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
bRet = FileGetString(hFile, Encoding,
|
||||
FileCacheBuffer, FileCacheBufferSize,
|
||||
&StringBuffer, &StringBufferLength,
|
||||
&dwReadBytes, &dwReadChars);
|
||||
if (!bRet || dwReadBytes == 0 || dwReadChars == 0)
|
||||
{
|
||||
/*
|
||||
* We failed at reading the file, bail out and
|
||||
* continue with the other files.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update the statistics for PagePrompt */
|
||||
dwSumReadBytes += dwReadBytes;
|
||||
dwSumReadChars += dwReadChars;
|
||||
|
||||
if ((Encoding == ENCODING_UTF16LE) || (Encoding == ENCODING_UTF16BE))
|
||||
{
|
||||
bContinue = ConWritePaging(&Pager, PagePrompt, FALSE,
|
||||
FileCacheBuffer, dwReadChars);
|
||||
}
|
||||
else
|
||||
{
|
||||
bContinue = ConWritePaging(&Pager, PagePrompt, FALSE,
|
||||
StringBuffer, dwReadChars);
|
||||
}
|
||||
/* If we Ctrl-C/Ctrl-Break, stop everything */
|
||||
if (!bContinue)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
goto Quit;
|
||||
}
|
||||
}
|
||||
while (bRet && dwReadBytes > 0);
|
||||
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
|
||||
Quit:
|
||||
if (StringBuffer) HeapFree(GetProcessHeap(), 0, StringBuffer);
|
||||
HeapFree(GetProcessHeap(), 0, FileCacheBuffer);
|
||||
CloseHandle(hKeyboard);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
|
||||
#include "resource.h"
|
||||
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS More Command"
|
||||
#define REACTOS_STR_INTERNAL_NAME "more"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "more.com"
|
||||
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||
|
||||
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS More Command"
|
||||
#define REACTOS_STR_INTERNAL_NAME "more"
|
||||
#define REACTOS_STR_ORIGINAL_FILENAME "more.com"
|
||||
#include <reactos/version.rc>
|
||||
|
||||
/* UTF-8 */
|
||||
#pragma code_page(65001)
|
||||
|
||||
#ifdef LANGUAGE_BG_BG
|
||||
#include "lang/bg-BG.rc"
|
||||
#endif
|
||||
|
@ -71,4 +74,4 @@
|
|||
#endif
|
||||
#ifdef LANGUAGE_ZH_TW
|
||||
#include "lang/zh-TW.rc"
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
|
||||
#define IDS_USAGE 100
|
||||
#define IDS_CONTINUE 101
|
||||
#define IDS_FILE_ACCESS 102
|
||||
#define IDS_CONTINUE_PROGRESS 102
|
||||
#define IDS_FILE_ACCESS 103
|
||||
|
|
Loading…
Reference in a new issue