File: vtredir.c

package info (click to toggle)
termrec 0.19-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,148 kB
  • sloc: ansic: 8,430; makefile: 181; perl: 16; sh: 15
file content (259 lines) | stat: -rw-r--r-- 6,006 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#include "config.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "tty.h"
#include "sys/ttysize.h"
#include "export.h"
#include "charsets.h"
#include "wcwidth.h"

struct vtvt_data
{
    FILE *f;
    int sx,sy;

    uint64_t attr;
    int cx,cy;
};

#define DATA ((struct vtvt_data*)(vt->l_data))
#define SX      DATA->sx
#define SY      DATA->sy
#define CX      DATA->cx
#define CY      DATA->cy

static void print_color(FILE *f, uint32_t c, int bg)
{
    switch (c&VT100_ATTR_COLOR_TYPE)
    {
    case 1<<24:
        if (c&8)
            fprintf(f, ";%d%u", 9+bg, c&7);
        else
            fprintf(f, ";%d%u", 3+bg, c&7);
        break;
    case 2<<24:
        fprintf(f, ";%d8;5;%u", 3+bg, c&0xff);
        break;
    case 3<<24:
        fprintf(f, ";%d8;2;%u;%u;%u", 3+bg, (c>>16)&0xff, (c>>8)&0xff, c&0xff);
    }
}

static void setattr(tty vt, uint64_t attr)
{
    if (DATA->attr==attr)
        return;

    DATA->attr=attr;
    fprintf(DATA->f, "\e[0");
    if (attr&VT100_ATTR_BOLD)
        fprintf(DATA->f, ";1");
    if (attr&VT100_ATTR_DIM)
        fprintf(DATA->f, ";2");
    if (attr&VT100_ATTR_ITALIC)
        fprintf(DATA->f, ";3");
    if (attr&VT100_ATTR_UNDERLINE)
        fprintf(DATA->f, ";4");
    if (attr&VT100_ATTR_BLINK)
        fprintf(DATA->f, ";5");
    if (attr&VT100_ATTR_INVERSE)
        fprintf(DATA->f, ";7");
    if (attr&VT100_ATTR_STRIKE)
        fprintf(DATA->f, ";9");
    print_color(DATA->f, attr, 0);
    print_color(DATA->f, attr>>32, 1);
    fprintf(DATA->f, "m");
}

static void vtvt_cursor(tty vt, int x, int y)
{
    if (x==CX && y==CY)
        return;
    fprintf(DATA->f, "\e[%d;%df", y+1, x+1);
    CX=x;
    CY=y;
}

#define MAXVT100GRAPH 0x2666 // biggest codepoint is U+2666 BLACK DIAMOND
static char *vt100graph = 0;
static void build_vt100graph(void)
{
    int i;

    /* the reverse mapping Unicode->tty_graphic takes a chunk of memory, so
       build it only on demand.  This won't happen most of the time. */
    if (!(vt100graph=malloc(MAXVT100GRAPH+1)))
        abort();
    memset(vt100graph, 0, MAXVT100GRAPH+1);
    for (i=32; i<127; i++)
        if (charset_vt100[i]<=MAXVT100GRAPH)
            vt100graph[charset_vt100[i]]=i;
}

static void vtvt_char(tty vt, int x, int y, ucs ch, uint64_t attr, int width)
{
    if (x>=SX || y>SY)
        return;
    if (x!=CX || y!=CY)
        vtvt_cursor(vt, x, y);
    setattr(vt, attr);
    if (fprintf(DATA->f, "%lc", ch)<0)
    {
        clearerr(DATA->f); // required on BSD
        if (width==2)
            fprintf(DATA->f, "??"); // nothing is wide in cp437
        else if (vt->cp437)
        {
            if (!vt100graph)
                build_vt100graph();
            if (ch<=MAXVT100GRAPH && vt100graph[ch])
                fprintf(DATA->f, "\016%c\017", vt100graph[ch]);
            else
                fprintf(DATA->f, "?");
        }
        else
            fprintf(DATA->f, "?");
    }
    CX++;
}

