Skip to content

Commit 56ec19f

Browse files
committed
Add very limited support for DCS Request Termcap/Terminfo String (bug 2220)
1 parent bb852d8 commit 56ec19f

11 files changed

+128
-3
lines changed

NSStringITerm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ int decode_utf8_char(const unsigned char * restrict datap,
109109
// Fonts are encoded as strings when stored in a profile. This returns the font for such a string.
110110
- (NSFont *)fontValue;
111111

112+
// Returns a 2-hex-chars-per-char encoding of this string.
113+
- (NSString *)hexEncodedString;
114+
+ (NSString *)stringWithHexEncodedString:(NSString *)hexEncodedString;
115+
112116
@end
113117

114118
@interface NSMutableString (iTerm)

NSStringITerm.m

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,27 @@ - (NSFont *)fontValue {
878878
return aFont;
879879
}
880880

881+
- (NSString *)hexEncodedString {
882+
NSMutableString *result = [NSMutableString string];
883+
for (int i = 0; i < self.length; i++) {
884+
[result appendFormat:@"%02X", [self characterAtIndex:i]];
885+
}
886+
return [[result copy] autorelease];
887+
}
888+
889+
+ (NSString *)stringWithHexEncodedString:(NSString *)hexEncodedString {
890+
NSMutableString *result = [NSMutableString string];
891+
for (int i = 0; i + 1 < hexEncodedString.length; i += 2) {
892+
char buffer[3] = { [hexEncodedString characterAtIndex:i],
893+
[hexEncodedString characterAtIndex:i + 1],
894+
0 };
895+
int value;
896+
sscanf(buffer, "%02x", &value);
897+
[result appendFormat:@"%C", (unichar)value];
898+
}
899+
return [[result copy] autorelease];
900+
}
901+
881902
@end
882903

883904
@implementation NSMutableString (iTerm)

VT100DCSParser.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
#import <Foundation/Foundation.h>
1010
#import "VT100Token.h"
1111

12+
typedef enum {
13+
kDcsTermcapTerminfoRequestUnrecognizedName,
14+
kDcsTermcapTerminfoRequestTerminalName,
15+
kDcsTermcapTerminfoRequestTerminfoName
16+
} DcsTermcapTerminfoRequestName;
17+
1218
NS_INLINE BOOL isDCS(unsigned char *code, int len) {
1319
return (len >= 2 && code[0] == ESC && code[1] == 'P');
1420
}
@@ -22,5 +28,8 @@ NS_INLINE BOOL isDCS(unsigned char *code, int len) {
2228
token:(VT100Token *)result
2329
encoding:(NSStringEncoding)encoding;
2430

31+
+ (NSDictionary *)termcapTerminfoNameDictionary; // string name -> DcsTermcapTerminfoRequestName
32+
+ (NSDictionary *)termcapTerminfoInverseNameDictionary; // DcsTermcapTerminfoRequestName -> string name
33+
2534
@end
2635

VT100DCSParser.m

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,41 @@ + (void)decodeBytes:(unsigned char *)datap
2020
// Can assume we have "ESC P" so skip past that.
2121
datap += 2;
2222
datalen -= 2;
23-
*rmlen=2;
23+
*rmlen = 2;
24+
if (datalen >= 2) {
25+
if (!strncmp((char *)datap, "+q", 2)) {
26+
datap += 2;
27+
datalen -= 2;
28+
*rmlen += 2;
29+
char st[3] = { ESC, '\\', '\0' };
30+
char *positionOfST = strnstr((const char *)datap, st, datalen);
31+
if (!positionOfST) {
32+
return;
33+
}
34+
int length = positionOfST - (char *)datap;
35+
*rmlen += length + 2;
36+
NSString *semicolonDelimitedHexEncodedNames =
37+
[NSString stringWithFormat:@"%.*s", length, (char *)datap];
38+
NSArray *hexEncodedNames =
39+
[semicolonDelimitedHexEncodedNames componentsSeparatedByString:@";"];
40+
result->type = DCS_REQUEST_TERMCAP_TERMINFO;
41+
result.csi->count = 0;
42+
NSDictionary *nameMap = [[self class] termcapTerminfoNameDictionary];
43+
for (NSString *hexEncodedName in hexEncodedNames) {
44+
NSString *name = [NSString stringWithHexEncodedString:hexEncodedName];
45+
NSNumber *value = nameMap[name];
46+
if (value) {
47+
result.csi->p[result.csi->count++] = [value intValue];
48+
} else {
49+
result.csi->p[result.csi->count++] = kDcsTermcapTerminfoRequestUnrecognizedName;
50+
}
51+
if (result.csi->count == VT100CSIPARAM_MAX) {
52+
break;
53+
}
54+
}
55+
return;
56+
}
57+
}
2458
if (datalen >= 5) {
2559
if (!strncmp((char *)datap, "1000p", 5)) {
2660
result->type = DCS_TMUX;
@@ -31,4 +65,20 @@ + (void)decodeBytes:(unsigned char *)datap
3165
}
3266
}
3367

68+
+ (NSDictionary *)termcapTerminfoNameDictionary {
69+
return @{ @"TN": @(kDcsTermcapTerminfoRequestTerminalName),
70+
@"name": @(kDcsTermcapTerminfoRequestTerminfoName) };
71+
}
72+
73+
+ (NSDictionary *)termcapTerminfoInverseNameDictionary {
74+
NSMutableDictionary *result = [NSMutableDictionary dictionary];
75+
NSDictionary *dict = [self termcapTerminfoNameDictionary];
76+
for (NSString *key in dict) {
77+
id value = dict[key];
78+
result[value] = key;
79+
}
80+
return result;
81+
}
82+
83+
3484
@end

VT100Screen.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#import "iTermGrowlDelegate.h"
1919
#import "iTermPreferences.h"
2020
#import "iTermSelection.h"
21+
#import "VT100DCSParser.h"
2122
#import "VT100Token.h"
2223

2324
#import <apr-1/apr_base64.h>

VT100Terminal.m

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#import "VT100Terminal.h"
22
#import "DebugLogging.h"
33
#import "NSColor+iTerm.h"
4+
#import "VT100DCSParser.h"
45
#import "VT100Parser.h"
56
#import <apr-1/apr_base64.h> // for xterm's base64 decoding (paste64)
67
#include <term.h>
@@ -1547,6 +1548,38 @@ - (void)executeToken:(VT100Token *)token {
15471548
[self executeXtermSetRgb:token];
15481549
break;
15491550

1551+
case DCS_REQUEST_TERMCAP_TERMINFO: {
1552+
static NSString *const kFormat = @"%@=%@";
1553+
BOOL ok = NO;
1554+
NSMutableArray *parts = [NSMutableArray array];
1555+
NSDictionary *inverseMap = [VT100DCSParser termcapTerminfoInverseNameDictionary];
1556+
for (int i = 0; i < token.csi->count; i++) {
1557+
NSString *stringKey = inverseMap[@(token.csi->p[i])];
1558+
NSString *hexEncodedKey = [stringKey hexEncodedString];
1559+
switch (token.csi->p[i]) {
1560+
case kDcsTermcapTerminfoRequestTerminfoName:
1561+
[parts addObject:[NSString stringWithFormat:kFormat,
1562+
hexEncodedKey,
1563+
[_termType hexEncodedString]]];
1564+
ok = YES;
1565+
break;
1566+
case kDcsTermcapTerminfoRequestTerminalName:
1567+
[parts addObject:[NSString stringWithFormat:kFormat,
1568+
hexEncodedKey,
1569+
[@"iTerm2" hexEncodedString]]];
1570+
ok = YES;
1571+
break;
1572+
case kDcsTermcapTerminfoRequestUnrecognizedName:
1573+
i = token.csi->count;
1574+
break;
1575+
}
1576+
}
1577+
NSString *s = [NSString stringWithFormat:@"\033P%d+r%@\033\\",
1578+
ok ? 1 : 0,
1579+
[parts componentsJoinedByString:@";"]];
1580+
[delegate_ terminalSendReport:[s dataUsingEncoding:NSUTF8StringEncoding]];
1581+
break;
1582+
}
15501583
default:
15511584
NSLog(@"Unexpected token type %d", (int)token->type);
15521585
break;

VT100Token.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,12 @@ typedef enum {
151151
ANSICSI_SCP, // Save cursor position
152152
ANSICSI_RCP, // Restore cursor position
153153
ANSICSI_CBT, // Back tab
154-
154+
155155
ANSI_RIS, // Reset to initial state (there's also a CSI version)
156156

157+
// DCS
158+
DCS_REQUEST_TERMCAP_TERMINFO, // Request Termcap/Terminfo String
159+
157160
// Toggle between ansi/vt52
158161
STRICT_ANSI_MODE,
159162

VT100Token.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,8 @@ - (NSString *)codeName {
209209
@(DCS_TMUX): @"DCS_TMUX",
210210
@(TMUX_LINE): @"TMUX_LINE",
211211
@(TMUX_EXIT): @"TMUX_EXIT",
212-
@(VT100CSI_DECSLRM_OR_ANSICSI_SCP): @"VT100CSI_DECSLRM_OR_ANSICSI_SCP" };
212+
@(VT100CSI_DECSLRM_OR_ANSICSI_SCP): @"VT100CSI_DECSLRM_OR_ANSICSI_SCP",
213+
@(DCS_REQUEST_TERMCAP_TERMINFO): @"DCS_REQUEST_TERMCAP_TERMINFO", };
213214
NSString *name = map[@(type)];
214215
if (name) {
215216
return name;

tests/report_broken

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
P+q\

tests/report_name_tn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
P+q6E616D65;544E\

tests/report_tn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
P+q544E\

0 commit comments

Comments
 (0)