| #include <stdio.h> |
| #include <string.h> |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <getopt.h> |
| #include <unistd.h> |
| |
| #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; |
| } |