Rewrite I/O functions so that they handle properly
non printable characters.
This commit is contained in:
1 parent
06b330ec51
commit
a12e3534c6
2 files changed
+96
-18
No files matched your search
+81
-18
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user