summaryrefslogtreecommitdiffstats
path: root/src/libvterm/bin/unterm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libvterm/bin/unterm.c')
-rw-r--r--src/libvterm/bin/unterm.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/src/libvterm/bin/unterm.c b/src/libvterm/bin/unterm.c
new file mode 100644
index 0000000..5c310d7
--- /dev/null
+++ b/src/libvterm/bin/unterm.c
@@ -0,0 +1,288 @@
+#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;
+}