GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcurses/tinfo/trim_sgr0.c Lines: 75 117 64.1 %
Date: 2017-11-13 Branches: 45 112 40.2 %

Line Branch Exec Source
1
/* $OpenBSD: trim_sgr0.c,v 1.1 2010/01/12 23:22:06 nicm Exp $ */
2
3
/****************************************************************************
4
 * Copyright (c) 2005-2006,2007 Free Software Foundation, Inc.              *
5
 *                                                                          *
6
 * Permission is hereby granted, free of charge, to any person obtaining a  *
7
 * copy of this software and associated documentation files (the            *
8
 * "Software"), to deal in the Software without restriction, including      *
9
 * without limitation the rights to use, copy, modify, merge, publish,      *
10
 * distribute, distribute with modifications, sublicense, and/or sell       *
11
 * copies of the Software, and to permit persons to whom the Software is    *
12
 * furnished to do so, subject to the following conditions:                 *
13
 *                                                                          *
14
 * The above copyright notice and this permission notice shall be included  *
15
 * in all copies or substantial portions of the Software.                   *
16
 *                                                                          *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
20
 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
21
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
22
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
23
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
24
 *                                                                          *
25
 * Except as contained in this notice, the name(s) of the above copyright   *
26
 * holders shall not be used in advertising or otherwise to promote the     *
27
 * sale, use or other dealings in this Software without prior written       *
28
 * authorization.                                                           *
29
 ****************************************************************************/
30
31
/****************************************************************************
32
 *  Author: Thomas Dickey                                                   *
33
 ****************************************************************************/
34
35
#include <curses.priv.h>
36
37
#include <ctype.h>
38
39
#include <tic.h>
40
#include <term_entry.h>
41
42
MODULE_ID("$Id: trim_sgr0.c,v 1.1 2010/01/12 23:22:06 nicm Exp $")
43
44
#undef CUR
45
#define CUR tp->
46
47
#define CSI       233
48
#define ESC       033		/* ^[ */
49
#define L_BRACK   '['
50
51
static char *
52
set_attribute_9(TERMTYPE *tp, int flag)
53
{
54
    const char *result;
55
56
12
    if ((result = tparm(set_attributes, 0, 0, 0, 0, 0, 0, 0, 0, flag)) == 0)
57
	result = "";
58
6
    return strdup(result);
59
}
60
61
static int
62
is_csi(const char *s)
63
{
64
24
    if (UChar(s[0]) == CSI)
65
	return 1;
66

24
    else if (s[0] == ESC && s[1] == L_BRACK)
67
12
	return 2;
68
    return 0;
69
12
}
70
71
static char *
72
skip_zero(char *s)
73
{
74
12
    if (s[0] == '0') {
75
3
	if (s[1] == ';')
76
	    s += 2;
77
3
	else if (isalpha(UChar(s[1])))
78
3
	    s += 1;
79
    }
80
6
    return s;
81
}
82
83
static const char *
84
skip_delay(const char *s)
85
{
86
    if (s[0] == '$' && s[1] == '<') {
87
	s += 2;
88
	while (isdigit(UChar(*s)) || *s == '/')
89
	    ++s;
90
	if (*s == '>')
91
	    ++s;
92
    }
93
    return s;
94
}
95
96
/*
97
 * Improve similar_sgr a little by moving the attr-string from the beginning
98
 * to the end of the s-string.
99
 */
