Skip to content

Commit

Permalink
Implement MORE.COM command
Browse files Browse the repository at this point in the history
  • Loading branch information
FeralChild64 committed Oct 12, 2022
1 parent c437482 commit c660d66
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/dos/dos_programs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/dos/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
164 changes: 164 additions & 0 deletions src/dos/program_more.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* 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 "checks.h"

#include "../ints/int10.h"

CHECK_NARROWING();

// ASCII control characters
static constexpr char char_break = 0x03;
static constexpr char char_backspace = 0x08;
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 uint16_t screen_max_x = INT10_GetTextColumns() - 1;
const uint16_t screen_max_y = INT10_GetTextRows() - 1;

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"));

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.");
}
42 changes: 42 additions & 0 deletions src/dos/program_more.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit c660d66

Please sign in to comment.