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 <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
|
||||
const char *NAMES[128][2] = {
|
||||
{"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,
|
||||
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;
|
||||
int W = 0;
|
||||
@ -158,25 +164,30 @@ static void redraw(int 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);
|
||||
mvprintw(H-1, 0, " Output:");
|
||||
attroff(OUTPUT_LABEL_COLORS);
|
||||
addch(' ');
|
||||
attroff(OUTPUT_LABEL_COLORS);
|
||||
for (char *c = start; c < stop; c++) {
|
||||
if (' ' <= *c && *c <= '~') { // printable range
|
||||
printwattrs(OUTPUT_CHAR_COLORS, "%c", *c);
|
||||
} else {
|
||||
printwattrs(OUTPUT_ESCAPE_COLORS, "\\x%02X", *c);
|
||||
if (searchbuf[0] == '\0') return fallback;
|
||||
char tmp[COL_WIDTH+6];
|
||||
for (int i = 0; i <= 127; i++) {
|
||||
int c = (start + i*direction) % 128; // relative to starting point
|
||||
if (searchbuf[0] == c && searchbuf[1] == '\0')
|
||||
return c;
|
||||
// Only do full match for search strings longer than 1
|
||||
if (searchbuf[1]) {
|
||||
if (NAMES[c][1]) {
|
||||
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;
|
||||
getyx(stdscr, y, x);
|
||||
// Clear to end of line
|
||||
for (int x2 = x; x2 < W; x2++) mvaddch(y, x2, ' ');
|
||||
move(y, x);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
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_ESCAPE_COLORS = new_colorpair(COLOR_RED, COLOR_WHITE) | A_BOLD;
|
||||
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);
|
||||
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 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
|
||||
// the output buffer
|
||||
for (int i = 1; i < argc; i++) {
|
||||
@ -246,118 +262,207 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
int insert_mode = 0;
|
||||
int selected = 0;
|
||||
Mode mode = BROWSE_MODE;
|
||||
int prev_selected = 0, selected = 0;
|
||||
while (1) {
|
||||
redraw(selected);
|
||||
// Title bar
|
||||
move(0,0);
|
||||
if (insert_mode) {
|
||||
const char *str = "ASCII TABLE (typing, press 'esc' to browse)";
|
||||
int spacer = W/2-strlen(str)/2;
|
||||
printwattrs(INSERT_MODE_COLORS, "%*s%s%*s", spacer, "", str, spacer+1, "");
|
||||
char *title;
|
||||
int title_colors;
|
||||
switch (mode) {
|
||||
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 {
|
||||
const char *str = "ASCII TABLE (browsing, press 'esc' to exit)";
|
||||
int spacer = W/2-strlen(str)/2;
|
||||
printwattrs(BROWSE_MODE_COLORS, "%*s%s%*s", spacer, "", str, spacer+1, "");
|
||||
// Bar at the bottom of the screen showing the output text:
|
||||
// left-truncate output so the end of it fits on screen:
|
||||
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:
|
||||
// left-truncate output so the end of it fits on screen:
|
||||
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;
|
||||
}
|
||||
draw_output(visible, &outbuf[buf_i]);
|
||||
int y, x;
|
||||
getyx(stdscr, y, x);
|
||||
// Clear to end of line
|
||||
for (int x2 = x; x2 < W; x2++) mvaddch(y, x2, ' ');
|
||||
move(y, x);
|
||||
|
||||
refresh();
|
||||
next_input:;
|
||||
int key = getch();
|
||||
if (insert_mode) {
|
||||
if (key == 27) {
|
||||
insert_mode = 0;
|
||||
continue;
|
||||
} else if (key == 127) {
|
||||
// Backspace
|
||||
if (buf_i > 0) buf_i--;
|
||||
continue;
|
||||
} else if (0 <= key && key < 127) {
|
||||
outbuf[buf_i++] = (char)key;
|
||||
if (buf_i >= buf_size) {
|
||||
buf_size *= 2;
|
||||
outbuf = realloc(outbuf, buf_size);
|
||||
}
|
||||
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);
|
||||
switch (mode) {
|
||||
case INSERT_MODE:
|
||||
if (key == ESCAPE_KEY) {
|
||||
mode = BROWSE_MODE;
|
||||
} else if (key == DELETE_KEY) { // Backspace
|
||||
if (buf_i > 0) buf_i--;
|
||||
} else if (0 <= key && key < 127) {
|
||||
outbuf[buf_i++] = (char)key;
|
||||
if (buf_i >= buf_size) {
|
||||
buf_size *= 2;
|
||||
outbuf = realloc(outbuf, buf_size);
|
||||
}
|
||||
} else {
|
||||
goto next_input; // skip redraw
|
||||
}
|
||||
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;
|
||||
|
||||
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 >= 128) selected = 127;
|
||||
if (selected > 127) selected = 127;
|
||||
}
|
||||
|
||||
endwin();
|
||||
|
Loading…
Reference in New Issue
Block a user