#include #include #include #include #include #include #include #include #include #define VERSION "1.0" char *helptext[] = { "Left/Up/Right/Down - move", "Space - Toggle", "L - Load file", "S - Save file", "C - Save font to console", "D - Load font from console", "Q - Quit", "R - redraw screen", "PgUp - previous char", "PgDown - next char", "# - jump to specific char" }; const int helplines = 11; char *title = "fnteditfs "VERSION" - A Full-Screen Console Font Editor"; int charnum = 65; int editx = 0, edity = 0; WINDOW *helpwin, *editwin, *statusln; char fontbuf[4096]; char fnamebuf[_POSIX_PATH_MAX+1]; #define edit_line_refresh \ prefresh(pad, 0, x / (width - 10) * (width - 10) - 10, top, left, top, left + width) char *edit_line (char *buf, int bufsize, int top, int left, int width, int numeric) { WINDOW *pad = newpad(1, bufsize); int ch, buflen = strlen(buf); int insertmode = 1; int y = 0, x = buflen; if (!pad) return (char*)0; keypad(pad, 1); wattrset(pad, A_BOLD); wclear(pad); waddstr(pad, buf); edit_line_refresh; while (1) { getyx(pad, y, x); ch = wgetch(pad); switch (ch) { case -1: return NULL; case KEY_IC: // insert insertmode = !insertmode; break; case KEY_DC: // delete if (buflen == 0) { beep(); edit_line_refresh; break; } if (x == buflen) wmove(pad, y, --x); memcpy(&buf[x], &buf[x+1], buflen - x + 1); buf[--buflen] = (char)0; waddstr(pad, &buf[x]); wclrtoeol(pad); wmove(pad, y, x); edit_line_refresh; break; case KEY_BACKSPACE: // backspace if (buflen == 0 || x == 0) { beep(); edit_line_refresh; break; } if (x == buflen) { wmove(pad, y, --x); waddch(pad, ' '); wmove(pad, y, x); buflen--; } else { wmove(pad, y, --x); memcpy(&buf[x], &buf[x+1], buflen - x + 1); buf[--buflen] = (char)0; waddstr(pad, &buf[x]); wclrtoeol(pad); wmove(pad, y, x); } edit_line_refresh; break; case KEY_HOME: // home x = 0; wmove(pad, y, x); edit_line_refresh; break; case KEY_END: // end x = buflen; wmove(pad, y, x); edit_line_refresh; break; case KEY_LEFT: // left arrow if (!x) { beep(); edit_line_refresh; break; } x--; wmove(pad, y, x); edit_line_refresh; break; case KEY_RIGHT: // right arrow if (x == buflen) { beep(); edit_line_refresh; break; } x++; wmove(pad, y, x); edit_line_refresh; break; case 12: // ^L char redrawwin(pad); edit_line_refresh; break; case '\r': // CR case '\n': // LF (line feed) wattrset(pad, 0); wmove(pad, 0, 0); wclear(pad); edit_line_refresh; delwin(pad); buf[buflen] = (char)0; return (char*)buf; case 21: // ^U char x = 0; buflen = 0; wclear(pad); edit_line_refresh; break; case 27: // ESC wattrset(pad, 0); wmove(pad, 0, 0); wclear(pad); edit_line_refresh; delwin(pad); return (char*) 0; default: // any other key if ((ch > 255 || ch < 32) || (numeric && (ch < '0' || ch > '9'))) { beep(); edit_line_refresh; break; } if (buflen >= bufsize - 1) { // end of buffer beep(); edit_line_refresh; break; } if (x == buflen) { buf[x] = ch; waddch(pad, ch); buflen++; } else { if (insertmode) { memcpy(&buf[x+1], &buf[x], buflen - x); buf[++buflen] = (char)0; buf[x] = ch; waddstr(pad, &buf[x]); wmove(pad, 0, ++x); } else { buf[x] = ch; waddch(pad, ch); } } edit_line_refresh; } } } void draw_char (WINDOW *win, int num, char buf[]) { int i; wmove(win, 0, 12 / 2 - 5); wprintw(win, " Char %03d ", charnum); for (i = 0; i < 128; i++) { if (i % 8 == 0) wmove(win, i / 8 + 1, 2); waddch(win, buf[i / 8] & (1 << (7 - i % 8)) ? ACS_BLOCK : ' '); } wmove(win, edity + 1, editx + 2); } void toggle_char_bit(WINDOW *win, int num, char *buf, int y, int x) { buf[num * 16 + y] ^= (1 << (7 - x)); wmove(win, y + 1, x + 2); waddch(win, buf[num * 16 + y] & (1 << (7 - x)) ? ACS_BLOCK : ' '); wmove(win, y + 1, x + 2); } void draw_screen () { int i, len = strlen(title); attrset(A_STANDOUT); move(0, 0); for (i = 0; i < (80 - len) / 2; i++) addch(' '); addstr(title); for (i = (80 - len) / 2 + len; i < COLS; i++) addch(' '); helpwin = newwin(helplines + 2, 30, 5, 5); box(helpwin, ACS_VLINE, ACS_HLINE); wmove(helpwin, 0, 30 / 2 - 3); waddstr(helpwin, " Keys "); for (i = 0; i < helplines; i++) { wmove(helpwin, 1 + i, 2); waddstr(helpwin, helptext[i]); } editwin = newwin(18, 12, 5, 59); box(editwin, ACS_VLINE, ACS_HLINE); draw_char(editwin, charnum, &fontbuf[charnum * 16]); refresh(); statusln = newwin(1, COLS, LINES - 1, 0); wrefresh(helpwin); wrefresh(editwin); } void ask_move_char () { char buf[4]; buf[0] = 0; wclear(statusln); mvwaddstr(statusln, 0, 0, "New character #:"); wrefresh(statusln); if (edit_line(buf, sizeof(buf), LINES - 1, 17, 4, 1)) { charnum = atol(buf) % 256; draw_char(editwin, charnum, &fontbuf[charnum * 16]); wrefresh(editwin); } wclear(statusln); wrefresh(statusln); wrefresh(editwin); } void interactive_load_file () { char buf[sizeof(fnamebuf)]; int fd, rc; strcpy(buf, fnamebuf); wclear(statusln); mvwaddstr(statusln, 0, 0, "Load from file:"); wrefresh(statusln); if (!edit_line(buf, sizeof(buf), LINES - 1, 16, COLS - 16, 0)) { wclear(statusln); mvwaddstr(statusln, 0, 0, "Load canceled."); wrefresh(statusln); wrefresh(editwin); return; } strcpy(fnamebuf, buf); fd = open(buf, O_RDONLY); if (fd < 0) { wclear(statusln); mvwprintw(statusln, 0, 0, "Load error: open: %s", strerror(errno)); wrefresh(statusln); wrefresh(editwin); return; } rc = read(fd, fontbuf, sizeof(fontbuf)); if (rc < sizeof(fontbuf)) { wclear(statusln); if (rc < 0) mvwprintw(statusln, 0, 0, "Load error: read: %s", strerror(errno)); else if (rc == 0) mvwaddstr(statusln, 0, 0, "Load error: Font is empty"); else mvwaddstr(statusln, 0, 0, "Load warning: Font is too short; partially loaded"); wrefresh(statusln); draw_char(editwin, charnum, &fontbuf[charnum * 16]); wrefresh(editwin); close(fd); return; } close(fd); wclear(statusln); mvwaddstr(statusln, 0, 0, "Font loaded."); wrefresh(statusln); draw_char(editwin, charnum, &fontbuf[charnum * 16]); wrefresh(editwin); } void interactive_save_file () { char buf[sizeof(fnamebuf)]; int fd, rc; strcpy(buf, fnamebuf); wclear(statusln); mvwaddstr(statusln, 0, 0, "Save to file:"); wrefresh(statusln); if (!edit_line(buf, sizeof(buf), LINES - 1, 14, COLS - 14, 0)) { wclear(statusln); mvwaddstr(statusln, 0, 0, "Save canceled."); wrefresh(statusln); wrefresh(editwin); return; } strcpy(fnamebuf, buf); fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { wclear(statusln); mvwprintw(statusln, 0, 0, "Save error: open: %s", strerror(errno)); wrefresh(statusln); wrefresh(editwin); return; } rc = write(fd, fontbuf, sizeof(fontbuf)); if (rc < sizeof(fontbuf)) { wclear(statusln); mvwprintw(statusln, 0, 0, "Save error: write: %s", strerror(errno)); wrefresh(statusln); wrefresh(editwin); close(fd); return; } close(fd); wclear(statusln); mvwaddstr(statusln, 0, 0, "Font saved."); wrefresh(statusln); wrefresh(editwin); } /**********************************/ /* operation system depended code */ /**********************************/ #if defined(__FreeBSD__) #include #include int do_ioctl(const char *header, unsigned long request, char *buf) { int fd; if (ioctl(0, request, buf) < 0) { fd = open("/dev/console", O_RDONLY, 0); if (fd < 0) { wclear(statusln); mvwprintw(statusln, 0, 0, "%s failed to open /dev/console: %s", header, strerror(errno)); wrefresh(statusln); wrefresh(editwin); return -1; } if (ioctl(fd, request, buf) < 0) { wclear(statusln); mvwprintw(statusln, 0, 0, "%s failed to ioctl /dev/console: %s", header, strerror(errno)); wrefresh(statusln); wrefresh(editwin); close(fd); return -1; } } return 0; } void save_font_to_console () { if (do_ioctl("Save error:", PIO_FONT8x16, fontbuf) < 0) return; wclear(statusln); mvwaddstr(statusln, 0, 0, "Font saved to console."); wrefresh(statusln); wrefresh(editwin); } void load_font_from_console () { if (do_ioctl("Load error:", GIO_FONT8x16, fontbuf) < 0) return; wclear(statusln); mvwaddstr(statusln, 0, 0, "Font loaded from console."); wrefresh(statusln); draw_char(editwin, charnum, &fontbuf[charnum * 16]); wrefresh(editwin); } #else void save_font_to_console () { wclear(statusln); mvwaddstr(statusln, 0, 0, "No console interaction is supported under this OS"); wrefresh(statusln); wrefresh(editwin); } void load_font_from_console () { save_font_to_console(); } #endif /* OS is not supported */ /*****************************************/ /* end of operation system depended code */ /*****************************************/ void input_loop () { int c; while (1) { c = getch(); switch (c) { case KEY_UP: edity ? edity -- : (edity = 15); wmove(editwin, edity+1, editx+2); wrefresh(editwin); break; case KEY_LEFT: editx ? editx -- : (editx = 7); wmove(editwin, edity+1, editx+2); wrefresh(editwin); break; case KEY_DOWN: edity ++; edity %= 16; wmove(editwin, edity+1, editx+2); wrefresh(editwin); break; case KEY_RIGHT: editx ++; editx %= 8; wmove(editwin, edity+1, editx+2); wrefresh(editwin); break; case KEY_PPAGE: charnum ? charnum-- : (charnum = 255); draw_char(editwin, charnum, &fontbuf[charnum * 16]); wrefresh(editwin); break; case KEY_NPAGE: charnum++; charnum %= 256; draw_char(editwin, charnum, &fontbuf[charnum * 16]); wrefresh(editwin); break; case '#': ask_move_char(); break; case ' ': toggle_char_bit(editwin, charnum, fontbuf, edity, editx); wrefresh(editwin); break; case 'l': case 'L': interactive_load_file(); break; case 's': case 'S': interactive_save_file(); break; case 'c': case 'C': save_font_to_console(); break; case 'd': case 'D': load_font_from_console(); break; case 'r': case 'R': redrawwin(stdscr); redrawwin(helpwin); redrawwin(editwin); refresh(); wrefresh(helpwin); wrefresh(editwin); break; case 'q': case 'Q': return; } } } void print_usage (char *argv[]) { printf("Full screen font editor v" VERSION " by Uri Shaked \n"); printf("Usage: %s fontfile\n", argv[0]); exit(1); } int main (int argc, char *argv[]) { int fd, rc; if (argc > 2) print_usage(argv); memset(fontbuf, 0, sizeof(fontbuf)); if (argc == 2) { strcpy(fnamebuf, argv[1]); fd = open(argv[1], O_RDONLY); if (fd == -1) { perror("open"); return 1; } rc = read(fd, fontbuf, sizeof(fontbuf)); if (rc == -1) { perror("read"); return 1; } close(fd); } else fnamebuf[0] = 0; initscr(); cbreak(); noecho(); intrflush(stdscr,FALSE); keypad(stdscr, TRUE); nonl(); draw_screen(); // if no font file loaded, try loading console font. if (fnamebuf[0] == 0) load_font_from_console(); input_loop(); endwin(); return 0; }