History

Better handling of UCNs in strings

As the standard requires, take 4 hex digits after the \u opener of a Universal Character Name, or take 8 hex digits after \U, but reject smaller counts and don't consume more (https://port70.net/~nsz/c/c11/n1570.html#6.4.3, https://port70.net/~nsz/c/c99/n1256.html#6.4.3). The unicode codepoint used to get truncated to 1 byte. Now it gets expanded into UTF-8, matching gcc & clang behavior on Linux.

Petr Skocik committed 5 years ago

Commit ffb95c21 parent 6b614c42 files · +46 −7Browse files

Unified · Split

2 files
  1. tccpp.c +38 −6
  2. tests/tests2/97_utf8_string_literal.c +8 −1
tccpp.c+38−6
@@ -345,6 +345,31 @@ ST_INLN void cstr_ccat(CString *cstr, int ch) · 344 unmodified lines
345 cstr->size = size;345 cstr->size = size;
346}346}
347 347
348char *unicode_to_utf8 (char *b, uint32_t Uc)
349{
350 if (Uc<0x80) *b++=Uc;
351 else if (Uc<0x800) *b++=192+Uc/64, *b++=128+Uc%64;
352 else if (Uc-0xd800u<0x800) return b;
353 else if (Uc<0x10000) *b++=224+Uc/4096, *b++=128+Uc/64%64, *b++=128+Uc%64;
354 else if (Uc<0x110000) *b++=240+Uc/262144, *b++=128+Uc/4096%64, *b++=128+Uc/64%64, *b++=128+Uc%64;
355 return b;
356}
357
358/* add a unicode character expanded into utf8 */
359void cstr_u8cat(CString *cstr, int ch)
360{
361 unsigned char buf[4];
362 int size;
363 int add = (int)((unsigned char*)unicode_to_utf8(&buf[0],(uint32_t)ch) - &buf[0]);
364 unsigned char *p,*b=buf;
365 size = cstr->size + add;
366 if (size > cstr->size_allocated)
367 cstr_realloc(cstr, size);
368 for(p = (unsigned char*)cstr->data + (size - add); add; add--) *p++=*b++;
369 cstr->size = size;
370}
371
372
348ST_FUNC void cstr_cat(CString *cstr, const char *str, int len)373ST_FUNC void cstr_cat(CString *cstr, const char *str, int len)
349{374{
350 int size;375 int size;
@@ -2100,12 +2125,13 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long · 1749 unmodified lines
2100 }2125 }
2101 c = n;2126 c = n;
2102 goto add_char_nonext;2127 goto add_char_nonext;
2103 case 'x':2128 case 'x': { unsigned ucn_chars_nr = -1u; goto parse_hex_or_ucn;
2104 case 'u':2129 case 'u': ucn_chars_nr = 4; goto parse_hex_or_ucn;
2105 case 'U':2130 case 'U': ucn_chars_nr = 8; goto parse_hex_or_ucn;
2131 parse_hex_or_ucn:;
2106 p++;2132 p++;
2107 n = 0;2133 n = 0;
2108 for(;;) {2134 for(unsigned i=1;i<=ucn_chars_nr;i++) {
2109 c = *p;2135 c = *p;
2110 if (c >= 'a' && c <= 'f')2136 if (c >= 'a' && c <= 'f')
2111 c = c - 'a' + 10;2137 c = c - 'a' + 10;
@@ -2113,13 +2139,19 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long · 1 unmodified line
2113 c = c - 'A' + 10;2139 c = c - 'A' + 10;
2114 else if (isnum(c))2140 else if (isnum(c))
2115 c = c - '0';2141 c = c - '0';
2116 else2142 else{
2143 if (ucn_chars_nr!=-1)
2144 tcc_error("%u hex digits expected in universal-character-name\n", ucn_chars_nr);
2117 break;2145 break;
2146 }
2118 n = n * 16 + c;2147 n = n * 16 + c;
2119 p++;2148 p++;
2120 }2149 }
2121 c = n;2150 c = n;
2122 goto add_char_nonext;2151 if(ucn_chars_nr==-1) goto add_char_nonext;
2152 cstr_u8cat(outstr, c);
2153 continue;
2154 }
2123 case 'a':2155 case 'a':
2124 c = '\a';2156 c = '\a';
2125 break;2157 break;
tests/tests2/97_utf8_string_literal.c+8−1
@@ -1,12 +1,19 @@
1// this file contains BMP chars encoded in UTF-81// this file contains BMP chars encoded in UTF-8
2#include <stdio.h>2#include <stdio.h>
3#include <wchar.h>3#include <wchar.h>
4#include <stdlib.h>
5#include <string.h>
4 6
5int main()7int main()
6{8{
9 char hello_world_in_czech[] = "čau, světe";
10 char hello_world_in_czech_ucn[] = "\u010dau, sv\u011bte";
11 if (sizeof(hello_world_in_czech) != sizeof(hello_world_in_czech_ucn)
12 || strcmp(hello_world_in_czech, hello_world_in_czech_ucn))
13 abort();
14
7 wchar_t s[] = L"hello$$你好¢¢世界€€world";15 wchar_t s[] = L"hello$$你好¢¢世界€€world";
8 wchar_t *p;16 wchar_t *p;
9 for (p = s; *p; p++) printf("%04X ", (unsigned) *p);17 for (p = s; *p; p++) printf("%04X ", (unsigned) *p);
10 printf("\n");
11 return 0;18 return 0;
12}19}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t