aboutsummaryrefslogtreecommitdiffstats
path: root/util/alevt/exp-txt.c
blob: 8009c171bc950f92a56e33bbb1219157b27493dd (plain)
1
2
3
4
5
6
7
8
9
10
pre { line-height: 125%; margin: 0; }
td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }
span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }
td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
arte:198500000:INVERSION_AUTO:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:4385:4386:2
Phoenix:198500000:INVERSION_AUTO:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:4401:4402:3
EinsExtra:198500000:INVERSION_AUTO:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:4417:4418:4
Das Erste:198500000:INVERSION_AUTO:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:4369:4370:128
ZDF:490000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:545:546:514
Info/3sat:490000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:561:562:515
Doku/KiKa:490000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:593:594:517
RTL Television:498000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_AUTO:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:337:338:16405
RTL2:498000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_AUTO:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:353:354:16406
Super RTL:498000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_AUTO:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:369:370:16407
VOX:498000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_AUTO:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:545:546:16418
hr-fernsehen:594000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:4673:4674:65
MDR FERNSEHEN:594000000:INVERSION_AUTO:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:4657:4658:100
NDR FS NDS:594000000:INVERSION_AUTO:BANDWIDTH_8_MHZ
#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;
}