forked from Bill-Gray/PDCursesMod
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpdcdisp.c
More file actions
349 lines (314 loc) · 9.77 KB
/
pdcdisp.c
File metadata and controls
349 lines (314 loc) · 9.77 KB
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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#define USE_UNICODE_ACS_CHARS 1
#include <wchar.h>
#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#define USE_UNICODE_ACS_CHARS 1
#include "curspriv.h"
#include "pdcvt.h"
#include "../common/acs_defs.h"
#include "../common/pdccolor.h"
int PDC_get_terminal_fd( void)
{
static int stdout_fd = -1;
if( stdout_fd == -1)
{
#ifdef _WIN32
// if( FILE_TYPE_CHAR == GetFileType( GetStdHandle( STD_OUTPUT_HANDLE)))
stdout_fd = 2;
#else
if( isatty( STDOUT_FILENO))
stdout_fd = STDOUT_FILENO; /* stdout hasn't been redirected; use it */
else if( isatty( STDERR_FILENO))
stdout_fd = STDERR_FILENO; /* stdout is redirected to a file; use stderr */
else
{
fprintf(stderr, "No output device found\n");
exit( -1);
}
#endif
}
return( stdout_fd);
}
/* Rarely, writes to stdout fail if a signal handler is
called. In which case we just try to write out the
remainder of the buffer until success happens. */
#define TBUFF_SIZE 512
static void put_to_stdout( const char *buff, size_t bytes_out)
{
static char *tbuff = NULL;
static size_t bytes_cached;
int stdout_fd;
if( !buff && !tbuff)
return;
if( !buff && bytes_out == 1) /* release memory at shutdown */
{
free( tbuff);
tbuff = NULL;
bytes_cached = 0;
return;
}
if( buff && !tbuff)
tbuff = (char *)malloc( TBUFF_SIZE);
stdout_fd = PDC_get_terminal_fd( );
while( bytes_out || (!buff && bytes_cached))
{
if( buff)
{
size_t n_copy = bytes_out;
if( n_copy > TBUFF_SIZE - bytes_cached)
n_copy = TBUFF_SIZE - bytes_cached;
memcpy( tbuff + bytes_cached, buff, n_copy);
buff += n_copy;
bytes_out -= n_copy;
bytes_cached += n_copy;
}
if( bytes_cached == TBUFF_SIZE || !buff)
while( bytes_cached)
{
#ifdef _WIN32
const size_t bytes_written = _write( stdout_fd, tbuff,
(unsigned int)bytes_cached);
#else
const size_t bytes_written = write( stdout_fd, tbuff, bytes_cached);
#endif
bytes_cached -= bytes_written;
if( bytes_cached)
memmove( tbuff, tbuff + bytes_written, bytes_cached);
}
}
}
void PDC_puts_to_stdout( const char *buff)
{
put_to_stdout( buff, (buff ? strlen( buff) : 1));
}
void PDC_gotoyx(int y, int x)
{
char tbuff[50];
#ifdef HAVE_SNPRINTF
snprintf( tbuff, sizeof( tbuff), CSI "%d;%dH", y + 1, x + 1);
#else
sprintf( tbuff, CSI "%d;%dH", y + 1, x + 1);
#endif
PDC_puts_to_stdout( tbuff);
PDC_doupdate( );
}
#define RESET_ATTRS CSI "0m"
#define ITALIC_ON CSI "3m"
#define ITALIC_OFF CSI "23m"
#define UNDERLINE_ON CSI "4m"
#define UNDERLINE_OFF CSI "24m"
#define BLINK_ON CSI "5m"
#define BLINK_OFF CSI "25m"
#define BOLD_ON CSI "1m"
#define BOLD_OFF CSI "22m"
#define DIM_ON CSI "2m"
#define DIM_OFF CSI "22m"
#define REVERSE_ON CSI "7m"
#define STRIKEOUT_ON CSI "9m"
/* see 'addch.c' for an explanation of how combining chars are handled. */
#ifdef USING_COMBINING_CHARACTER_SCHEME
int PDC_expand_combined_characters( const cchar_t c, cchar_t *added); /* addch.c */
#endif
static void color_string( char *otext, const PACKED_RGB rgb)
{
extern bool PDC_has_rgb_color; /* pdcscrn.c */
const int red = Get_RValue( rgb);
const int green = Get_GValue( rgb);
const int blue = Get_BValue( rgb);
if( PDC_has_rgb_color)
sprintf( otext, "2;%d;%d;%dm", red, green, blue);
else
{
int idx;
if( red == green && red == blue) /* gray scale: indices from */
{
if( red < 27) /* this would underflow; remap to black */
idx = COLOR_BLACK;
else if( red >= 243) /* this would overflow */
idx = COLOR_WHITE;
else
idx = (red - 3) / 10 + 232; /* 232 to 255 */
}
else
idx = ((blue - 35) / 40) + ((green - 35) / 40) * 6
+ ((red - 35) / 40) * 36 + 16;
sprintf( otext, "5;%dm", idx);
}
}
static int get_sixteen_color_idx( const PACKED_RGB rgb)
{
int rval = 0;
if( rgb & 0x80) /* red value >= 128 */
rval = 1;
if( rgb & 0x8000) /* green value >= 128 */
rval |= 2;
if( rgb & 0x800000) /* blue value >= 128 */
rval |= 4;
return( rval);
}
static void reset_color( char *obuff, const chtype ch)
{
static PACKED_RGB prev_bg = (PACKED_RGB)-2;
static PACKED_RGB prev_fg = (PACKED_RGB)-2;
PACKED_RGB bg, fg;
if( !obuff)
{
prev_bg = prev_fg = (PACKED_RGB)-2;
return;
}
PDC_get_rgb_values( ch, &fg, &bg);
*obuff = '\0';
if( bg != prev_bg)
{
if( bg == (PACKED_RGB)-1) /* default background */
strcpy( obuff, CSI "49m");
else if( !bg)
strcpy( obuff, CSI "40m");
else if( COLORS == 16)
sprintf( obuff, CSI "4%dm", get_sixteen_color_idx( bg));
else
{
strcpy( obuff, CSI "48;");
color_string( obuff + 5, bg);
}
prev_bg = bg;
}
if( fg != prev_fg)
{
obuff += strlen( obuff);
if( fg == (PACKED_RGB)-1) /* default foreground */
strcpy( obuff, CSI "39m");
else if( COLORS == 16)
sprintf( obuff, CSI "3%dm", get_sixteen_color_idx( fg));
else
{
strcpy( obuff, CSI "38;");
color_string( obuff + 5, fg);
}
prev_fg = fg;
}
}
int PDC_wc_to_utf8( char *dest, const int32_t code);
#define OBUFF_SIZE 100
void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
{
static chtype prev_ch = 0;
static bool force_reset_all_attribs = TRUE;
char obuff[OBUFF_SIZE];
if( !srcp)
{
prev_ch = 0;
force_reset_all_attribs = TRUE;
PDC_puts_to_stdout( RESET_ATTRS);
return;
}
assert( x >= 0);
assert( len <= SP->cols - x);
assert( lineno >= 0);
assert( lineno < SP->lines);
assert( len > 0);
assert( len < MAX_PACKET_LEN);
PDC_gotoyx( lineno, x);
if( force_reset_all_attribs || (!x && !lineno))
{
force_reset_all_attribs = FALSE;
reset_color( NULL, 0);
prev_ch = ~*srcp;
}
while( len)
{
int ch = (int)( *srcp & A_CHARTEXT), count = 1;
chtype changes = *srcp ^ prev_ch;
size_t bytes_out = 0;
assert( ch != MAX_UNICODE);
assert( len == 1 || ch < MAX_UNICODE);
if( _is_altcharset( *srcp))
ch = (int)acs_map[ch & 0x7f];
if( ch < (int)' ' || (ch >= 0x80 && ch <= 0x9f))
ch = ' ';
*obuff = '\0';
if( changes & (A_REVERSE | A_STRIKEOUT | A_BOLD))
{
prev_ch = 0;
changes = *srcp | A_COLOR;
strcpy( obuff, RESET_ATTRS);
reset_color( NULL, 0);
}
if( SP->termattrs & *srcp & A_BOLD)
strcat( obuff, BOLD_ON);
if( changes & A_UNDERLINE)
strcat( obuff, (*srcp & A_UNDERLINE) ? UNDERLINE_ON : UNDERLINE_OFF);
if( changes & A_ITALIC)
strcat( obuff, (*srcp & A_ITALIC) ? ITALIC_ON : ITALIC_OFF);
if( changes & A_REVERSE)
strcat( obuff, REVERSE_ON);
#ifndef _WIN32 /* MS doesn't support strikeout text */
if( changes & A_STRIKEOUT)
strcat( obuff, STRIKEOUT_ON);
#endif
if( SP->termattrs & changes & A_BLINK)
strcat( obuff, (*srcp & A_BLINK) ? BLINK_ON : BLINK_OFF);
if( changes & (A_COLOR | A_STANDOUT | A_BLINK | A_REVERSE))
reset_color( obuff + strlen( obuff), *srcp & ~A_REVERSE);
PDC_puts_to_stdout( obuff);
#ifdef USING_COMBINING_CHARACTER_SCHEME
if( ch > (int)MAX_UNICODE) /* chars & fullwidth supported */
{
cchar_t root, newchar;
root = ch;
while( (root = PDC_expand_combined_characters( root,
&newchar)) > MAX_UNICODE)
;
bytes_out = PDC_wc_to_utf8( obuff, (wchar_t)root);
root = ch;
while( (root = PDC_expand_combined_characters( root,
&newchar)) > MAX_UNICODE)
{
bytes_out += PDC_wc_to_utf8( obuff + bytes_out, (wchar_t)newchar);
if( bytes_out > OBUFF_SIZE - 6)
{
put_to_stdout( obuff, bytes_out);
bytes_out = 0;
}
}
bytes_out += PDC_wc_to_utf8( obuff + bytes_out, (wchar_t)newchar);
}
else if( ch < (int)MAX_UNICODE)
#endif
{
bytes_out = PDC_wc_to_utf8( obuff, (wchar_t)ch);
while( count < len && !((srcp[0] ^ srcp[count]) & ~A_CHARTEXT)
&& (ch = (srcp[count] & A_CHARTEXT)) < (int)MAX_UNICODE)
{
if( _is_altcharset( srcp[count]))
ch = (int)acs_map[ch & 0x7f];
if( ch < (int)' ' || (ch >= 0x80 && ch <= 0x9f))
ch = ' ';
bytes_out += PDC_wc_to_utf8( obuff + bytes_out, (wchar_t)ch);
if( bytes_out > OBUFF_SIZE - 6)
{
put_to_stdout( obuff, bytes_out);
bytes_out = 0;
}
count++;
}
}
put_to_stdout( obuff, bytes_out);
bytes_out = 0;
prev_ch = *srcp;
srcp += count;
len -= count;
}
}
void PDC_doupdate(void)
{
put_to_stdout( NULL, 0);
}