100
static bool
101
rewrite_sgr(char *s, char *attr)
102
{
103
18
    if (PRESENT(s)) {
104
9
	if (PRESENT(attr)) {
105
9
	    unsigned len_s = strlen(s);
106
9
	    unsigned len_a = strlen(attr);
107
108

18
	    if (len_s > len_a && !strncmp(attr, s, len_a)) {
109
		unsigned n;
110
		TR(TRACE_DATABASE, ("rewrite:\n\t%s", s));
111
		for (n = 0; n < len_s - len_a; ++n) {
112
		    s[n] = s[n + len_a];
113
		}
114
		strlcpy(s + n, attr, len_s - n);
115
		TR(TRACE_DATABASE, ("to:\n\t%s", s));
116
	    }
117
9
	}
118
9
	return TRUE;
119
    }
120
    return FALSE;		/* oops */
121
9
}
122
123
static bool
124
similar_sgr(char *a, char *b)
125
{
126
    bool result = FALSE;
127
12
    int csi_a = is_csi(a);
128
6
    int csi_b = is_csi(b);
129
    unsigned len_a;
130
    unsigned len_b;
131
132
    TR(TRACE_DATABASE, ("similar_sgr:\n\t%s\n\t%s",
133
			_nc_visbuf2(1, a),
134
			_nc_visbuf2(2, b)));
135

12
    if (csi_a != 0 && csi_b != 0 && csi_a == csi_b) {
136
6
	a += csi_a;
137
6
	b += csi_b;
138
6
	if (*a != *b) {
139
3
	    a = skip_zero(a);
140
3
	    b = skip_zero(b);
141
3
	}
142
    }
143
6
    len_a = strlen(a);
144
6
    len_b = strlen(b);
145
6
    if (len_a && len_b) {
146
6
	if (len_a > len_b)
147
	    result = (strncmp(a, b, len_b) == 0);
148
	else
149
6
	    result = (strncmp(a, b, len_a) == 0);
150
    }
151
    TR(TRACE_DATABASE, ("...similar_sgr: %d\n\t%s\n\t%s", result,
152
			_nc_visbuf2(1, a),
153
			_nc_visbuf2(2, b)));
154
6
    return result;
155
}
156
157
static unsigned
158
chop_out(char *string, unsigned i, unsigned j)
159
{
160
    TR(TRACE_DATABASE, ("chop_out %d..%d from %s", i, j, _nc_visbuf(string)));
161
9
    while (string[j] != '\0') {
162
	string[i++] = string[j++];
163
    }
164
3
    string[i] = '\0';
165
3
    return i;
166
}
167
168
/*
169
 * Compare, ignoring delays.  Some of the delay values are inconsistent, and
170
 * we do not want to be stopped by that.
171
 *
172
 * Returns the number of chars from 'full' that we matched.  If any mismatch
173
 * occurs, return zero.
174
 */
175
static int
176
compare_part(const char *part, const char *full)
177
{
178
    const char *next_part;
179
    const char *next_full;
180
    int used_full = 0;
181
    int used_delay = 0;
182
183
51
    while (*part != 0) {
184
15
	if (*part != *full) {
185
	    used_full = 0;
186
12
	    break;
187
	}
188
189
	/*
190
	 * Adjust the return-value to allow the rare case of
191
	 *      string<delay>string
192
	 * to remove the whole piece.  The most common case is a delay at the
193
	 * end of the string.  The adjusted string will retain the delay, which
194
	 * is conservative.
195
	 */
196
3
	if (used_delay != 0) {
197
	    used_full += used_delay;
198
	    used_delay = 0;
199
	}
200

3
	if (*part == '$' && *full == '$') {
201
	    next_part = skip_delay(part);
202
	    next_full = skip_delay(full);
203
	    if (next_part != part && next_full != full) {
204
		used_delay += (next_full - full);
205
		full = next_full;
206
		part = next_part;
207
		continue;
208
	    }
209
	}
210
3
	++used_full;
211
3
	++part;
212
3
	++full;
213
    }
214
15
    return used_full;
215
}
216
217
/*
218
 * While 'sgr0' is the "same" as termcap 'me', there is a compatibility issue.
219
 * The sgr/sgr0 capabilities include setting/clearing alternate character set
220
 * mode.  A termcap application cannot use sgr, so sgr0 strings that reset
221
 * alternate character set mode will be misinterpreted.  Here, we remove those
222
 * from the more common ISO/ANSI/VT100 entries, which have sgr0 agreeing with
223
 * sgr.
224
 *
225
 * This function returns the modified sgr0 if it can be modified, a null if
226
 * an error occurs, or the original sgr0 if no change is needed.
227
 */