static void vtvt_comb(tty vt, int x, int y, ucs ch, uint64_t attr)
{
    if (x>=SX || y>SY)
        return;
    if (x+1!=CX || y!=CY) // cursor should be _after_ the glyph
        vtvt_cursor(vt, x+1, y);
    setattr(vt, attr);
    if (fprintf(DATA->f, "%lc", ch)<0)
        clearerr(DATA->f); // No fallback, just ignore.
}

export void vtvt_dump(tty vt)
{
    int x,y;
    attrchar *ch;

    ch=vt->scr;
    for (y=0; y<vt->sy; y++)
    {
        for (x=0; x<vt->sx; x++)
        {
            if (ch->ch != VT100_CJK_RIGHT)
                vtvt_char(vt, x, y, ch->ch, ch->attr, mk_wcwidth(ch->ch));
            ch++;
        }
    }
    vtvt_cursor(vt, vt->cx, vt->cy);
}

static void vtvt_clear(tty vt, int x, int y, int len)
{
    int c;

    setattr(vt, vt->attr);
    if (x==0 && y==0 && len==SX*SY)
        fprintf(DATA->f, "\e[2J");
    else if (x==0 && y==0 && len==CY*SX+CX)
        fprintf(DATA->f, "\e[1J");
    else if (x==CX && y==CY && len==SX*SY-CY*SX-CX)
        fprintf(DATA->f, "\e[0J");
    else if (x==0 && y==CY && len==SX)
        fprintf(DATA->f, "\e[2K");
    else if (x==0 && y==CY && len==CX)
        fprintf(DATA->f, "\e[1K");
    else if (x==CX && y==CY && len==SX-CX)
        fprintf(DATA->f, "\e[0K");
    else
        while (len)
        {
            vtvt_cursor(vt, x, y);
            c=(len>SX-x)? SX-x : len;
            fprintf(DATA->f, "\e[%dX", c);
            len-=c;
            x=0;
            y++;
        }
    vtvt_cursor(vt, vt->cx, vt->cy);
}

static void vtvt_scroll(tty vt, int nl)
{
    if (nl>0)
        fprintf(DATA->f, "\e[0m\e[%d;%dr\e[%d;1f\e[%dM\e[r", vt->s1+1, vt->s2, vt->s1+1, nl);
    else if (nl<0)
        fprintf(DATA->f, "\e[0m\e[%d;%dr\e[%d;1f\e[%dL\e[r", vt->s1+1, vt->s2, vt->s1+1, -nl);
    CX=CY=-1;
    DATA->attr=0;

//  vtvt_dump(vt);
}

static void vtvt_flag(tty vt, int f, int v)
{
    // TODO: invisible cursor
}

static void vtvt_osc(tty vt, int cmd, const char *str)
{
    // don't passthrough unknown commands
    if (cmd==0) // set window title
        fprintf(DATA->f, "\e]0;%s\e\\", str);
}

static void vtvt_resized(tty vt, int sx, int sy)
{
    fprintf(DATA->f, "\e[8;%u;%ut", sy, sx);
}

static void vtvt_flush(tty vt)
{
    fflush(DATA->f);
}

static void vtvt_bell(tty vt)
{
    putc('\a', DATA->f);
}

static void vtvt_free(tty vt)
{
    free(vt->l_data);
}

export void vtvt_resize(tty vt, int sx, int sy)
{
    SX=sx; SY=sy;
}

export void vtvt_attach(tty vt, FILE *f, int dump)
{
    vt->l_data=malloc(sizeof(struct vtvt_data));
    CX=CY=-1;
    DATA->attr=-1;
    DATA->f=f;

    SX=80; SY=25;
    get_tty_size(fileno(f), &SX, &SY);

    vt->l_char=vtvt_char;
    vt->l_comb=vtvt_comb;
    vt->l_cursor=vtvt_cursor;
    vt->l_clear=vtvt_clear;
    vt->l_scroll=vtvt_scroll;
    vt->l_flag=vtvt_flag;
    vt->l_osc=vtvt_osc;
    vt->l_resize=vtvt_resized;
    vt->l_flush=vtvt_flush;
    vt->l_bell=vtvt_bell;
    vt->l_free=vtvt_free;

    if (dump)
    {
        fprintf(DATA->f, "\ec");
        vtvt_dump(vt);
        fflush(stdout);
    }
}