#include #include #include #include #include #define ERROR_COLOR _COLOR_BG_LGRAY | _COLOR_FG_RED #define UI_COLOR _COLOR_BG_LGRAY | _COLOR_FG_BLACK #define DEFAULT_TEXT_COLOR _COLOR_BG_BLACK | _COLOR_FG_WHITE #define MAN_ROOT "man/" #define MRL 4 #define MAN_EXT "man" #define MAX_PATH_LEN 255 #define SP80 " " #define SP79 " " #define SP69 " " #define SP10 " " struct file *cur_file = 0; char *name_backup = 0; uint32_t *line_offsets = 0; uint32_t n_lines; struct link { uint32_t line; uint8_t col; uint8_t len; char *lto; }; struct link *link_table_start = 0; struct link *link_table_end; struct link *cur_link = 0; uint32_t line_on; #define DATA_BUF_SIZE 2000 void print_page() { uint8_t buf[DATA_BUF_SIZE];//1840 + up to 160 color codes seek_file_to(cur_file, line_offsets[line_on]); uint8_t *bufp = buf + DATA_BUF_SIZE; uint8_t *bufend; uint8_t row = 1, col = 0; _set_color(DEFAULT_TEXT_COLOR); while (row != 24) { if (bufp == buf + DATA_BUF_SIZE) { bufp = buf; uint16_t bl = read_from_file(cur_file, DATA_BUF_SIZE, buf); bufend = bl == DATA_BUF_SIZE ? 0 : buf + bl; } if (bufp == bufend) { uint32_t *i = buf; uint16_t l = 80 - col + (23 - row) * 80; uint32_t *e = i + l / 4 + 1; while (i != e) *(i++) = 0x20202020; buf[l] = '\0'; _print_at(row, col, buf); break; } if (*bufp & 0x80) _set_color(*bufp & 0x7f); else { char bufpb[2] = {*bufp, '\0'}; _print_at(row, col, bufpb); if (++col == 80) { col = 0; ++row; } } ++bufp; } if (cur_link) for (uint8_t c = cur_link->col; c < cur_link->col + cur_link->len; ++c) _swap_color(cur_link->line - line_on + 1, c); } void scroll_to(uint32_t n) { if (n > n_lines - 23) n = n_lines - 23; if (cur_link && ((cur_link->line < n) || (cur_link->line >= n + 23))) cur_link = 0; line_on = n; print_page(); char b[16] = "Line "; itosz(line_on, b + 5); _set_color(UI_COLOR); _print_at(24, 0, SP69); _print_at(24, 0, b); } void scroll_link() { if (cur_link->line < line_on) scroll_to(cur_link->line); else if (cur_link->line >= line_on + 23) scroll_to(cur_link->line - 22); else print_page(); } void load_file(const char *name) { static char cur_page[MAX_PATH_LEN + 1] = MAN_ROOT; uint32_t name_len = strcpy(cur_page + MRL, name); strcpy(cur_page + MRL + name_len, "." MAN_EXT); struct file *new_file = open_file(cur_page); if (!new_file) { _set_color(ERROR_COLOR); _print_at(24, 0, SP79); _print_at(24, 0, "Could not open file."); return; } if (name_backup) free_block(name_backup); name_backup = strdup(name); if (cur_file) close_file(cur_file); cur_file = new_file; uint32_t tlen; read_from_file(cur_file, 4, &tlen); char title[81]; read_from_file(cur_file, tlen + 1, title); _set_color(UI_COLOR); _print_at(0, 0, SP80); _print_at(0, 0, title); if (link_table_start) { for (struct link *l = link_table_start; l != link_table_end; ++l) free_block(l->lto); free_block(link_table_start); } uint32_t linktc; read_from_file(cur_file, 4, &linktc); if (linktc) { link_table_start = get_block(sizeof(struct link) * linktc); link_table_end = link_table_start + linktc; read_from_file(cur_file, 4, &linktc);//dummy for (struct link *l = link_table_start; l != link_table_end; ++l) { read_from_file(cur_file, 4, &l->line); read_from_file(cur_file, 1, &l->col); read_from_file(cur_file, 1, &l->len); uint32_t lto_l; read_from_file(cur_file, 4, <o_l); l->lto = get_block(lto_l + 1); read_from_file(cur_file, lto_l + 1, l->lto); } } else { link_table_start = 0; read_from_file(cur_file, 4, &linktc);//dummy } cur_link = 0; if (line_offsets) free_block(line_offsets); read_from_file(cur_file, 4, &n_lines); line_offsets = get_block(n_lines * 4); read_from_file(cur_file, n_lines * 4, line_offsets); char b[11]; itosz(n_lines, b); _set_color(UI_COLOR); _print_at(24, 69, SP10); _print_at(24, 69, b); scroll_to(0); } struct stack_entry { struct stack_entry *down; char *name; uint32_t line; }; struct stack_entry *stack_top = 0; void push() { struct stack_entry *new_entry = get_block(sizeof(struct stack_entry)); new_entry->down = stack_top; new_entry->name = strdup(name_backup); new_entry->line = line_on; stack_top = new_entry; } void pop() { if (stack_top) { load_file(stack_top->name); scroll_to(stack_top->line); free_block(stack_top->name); free_block(stack_top); stack_top = stack_top->down; } } void main() { _set_color(UI_COLOR); _print_at(24, 79, " "); load_file("index"); while (true) { switch (_get_key()) { case 0: default: _yield_task(); break; case _KEY_UP: if (n_lines <= 23) break; if (line_on) scroll_to(line_on - 1); break; case _KEY_DOWN: if (n_lines <= 23) break; if (line_on < n_lines - 23) scroll_to(line_on + 1); break; case _KEY_PUP: if (n_lines <= 23) break; scroll_to(line_on <= 22 ? 0 : line_on - 22); break; case _KEY_PDOWN: if (n_lines <= 23) break; scroll_to(line_on + 22); break; case _KEY_LEFT: if (cur_link == link_table_start) break; if (cur_link) { --cur_link; scroll_link(); } else if (link_table_start) { struct link *l = link_table_end; while (l != link_table_start) { --l; if (l->line <= line_on + 22) break; } cur_link = l; scroll_link(); } break; case _KEY_RIGHT: if (cur_link == link_table_end - 1) break; if (cur_link) { ++cur_link; scroll_link(); } else if (link_table_start) { struct link *l = link_table_start; while (l != link_table_end) { if (l->line >= line_on) break; ++l; } cur_link = l; scroll_link(); } break; case ' ': case '\n': case _KEY_NENTER: if (cur_link) { push(); load_file(cur_link->lto); } break; case _KEY_ESC: if (stack_top) pop(); break; case 'q': return; } } }