new strsep
[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)
19static char sccsid[] = "@(#)vis.c 5.1 (Berkeley) %G%";
20#endif /* LIBC_SCCS and not lint */
21
22#include <sys/types.h>
23#include <ctype.h>
24#include <cencode.h>
25
26#define iswhite(c) ((c)==' '||(c)=='\t'||(c)=='\n')
27#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
28
29/*
30 * cencode
31 */
32
33/*VARARGS2*/
34char *
35cencode(sc, flags, rachar)
36 char sc, rachar;
37{
38 static char buff[5];
39 register char *s = buff;
40 register u_char c = sc;
41
42 if (isgraph(c) || (!(flags&CENC_WHITE) && iswhite(c))) {
43 if (c == '\\')
44 *s++ = '\\';
45 *s++ = c;
46 goto done;
47 }
48 *s++ = '\\';
49 if (flags&CENC_CSTYLE) {
50 switch(c) {
51 case '\n':
52 *s++ = 'n';
53 goto done;
54 case '\r':
55 *s++ = 'r';
56 goto done;
57 case '\b':
58 *s++ = 'b';
59 goto done;
60 case '\007':
61 *s++ = 'a';
62 goto done;
63 case '\v':
64 *s++ = 'v';
65 goto done;
66 case '\t':
67 *s++ = 't';
68 goto done;
69 case '\f':
70 *s++ = 'f';
71 goto done;
72 case ' ':
73 *s++ = 's';
74 goto done;
75 case '\0':
76 *s++ = '0';
77 if (!(flags&CENC_RACHAR) || isoctal(rachar)) {
78 *s++ = '0';
79 *s++ = '0';
80 }
81 goto done;
82 }
83 }
84 if ((flags&CENC_GRAPH) && (c&0177) != ' ') {
85 if (c & 0200) {
86 c &= 0177;
87 *s++ = 'M';
88 }
89 if (iscntrl(c)) {
90 *s++ = '^';
91 if (c == 0177)
92 *s++ = '?';
93 else
94 *s++ = c + '@';
95 } else {
96 *s++ = '-';
97 *s++ = c;
98 }
99 goto done;
100 }
101 if (flags&CENC_OCTAL) {
102 if (flags&CENC_RACHAR && !isoctal(rachar))
103 (void)sprintf(s, "%o", (int)c);
104 else
105 (void)sprintf(s, "%03o", (int)c);
106 while (*s++)
107 ;
108 goto done;
109 }
110 /*
111 * Couldn't encode.
112 */
113 s--;
114 *s = c;
115done:
116 *s = '\0';
117 return(buff);
118}
119
120/*
121 * decode driven by state machine
122 */
123#define S_NORMAL 1 /* haven't seen escape char */
124#define S_START 2 /* start decoding special sequence */
125#define S_META 3 /* metachar started (M) */
126#define S_META1 4 /* metachar more, regular char (-) */
127#define S_CTRL 5 /* control char started (^) */
128#define S_OCTAL 6 /* octal number */
129
130/*
131 *
132 */
133cdecode(c, cp, flags)
134 char c;
135 char *cp;
136{
137 static int state = S_NORMAL;
138 u_char buildchar;
139 int octal;
140
141 if (flags&CDEC_END) {
142 int ostate = state;
143 state = S_NORMAL;
144 if (ostate == S_OCTAL) {
145 *cp = buildchar;
146 return(CDEC_OK);
147 } else if (ostate == S_META1) {
148 /* slightly forgiving, if not wrong */
149 *cp = ' ' | 0200;
150 return(CDEC_OK);
151 } else
152 return(ostate == S_NORMAL ? CDEC_NOCHAR : CDEC_SYNBAD);
153 }
154
155 switch (state) {
156 case S_NORMAL:
157 buildchar = 0;
158 if (c == '\\') {
159 state = S_START;
160 return(CDEC_NEEDMORE);
161 } else if (flags&CDEC_HAT && c == '^') {
162 state = S_CTRL;
163 return(CDEC_NEEDMORE);
164 } else {
165 *cp = c;
166 return(CDEC_OK);
167 }
168 break;
169 case S_START:
170 state = S_NORMAL;
171 if (c == '\\') {
172 *cp = c;
173 return(CDEC_OK);
174 }
175 if (isoctal(c)) {
176 buildchar = (c-'0');
177 octal = 1;
178 state = S_OCTAL;
179 return(CDEC_NEEDMORE);
180 }
181 switch(c) {
182 case 'M':
183 buildchar |= 0200;
184 state = S_META;
185 return(CDEC_NEEDMORE);
186 case '^':
187 state = S_CTRL;
188 return(CDEC_NEEDMORE);
189 case 'n':
190 *cp = '\n';
191 return(CDEC_OK);
192 case 'r':
193 *cp = '\r';
194 return(CDEC_OK);
195 case 'b':
196 *cp = '\b';
197 return(CDEC_OK);
198 case 'a':
199 *cp = '\007';
200 return(CDEC_OK);
201 case 'v':
202 *cp = '\v';
203 return(CDEC_OK);
204 case 't':
205 *cp = '\t';
206 return(CDEC_OK);
207 case 'f':
208 *cp = '\f';
209 return(CDEC_OK);
210 case 's': /* does anyone use this ? */
211 *cp = ' ';
212 return(CDEC_OK);
213 case 'E':
214 *cp = '\033';
215 return(CDEC_OK);
216 case '\n':
217 return(CDEC_NOCHAR); /* hidden newline */
218 }
219 state = S_NORMAL;
220 return(CDEC_SYNBAD);
221 case S_META:
222 if (c == '-')
223 state = S_META1;
224 else if (c == '^')
225 state = S_CTRL;
226 else {
227 state = S_NORMAL;
228 return(CDEC_SYNBAD);
229 }
230 return(CDEC_NEEDMORE);
231 case S_META1:
232 state = S_NORMAL;
233 *cp = c | buildchar;
234 return(CDEC_OK);
235 case S_CTRL:
236 if (c == '?')
237 buildchar |= 0177;
238 else
239 buildchar |= c&037;
240 state = S_NORMAL;
241 *cp = buildchar;
242 return(CDEC_OK);
243 case S_OCTAL:
244 if (isoctal(c)) {
245 buildchar = (buildchar<<3) + (c-'0');
246 if (++octal == 3) {
247 state = S_NORMAL;
248 *cp = buildchar;
249 return(CDEC_OK);
250 } else
251 return(CDEC_NEEDMORE);
252 } else {
253 state = S_NORMAL;
254 *cp = buildchar;
255 return(CDEC_OKPUSH);
256 }
257 }
258}