diff options
author | FeralChild64 <> | 2022-10-12 01:19:18 +0300 |
---|---|---|
committer | FeralChild64 <> | 2022-10-12 10:50:01 +0300 |
commit | 89fa10b8270f7e99f71b78c3cc38655ddfa97752 (patch) | |
tree | 0e3c951a14892946066974681d2d1b36963243ed | |
parent | 83a2ab3ec59a4dffc8a78dad554aecf64422b001 (diff) |
Implement MORE.COM commandfc/command-more-1
-rw-r--r-- | src/dos/dos_programs.cpp | 2 | ||||
-rw-r--r-- | src/dos/meson.build | 1 | ||||
-rw-r--r-- | src/dos/program_more.cpp | 173 | ||||
-rw-r--r-- | src/dos/program_more.h | 42 | ||||
-rw-r--r-- | vs/dosbox.vcxproj | 1 | ||||
-rw-r--r-- | vs/dosbox.vcxproj.filters | 3 |
6 files changed, 222 insertions, 0 deletions
diff --git a/src/dos/dos_programs.cpp b/src/dos/dos_programs.cpp index 48ed523d6..2bf99f99e 100644 --- a/src/dos/dos_programs.cpp +++ b/src/dos/dos_programs.cpp @@ -32,6 +32,7 @@ #include "program_loadrom.h" #include "program_ls.h" #include "program_mem.h" +#include "program_more.h" #include "program_mount.h" #include "program_placeholder.h" #include "program_rescan.h" @@ -74,6 +75,7 @@ void Add_VFiles(const bool add_autoexec) PROGRAMS_MakeFile("LOADROM.COM", ProgramCreate<LOADROM>); PROGRAMS_MakeFile("LS.COM", ProgramCreate<LS>); PROGRAMS_MakeFile("MEM.COM", ProgramCreate<MEM>); + PROGRAMS_MakeFile("MORE.COM", ProgramCreate<MORE>); PROGRAMS_MakeFile("MOUNT.COM", ProgramCreate<MOUNT>); PROGRAMS_MakeFile("RESCAN.COM", ProgramCreate<RESCAN>); PROGRAMS_MakeFile("MIXER.COM", MIXER_ProgramCreate); diff --git a/src/dos/meson.build b/src/dos/meson.build index 4a31a1bf1..d9021ef34 100644 --- a/src/dos/meson.build +++ b/src/dos/meson.build @@ -34,6 +34,7 @@ libdos_sources = files( 'program_loadrom.cpp', 'program_ls.cpp', 'program_mem.cpp', + 'program_more.cpp', 'program_mount.cpp', 'program_mount_common.cpp', 'program_placeholder.cpp', diff --git a/src/dos/program_more.cpp b/src/dos/program_more.cpp new file mode 100644 index 000000000..cb23e6223 --- /dev/null +++ b/src/dos/program_more.cpp @@ -0,0 +1,173 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (C) 2022 The DOSBox Staging Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "program_more.h" + +#include "../ints/int10.h" +#include "checks.h" + +CHECK_NARROWING(); + + +// ASCII control characters +static constexpr char char_break = 0x03; +static constexpr char char_line_feed = 0x0a; +static constexpr char char_carriage_return = 0x0d; + + +void MORE::Run() +{ + // Check command line + + if (HelpRequested()) { + WriteOut(MSG_Get("SHELL_CMD_MORE_HELP_LONG")); + return; + } + + if (cmd->GetCount()) { + WriteOut(MSG_Get("SHELL_CMD_MORE_SYNTAX")); + return; + } + + // Prepare screen parameters information + + const auto adapt_dimension = [](const uint16_t d) { + const uint16_t min = 10; + if (d < min) + return min; + else + return static_cast<uint16_t>(d - 1); + }; + + const uint16_t screen_max_x = adapt_dimension(INT10_GetTextColumns()); + const uint16_t screen_max_y = adapt_dimension(INT10_GetTextRows()); + + auto get_column = []() { + const auto page = real_readb(BIOSMEM_SEG, BIOSMEM_CURRENT_PAGE); + return CURSOR_POS_COL(page); + }; + + // We need to be able to read STDIN for key presses, but it is most + // likely redirected - so clone the handle, and reconstruct real STDIN + // from STDERR (idea from FreeDOS implementation, + // https://github.com/FDOS/more/blob/master/src/more.c) + + uint16_t in_handle = 0; + if (!DOS_DuplicateEntry(STDIN, &in_handle) || + !DOS_ForceDuplicateEntry(STDERR, STDIN)) { + LOG_ERR("DOS: Unable to prepare handles in MORE.COM"); + return; + } + + // Main loop + + char character = '\0'; + uint16_t amount = 1; + uint16_t counter = 0; + + auto previous_column = get_column(); + bool previous_was_cr = false; // if last character was 'carriage return' + bool previous_was_lf = false; // if last character was 'line feed' + + while (true) { + if (!counter) + counter = screen_max_y; + + // Read character and duplicate it on the output + + amount = 1; + DOS_ReadFile(in_handle, reinterpret_cast<uint8_t *>(&character), &amount); + if (!amount) + break; // end of stream + WriteOut("%c", character); + + // Detect new line; we can't just simply the characters, + // as some might be ANSI escape codes + + const auto column = get_column(); + + if ((!previous_was_cr && character == char_line_feed) || + (!previous_was_lf && character == char_carriage_return)) + --counter; // new line in the input stream + else if (character != char_line_feed && + character != char_carriage_return && + (!column && (previous_column == screen_max_x))) + --counter; // line longer than screen size + + previous_column = column; + previous_was_cr = (character == char_carriage_return); + previous_was_lf = (character == char_line_feed); + + if (counter) + continue; + + // Scrolling occured several times, pause until key press + + if (!column) + WriteOut("\n"); + WriteOut(MSG_Get("SHELL_CMD_PAUSE")); + WriteOut("\n"); + + amount = 0; + while (!amount) { + amount = 1; + DOS_ReadFile(STDIN, + reinterpret_cast<uint8_t *>(&character), + &amount); + } + + // Check for termination by user (CTRL+C) + + if (character == char_break) { + WriteOut("^C\n"); + break; + } + } + + // End of processing + + WriteOut("\n"); +} + +void MORE::AddMessages() +{ + MSG_Add("SHELL_CMD_MORE_HELP", + "Display command output or text file one screen at a time.\n"); + MSG_Add("SHELL_CMD_MORE_HELP_LONG", + "Display command output or text file one screen at a time.\n" + "\n" + "Usage:\n" + " [color=cyan]COMMAND[reset] | [color=green]more[reset]\n" + " [color=green]more[reset] < [color=cyan]FILE[reset]\n" + "\n" + "Where:\n" + " [color=cyan]COMMAND[reset] is the command to diplay output one screen at a time.\n" + " [color=cyan]FILE[reset] is the name of the file to display.\n" + "\n" + "Notes:\n" + " The file must be an exact file name, optionally with a path.\n" + " This command is only for viewing text files, not binary files.\n" + "\n" + "Examples:\n" + " [color=cyan]dir /on[reset] | [color=green]more[reset] ; shows sorted directory content one screen at a time\n" + " [color=green]more[reset] < [color=cyan]A:\\MANUAL.TXT[reset] ; displays the file content one screen at a time"); + + MSG_Add("SHELL_CMD_MORE_SYNTAX", "Wrong command syntax."); +} diff --git a/src/dos/program_more.h b/src/dos/program_more.h new file mode 100644 index 000000000..536c5df9e --- /dev/null +++ b/src/dos/program_more.h @@ -0,0 +1,42 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (C) 2022 The DOSBox Staging Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef DOSBOX_PROGRAM_MORE_H +#define DOSBOX_PROGRAM_MORE_H + +#include "programs.h" + +class MORE final : public Program { +public: + MORE() + { + AddMessages(); + help_detail = {HELP_Filter::All, + HELP_Category::Dosbox, + HELP_CmdType::Program, + "MORE"}; + } + void Run(); + +private: + void AddMessages(); +}; + +#endif diff --git a/vs/dosbox.vcxproj b/vs/dosbox.vcxproj index 36269342e..384b99920 100644 --- a/vs/dosbox.vcxproj +++ b/vs/dosbox.vcxproj @@ -553,6 +553,7 @@ IF %ERRORLEVEL% LSS 8 SET ERRORLEVEL = 0</Command> <ClCompile Include="..\src\dos\program_loadrom.cpp" /> <ClCompile Include="..\src\dos\program_ls.cpp" /> <ClCompile Include="..\src\dos\program_mem.cpp" /> + <ClCompile Include="..\src\dos\program_more.cpp" /> <ClCompile Include="..\src\dos\program_mount_common.cpp" /> <ClCompile Include="..\src\dos\program_mount.cpp" /> <ClCompile Include="..\src\dos\program_placeholder.cpp" /> diff --git a/vs/dosbox.vcxproj.filters b/vs/dosbox.vcxproj.filters index 3823a9f06..a4627ead5 100644 --- a/vs/dosbox.vcxproj.filters +++ b/vs/dosbox.vcxproj.filters @@ -559,6 +559,9 @@ <ClCompile Include="..\src\dos\program_mem.cpp"> <Filter>src\dos</Filter> </ClCompile> + <ClCompile Include="..\src\dos\program_more.cpp"> + <Filter>src\dos</Filter> + </ClCompile> <ClCompile Include="..\src\dos\program_mount.cpp"> <Filter>src\dos</Filter> </ClCompile> |