Added search functionality.
This commit is contained in:
parent
185f9a6b42
commit
d6e65a89e8
329
ascii.c
329
ascii.c
@ -35,6 +35,11 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
typedef enum {BROWSE_MODE, INSERT_MODE, SEARCH_MODE} Mode;
|
||||||
|
|
||||||
|
#define DELETE_KEY 127
|
||||||
|
#define ESCAPE_KEY 27
|
||||||
|
|
||||||
// The descriptive names of the ASCII characters
|
// The descriptive names of the ASCII characters
|
||||||
const char *NAMES[128][2] = {
|
const char *NAMES[128][2] = {
|
||||||
{"NUL", "null"}, // 0
|
{"NUL", "null"}, // 0
|
||||||
@ -81,7 +86,8 @@ static int new_colorpair(int fg, int bg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int DECIMAL_COLORS, HEX_COLORS, CHAR_COLORS, DESCRIPTION_COLORS, OUTPUT_CHAR_COLORS,
|
int DECIMAL_COLORS, HEX_COLORS, CHAR_COLORS, DESCRIPTION_COLORS, OUTPUT_CHAR_COLORS,
|
||||||
OUTPUT_ESCAPE_COLORS, OUTPUT_LABEL_COLORS, BROWSE_MODE_COLORS, INSERT_MODE_COLORS;
|
OUTPUT_ESCAPE_COLORS, OUTPUT_LABEL_COLORS, SEARCH_BAR_COLORS, BROWSE_MODE_COLORS,
|
||||||
|
INSERT_MODE_COLORS, SEARCH_MODE_COLORS;
|
||||||
|
|
||||||
const int COL_WIDTH = 42;
|
const int COL_WIDTH = 42;
|
||||||
int W = 0;
|
int W = 0;
|
||||||
@ -158,25 +164,30 @@ static void redraw(int selected)
|
|||||||
last_selected = selected;
|
last_selected = selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_output(char *start, char *stop)
|
static int find_ascii_match(int start, int fallback, int direction, char *searchbuf)
|
||||||
{
|
{
|
||||||
attron(OUTPUT_LABEL_COLORS);
|
if (searchbuf[0] == '\0') return fallback;
|
||||||
mvprintw(H-1, 0, " Output:");
|
char tmp[COL_WIDTH+6];
|
||||||
attroff(OUTPUT_LABEL_COLORS);
|
for (int i = 0; i <= 127; i++) {
|
||||||
addch(' ');
|
int c = (start + i*direction) % 128; // relative to starting point
|
||||||
attroff(OUTPUT_LABEL_COLORS);
|
if (searchbuf[0] == c && searchbuf[1] == '\0')
|
||||||
for (char *c = start; c < stop; c++) {
|
return c;
|
||||||
if (' ' <= *c && *c <= '~') { // printable range
|
// Only do full match for search strings longer than 1
|
||||||
printwattrs(OUTPUT_CHAR_COLORS, "%c", *c);
|
if (searchbuf[1]) {
|
||||||
} else {
|
if (NAMES[c][1]) {
|
||||||
printwattrs(OUTPUT_ESCAPE_COLORS, "\\x%02X", *c);
|
sprintf(tmp, "%d 0x%02X 0x%02x %s %s", c, c, c, NAMES[c][0] ? NAMES[c][0] : "", NAMES[c][1]);
|
||||||
|
} else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
|
||||||
|
sprintf(tmp, "%d 0x%02X 0x%02x %s The letter %c", c, c, c, NAMES[c][0] ? NAMES[c][0] : "", c);
|
||||||
|
} else if ('0' <= c && c <= '9') {
|
||||||
|
sprintf(tmp, "%d 0x%02X 0x%02x %s The number %c", c, c, c, NAMES[c][0] ? NAMES[c][0] : "", c);
|
||||||
|
} else {
|
||||||
|
sprintf(tmp, "%d 0x%02X 0x%02x %s The %c character", c, c, c, NAMES[c][0] ? NAMES[c][0] : "", c);
|
||||||
|
}
|
||||||
|
if (strstr(tmp, searchbuf) != NULL)
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int y, x;
|
return fallback;
|
||||||
getyx(stdscr, y, x);
|
|
||||||
// Clear to end of line
|
|
||||||
for (int x2 = x; x2 < W; x2++) mvaddch(y, x2, ' ');
|
|
||||||
move(y, x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -211,8 +222,10 @@ int main(int argc, char *argv[])
|
|||||||
OUTPUT_CHAR_COLORS = new_colorpair(COLOR_BLACK, COLOR_WHITE) | A_BOLD;
|
OUTPUT_CHAR_COLORS = new_colorpair(COLOR_BLACK, COLOR_WHITE) | A_BOLD;
|
||||||
OUTPUT_ESCAPE_COLORS = new_colorpair(COLOR_RED, COLOR_WHITE) | A_BOLD;
|
OUTPUT_ESCAPE_COLORS = new_colorpair(COLOR_RED, COLOR_WHITE) | A_BOLD;
|
||||||
OUTPUT_LABEL_COLORS = new_colorpair(COLOR_BLACK, COLOR_YELLOW);
|
OUTPUT_LABEL_COLORS = new_colorpair(COLOR_BLACK, COLOR_YELLOW);
|
||||||
|
SEARCH_BAR_COLORS = new_colorpair(COLOR_BLACK, COLOR_GREEN);
|
||||||
BROWSE_MODE_COLORS = new_colorpair(COLOR_BLACK, COLOR_BLUE);
|
BROWSE_MODE_COLORS = new_colorpair(COLOR_BLACK, COLOR_BLUE);
|
||||||
INSERT_MODE_COLORS = new_colorpair(COLOR_WHITE, COLOR_RED) | A_BOLD;
|
INSERT_MODE_COLORS = new_colorpair(COLOR_WHITE, COLOR_RED) | A_BOLD;
|
||||||
|
SEARCH_MODE_COLORS = new_colorpair(COLOR_WHITE, COLOR_GREEN) | A_BOLD;
|
||||||
|
|
||||||
size_t chunk = 256;
|
size_t chunk = 256;
|
||||||
size_t buf_size = chunk, buf_i = 0;
|
size_t buf_size = chunk, buf_i = 0;
|
||||||
@ -235,6 +248,9 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char searchbuf[1024] = {'\0'};
|
||||||
|
size_t searchlen = 0;
|
||||||
|
|
||||||
// If any command line args, treat them as bytes to append to
|
// If any command line args, treat them as bytes to append to
|
||||||
// the output buffer
|
// the output buffer
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
@ -246,118 +262,207 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int insert_mode = 0;
|
Mode mode = BROWSE_MODE;
|
||||||
int selected = 0;
|
int prev_selected = 0, selected = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
redraw(selected);
|
redraw(selected);
|
||||||
// Title bar
|
// Title bar
|
||||||
move(0,0);
|
move(0,0);
|
||||||
if (insert_mode) {
|
char *title;
|
||||||
const char *str = "ASCII TABLE (typing, press 'esc' to browse)";
|
int title_colors;
|
||||||
int spacer = W/2-strlen(str)/2;
|
switch (mode) {
|
||||||
printwattrs(INSERT_MODE_COLORS, "%*s%s%*s", spacer, "", str, spacer+1, "");
|
case INSERT_MODE:
|
||||||
|
title = "ASCII TABLE (typing, 'esc' to browse)";
|
||||||
|
title_colors = INSERT_MODE_COLORS;
|
||||||
|
break;
|
||||||
|
case SEARCH_MODE:
|
||||||
|
title = "ASCII TABLE (searching, 'esc' to browse)";
|
||||||
|
title_colors = SEARCH_MODE_COLORS;
|
||||||
|
break;
|
||||||
|
case BROWSE_MODE:
|
||||||
|
title = "ASCII TABLE (browsing, 'esc' to exit)";
|
||||||
|
title_colors = BROWSE_MODE_COLORS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int spacer = W/2-strlen(title)/2;
|
||||||
|
printwattrs(title_colors, "%*s%s%*s", spacer, "", title, spacer+1, "");
|
||||||
|
|
||||||
|
if (mode == SEARCH_MODE) {
|
||||||
|
attron(SEARCH_BAR_COLORS);
|
||||||
|
mvprintw(H-1, 0, " Search:");
|
||||||
|
attroff(SEARCH_BAR_COLORS);
|
||||||
|
addch(' ');
|
||||||
|
printwattrs(OUTPUT_CHAR_COLORS, "%s", searchbuf);
|
||||||
} else {
|
} else {
|
||||||
const char *str = "ASCII TABLE (browsing, press 'esc' to exit)";
|
// Bar at the bottom of the screen showing the output text:
|
||||||
int spacer = W/2-strlen(str)/2;
|
// left-truncate output so the end of it fits on screen:
|
||||||
printwattrs(BROWSE_MODE_COLORS, "%*s%s%*s", spacer, "", str, spacer+1, "");
|
char *visible = &outbuf[buf_i];
|
||||||
|
for (int space = W-strlen(" Output: ")-1-5; space > 0 && visible > outbuf; visible--) {
|
||||||
|
int chlen = (' ' <= *visible && *visible <= '~') ? 1 : 4; // printable range
|
||||||
|
if (chlen > space) break;
|
||||||
|
else space -= chlen;
|
||||||
|
}
|
||||||
|
attron(mode == INSERT_MODE ? INSERT_MODE_COLORS : OUTPUT_LABEL_COLORS);
|
||||||
|
mvprintw(H-1, 0, " Output:");
|
||||||
|
attroff(mode == INSERT_MODE ? INSERT_MODE_COLORS : OUTPUT_LABEL_COLORS);
|
||||||
|
addch(' ');
|
||||||
|
for (char *c = visible; c < &outbuf[buf_i]; c++) {
|
||||||
|
if (' ' <= *c && *c <= '~') { // printable range
|
||||||
|
printwattrs(OUTPUT_CHAR_COLORS, "%c", *c);
|
||||||
|
} else {
|
||||||
|
printwattrs(OUTPUT_ESCAPE_COLORS, "\\x%02X", *c);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Bar at the bottom of the screen showing the output text:
|
int y, x;
|
||||||
// left-truncate output so the end of it fits on screen:
|
getyx(stdscr, y, x);
|
||||||
char *visible = &outbuf[buf_i];
|
// Clear to end of line
|
||||||
for (int space = W-strlen(" Output: ")-1-5; space > 0 && visible > outbuf; visible--) {
|
for (int x2 = x; x2 < W; x2++) mvaddch(y, x2, ' ');
|
||||||
int chlen = (' ' <= *visible && *visible <= '~') ? 1 : 4; // printable range
|
move(y, x);
|
||||||
if (chlen > space) break;
|
|
||||||
else space -= chlen;
|
|
||||||
}
|
|
||||||
draw_output(visible, &outbuf[buf_i]);
|
|
||||||
refresh();
|
refresh();
|
||||||
next_input:;
|
next_input:;
|
||||||
int key = getch();
|
int key = getch();
|
||||||
if (insert_mode) {
|
switch (mode) {
|
||||||
if (key == 27) {
|
case INSERT_MODE:
|
||||||
insert_mode = 0;
|
if (key == ESCAPE_KEY) {
|
||||||
continue;
|
mode = BROWSE_MODE;
|
||||||
} else if (key == 127) {
|
} else if (key == DELETE_KEY) { // Backspace
|
||||||
// Backspace
|
if (buf_i > 0) buf_i--;
|
||||||
if (buf_i > 0) buf_i--;
|
} else if (0 <= key && key < 127) {
|
||||||
continue;
|
outbuf[buf_i++] = (char)key;
|
||||||
} else if (0 <= key && key < 127) {
|
if (buf_i >= buf_size) {
|
||||||
outbuf[buf_i++] = (char)key;
|
buf_size *= 2;
|
||||||
if (buf_i >= buf_size) {
|
outbuf = realloc(outbuf, buf_size);
|
||||||
buf_size *= 2;
|
}
|
||||||
outbuf = realloc(outbuf, buf_size);
|
} else {
|
||||||
}
|
goto next_input; // skip redraw
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (key) {
|
|
||||||
case 'j': case KEY_DOWN:
|
|
||||||
selected++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'J':
|
|
||||||
selected += 10;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'k': case KEY_UP:
|
|
||||||
selected--;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'K':
|
|
||||||
selected -= 10;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'l': case 'L': case KEY_RIGHT: case KEY_SRIGHT:
|
|
||||||
selected += H-2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'h': case 'H': case KEY_LEFT: case KEY_SLEFT:
|
|
||||||
selected -= H-2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'i': case 'a':
|
|
||||||
insert_mode = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KEY_RESIZE:
|
|
||||||
// To prevent wasted work, wait until 200ms has elapsed
|
|
||||||
// with no additional resizes before doing anything
|
|
||||||
timeout(0);
|
|
||||||
do {
|
|
||||||
// Wait 200ms
|
|
||||||
usleep(2e5);
|
|
||||||
// Peek if there's another resize event
|
|
||||||
int k = getch();
|
|
||||||
if (k == KEY_RESIZE) continue;
|
|
||||||
if (k > 0) ungetch(k);
|
|
||||||
} while (0);
|
|
||||||
// Back to blocking input
|
|
||||||
timeout(-1);
|
|
||||||
W = getmaxx(stdscr);
|
|
||||||
H = getmaxy(stdscr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KEY_ENTER: case '\n':
|
|
||||||
outbuf[buf_i++] = (char)selected;
|
|
||||||
if (buf_i >= buf_size) {
|
|
||||||
buf_size *= 2;
|
|
||||||
outbuf = realloc(outbuf, buf_size);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_BACKSPACE: case KEY_DC: case 127:
|
|
||||||
if (buf_i > 0) buf_i--;
|
case SEARCH_MODE:
|
||||||
|
switch (key) {
|
||||||
|
case ESCAPE_KEY: // Escape
|
||||||
|
selected = prev_selected;
|
||||||
|
searchbuf[0] = '\0';
|
||||||
|
searchlen = 0;
|
||||||
|
mode = BROWSE_MODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
mode = BROWSE_MODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DELETE_KEY:
|
||||||
|
if (searchlen > 0) {
|
||||||
|
searchlen--;
|
||||||
|
searchbuf[searchlen] = '\0';
|
||||||
|
selected = find_ascii_match(prev_selected, prev_selected, 1, searchbuf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (0 <= key && key < 127) {
|
||||||
|
if (searchlen < sizeof(searchbuf)-1) {
|
||||||
|
searchbuf[searchlen++] = (char)key;
|
||||||
|
searchbuf[searchlen] = '\0';
|
||||||
|
}
|
||||||
|
selected = find_ascii_match(prev_selected, prev_selected, 1, searchbuf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
goto next_input; // skip redraw
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'q': case 'Q': case KEY_CANCEL: case KEY_CLOSE: case KEY_EXIT: case 27:
|
|
||||||
endwin();
|
|
||||||
write(STDOUT_FILENO, outbuf, buf_i);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
default: goto next_input;
|
case BROWSE_MODE:
|
||||||
|
switch (key) {
|
||||||
|
case 'j': case KEY_DOWN:
|
||||||
|
selected++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'J':
|
||||||
|
selected += 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'k': case KEY_UP:
|
||||||
|
selected--;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'K':
|
||||||
|
selected -= 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l': case 'L': case KEY_RIGHT: case KEY_SRIGHT:
|
||||||
|
selected += H-2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'h': case 'H': case KEY_LEFT: case KEY_SLEFT:
|
||||||
|
selected -= H-2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'i': case 'a':
|
||||||
|
mode = INSERT_MODE;
|
||||||
|
prev_selected = selected;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '/':
|
||||||
|
mode = SEARCH_MODE;
|
||||||
|
searchbuf[0] = '\0';
|
||||||
|
searchlen = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
selected = find_ascii_match(selected+1, selected, 1, searchbuf);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'N':
|
||||||
|
selected = find_ascii_match(selected-1, selected, -1, searchbuf);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KEY_RESIZE:
|
||||||
|
// To prevent wasted work, wait until 200ms has elapsed
|
||||||
|
// with no additional resizes before doing anything
|
||||||
|
timeout(0);
|
||||||
|
do {
|
||||||
|
// Wait 200ms
|
||||||
|
usleep(2e5);
|
||||||
|
// Peek if there's another resize event
|
||||||
|
int k = getch();
|
||||||
|
if (k == KEY_RESIZE) continue;
|
||||||
|
if (k > 0) ungetch(k);
|
||||||
|
} while (0);
|
||||||
|
// Back to blocking input
|
||||||
|
timeout(-1);
|
||||||
|
W = getmaxx(stdscr);
|
||||||
|
H = getmaxy(stdscr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KEY_ENTER: case '\n':
|
||||||
|
outbuf[buf_i++] = (char)selected;
|
||||||
|
if (buf_i >= buf_size) {
|
||||||
|
buf_size *= 2;
|
||||||
|
outbuf = realloc(outbuf, buf_size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KEY_BACKSPACE: case KEY_DC: case DELETE_KEY:
|
||||||
|
if (buf_i > 0) buf_i--;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'q': case 'Q': case KEY_CANCEL: case KEY_CLOSE: case KEY_EXIT: case ESCAPE_KEY:
|
||||||
|
endwin();
|
||||||
|
write(STDOUT_FILENO, outbuf, buf_i);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto next_input; // skip redraw
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (selected < 0) selected = 0;
|
if (selected < 0) selected = 0;
|
||||||
if (selected >= 128) selected = 127;
|
if (selected > 127) selected = 127;
|
||||||
}
|
}
|
||||||
|
|
||||||
endwin();
|
endwin();
|
||||||
|
Loading…
Reference in New Issue
Block a user