aboutsummaryrefslogtreecommitdiffstats
path: root/util/alevt/exp-txt.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/alevt/exp-txt.c')
-rw-r--r--util/alevt/exp-txt.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/util/alevt/exp-txt.c b/util/alevt/exp-txt.c
new file mode 100644
index 0000000..8009c17
--- /dev/null
+++ b/util/alevt/exp-txt.c
@@ -0,0 +1,226 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "os.h"
+#include "export.h"
+
+static int txt_open(struct export *e);
+static int txt_option(struct export *e, int opt, char *arg);
+static int txt_output(struct export *e, char *name, struct fmt_page *pg);
+static char *txt_opts[] = // module options
+{
+ "color", // generate ansi color codes (and attributes)
+ "gfx-chr=<char>", // substitute <char> for gfx-symbols
+ "fg=<0-7|none>", // assume term has <x> as foreground color
+ "bg=<0-7|none>", // assume term has <x> as background color
+ "lines=<1-25>", // output 24 or 25 lines
+ 0
+};
+
+
+struct txt_data // private data in struct export
+{
+ u8 color;
+ u8 gfx_chr;
+ u8 def_fg;
+ u8 def_bg;
+ int endline;
+ struct fmt_char curr[1];
+ FILE *fp;
+};
+
+
+struct export_module export_txt = // exported module definition
+{
+ "ascii", // id
+ "txt", // extension
+ txt_opts, // options
+ sizeof(struct txt_data), // data size
+ txt_open, // open
+ 0, // close
+ txt_option, // option
+ txt_output, // output
+};
+
+
+struct export_module export_ansi = // exported module definition
+{
+ "ansi", // id
+ "txt", // extension
+ txt_opts, // options
+ sizeof(struct txt_data), // data size
+ txt_open, // open
+ 0, // close
+ txt_option, // option
+ txt_output, // output
+};
+
+#define D ((struct txt_data *)e->data)
+
+
+char * my_stpcpy(char *dst, const char *src)
+{
+ while (*dst = *src++)
+ dst++;
+ return dst;
+}
+
+
+static int txt_open(struct export *e)
+{
+ D->gfx_chr = '#';
+ D->def_fg = -1;
+ D->def_bg = -1;
+ D->endline = H;
+ if (e->mod == &export_ansi)
+ D->color = 1;
+ return 0;
+}
+
+
+static int txt_option(struct export *e, int opt, char *arg)
+{
+ switch (opt)
+ {
+ case 1: // color
+ D->color = 1;
+ break;
+ case 2: // gfx-chr=
+ D->gfx_chr = *arg ?: ' ';
+ break;
+ case 3: // fg=
+ D->def_fg = *arg - '0';
+ break;
+ case 4: // bg=
+ D->def_bg = *arg - '0';
+ break;
+ case 5: // lines=
+ D->endline = atoi(arg);
+ if (D->endline < 1 || D->endline > H)
+ {
+ export_error("lines: invalid number");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static void put_attr(struct export *e, struct fmt_char *new)
+{
+ char buf[512];
+ char *p = buf;
+ int fg, bg, attr;
+ int reset = 0;
+
+ if (D->color)
+ {
+ fg = D->curr->fg ^ new->fg;
+ bg = D->curr->bg ^ new->bg;
+ attr = (D->curr->attr ^ new->attr) & (EA_BLINK | EA_DOUBLE);
+
+ if (fg | bg | attr)
+ {
+ if (~new->attr & attr) // reset some attributes -> reset all.
+ reset = 1;
+ if (fg && new->fg == D->def_fg) // switch to def fg -> reset all
+ reset = 1;
+ if (bg && new->bg == D->def_bg) // switch to def bg -> reset all
+ reset = 1;
+
+ p = my_stpcpy(buf, "\e[");
+ if (reset)
+ {
+ p = my_stpcpy(p, ";"); // "0;" but 0 isn't neccesary
+ attr = -1; // set all attributes
+ fg = new->fg ^ D->def_fg; // set fg if != default fg
+ bg = new->bg ^ D->def_bg; // set bg if != default bg
+ }
+ if (attr & new->attr & EA_BLINK)
+ p = my_stpcpy(p, "5;"); // blink
+ if (attr & new->attr & EA_DOUBLE)
+ p = my_stpcpy(p, "1;"); // bold
+ if (fg)
+ p += sprintf(p, "%d;", new->fg + 30); // fg-color
+ if (bg)
+ p += sprintf(p, "%d;", new->bg + 40); // bg-color
+ p[-1] = 'm'; // replace last ;
+ *D->curr = *new;
+ }
+ }
+ *p++ = new->ch;
+ *p = 0;
+ fputs(buf, D->fp);
+}
+
+
+static int txt_output(struct export *e, char *name, struct fmt_page *pg)
+{
+ struct fmt_char def_c[1];
+ struct fmt_char l[W+2];
+ #define L (l+1)
+ int x, y;
+
+ D->fp = fopen(name, "w");
+ if (not D->fp)
+ {
+ export_error("cannot create file");
+ return -1;
+ }
+
+ /* initialize default colors. These have to be restored at EOL. */
+ def_c->ch = '\n';
+ def_c->fg = D->def_fg;
+ def_c->bg = D->def_bg;
+ def_c->attr = E_DEF_ATTR;
+ *D->curr = *def_c;
+ L[-1] = L[W] = *def_c;
+
+ for (y = 0; y < D->endline; y++)
+ if (~pg->hid & (1 << y)) // not hidden
+ {
+ // character conversion
+ for (x = 0; x < W; ++x)
+ {
+ struct fmt_char c = pg->data[y][x];
+
+ switch (c.ch)
+ {
+ case 0x00: case 0xa0: c.ch = ' '; break;
+ case 0x7f: c.ch = '*'; break;
+ case BAD_CHAR: c.ch = '?'; break;
+ default:
+ if (c.attr & EA_GRAPHIC)
+ c.ch = D->gfx_chr;
+ break;
+ }
+ L[x] = c;
+ }
+
+ if (D->color)
+ {
+ // optimize color and attribute changes
+ // delay fg and attr changes as far as possible
+ for (x = 0; x < W; ++x)
+ if (L[x].ch == ' ')
+ {
+ L[x].fg = L[x-1].fg;
+ l[x].attr = L[x-1].attr;
+ }
+
+ // move fg and attr changes to prev bg change point
+ for (x = W-1; x >= 0; x--)
+ if (L[x].ch == ' ' && L[x].bg == L[x+1].bg)
+ {
+ L[x].fg = L[x+1].fg;
+ L[x].attr = L[x+1].attr;
+ }
+ }
+
+ // now emit the whole line (incl EOL)
+ for (x = 0; x < W+1; ++x)
+ put_attr(e, L + x);
+ }
+ fclose(D->fp);
+ return 0;
+}