Rewrite I/O functions so that they handle properly

non printable characters.
This commit is contained in:
Patrick Pelissier committed 2018-04-21 10:26:05 +02:00
1 parent 06b330ec51
commit a12e3534c6
2 files changed
+96 -18

No files matched your search

+81 -18
View File
@@ -762,29 +762,53 @@ string_strim(string_t v, const char charac[])
/* I/O */
/* Output: "string" with quote around
Replace " by \" within the string (and \ to \\)
\n, \t & \r by their standard representation
and other not printable character with \0xx */
static inline void
string_get_str(string_t v, const string_t v2, bool append)
{
/* Output: "string" with quote around
Replace " by \" within the string */
STRINGI_CONTRACT(v2);
STRINGI_CONTRACT(v);
M_ASSUME (v != v2); // Limitation
if(append==false) v->size = 0;
size_t targetSize = v->size + v2->size + 3;
size_t size = append ? v->size : 0;
size_t targetSize = size + v2->size + 3;
stringi_fit2size(v, targetSize);
v->ptr[v->size ++] = '"';
v->ptr[size ++] = '"';
for(size_t i = 0 ; i < v2->size; i++) {
const char c = v2->ptr[i];
if (c == '"') {
targetSize ++ ;
stringi_fit2size(v, targetSize);
v->ptr[v->size ++] = '\\';
switch (c) {
case '\\':
case '"':
case '\n':
case '\t':
case '\r':
// Special characters which can be displayed in a short form.
stringi_fit2size(v, ++targetSize);
v->ptr[size ++] = '\\';
// This string acts as a perfect hashmap which supposes an ASCII mapping
// and (c^(c>>5)) is the hash function
v->ptr[size ++] = " tn\" r\\"[(c ^ (c >>5)) & 0x07];
break;
default:
if (M_UNLIKELY (!isprint(c))) {
targetSize += 3;
stringi_fit2size(v, targetSize);
int d1 = c & 0x07, d2 = (c>>3) & 0x07, d3 = (c>>6) & 0x07;
v->ptr[size ++] = '\\';
v->ptr[size ++] = '0' + d3;
v->ptr[size ++] = '0' + d2;
v->ptr[size ++] = '0' + d1;
} else {
v->ptr[size ++] = c;
}
break;
}
v->ptr[v->size ++] = c;
}
v->ptr[v->size ++] = '"';
v->ptr[v->size] = 0;
v->ptr[size ++] = '"';
v->ptr[size] = 0;
v->size = size;
M_ASSUME (v->size <= targetSize);
STRINGI_CONTRACT (v);
}
@@ -792,17 +816,32 @@ string_get_str(string_t v, const string_t v2, bool append)
static inline void
string_out_str(FILE *f, const string_t v)
{
/* Output: "string" with quote around
Replace " by \" within the string */
STRINGI_CONTRACT(v);
M_ASSUME (f != NULL);
fputc('"', f);
for(size_t i = 0 ; i < v->size; i++) {
const char c = v->ptr[i];
if (c == '"') {
switch (c) {
case '\\':
case '"':
case '\n':
case '\t':
case '\r':
fputc('\\', f);
fputc(" tn\" r\\"[(c ^ c >>5) & 0x07], f);
break;
default:
if (M_UNLIKELY (!isprint(c))) {
int d1 = c & 0x07, d2 = (c>>3) & 0x07, d3 = (c>>6) & 0x07;
fputc('\\', f);
fputc('0' + d3, f);
fputc('0' + d2, f);
fputc('0' + d1, f);
} else {
fputc(c, f);
}
break;
}
fputc(c, f);
}
fputc('"', f);
}
@@ -817,9 +856,33 @@ string_in_str(string_t v, FILE *f)
string_clean(v);
c = fgetc(f);
while (c != '"' && c != EOF) {
if (c == '\\') {
if (M_UNLIKELY (c == '\\')) {
c = fgetc(f);
if (c != '"') string_push_back (v, '\\');
switch (c) {
case 'n':
case 't':
case 'r':
case '\\':
case '\"':
// This string acts as a perfect hashmap which supposes an ASCII mapping
// and (c^(c>>5)) is the hash function
c = " \r \" \n\\\t"[(c^(c>>5))& 0x07];
break;
default:
if (!(c >= '0' && c <= '7'))
return false;
int d1 = c - '0';
c = fgetc(f);
if (!(c >= '0' && c <= '7'))
return false;
int d2 = c - '0';
c = fgetc(f);
if (!(c >= '0' && c <= '7'))
return false;
int d3 = c - '0';
c = (d1 << 6) + (d2 << 3) + d3;
break;
}
}
string_push_back (v, c);
c = fgetc(f);
+15
View File
@@ -300,6 +300,21 @@ static void test0(void)
fclose(f);
assert (string_equal_p(s1, s2));
string_set_str(s1, "\tHell\\o\n\"World\"\r\001");
string_get_str(s2, s1, false);
assert (string_cmp_str(s2, "\"\\tHell\\\\o\\n\\\"World\\\"\\r\\001\"") == 0);
f = fopen ("a-mstring.dat", "wt");
assert (f != NULL);
string_out_str (f, s1);
fclose (f);
f = fopen("a-mstring.dat", "rt");
assert (f != NULL);
b = string_in_str(s2, f);
assert(b);
fclose(f);
assert (string_equal_p(s1, s2));
string_set_str(s1, "AZERTY");
string_set_str(s2, "QWERTY");
string_swap (s1, s2);