Gordon said:
In BSD there are non-standard functions strunvis(), strunvisx(),
strvis(), and strvisx() which translate strings from and to a visual
representation of the string. There are several visual representations,
one of them being C-style, and another being octal escapes. strunvis()
decodes all these escapes back into a string. The strvis*() forms
have many options as to what to encode.
It isn't that I didn't already have my own code for this (see below my
signature, includes not shown, it needs limits.h). I just wanted to
know if there might not be a function always present in the C library
that would do this.
Thanks,
David Mathog
/* Convert text form for special characters in a string to the
corresponding (unsigned) character. Handles:
Some C escape sequences: \\, \a,\b,\f,\t,\r, and \n.
ASCII control characters like ^J (masks the 2nd character
retaining only the lowest 6 bits)
For a lone "^" use "/^".
Numerically specified character values as \###,\o###,\x## (3,3,
and 2 digits, as shown, ONLY)
Range is 0-255.
Returns 1 on success, 0 on error
*/
int convert_escape(char *string){
unsigned char *parsed;
unsigned char *scan;
#define NORMAL 0
#define ESCAPE 1
#define CONTROL 2
#define DNUMERIC 3
#define ONUMERIC 4
#define XNUMERIC 5
int state = NORMAL;
int sum = 0;
int count = 0;
int status = 1;
int ok = 1;
for(scan = parsed = (unsigned char *) string; ok; scan++){
switch(state){
case NORMAL:
switch(*scan){
case '\\':
state=ESCAPE;
break;
case '^':
state=CONTROL;
break;
case '\0':
*parsed = *scan; ok = 0;
break;
default:
*parsed=*scan; parsed++;
}
break;
case ESCAPE:
switch(*scan){
case '\\':
state=NORMAL; *parsed=*scan; parsed++;
break;
case 'a':
state=NORMAL; *parsed='\a'; parsed++;
break;
case 'b':
state=NORMAL; *parsed='\b'; parsed++;
break;
case 'f':
state=NORMAL; *parsed='\f'; parsed++;
break;
case 't':
state=NORMAL; *parsed='\t'; parsed++;
break;
case 'r':
state=NORMAL; *parsed='\r'; parsed++;
break;
case 'n':
state=NORMAL; *parsed='\n'; parsed++;
break;
case 'd':
state=DNUMERIC; sum=0; count=0;
break;
case 'o':
state=ONUMERIC; sum=0; count=0;
break;
case 'x':
state=XNUMERIC; sum=0; count=0;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
state=DNUMERIC; sum = *scan - '0'; count=1;
break;
case '\0':
ok = status = 0;
break;
default:
state=NORMAL; *parsed=*scan; parsed++;
}
break;
case CONTROL:
if(*scan=='\0'){
ok = status = 0;
}
else {
state=NORMAL; *parsed = *scan & 31; parsed++;
}
break;
case DNUMERIC:
switch(*scan){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
sum=(10*sum) + (*scan - '0');
if(++count == 3){ /* There must be exactly 3 digits */
if(sum > UCHAR_MAX){
ok = status = 0;
}
else {
state = NORMAL; *parsed=sum; parsed++;
}
}
break;
default:
ok = status = 0;
}
break;
case ONUMERIC:
switch(*scan){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
sum= (8*sum) + (*scan - '0');
if(++count == 3){ /* There must be exactly 3 digits */
if(sum > UCHAR_MAX){
ok = status = 0;
}
else {
state = NORMAL; *parsed=sum; parsed++;
}
}
break;
default:
ok = status = 0;
}
break;
case XNUMERIC:
switch(*scan){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
sum=(16*sum) + (*scan - '0');
if(++count == 2){ /* There must be exactly 2 digits */
state = NORMAL; *parsed=sum; parsed++;
}
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
sum=(16*sum) + (10 + *scan - 'A');
if(++count == 2){ /* There must be exactly 2 digits */
state = NORMAL; *parsed=sum; parsed++;
}
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
sum=(16*sum) + (10 + *scan - 'a');
if(++count == 2){ /* There must be exactly 2 digits */
state = NORMAL; *parsed=sum; parsed++;
}
break;
default:
ok = status = 0;
}
break;
default: /* catch what should be an impossible state */
ok = status = 0;
}
}
return(status);
}