1 /*
2  * cstring.c -- parse and print strings using the C escape sequences
3  */
4 
5 #include "config.h"
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <ctype.h>
9 #ifdef HAVE_GETOPT_H
10 #include <getopt.h>
11 #endif
12 #include <string.h>
13 
14 #include "cstring.h"
15 
parse_c_string(char * str)16 int parse_c_string(char *str)
17 {
18 	char *to, *from, ch;
19 	int v;
20 
21 	to = from = str;
22 
23 	for (to = from = (char *) str;
24 	     *from && *from != '"'; to++, from++) {
25 		if (*from == '\\') {
26 			ch = *(++from);
27 			switch (ch) {
28 			case 'a':
29 				*to = '\a';
30 				break;
31 			case 'b':
32 				*to = '\b';
33 				break;
34 			case 'f':
35 				*to = '\f';
36 				break;
37 			case 'n':
38 				*to = '\n';
39 				break;
40 			case 't':
41 				*to = '\t';
42 				break;
43 			case 'v':
44 				*to = '\v';
45 				break;
46 			case 'x':
47 				ch = *(from + 1);
48 				if (ch >= 'a' && ch <= 'f')
49 					ch = ch - 'a' + 'A';
50 				if (ch >= '0' && ch <= '9')
51 					v = ch - '0';
52 				else if (ch >= 'A' && ch <= 'F')
53 					v = ch + 10 - 'A';
54 				else {
55 					*to = 'x';
56 					break;
57 				}
58 				from++;
59 				ch = *(from + 1);
60 				if (ch >= 'a' && ch <= 'f')
61 					ch = ch - 'a' + 'A';
62 				if (ch >= '0' && ch <= '9')
63 					v = (v * 16) + (ch - '0');
64 				else if (ch >= 'A' && ch <= 'F')
65 					v = (v * 16) + (ch + 10 - 'A');
66 				else {
67 					*to = 'x';
68 					from--;
69 					break;
70 				}
71 				from++;
72 				*to = v;
73 				break;
74 			default:
75 				if (ch >= '0' && ch <= '9') {
76 					v = ch - '0';
77 					ch = *(from + 1);
78 					if (ch >= '0' && ch <= '9') {
79 						from++;
80 						v = (8 * v) + (ch - '0');
81 						ch = *(from + 1);
82 						if (ch >= '0' && ch <= '9') {
83 							from++;
84 							v = (8 * v) + (ch - '0');
85 						}
86 					}
87 					ch = v;
88 				}
89 				*to = ch;
90 			}
91 			continue;
92 		}
93 		*to = *from;
94 	}
95 	*to = '\0';
96 	return to - (char *) str;
97 }
98 
print_c_string(FILE * f,const char * cp,int len)99 void print_c_string(FILE *f, const char *cp, int len)
100 {
101 	unsigned char	ch;
102 
103 	if (len < 0)
104 		len = strlen(cp);
105 
106 	while (len--) {
107 		ch = *cp++;
108 		if (ch == '\a')
109 			fputs("\\a", f);
110 		else if (ch == '\b')
111 			fputs("\\b", f);
112 		else if (ch == '\f')
113 			fputs("\\f", f);
114 		else if (ch == '\n')
115 			fputs("\\n", f);
116 		else if (ch == '\t')
117 			fputs("\\t", f);
118 		else if (ch == '\v')
119 			fputs("\\v", f);
120 		else if (ch == '\\')
121 			fputs("\\\\", f);
122 		else if (ch == '\'')
123 			fputs("\\\'", f);
124 		else if (ch == '\"')
125 			fputs("\\\"", f);
126 		else if ((ch < 32) || (ch > 126))
127 			fprintf(f, "\\%03o", ch);
128 		else
129 			fputc(ch, f);
130 	}
131 }
132 
133 #ifdef DEBUG_PROGRAM
main(int argc,char ** argv)134 int main(int argc, char **argv)
135 {
136 	char buf[4096];
137 	int c, raw = 0;
138 
139 	while ((c = getopt(argc, argv, "r")) != EOF) {
140 		switch (c) {
141 		case 'r':
142 			raw++;
143 			break;
144 		default:
145 			fprintf(stderr, "Usage: %s [-r]\n", argv[0]);
146 			exit(1);
147 		}
148 	}
149 
150 	while (!feof(stdin)) {
151 		if (fgets(buf, sizeof(buf), stdin) == NULL)
152 			break;
153 		c = parse_c_string(buf);
154 		if (raw)
155 			fputs(buf, stdout);
156 		else {
157 			print_c_string(stdout, buf, c);
158 			printf(" <%d>\n", c);
159 		}
160 	}
161 }
162 #endif
163