Author: bonefish Date: 2010-03-11 18:09:11 +0100 (Thu, 11 Mar 2010) New Revision: 35812 Changeset: http://dev.haiku-os.org/changeset/35812/haiku Added: haiku/trunk/src/system/boot/loader/pager.cpp haiku/trunk/src/system/boot/loader/pager.h Log: A simple pager implemented on top of the generic text console interface. Added: haiku/trunk/src/system/boot/loader/pager.cpp =================================================================== --- haiku/trunk/src/system/boot/loader/pager.cpp (rev 0) +++ haiku/trunk/src/system/boot/loader/pager.cpp 2010-03-11 17:09:11 UTC (rev 35812) @@ -0,0 +1,207 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Distributed under the terms of the MIT License. + */ + + +#include "pager.h" + +#include <ctype.h> +#include <string.h> + +#include <algorithm> + +#include <boot/platform/generic/text_console.h> + + +// #pragma mark - PagerTextSource + + +PagerTextSource::~PagerTextSource() +{ +} + + +// #pragma mark - + + +static size_t +next_line(const PagerTextSource& textSource, size_t width, size_t offset, + char* buffer, size_t bufferSize) +{ + size_t bytesRead = textSource.Read(offset, buffer, bufferSize - 1); + if (bytesRead == 0) + return 0; + + buffer[bytesRead] = '\0'; + + // replace all '\0's by spaces + for (size_t i = 0; i < bytesRead; i++) { + if (buffer[i] == '\0') + buffer[i] = ' '; + } + + if (const char* lineEnd = strchr(buffer, '\n')) + bytesRead = lineEnd - buffer; + + if (bytesRead > (size_t)width) + bytesRead = width; + + // replace unprintables by '.' + for (size_t i = 0; i < bytesRead; i++) { + if (!isprint(buffer[i])) + buffer[i] = '.'; + } + + bool lineBreak = buffer[bytesRead] == '\n'; + + buffer[bytesRead] = '\0'; + + return bytesRead + (lineBreak ? 1 : 0); +} + + +static int32 +count_lines(const PagerTextSource& textSource, size_t width, char* buffer, + size_t bufferSize) +{ + int32 lineCount = 0; + size_t offset = 0; + + while (true) { + size_t bytesRead = next_line(textSource, width, offset, buffer, + bufferSize); + if (bytesRead == 0) + break; + + offset += bytesRead; + lineCount++; + } + + return lineCount; +} + + +static size_t +offset_of_line(const PagerTextSource& textSource, size_t width, char* buffer, + size_t bufferSize, int32 line) +{ + int32 lineCount = 0; + size_t offset = 0; + + while (true) { + if (line == lineCount) + return offset; + + size_t bytesRead = next_line(textSource, width, offset, buffer, + bufferSize); + if (bytesRead == 0) + break; + + offset += bytesRead; + lineCount++; + } + + return offset; +} + + +// #pragma mark - + + +void +pager(const PagerTextSource& textSource) +{ + console_set_cursor(0, 0); + + int32 width = console_width(); + int32 height = console_height(); + + char lineBuffer[256]; + + int32 lineCount = count_lines(textSource, width, lineBuffer, + sizeof(lineBuffer)); + int32 topLine = 0; + + bool quit = false; + while (!quit) { + // get the text offset for the top line + size_t offset = offset_of_line(textSource, width, lineBuffer, + sizeof(lineBuffer), topLine); + + // clear the screen and print the lines + console_clear_screen(); + + int32 screenLine = 0; + while (screenLine + 1 < height) { + size_t bytesRead = next_line(textSource, width, offset, lineBuffer, + sizeof(lineBuffer)); + if (bytesRead == 0) + break; + + console_set_cursor(0, screenLine); + puts(lineBuffer); + + offset += bytesRead; + screenLine++; + } + + // print the statistics line at the bottom + console_set_cursor(0, height - 1); + console_set_color(BLACK, WHITE); + int32 bottomLine = std::min(topLine + height - 2, lineCount - 1); + printf("%" B_PRIuSIZE " - %" B_PRIuSIZE " %" B_PRIuSIZE "%%", + topLine, bottomLine, (bottomLine + 1) * 100 / lineCount); + console_set_color(WHITE, BLACK); + + // wait for a key that changes the position + int32 previousTopLine = topLine; + + while (!quit && topLine == previousTopLine) { + switch (console_wait_for_key()) { + case TEXT_CONSOLE_KEY_ESCAPE: + case 'q': + case 'Q': + // quit + quit = true; + break; + + case TEXT_CONSOLE_KEY_DOWN: + case TEXT_CONSOLE_KEY_RETURN: + // next line + topLine++; + break; + + case TEXT_CONSOLE_KEY_UP: + // previous line + topLine--; + break; + + case TEXT_CONSOLE_KEY_PAGE_UP: + // previous page + topLine -= height - 1; + break; + + case TEXT_CONSOLE_KEY_PAGE_DOWN: + // next page + topLine += height - 1; + break; + + case TEXT_CONSOLE_KEY_HOME: + // beginning of text + topLine = 0; + break; + + case TEXT_CONSOLE_KEY_END: + // end of text + topLine = lineCount; + break; + } + + if (topLine > lineCount - (height - 1)) + topLine = lineCount - (height - 1); + if (topLine < 0) + topLine = 0; + } + } +} Added: haiku/trunk/src/system/boot/loader/pager.h =================================================================== --- haiku/trunk/src/system/boot/loader/pager.h (rev 0) +++ haiku/trunk/src/system/boot/loader/pager.h 2010-03-11 17:09:11 UTC (rev 35812) @@ -0,0 +1,25 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * Distributed under the terms of the MIT License. + */ +#ifndef PAGER_H +#define PAGER_H + + +#include <SupportDefs.h> + + +class PagerTextSource { +public: + virtual ~PagerTextSource(); + + virtual size_t BytesAvailable() const = 0; + virtual size_t Read(size_t offset, void* buffer, + size_t size) const = 0; +}; + + +void pager(const PagerTextSource& textSource); + + +#endif // PAGER_H