228
NCURSES_EXPORT(char *)
229
_nc_trim_sgr0(TERMTYPE *tp)
230
{
231
6
    char *result = exit_attribute_mode;
232
233
    T((T_CALLED("_nc_trim_sgr0()")));
234
235

9
    if (PRESENT(exit_attribute_mode)
236

9
	&& PRESENT(set_attributes)) {
237
	bool found = FALSE;
238
3
	char *on = set_attribute_9(tp, 1);
239
3
	char *off = set_attribute_9(tp, 0);
240
3
	char *end = strdup(exit_attribute_mode);
241
	char *tmp;
242
	size_t i, j, k;
243
244
	TR(TRACE_DATABASE, ("checking if we can trim sgr0 based on sgr"));
245
	TR(TRACE_DATABASE, ("sgr0       %s", _nc_visbuf(end)));
246
	TR(TRACE_DATABASE, ("sgr(9:off) %s", _nc_visbuf(off)));
247
	TR(TRACE_DATABASE, ("sgr(9:on)  %s", _nc_visbuf(on)));
248
249
6
	if (!rewrite_sgr(on, enter_alt_charset_mode)
250
6
	    || !rewrite_sgr(off, exit_alt_charset_mode)
251
6
	    || !rewrite_sgr(end, exit_alt_charset_mode)) {
252
	    FreeIfNeeded(off);
253
6
	} else if (similar_sgr(off, end)
254
6
		   && !similar_sgr(off, on)) {
255
	    TR(TRACE_DATABASE, ("adjusting sgr(9:off) : %s", _nc_visbuf(off)));
256
	    result = off;
257
	    /*
258
	     * If rmacs is a substring of sgr(0), remove that chunk.
259
	     */
260
3
	    if (exit_alt_charset_mode != 0) {
261
		TR(TRACE_DATABASE, ("scan for rmacs %s", _nc_visbuf(exit_alt_charset_mode)));
262
3
		j = strlen(off);
263
3
		k = strlen(exit_alt_charset_mode);
264
3
		if (j > k) {
265
30
		    for (i = 0; i <= (j - k); ++i) {
266
15
			int k2 = compare_part(exit_alt_charset_mode, off + i);
267
15
			if (k2 != 0) {
268
			    found = TRUE;
269
3
			    chop_out(off, i, i + k2);
270
3
			    break;
271
			}
272
12
		    }
273
		}
274
	    }
275
	    /*
276
	     * SGR 10 would reset to normal font.
277
	     */
278
3
	    if (!found) {
279
		if ((i = is_csi(off)) != 0
280
		    && off[strlen(off) - 1] == 'm') {
281
		    TR(TRACE_DATABASE, ("looking for SGR 10 in %s",
282
					_nc_visbuf(off)));
283
		    tmp = skip_zero(off + i);
284
		    if (tmp[0] == '1'
285
			&& skip_zero(tmp + 1) != tmp + 1) {
286
			i = tmp - off;
287
			if (off[i - 1] == ';')
288
			    i--;
289
			j = skip_zero(tmp + 1) - off;
290
			i = chop_out(off, i, j);
291
			found = TRUE;
292
		    }
293
		}
294
	    }
295
3
	    if (!found
296
3
		&& (tmp = strstr(end, off)) != 0
297
		&& strcmp(end, off) != 0) {
298
		i = tmp - end;
299
		j = strlen(off);
300
		tmp = strdup(end);
301
		chop_out(tmp, i, j);
302
		free(off);
303
		result = tmp;
304
	    }
305
	    TR(TRACE_DATABASE, ("...adjusted sgr0 : %s", _nc_visbuf(result)));
306
3
	    if (!strcmp(result, exit_attribute_mode)) {
307
		TR(TRACE_DATABASE, ("...same result, discard"));
308
		free(result);
309
		result = exit_attribute_mode;
310
	    }
311
	} else {
312
	    /*
313
	     * Either the sgr does not reference alternate character set,
314
	     * or it is incorrect.  That's too hard to decide right now.
315
	     */
316
	    free(off);
317
	}
318
6
	FreeIfNeeded(end);
319
6
	FreeIfNeeded(on);
320
3
    } else {
321
	/*
322
	 * Possibly some applications are confused if sgr0 contains rmacs,
323
	 * but that would be a different bug report -TD
324
	 */
325
    }
326
327
3
    returnPtr(result);
328
}