headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / boot / loader / pager.cpp
blob24445e55f2597134fee3a904d24ae3c5b9e7272f
1 /*
2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "pager.h"
9 #include <ctype.h>
10 #include <string.h>
12 #include <algorithm>
14 #include <boot/platform/generic/text_console.h>
17 // #pragma mark - PagerTextSource
20 PagerTextSource::~PagerTextSource()
25 // #pragma mark -
28 static size_t
29 next_line(const PagerTextSource& textSource, size_t width, size_t offset,
30 char* buffer, size_t bufferSize)
32 size_t bytesRead = textSource.Read(offset, buffer, bufferSize - 1);
33 if (bytesRead == 0)
34 return 0;
36 buffer[bytesRead] = '\0';
38 // replace all '\0's by spaces
39 for (size_t i = 0; i < bytesRead; i++) {
40 if (buffer[i] == '\0')
41 buffer[i] = ' ';
44 if (const char* lineEnd = strchr(buffer, '\n'))
45 bytesRead = lineEnd - buffer;
47 if (bytesRead > (size_t)width)
48 bytesRead = width;
50 // replace unprintables by '.'
51 for (size_t i = 0; i < bytesRead; i++) {
52 if (!isprint(buffer[i]))
53 buffer[i] = '.';
56 bool lineBreak = buffer[bytesRead] == '\n';
58 buffer[bytesRead] = '\0';
60 return bytesRead + (lineBreak ? 1 : 0);
64 static int32
65 count_lines(const PagerTextSource& textSource, size_t width, char* buffer,
66 size_t bufferSize)
68 int32 lineCount = 0;
69 size_t offset = 0;
71 while (true) {
72 size_t bytesRead = next_line(textSource, width, offset, buffer,
73 bufferSize);
74 if (bytesRead == 0)
75 break;
77 offset += bytesRead;
78 lineCount++;
81 return lineCount;
85 static size_t
86 offset_of_line(const PagerTextSource& textSource, size_t width, char* buffer,
87 size_t bufferSize, int32 line)
89 int32 lineCount = 0;
90 size_t offset = 0;
92 while (true) {
93 if (line == lineCount)
94 return offset;
96 size_t bytesRead = next_line(textSource, width, offset, buffer,
97 bufferSize);
98 if (bytesRead == 0)
99 break;
101 offset += bytesRead;
102 lineCount++;
105 return offset;
109 // #pragma mark -
112 void
113 pager(const PagerTextSource& textSource)
115 console_set_cursor(0, 0);
117 int32 width = console_width();
118 int32 height = console_height();
120 char lineBuffer[256];
122 int32 lineCount = count_lines(textSource, width, lineBuffer,
123 sizeof(lineBuffer));
124 int32 topLine = 0;
126 bool quit = false;
127 while (!quit) {
128 // get the text offset for the top line
129 size_t offset = offset_of_line(textSource, width, lineBuffer,
130 sizeof(lineBuffer), topLine);
132 // clear the screen and print the lines
133 console_clear_screen();
135 int32 screenLine = 0;
136 while (screenLine + 1 < height) {
137 size_t bytesRead = next_line(textSource, width, offset, lineBuffer,
138 sizeof(lineBuffer));
139 if (bytesRead == 0)
140 break;
142 console_set_cursor(0, screenLine);
143 puts(lineBuffer);
145 offset += bytesRead;
146 screenLine++;
149 // print the statistics line at the bottom
150 console_set_cursor(0, height - 1);
151 console_set_color(BLACK, GRAY);
152 int32 bottomLine = std::min(topLine + height - 2, lineCount - 1);
153 printf("%" B_PRIuSIZE " - %" B_PRIuSIZE " %" B_PRIuSIZE "%%",
154 topLine, bottomLine, (bottomLine + 1) * 100 / lineCount);
155 console_set_color(WHITE, BLACK);
157 // wait for a key that changes the position
158 int32 previousTopLine = topLine;
160 while (!quit && topLine == previousTopLine) {
161 switch (console_wait_for_key()) {
162 case TEXT_CONSOLE_KEY_ESCAPE:
163 case 'q':
164 case 'Q':
165 // quit
166 quit = true;
167 break;
169 case TEXT_CONSOLE_KEY_DOWN:
170 case TEXT_CONSOLE_KEY_RETURN:
171 // next line
172 topLine++;
173 break;
175 case TEXT_CONSOLE_KEY_UP:
176 // previous line
177 topLine--;
178 break;
180 case TEXT_CONSOLE_KEY_PAGE_UP:
181 // previous page
182 topLine -= height - 1;
183 break;
185 case TEXT_CONSOLE_KEY_PAGE_DOWN:
186 // next page
187 topLine += height - 1;
188 break;
190 case TEXT_CONSOLE_KEY_HOME:
191 // beginning of text
192 topLine = 0;
193 break;
195 case TEXT_CONSOLE_KEY_END:
196 // end of text
197 topLine = lineCount;
198 break;
201 if (topLine > lineCount - (height - 1))
202 topLine = lineCount - (height - 1);
203 if (topLine < 0)
204 topLine = 0;