1 /****************************************************************************
2 * Copyright (c) 2005-2010,2012 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Thomas Dickey *
31 ****************************************************************************/
33 #include <curses.priv.h>
39 MODULE_ID("$Id: trim_sgr0.c,v 1.15 2012/12/15 20:57:17 tom Exp $")
45 #define ESC 033 /* ^[ */
49 set_attribute_9(TERMTYPE
*tp
, int flag
)
54 value
= tparm(set_attributes
, 0, 0, 0, 0, 0, 0, 0, 0, flag
);
56 result
= strdup(value
);
67 if (UChar(s
[0]) == CSI
)
69 else if (s
[0] == ESC
&& s
[1] == L_BRACK
)
81 else if (isalpha(UChar(s
[1])))
88 skip_delay(const char *s
)
90 if (s
[0] == '$' && s
[1] == '<') {
92 while (isdigit(UChar(*s
)) || *s
== '/')
101 * Improve similar_sgr a little by moving the attr-string from the beginning
102 * to the end of the s-string.
105 rewrite_sgr(char *s
, char *attr
)
109 size_t len_s
= strlen(s
);
110 size_t len_a
= strlen(attr
);
112 if (len_s
> len_a
&& !strncmp(attr
, s
, len_a
)) {
114 TR(TRACE_DATABASE
, ("rewrite:\n\t%s", s
));
115 for (n
= 0; n
< len_s
- len_a
; ++n
) {
118 _nc_STRCPY(s
+ n
, attr
, strlen(s
) + 1);
119 TR(TRACE_DATABASE
, ("to:\n\t%s", s
));
124 return FALSE
; /* oops */
128 similar_sgr(char *a
, char *b
)
131 if (a
!= 0 && b
!= 0) {
132 int csi_a
= is_csi(a
);
133 int csi_b
= is_csi(b
);
137 TR(TRACE_DATABASE
, ("similar_sgr:\n\t%s\n\t%s",
140 if (csi_a
!= 0 && csi_b
!= 0 && csi_a
== csi_b
) {
150 if (len_a
&& len_b
) {
152 result
= (strncmp(a
, b
, len_b
) == 0);
154 result
= (strncmp(a
, b
, len_a
) == 0);
156 TR(TRACE_DATABASE
, ("...similar_sgr: %d\n\t%s\n\t%s", result
,
164 chop_out(char *string
, unsigned i
, unsigned j
)
166 TR(TRACE_DATABASE
, ("chop_out %d..%d from %s", i
, j
, _nc_visbuf(string
)));
167 while (string
[j
] != '\0') {
168 string
[i
++] = string
[j
++];
175 * Compare, ignoring delays. Some of the delay values are inconsistent, and
176 * we do not want to be stopped by that.
178 * Returns the number of chars from 'full' that we matched. If any mismatch
179 * occurs, return zero.
182 compare_part(const char *part
, const char *full
)
184 const char *next_part
;
185 const char *next_full
;
186 unsigned used_full
= 0;
187 unsigned used_delay
= 0;
190 if (*part
!= *full
) {
196 * Adjust the return-value to allow the rare case of
197 * string<delay>string
198 * to remove the whole piece. The most common case is a delay at the
199 * end of the string. The adjusted string will retain the delay, which
202 if (used_delay
!= 0) {
203 used_full
+= used_delay
;
206 if (*part
== '$' && *full
== '$') {
207 next_part
= skip_delay(part
);
208 next_full
= skip_delay(full
);
209 if (next_part
!= part
&& next_full
!= full
) {
210 used_delay
+= (unsigned) (next_full
- full
);
224 * While 'sgr0' is the "same" as termcap 'me', there is a compatibility issue.
225 * The sgr/sgr0 capabilities include setting/clearing alternate character set
226 * mode. A termcap application cannot use sgr, so sgr0 strings that reset
227 * alternate character set mode will be misinterpreted. Here, we remove those
228 * from the more common ISO/ANSI/VT100 entries, which have sgr0 agreeing with
231 * This function returns the modified sgr0 if it can be modified, a null if
232 * an error occurs, or the original sgr0 if no change is needed.
234 NCURSES_EXPORT(char *)
235 _nc_trim_sgr0(TERMTYPE
*tp
)
237 char *result
= exit_attribute_mode
;
239 T((T_CALLED("_nc_trim_sgr0()")));
241 if (PRESENT(exit_attribute_mode
)
242 && PRESENT(set_attributes
)) {
244 char *on
= set_attribute_9(tp
, 1);
245 char *off
= set_attribute_9(tp
, 0);
246 char *end
= strdup(exit_attribute_mode
);
250 TR(TRACE_DATABASE
, ("checking if we can trim sgr0 based on sgr"));
251 TR(TRACE_DATABASE
, ("sgr0 %s", _nc_visbuf(end
)));
252 TR(TRACE_DATABASE
, ("sgr(9:off) %s", _nc_visbuf(off
)));
253 TR(TRACE_DATABASE
, ("sgr(9:on) %s", _nc_visbuf(on
)));
255 if (!rewrite_sgr(on
, enter_alt_charset_mode
)
256 || !rewrite_sgr(off
, exit_alt_charset_mode
)
257 || !rewrite_sgr(end
, exit_alt_charset_mode
)) {
259 } else if (similar_sgr(off
, end
)
260 && !similar_sgr(off
, on
)) {
261 TR(TRACE_DATABASE
, ("adjusting sgr(9:off) : %s", _nc_visbuf(off
)));
264 * If rmacs is a substring of sgr(0), remove that chunk.
266 if (exit_alt_charset_mode
!= 0) {
267 TR(TRACE_DATABASE
, ("scan for rmacs %s", _nc_visbuf(exit_alt_charset_mode
)));
269 k
= strlen(exit_alt_charset_mode
);
271 for (i
= 0; i
<= (j
- k
); ++i
) {
272 unsigned k2
= compare_part(exit_alt_charset_mode
,
276 chop_out(off
, (unsigned) i
, (unsigned) (i
+ k2
));
283 * SGR 10 would reset to normal font.
286 if ((i
= (size_t) is_csi(off
)) != 0
287 && off
[strlen(off
) - 1] == 'm') {
288 TR(TRACE_DATABASE
, ("looking for SGR 10 in %s",
290 tmp
= skip_zero(off
+ i
);
292 && skip_zero(tmp
+ 1) != tmp
+ 1) {
293 i
= (size_t) (tmp
- off
);
294 if (off
[i
- 1] == ';')
296 j
= (size_t) (skip_zero(tmp
+ 1) - off
);
297 (void) chop_out(off
, (unsigned) i
, (unsigned) j
);
303 && (tmp
= strstr(end
, off
)) != 0
304 && strcmp(end
, off
) != 0) {
305 i
= (size_t) (tmp
- end
);
308 chop_out(tmp
, (unsigned) i
, (unsigned) j
);
312 TR(TRACE_DATABASE
, ("...adjusted sgr0 : %s", _nc_visbuf(result
)));
313 if (!strcmp(result
, exit_attribute_mode
)) {
314 TR(TRACE_DATABASE
, ("...same result, discard"));
316 result
= exit_attribute_mode
;
320 * Either the sgr does not reference alternate character set,
321 * or it is incorrect. That's too hard to decide right now.
329 * Possibly some applications are confused if sgr0 contains rmacs,
330 * but that would be a different bug report -TD