new copyright, cflag CIGNORE implements TCSASOFT
[unix-history] / usr / src / lib / libc / gen / vis.c
CommitLineData
9c260c06
MT
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18#if defined(LIBC_SCCS) && !defined(lint)
a11b735c 19static char sccsid[] = "@(#)vis.c 5.2 (Berkeley) %G%";
9c260c06
MT
20#endif /* LIBC_SCCS and not lint */
21
22#include <sys/types.h>
23#include <ctype.h>
24#include <cencode.h>
25
9c260c06
MT
26#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
27
28/*
a11b735c 29 * vis - visually encode characters
9c260c06 30 */
9c260c06 31char *
a11b735c
MT
32vis(dst, c, flag, nextc)
33 register char *dst, c;
34 char nextc;
35 register int flag;
9c260c06 36{
a11b735c
MT
37 if (isascii(c) && isgraph(c) ||
38 ((flag & VIS_WHITE) == 0 &&
39 (c == ' ' || c == '\n' || (flag & VIS_TAB) == 0 && c == '\t')) ||
40 ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) {
41 *dst++ = c;
42 if (c == '\\' && (flag & VIS_NOSLASH) == 0)
43 *dst++ = '\\';
44 *dst = '\0';
45 return (dst);
9c260c06 46 }
a11b735c
MT
47
48 if ((flag & VIS_NOSLASH) == 0)
49 *dst++ = '\\';
50 if (flag & VIS_CSTYLE) {
9c260c06
MT
51 switch(c) {
52 case '\n':
a11b735c 53 *dst++ = 'n';
9c260c06
MT
54 goto done;
55 case '\r':
a11b735c 56 *dst++ = 'r';
9c260c06
MT
57 goto done;
58 case '\b':
a11b735c 59 *dst++ = 'b';
9c260c06 60 goto done;
a11b735c
MT
61 case '\007': /* waiting for ansi compiler */
62 *dst++ = 'a';
9c260c06
MT
63 goto done;
64 case '\v':
a11b735c 65 *dst++ = 'v';
9c260c06
MT
66 goto done;
67 case '\t':
a11b735c 68 *dst++ = 't';
9c260c06
MT
69 goto done;
70 case '\f':
a11b735c 71 *dst++ = 'f';
9c260c06
MT
72 goto done;
73 case ' ':
a11b735c 74 *dst++ = 's';
9c260c06
MT
75 goto done;
76 case '\0':
a11b735c
MT
77 *dst++ = '0';
78 if ((flag & VIS_NEXTC) == 0 || isoctal(nextc)) {
79 *dst++ = '0';
80 *dst++ = '0';
9c260c06
MT
81 }
82 goto done;
83 }
84 }
a11b735c
MT
85 if (((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
86 *dst++ = ((u_char)c >> 6 & 07) + '0';
87 *dst++ = ((u_char)c >> 3 & 07) + '0';
88 *dst++ = ((u_char)c & 07) + '0';
9c260c06
MT
89 goto done;
90 }
a11b735c
MT
91 if (c & 0200) {
92 c &= 0177;
93 *dst++ = 'M';
94 }
95 if (iscntrl(c)) {
96 *dst++ = '^';
97 if (c == 0177)
98 *dst++ = '?';
9c260c06 99 else
a11b735c
MT
100 *dst++ = c + '@';
101 } else {
102 *dst++ = '-';
103 *dst++ = c;
9c260c06 104 }
9c260c06 105done:
a11b735c
MT
106 *dst = '\0';
107 return (dst);
9c260c06
MT
108}
109
a11b735c 110
9c260c06
MT
111/*
112 * decode driven by state machine
113 */
114#define S_NORMAL 1 /* haven't seen escape char */
115#define S_START 2 /* start decoding special sequence */
116#define S_META 3 /* metachar started (M) */
117#define S_META1 4 /* metachar more, regular char (-) */
118#define S_CTRL 5 /* control char started (^) */
119#define S_OCTAL 6 /* octal number */
120
121/*
122 *
123 */
a11b735c 124cunvis(c, cp, flags)
9c260c06
MT
125 char c;
126 char *cp;
127{
128 static int state = S_NORMAL;
a11b735c
MT
129 static u_char buildchar;
130 static int octal;
9c260c06 131
a11b735c 132 if (flags&UNVIS_END) {
9c260c06
MT
133 int ostate = state;
134 state = S_NORMAL;
135 if (ostate == S_OCTAL) {
136 *cp = buildchar;
a11b735c 137 return(UNVIS_OK);
9c260c06
MT
138 } else if (ostate == S_META1) {
139 /* slightly forgiving, if not wrong */
140 *cp = ' ' | 0200;
a11b735c 141 return(UNVIS_OK);
9c260c06 142 } else
a11b735c 143 return(ostate == S_NORMAL ? UNVIS_NOCHAR : CDEC_SYNBAD);
9c260c06
MT
144 }
145
146 switch (state) {
147 case S_NORMAL:
148 buildchar = 0;
149 if (c == '\\') {
150 state = S_START;
a11b735c
MT
151 return(UNVIS_NEEDMORE);
152 } else if (flags&UNVIS_HAT && c == '^') {
9c260c06 153 state = S_CTRL;
a11b735c 154 return(UNVIS_NEEDMORE);
9c260c06
MT
155 } else {
156 *cp = c;
a11b735c 157 return(UNVIS_OK);
9c260c06
MT
158 }
159 break;
160 case S_START:
161 state = S_NORMAL;
162 if (c == '\\') {
163 *cp = c;
a11b735c 164 return(UNVIS_OK);
9c260c06
MT
165 }
166 if (isoctal(c)) {
167 buildchar = (c-'0');
168 octal = 1;
169 state = S_OCTAL;
a11b735c 170 return(UNVIS_NEEDMORE);
9c260c06
MT
171 }
172 switch(c) {
173 case 'M':
174 buildchar |= 0200;
175 state = S_META;
a11b735c 176 return(UNVIS_NEEDMORE);
9c260c06
MT
177 case '^':
178 state = S_CTRL;
a11b735c 179 return(UNVIS_NEEDMORE);
9c260c06
MT
180 case 'n':
181 *cp = '\n';
a11b735c 182 return(UNVIS_OK);
9c260c06
MT
183 case 'r':
184 *cp = '\r';
a11b735c 185 return(UNVIS_OK);
9c260c06
MT
186 case 'b':
187 *cp = '\b';
a11b735c 188 return(UNVIS_OK);
9c260c06
MT
189 case 'a':
190 *cp = '\007';
a11b735c 191 return(UNVIS_OK);
9c260c06
MT
192 case 'v':
193 *cp = '\v';
a11b735c 194 return(UNVIS_OK);
9c260c06
MT
195 case 't':
196 *cp = '\t';
a11b735c 197 return(UNVIS_OK);
9c260c06
MT
198 case 'f':
199 *cp = '\f';
a11b735c 200 return(UNVIS_OK);
9c260c06
MT
201 case 's': /* does anyone use this ? */
202 *cp = ' ';
a11b735c 203 return(UNVIS_OK);
9c260c06
MT
204 case 'E':
205 *cp = '\033';
a11b735c 206 return(UNVIS_OK);
9c260c06 207 case '\n':
a11b735c 208 return(UNVIS_NOCHAR); /* hidden newline */
9c260c06
MT
209 }
210 state = S_NORMAL;
a11b735c 211 return(UNVIS_SYNBAD);
9c260c06
MT
212 case S_META:
213 if (c == '-')
214 state = S_META1;
215 else if (c == '^')
216 state = S_CTRL;
217 else {
218 state = S_NORMAL;
a11b735c 219 return(UNVIS_SYNBAD);
9c260c06 220 }
a11b735c 221 return(UNVIS_NEEDMORE);
9c260c06
MT
222 case S_META1:
223 state = S_NORMAL;
224 *cp = c | buildchar;
a11b735c 225 return(UNVIS_OK);
9c260c06
MT
226 case S_CTRL:
227 if (c == '?')
228 buildchar |= 0177;
229 else
230 buildchar |= c&037;
231 state = S_NORMAL;
232 *cp = buildchar;
a11b735c 233 return(UNVIS_OK);
9c260c06
MT
234 case S_OCTAL:
235 if (isoctal(c)) {
236 buildchar = (buildchar<<3) + (c-'0');
237 if (++octal == 3) {
238 state = S_NORMAL;
239 *cp = buildchar;
a11b735c 240 return(UNVIS_OK);
9c260c06 241 } else
a11b735c 242 return(UNVIS_NEEDMORE);
9c260c06
MT
243 } else {
244 state = S_NORMAL;
245 *cp = buildchar;
a11b735c 246 return(UNVIS_OKPUSH);
9c260c06
MT
247 }
248 }
249}
a11b735c
MT
250
251/*
252 * strvis - visually encode characters from src into dst
253 *
254 * If len >= 0, encodes exactly len chars from src (including NULL's).
255 * Otherwise, stops before first NULL in src. In all cases, dst is
256 * NULL terminated.
257 *
258 * Dst must be 4 times the size of src to account for possible
259 * expansion. The length of dst, not including the trailing NULL,
260 * is returned.
261 */
262strvis(dst, src, len, flag)
263 register char *dst, *src;
264 register int len;
265{
266 char *start = dst;
267
268 for (;;) {
269 if (len > 0) {
270 if (len-- == 0)
271 break;
272 } else if (!*src)
273 break;
274 dst = vis(dst, *src, flag | VIS_NEXTC, *(src+1));
275 src++;
276 }
277
278 return (dst - start);
279}