#include #include #include #include #include #include #include "vterm.h" #define DEFINE_INLINES #include "../src/utf8.h" // fill_utf8 #define streq(a,b) (!strcmp(a,b)) static VTerm *vt; static VTermScreen *vts; static int cols; static int rows; static enum { FORMAT_PLAIN, FORMAT_SGR, } format = FORMAT_PLAIN; static int col2index(VTermColor target) { int index; for(index = 0; index < 256; index++) { VTermColor col; vterm_state_get_palette_color(NULL, index, &col); if(col.red == target.red && col.green == target.green && col.blue == target.blue) return index; } return -1; } static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevcell) { switch(format) { case FORMAT_PLAIN: break; case FORMAT_SGR: { // If all 7 attributes change, that means 7 SGRs max // Each colour could consume up to 3 int sgr[7 + 2*3]; int sgri = 0; if(!prevcell->attrs.bold && cell->attrs.bold) sgr[sgri++] = 1; if(prevcell->attrs.bold && !cell->attrs.bold) sgr[sgri++] = 22; if(!prevcell->attrs.underline && cell->attrs.underline) sgr[sgri++] = 4; if(prevcell->attrs.underline && !cell->attrs.underline) sgr[sgri++] = 24; if(!prevcell->attrs.italic && cell->attrs.italic) sgr[sgri++] = 3; if(prevcell->attrs.italic && !cell->attrs.italic) sgr[sgri++] = 23; if(!prevcell->attrs.blink && cell->attrs.blink) sgr[sgri++] = 5; if(prevcell->attrs.blink && !cell->attrs.blink) sgr[sgri++] = 25; if(!prevcell->attrs.reverse && cell->attrs.reverse) sgr[sgri++] = 7; if(prevcell->attrs.reverse && !cell->attrs.reverse) sgr[sgri++] = 27; if(!prevcell->attrs.strike && cell->attrs.strike) sgr[sgri++] = 9; if(prevcell->attrs.strike && !cell->attrs.strike) sgr[sgri++] = 29; if(!prevcell->attrs.font && cell->attrs.font) sgr[sgri++] = 10 + cell->attrs.font; if(prevcell->attrs.font && !cell->attrs.font) sgr[sgri++] = 10; if(prevcell->fg.red != cell->fg.red || prevcell->fg.green != cell->fg.green || prevcell->fg.blue != cell->fg.blue) { int index = col2index(cell->fg); if(index == -1) sgr[sgri++] = 39; else if(index < 8) sgr[sgri++] = 30 + index; else if(index < 16) sgr[sgri++] = 90 + (index - 8); else { sgr[sgri++] = 38; sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE; sgr[sgri++] = index | CSI_ARG_FLAG_MORE; } } if(prevcell->bg.red != cell->bg.red || prevcell->bg.green != cell->bg.green || prevcell->bg.blue != cell->bg.blue) { int index = col2index(cell->bg); if(index == -1) sgr[sgri++] = 49; else if(index < 8) sgr[sgri++] = 40 + index; else if(index < 16) sgr[sgri++] = 100 + (index - 8); else { sgr[sgri++] = 48; sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE; sgr[sgri++] = index | CSI_ARG_FLAG_MORE; } } if(!sgri) break; printf("\x1b["); { int i; for(i = 0; i < sgri; i++) printf(!i ? "%d" : CSI_ARG_HAS_MORE(sgr[i]) ? ":%d" : ";%d", CSI_ARG(sgr[i])); } printf("m"); } break; } { int i; for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell->chars[i]; i++) { char bytes[6]; bytes[fill_utf8(cell->chars[i], bytes)] = 0; printf("%s", bytes); } } } static void dump_eol(const VTermScreenCell *prevcell) { switch(format) { case FORMAT_PLAIN: break; case FORMAT_SGR: if(prevcell->attrs.bold || prevcell->attrs.underline || prevcell->attrs.italic || prevcell->attrs.blink || prevcell->attrs.reverse || prevcell->attrs.strike || prevcell->attrs.font) printf("\x1b[m"); break; } printf("\n"); } void dump_row(int row) { VTermPos pos; VTermScreenCell prevcell; pos.row = row; pos.col = 0; memset(&prevcell, 0, sizeof(prevcell)); vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg); while(pos.col < cols) { VTermScreenCell cell; vterm_screen_get_cell(vts, pos, &cell); dump_cell(&cell, &prevcell); pos.col += cell.width; prevcell = cell; } dump_eol(&prevcell); } static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user) { VTermScreenCell prevcell; int col; memset(&prevcell, 0, sizeof(prevcell)); vterm_state_get_default_colors(vterm_obtain_state(vt), &prevcell.fg, &prevcell.bg); for(col = 0; col < cols; col++) { dump_cell(cells + col, &prevcell); prevcell = cells[col]; } dump_eol(&prevcell); return 1; } static int screen_resize(int new_rows, int new_cols, void *user) { rows = new_rows; cols = new_cols; return 1; } static VTermScreenCallbacks cb_screen = { NULL, /* damage */ NULL, /* moverect */ NULL, /* movecursor */ NULL, /* settermprop */ NULL, /* bell */ &screen_resize, /* resize */ &screen_sb_pushline, /* sb_pushline */ NULL, /* popline */ }; int main(int argc, char *argv[]) { int opt; const char *file; int fd; int len; char buffer[1024]; int row; rows = 25; cols = 80; while((opt = getopt(argc, argv, "f:l:c:")) != -1) { switch(opt) { case 'f': if(streq(optarg, "plain")) format = FORMAT_PLAIN; else if(streq(optarg, "sgr")) format = FORMAT_SGR; else { fprintf(stderr, "Unrecognised format '%s'\n", optarg); exit(1); } break; case 'l': rows = atoi(optarg); if(!rows) rows = 25; break; case 'c': cols = atoi(optarg); if(!cols) cols = 80; break; } } file = argv[optind++]; fd = open(file, O_RDONLY); if(fd == -1) { fprintf(stderr, "Cannot open %s - %s\n", file, strerror(errno)); exit(1); } vt = vterm_new(rows, cols); vterm_set_utf8(vt, TRUE); vts = vterm_obtain_screen(vt); vterm_screen_set_callbacks(vts, &cb_screen, NULL); vterm_screen_reset(vts, 1); while((len = read(fd, buffer, sizeof(buffer))) > 0) { vterm_input_write(vt, buffer, len); } for(row = 0; row < rows; row++) { dump_row(row); } close(fd); vterm_free(vt); return 0; }