1*67e74705SXin Li //===--- Encoding.h - Format C++ code -------------------------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li ///
10*67e74705SXin Li /// \file
11*67e74705SXin Li /// \brief Contains functions for text encoding manipulation. Supports UTF-8,
12*67e74705SXin Li /// 8-bit encodings and escape sequences in C++ string literals.
13*67e74705SXin Li ///
14*67e74705SXin Li //===----------------------------------------------------------------------===//
15*67e74705SXin Li
16*67e74705SXin Li #ifndef LLVM_CLANG_LIB_FORMAT_ENCODING_H
17*67e74705SXin Li #define LLVM_CLANG_LIB_FORMAT_ENCODING_H
18*67e74705SXin Li
19*67e74705SXin Li #include "clang/Basic/LLVM.h"
20*67e74705SXin Li #include "llvm/ADT/StringRef.h"
21*67e74705SXin Li #include "llvm/Support/ConvertUTF.h"
22*67e74705SXin Li #include "llvm/Support/Unicode.h"
23*67e74705SXin Li
24*67e74705SXin Li namespace clang {
25*67e74705SXin Li namespace format {
26*67e74705SXin Li namespace encoding {
27*67e74705SXin Li
28*67e74705SXin Li enum Encoding {
29*67e74705SXin Li Encoding_UTF8,
30*67e74705SXin Li Encoding_Unknown // We treat all other encodings as 8-bit encodings.
31*67e74705SXin Li };
32*67e74705SXin Li
33*67e74705SXin Li /// \brief Detects encoding of the Text. If the Text can be decoded using UTF-8,
34*67e74705SXin Li /// it is considered UTF8, otherwise we treat it as some 8-bit encoding.
detectEncoding(StringRef Text)35*67e74705SXin Li inline Encoding detectEncoding(StringRef Text) {
36*67e74705SXin Li const UTF8 *Ptr = reinterpret_cast<const UTF8 *>(Text.begin());
37*67e74705SXin Li const UTF8 *BufEnd = reinterpret_cast<const UTF8 *>(Text.end());
38*67e74705SXin Li if (::isLegalUTF8String(&Ptr, BufEnd))
39*67e74705SXin Li return Encoding_UTF8;
40*67e74705SXin Li return Encoding_Unknown;
41*67e74705SXin Li }
42*67e74705SXin Li
getCodePointCountUTF8(StringRef Text)43*67e74705SXin Li inline unsigned getCodePointCountUTF8(StringRef Text) {
44*67e74705SXin Li unsigned CodePoints = 0;
45*67e74705SXin Li for (size_t i = 0, e = Text.size(); i < e; i += getNumBytesForUTF8(Text[i])) {
46*67e74705SXin Li ++CodePoints;
47*67e74705SXin Li }
48*67e74705SXin Li return CodePoints;
49*67e74705SXin Li }
50*67e74705SXin Li
51*67e74705SXin Li /// \brief Gets the number of code points in the Text using the specified
52*67e74705SXin Li /// Encoding.
getCodePointCount(StringRef Text,Encoding Encoding)53*67e74705SXin Li inline unsigned getCodePointCount(StringRef Text, Encoding Encoding) {
54*67e74705SXin Li switch (Encoding) {
55*67e74705SXin Li case Encoding_UTF8:
56*67e74705SXin Li return getCodePointCountUTF8(Text);
57*67e74705SXin Li default:
58*67e74705SXin Li return Text.size();
59*67e74705SXin Li }
60*67e74705SXin Li }
61*67e74705SXin Li
62*67e74705SXin Li /// \brief Returns the number of columns required to display the \p Text on a
63*67e74705SXin Li /// generic Unicode-capable terminal. Text is assumed to use the specified
64*67e74705SXin Li /// \p Encoding.
columnWidth(StringRef Text,Encoding Encoding)65*67e74705SXin Li inline unsigned columnWidth(StringRef Text, Encoding Encoding) {
66*67e74705SXin Li if (Encoding == Encoding_UTF8) {
67*67e74705SXin Li int ContentWidth = llvm::sys::unicode::columnWidthUTF8(Text);
68*67e74705SXin Li // FIXME: Figure out the correct way to handle this in the presence of both
69*67e74705SXin Li // printable and unprintable multi-byte UTF-8 characters. Falling back to
70*67e74705SXin Li // returning the number of bytes may cause problems, as columnWidth suddenly
71*67e74705SXin Li // becomes non-additive.
72*67e74705SXin Li if (ContentWidth >= 0)
73*67e74705SXin Li return ContentWidth;
74*67e74705SXin Li }
75*67e74705SXin Li return Text.size();
76*67e74705SXin Li }
77*67e74705SXin Li
78*67e74705SXin Li /// \brief Returns the number of columns required to display the \p Text,
79*67e74705SXin Li /// starting from the \p StartColumn on a terminal with the \p TabWidth. The
80*67e74705SXin Li /// text is assumed to use the specified \p Encoding.
columnWidthWithTabs(StringRef Text,unsigned StartColumn,unsigned TabWidth,Encoding Encoding)81*67e74705SXin Li inline unsigned columnWidthWithTabs(StringRef Text, unsigned StartColumn,
82*67e74705SXin Li unsigned TabWidth, Encoding Encoding) {
83*67e74705SXin Li unsigned TotalWidth = 0;
84*67e74705SXin Li StringRef Tail = Text;
85*67e74705SXin Li for (;;) {
86*67e74705SXin Li StringRef::size_type TabPos = Tail.find('\t');
87*67e74705SXin Li if (TabPos == StringRef::npos)
88*67e74705SXin Li return TotalWidth + columnWidth(Tail, Encoding);
89*67e74705SXin Li TotalWidth += columnWidth(Tail.substr(0, TabPos), Encoding);
90*67e74705SXin Li TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth;
91*67e74705SXin Li Tail = Tail.substr(TabPos + 1);
92*67e74705SXin Li }
93*67e74705SXin Li }
94*67e74705SXin Li
95*67e74705SXin Li /// \brief Gets the number of bytes in a sequence representing a single
96*67e74705SXin Li /// codepoint and starting with FirstChar in the specified Encoding.
getCodePointNumBytes(char FirstChar,Encoding Encoding)97*67e74705SXin Li inline unsigned getCodePointNumBytes(char FirstChar, Encoding Encoding) {
98*67e74705SXin Li switch (Encoding) {
99*67e74705SXin Li case Encoding_UTF8:
100*67e74705SXin Li return getNumBytesForUTF8(FirstChar);
101*67e74705SXin Li default:
102*67e74705SXin Li return 1;
103*67e74705SXin Li }
104*67e74705SXin Li }
105*67e74705SXin Li
isOctDigit(char c)106*67e74705SXin Li inline bool isOctDigit(char c) { return '0' <= c && c <= '7'; }
107*67e74705SXin Li
isHexDigit(char c)108*67e74705SXin Li inline bool isHexDigit(char c) {
109*67e74705SXin Li return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') ||
110*67e74705SXin Li ('A' <= c && c <= 'F');
111*67e74705SXin Li }
112*67e74705SXin Li
113*67e74705SXin Li /// \brief Gets the length of an escape sequence inside a C++ string literal.
114*67e74705SXin Li /// Text should span from the beginning of the escape sequence (starting with a
115*67e74705SXin Li /// backslash) to the end of the string literal.
getEscapeSequenceLength(StringRef Text)116*67e74705SXin Li inline unsigned getEscapeSequenceLength(StringRef Text) {
117*67e74705SXin Li assert(Text[0] == '\\');
118*67e74705SXin Li if (Text.size() < 2)
119*67e74705SXin Li return 1;
120*67e74705SXin Li
121*67e74705SXin Li switch (Text[1]) {
122*67e74705SXin Li case 'u':
123*67e74705SXin Li return 6;
124*67e74705SXin Li case 'U':
125*67e74705SXin Li return 10;
126*67e74705SXin Li case 'x': {
127*67e74705SXin Li unsigned I = 2; // Point after '\x'.
128*67e74705SXin Li while (I < Text.size() && isHexDigit(Text[I]))
129*67e74705SXin Li ++I;
130*67e74705SXin Li return I;
131*67e74705SXin Li }
132*67e74705SXin Li default:
133*67e74705SXin Li if (isOctDigit(Text[1])) {
134*67e74705SXin Li unsigned I = 1;
135*67e74705SXin Li while (I < Text.size() && I < 4 && isOctDigit(Text[I]))
136*67e74705SXin Li ++I;
137*67e74705SXin Li return I;
138*67e74705SXin Li }
139*67e74705SXin Li return 1 + getNumBytesForUTF8(Text[1]);
140*67e74705SXin Li }
141*67e74705SXin Li }
142*67e74705SXin Li
143*67e74705SXin Li } // namespace encoding
144*67e74705SXin Li } // namespace format
145*67e74705SXin Li } // namespace clang
146*67e74705SXin Li
147*67e74705SXin Li #endif
148