]> git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/mangle.c
include: add some missing licence stuff to header files
[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 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
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 static inline const char *skip_nonspaces(const char *s)
99 {
100 while (s && *s && !(*s == ' ' || *s == '\t'))
101 s++;
102 return s;
103 }
104
105 /*
106 * Returns mallocated buffer or NULL in case of error.
107 */
108 char *unmangle(const char *s, const char **end)
109 {
110 char *buf;
111 const char *e;
112 size_t sz;
113
114 if (!s)
115 return NULL;
116
117 e = skip_nonspaces(s);
118 sz = e - s + 1;
119
120 if (end)
121 *end = e;
122 if (e == s)
123 return NULL; /* empty string */
124
125 buf = malloc(sz);
126 if (!buf)
127 return NULL;
128
129 unmangle_to_buffer(s, buf, sz);
130 return buf;
131 }
132
133 #ifdef TEST_PROGRAM_MANGLE
134 #include <errno.h>
135 int main(int argc, char *argv[])
136 {
137 char *p = NULL;
138 if (argc < 3) {
139 fprintf(stderr, "usage: %s --mangle|unmangle <string>\n",
140 program_invocation_short_name);
141 return EXIT_FAILURE;
142 }
143
144 if (!strcmp(argv[1], "--mangle")) {
145 p = mangle(argv[2]);
146 printf("mangled: '%s'\n", p);
147 free(p);
148 }
149
150 else if (!strcmp(argv[1], "--unmangle")) {
151 char *x = unmangle(argv[2], NULL);
152
153 if (x) {
154 printf("unmangled: '%s'\n", x);
155 free(x);
156 }
157
158 x = strdup(argv[2]);
159 if (x) {
160 unmangle_to_buffer(x, x, strlen(x) + 1);
161
162 printf("self-unmangled: '%s'\n", x);
163 free(x);
164 }
165 }
166
167 return EXIT_SUCCESS;
168 }
169 #endif /* TEST_PROGRAM_MANGLE */