/* Copyright (C) 2019 C. McEnroe * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #define _XOPEN_SOURCE_EXTENDED #include #include #include #include #include #include #include #include #include #include #include "term.h" #ifndef A_ITALIC #define A_ITALIC A_UNDERLINE #endif static short colorPair(int bg, int fg) { if (bg >= COLORS || fg >= COLORS) return 0; if (bg < 8 && fg < 8) { return 9 * (bg + 1) + (fg + 1); } enum { Base = 9 * 9, Ring = 256 - Base, }; static struct { int bg, fg; } pairs[Ring]; static size_t len = 0; short i; for (i = 0; i < Ring; ++i) { if (pairs[i].bg == bg && pairs[i].fg == fg) return Base + i; if (!pairs[i].bg && !pairs[i].fg) break; } i = len++ % Ring; pairs[i].bg = bg; pairs[i].fg = fg; init_pair(Base + i, fg, bg); touchwin(stdscr); return Base + i; } static void curse(void) { initscr(); cbreak(); noecho(); start_color(); use_default_colors(); for (int bg = -1; bg < 8; ++bg) { for (int fg = -1; fg < 8; ++fg) { init_pair(colorPair(bg, fg), fg, bg); } } } static attr_t styleAttr(struct Style style) { attr_t attr = A_NORMAL; if (style.attr & Bold) attr |= A_BOLD; if (style.attr & Dim) attr |= A_DIM; if (style.attr & Italic) attr |= A_ITALIC; if (style.attr & Underline) attr |= A_UNDERLINE; if (style.attr & Blink) attr |= A_BLINK; if (style.attr & Reverse) attr |= A_REVERSE; return attr; } static void render(WINDOW *win, const struct Term *term) { for (uint y = 0; y < term->rows; ++y) { for (uint x = 0; x < term->cols; ++x) { struct Cell cell = term->cells[term->cols * y + x]; if (!cell.ch) continue; wattr_set( win, styleAttr(cell.style), colorPair(cell.style.bg, cell.style.fg), NULL ); mvwaddnwstr(win, y, x, &cell.ch, 1); } } curs_set(!!(term->mode & Cursor)); leaveok(win, !(term->mode & Cursor)); wmove(win, term->y, term->x); } int main(void) { int error; setlocale(LC_CTYPE, ""); // TODO: Read info from file. const char *path = "example.sock"; struct Term *term = termAlloc(24, 80); int client = socket(PF_LOCAL, SOCK_STREAM, 0); if (client < 0) err(EX_OSERR, "socket"); struct sockaddr_un addr = { .sun_family = AF_LOCAL }; strncpy(addr.sun_path, path, sizeof(addr.sun_path)); error = connect(client, (struct sockaddr *)&addr, SUN_LEN(&addr)); if (error) err(EX_NOINPUT, "%s", path); curse(); WINDOW *win = newwin(24, 80, 0, 0); for (;;) { char buf[4096]; ssize_t len = read(client, buf, sizeof(buf)); if (len < 0) err(EX_IOERR, "read"); ssize_t pos = 0; while (pos < len) { wchar_t ch; int n = mbtowc(&ch, &buf[pos], len - pos); if (n <= 0) break; termUpdate(term, ch); pos += n; } render(win, term); wrefresh(win); } }