]> git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/mangle.c
4c505bce700172616ae4002f7fe5e4477cc8bf8e
[thirdparty/util-linux.git] / lib / mangle.c
1 /*
2 * Functions for \oct encoding used in mtab/fstab/swaps/etc.
3 *
4 * No copyright is claimed. This code is in the public domain; do with
5 * it what you wish.
6 *
7 * Written by Karel Zak <kzak@redhat.com> [2010]
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13
14 #include "mangle.h"
15 #include "c.h"
16
17 #define isoctal(a) (((a) & ~7) == '0')
18
19 #define from_hex(c) (isdigit(c) ? c - '0' : tolower(c) - 'a' + 10)
20
21 #define is_unwanted_char(x) (strchr(" \t\n\\", (unsigned int) x) != NULL)
22
23
24 char *mangle(const char *s)
25 {
26 char *ss, *sp;
27
28 if (!s)
29 return NULL;
30
31 ss = sp = malloc(4 * strlen(s) + 1);
32 if (!sp)
33 return NULL;
34 while(1) {
35 if (!*s) {
36 *sp = '\0';
37 break;
38 }
39 if (is_unwanted_char(*s)) {
40 *sp++ = '\\';
41 *sp++ = '0' + ((*s & 0300) >> 6);
42 *sp++ = '0' + ((*s & 070) >> 3);
43 *sp++ = '0' + (*s & 07);
44 } else
45 *sp++ = *s;
46 s++;
47 }
48 return ss;
49 }
50
51
52 void unmangle_to_buffer(const char *s, char *buf, size_t len)
53 {
54 size_t sz = 0;
55
56 if (!s)
57 return;
58
59 while(*s && sz < len - 1) {
60 if (*s == '\\' && sz + 3 < len - 1 && isoctal(s[1]) &&
61 isoctal(s[2]) && isoctal(s[3])) {
62
63 *buf++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7);
64 s += 4;
65 sz += 4;
66 } else {
67 *buf++ = *s++;
68 sz++;
69 }
70 }
71 *buf = '\0';
72 }
73
74 size_t unhexmangle_to_buffer(const char *s, char *buf, size_t len)
75 {
76 size_t sz = 0;
77 const char *buf0 = buf;
78
79 if (!s)
80 return 0;
81
82 while(*s && sz < len - 1) {
83 if (*s == '\\' && sz + 3 < len - 1 && s[1] == 'x' &&
84 isxdigit(s[2]) && isxdigit(s[3])) {
85
86 *buf++ = from_hex(s[2]) << 4 | from_hex(s[3]);
87 s += 4;
88 sz += 4;
89 } else {
90 *buf++ = *s++;
91 sz++;
92 }
93 }
94 *buf = '\0';
95 return buf - buf0 + 1;
96 }
97
98 size_t unescape_to_buffer(const char *s, const char *wanted, char *buf, size_t len)
99 {
100 size_t sz = 0;
101 const char *buf0 = buf;
102
103 while (*s && sz < len - 1) {
104 if (*s == '\\' && sz + 1 < len - 1 && strchr(wanted, s[1])) {
105 *buf++ = s[1];
106 s += 2;
107 sz += 2;
108 } else {
109 *buf++ = *s++;;
110 sz++;
111 }
112 }
113 *buf = '\0';
114 return buf - buf0 + 1;
115 }
116
117 static inline const char *skip_nonspaces(const char *s)
118 {
119 while (s && *s && !(*s == ' ' || *s == '\t'))
120 s++;
121 return s;
122 }
123
124 /*
125 * Returns mallocated buffer or NULL in case of error.
126 */
127 char *unmangle(const char *s, const char **end)
128 {
129 char *buf;
130 const char *e;
131 size_t sz;
132
133 if (!s)
134 return NULL;
135
136 e = skip_nonspaces(s);
137 sz = e - s + 1;
138
139 if (end)
140 *end = e;
141 if (e == s)
142 return NULL; /* empty string */
143
144 buf = malloc(sz);
145 if (!buf)
146 return NULL;
147
148 unmangle_to_buffer(s, buf, sz);
149 return buf;
150 }
151
152 #ifdef TEST_PROGRAM_MANGLE
153 #include <errno.h>
154 int main(int argc, char *argv[])
155 {
156 char *p = NULL;
157 if (argc < 3) {
158 fprintf(stderr, "usage: %s --mangle|unmangle|unescape <string>\n",
159 program_invocation_short_name);
160 return EXIT_FAILURE;
161 }
162
163 if (!strcmp(argv[1], "--mangle")) {
164 p = mangle(argv[2]);
165 printf("mangled: '%s'\n", p);
166 free(p);
167 }
168
169 else if (!strcmp(argv[1], "--unmangle")) {
170 char *x = unmangle(argv[2], NULL);
171
172 if (x) {
173 printf("unmangled: '%s'\n", x);
174 free(x);
175 }
176
177 x = strdup(argv[2]);
178 if (x) {
179 unmangle_to_buffer(x, x, strlen(x) + 1);
180
181 printf("self-unmangled: '%s'\n", x);
182 free(x);
183 }
184 }
185
186 else if (!strcmp(argv[1], "--unescape")) {
187 char *x = strdup(argv[2]);
188 if (x) {
189 unescape_to_buffer(x, ",\"", x, strlen(x) + 1);
190
191 printf("self-unescaped: '%s'\n", x);
192 free(x);
193 }
194 }
195
196 return EXIT_SUCCESS;
197 }
198 #endif /* TEST_PROGRAM_MANGLE */