Skip to content

Instantly share code, notes, and snippets.

@nic-hartley
Created March 29, 2017 22:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nic-hartley/104feded8dc0a75d983bebdeadb7fce5 to your computer and use it in GitHub Desktop.
Save nic-hartley/104feded8dc0a75d983bebdeadb7fce5 to your computer and use it in GitHub Desktop.
The escaping methods and its tests
//to simulate my environment
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned long long ERROR;
const ERROR TTO_WORDS_VALUELESS_FAIL = 9000;
const ERROR TTO_UNKNOWN_TYPE_FAIL = 9001;
const ERROR TTO_NOT_IMPLEMENTED_FAIL = 9002;
const ERROR TTO_CREATE_OBJ_FAIL = 9003;
const ERROR TTO_STRING_ESCAPE_FAIL = 9004;
const ERROR TTO_ESCAPE_END_FAIL = 9005;
const ERROR TTO_MALLOC_FAIL = 9006;
const ERROR TTO_ESCAPE_BAD_HEX_FAIL = 9007;
const ERROR NO_ERROR = 0;
//code
char tto_hexchar_to_val(const char c) {
switch (c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default: return 16;
}
}
ERROR tto_escape_hex(const char **pos, char **ret_pos, const char *const end) {
char x_val;
int t;
x_val = 0;
++(*pos);
if (*pos == end) {
return TTO_ESCAPE_END_FAIL;
}
t = tto_hexchar_to_val(**pos);
if (t > 15) {
return TTO_ESCAPE_BAD_HEX_FAIL;
}
x_val |= t << 4;
++(*pos);
if (*pos == end) {
return TTO_ESCAPE_END_FAIL;
}
t = tto_hexchar_to_val(**pos);
if (t > 15) {
return TTO_ESCAPE_BAD_HEX_FAIL;
}
x_val |= t;
**ret_pos = x_val;
return NO_ERROR;
}
ERROR tto_escape_string(const char *const str, size_t val_len, char **out) {
ERROR err;
char *ret = malloc(val_len);
if (!ret) return TTO_MALLOC_FAIL;
char *ret_pos = ret;
const char *const end_null = str + val_len - 1;
for (const char *pos = str; pos < end_null; ++pos, ++ret_pos) {
if (*pos == '\\') {
++pos;
if (pos == end_null) {
err = TTO_ESCAPE_END_FAIL;
goto error_handler;
}
switch (*pos) {
case '0': *ret_pos = '\0'; break;
case 'a': *ret_pos = '\a'; break;
case 'b': *ret_pos = '\b'; break;
case 'e': *ret_pos = '\x1B'; break;
case 'f': *ret_pos = '\f'; break;
case 'n': *ret_pos = '\n'; break;
case 'r': *ret_pos = '\r'; break;
case 't': *ret_pos = '\t'; break;
case 'v': *ret_pos = '\v'; break;
case 'x':
err = tto_escape_hex(&pos, &ret_pos, end_null);
if (err != NO_ERROR) goto error_handler;
break;
default:
*ret_pos = *pos;
}
} else {
*ret_pos = *pos;
}
}
*ret_pos = 0;
++ret_pos;
char *new_ret = realloc(ret, ret_pos - ret);
if (!new_ret) {
*out = ret;
} else {
*out = new_ret;
}
return NO_ERROR;
error_handler:;
free(ret);
return err;
}
//tests
int main() {
char *tests[] = {
"abc",// no effect
"ab\\c",// escape non-special characters
"ab\\x63",// hex escape
"ab\\tc",// standard escape
"ab\\t\\x21c",// multiple escapes
"ab\\\\c",// backslash escape
"\\\\abc",// escape at beginning
"ab\\\\",// escape at end
"\\x456",// hex followed by numbers
"abc\\",// incomplete
"abc\\x",// incomplete hex (differently)
"abc\\x0",// incomplete hex
"abc\\xO",// bad hex char
"abc\\0def",// null escape (printing stops at abc)
};
const char *expects[] = {
"abc",
"abc",
"abc",
"ab\tc",
"ab\t!c",
"ab\\c",
"\\abc",
"ab\\",
"E6",
"error 9005",
"error 9005",
"error 9005",
"error 9007",
"abc"
};
for (size_t i = 0; i < (sizeof(tests) / sizeof(char *)); ++i) {
printf("====test %zu:\n", i);
puts(tests[i]);
char *res;
ERROR err = tto_escape_string(tests[i], strlen(tests[i]) + 1, &res);
printf("-error:%llu\n", err);
if (err == NO_ERROR) puts(res);
else printf("error %llu\n", err);
puts(expects[i]);
if (err == NO_ERROR) free(res);
}
puts("==end");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment