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) 19 static char sccsid[] = "@(#)vis.c 5.2 (Berkeley) 05/11/90"; 20 #endif /* LIBC_SCCS and not lint */ 21 22 #include <sys/types.h> 23 #include <ctype.h> 24 #include <cencode.h> 25 26 #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') 27 28 /* 29 * vis - visually encode characters 30 */ 31 char * 32 vis(dst, c, flag, nextc) 33 register char *dst, c; 34 char nextc; 35 register int flag; 36 { 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); 46 } 47 48 if ((flag & VIS_NOSLASH) == 0) 49 *dst++ = '\\'; 50 if (flag & VIS_CSTYLE) { 51 switch(c) { 52 case '\n': 53 *dst++ = 'n'; 54 goto done; 55 case '\r': 56 *dst++ = 'r'; 57 goto done; 58 case '\b': 59 *dst++ = 'b'; 60 goto done; 61 case '\007': /* waiting for ansi compiler */ 62 *dst++ = 'a'; 63 goto done; 64 case '\v': 65 *dst++ = 'v'; 66 goto done; 67 case '\t': 68 *dst++ = 't'; 69 goto done; 70 case '\f': 71 *dst++ = 'f'; 72 goto done; 73 case ' ': 74 *dst++ = 's'; 75 goto done; 76 case '\0': 77 *dst++ = '0'; 78 if ((flag & VIS_NEXTC) == 0 || isoctal(nextc)) { 79 *dst++ = '0'; 80 *dst++ = '0'; 81 } 82 goto done; 83 } 84 } 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'; 89 goto done; 90 } 91 if (c & 0200) { 92 c &= 0177; 93 *dst++ = 'M'; 94 } 95 if (iscntrl(c)) { 96 *dst++ = '^'; 97 if (c == 0177) 98 *dst++ = '?'; 99 else 100 *dst++ = c + '@'; 101 } else { 102 *dst++ = '-'; 103 *dst++ = c; 104 } 105 done: 106 *dst = '\0'; 107 return (dst); 108 } 109 110 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 */ 124 cunvis(c, cp, flags) 125 char c; 126 char *cp; 127 { 128 static int state = S_NORMAL; 129 static u_char buildchar; 130 static int octal; 131 132 if (flags&UNVIS_END) { 133 int ostate = state; 134 state = S_NORMAL; 135 if (ostate == S_OCTAL) { 136 *cp = buildchar; 137 return(UNVIS_OK); 138 } else if (ostate == S_META1) { 139 /* slightly forgiving, if not wrong */ 140 *cp = ' ' | 0200; 141 return(UNVIS_OK); 142 } else 143 return(ostate == S_NORMAL ? UNVIS_NOCHAR : CDEC_SYNBAD); 144 } 145 146 switch (state) { 147 case S_NORMAL: 148 buildchar = 0; 149 if (c == '\\') { 150 state = S_START; 151 return(UNVIS_NEEDMORE); 152 } else if (flags&UNVIS_HAT && c == '^') { 153 state = S_CTRL; 154 return(UNVIS_NEEDMORE); 155 } else { 156 *cp = c; 157 return(UNVIS_OK); 158 } 159 break; 160 case S_START: 161 state = S_NORMAL; 162 if (c == '\\') { 163 *cp = c; 164 return(UNVIS_OK); 165 } 166 if (isoctal(c)) { 167 buildchar = (c-'0'); 168 octal = 1; 169 state = S_OCTAL; 170 return(UNVIS_NEEDMORE); 171 } 172 switch(c) { 173 case 'M': 174 buildchar |= 0200; 175 state = S_META; 176 return(UNVIS_NEEDMORE); 177 case '^': 178 state = S_CTRL; 179 return(UNVIS_NEEDMORE); 180 case 'n': 181 *cp = '\n'; 182 return(UNVIS_OK); 183 case 'r': 184 *cp = '\r'; 185 return(UNVIS_OK); 186 case 'b': 187 *cp = '\b'; 188 return(UNVIS_OK); 189 case 'a': 190 *cp = '\007'; 191 return(UNVIS_OK); 192 case 'v': 193 *cp = '\v'; 194 return(UNVIS_OK); 195 case 't': 196 *cp = '\t'; 197 return(UNVIS_OK); 198 case 'f': 199 *cp = '\f'; 200 return(UNVIS_OK); 201 case 's': /* does anyone use this ? */ 202 *cp = ' '; 203 return(UNVIS_OK); 204 case 'E': 205 *cp = '\033'; 206 return(UNVIS_OK); 207 case '\n': 208 return(UNVIS_NOCHAR); /* hidden newline */ 209 } 210 state = S_NORMAL; 211 return(UNVIS_SYNBAD); 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; 219 return(UNVIS_SYNBAD); 220 } 221 return(UNVIS_NEEDMORE); 222 case S_META1: 223 state = S_NORMAL; 224 *cp = c | buildchar; 225 return(UNVIS_OK); 226 case S_CTRL: 227 if (c == '?') 228 buildchar |= 0177; 229 else 230 buildchar |= c&037; 231 state = S_NORMAL; 232 *cp = buildchar; 233 return(UNVIS_OK); 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; 240 return(UNVIS_OK); 241 } else 242 return(UNVIS_NEEDMORE); 243 } else { 244 state = S_NORMAL; 245 *cp = buildchar; 246 return(UNVIS_OKPUSH); 247 } 248 } 249 } 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 */ 262 strvis(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 } 280