139284Smarc /* 239284Smarc * Copyright (c) 1989 The Regents of the University of California. 339284Smarc * All rights reserved. 439284Smarc * 539284Smarc * Redistribution and use in source and binary forms are permitted 639284Smarc * provided that the above copyright notice and this paragraph are 739284Smarc * duplicated in all such forms and that any documentation, 839284Smarc * advertising materials, and other materials related to such 939284Smarc * distribution and use acknowledge that the software was developed 1039284Smarc * by the University of California, Berkeley. The name of the 1139284Smarc * University may not be used to endorse or promote products derived 1239284Smarc * from this software without specific prior written permission. 1339284Smarc * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1439284Smarc * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1539284Smarc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1639284Smarc */ 1739284Smarc 1839284Smarc #if defined(LIBC_SCCS) && !defined(lint) 19*41757Smarc static char sccsid[] = "@(#)vis.c 5.2 (Berkeley) 05/11/90"; 2039284Smarc #endif /* LIBC_SCCS and not lint */ 2139284Smarc 2239284Smarc #include <sys/types.h> 2339284Smarc #include <ctype.h> 2439284Smarc #include <cencode.h> 2539284Smarc 2639284Smarc #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') 2739284Smarc 2839284Smarc /* 29*41757Smarc * vis - visually encode characters 3039284Smarc */ 3139284Smarc char * 32*41757Smarc vis(dst, c, flag, nextc) 33*41757Smarc register char *dst, c; 34*41757Smarc char nextc; 35*41757Smarc register int flag; 3639284Smarc { 37*41757Smarc if (isascii(c) && isgraph(c) || 38*41757Smarc ((flag & VIS_WHITE) == 0 && 39*41757Smarc (c == ' ' || c == '\n' || (flag & VIS_TAB) == 0 && c == '\t')) || 40*41757Smarc ((flag & VIS_SAFE) && (c == '\b' || c == '\007' || c == '\r'))) { 41*41757Smarc *dst++ = c; 42*41757Smarc if (c == '\\' && (flag & VIS_NOSLASH) == 0) 43*41757Smarc *dst++ = '\\'; 44*41757Smarc *dst = '\0'; 45*41757Smarc return (dst); 46*41757Smarc } 4739284Smarc 48*41757Smarc if ((flag & VIS_NOSLASH) == 0) 49*41757Smarc *dst++ = '\\'; 50*41757Smarc if (flag & VIS_CSTYLE) { 5139284Smarc switch(c) { 5239284Smarc case '\n': 53*41757Smarc *dst++ = 'n'; 5439284Smarc goto done; 5539284Smarc case '\r': 56*41757Smarc *dst++ = 'r'; 5739284Smarc goto done; 5839284Smarc case '\b': 59*41757Smarc *dst++ = 'b'; 6039284Smarc goto done; 61*41757Smarc case '\007': /* waiting for ansi compiler */ 62*41757Smarc *dst++ = 'a'; 6339284Smarc goto done; 6439284Smarc case '\v': 65*41757Smarc *dst++ = 'v'; 6639284Smarc goto done; 6739284Smarc case '\t': 68*41757Smarc *dst++ = 't'; 6939284Smarc goto done; 7039284Smarc case '\f': 71*41757Smarc *dst++ = 'f'; 7239284Smarc goto done; 7339284Smarc case ' ': 74*41757Smarc *dst++ = 's'; 7539284Smarc goto done; 7639284Smarc case '\0': 77*41757Smarc *dst++ = '0'; 78*41757Smarc if ((flag & VIS_NEXTC) == 0 || isoctal(nextc)) { 79*41757Smarc *dst++ = '0'; 80*41757Smarc *dst++ = '0'; 8139284Smarc } 8239284Smarc goto done; 8339284Smarc } 8439284Smarc } 85*41757Smarc if (((c & 0177) == ' ') || (flag & VIS_OCTAL)) { 86*41757Smarc *dst++ = ((u_char)c >> 6 & 07) + '0'; 87*41757Smarc *dst++ = ((u_char)c >> 3 & 07) + '0'; 88*41757Smarc *dst++ = ((u_char)c & 07) + '0'; 8939284Smarc goto done; 9039284Smarc } 91*41757Smarc if (c & 0200) { 92*41757Smarc c &= 0177; 93*41757Smarc *dst++ = 'M'; 94*41757Smarc } 95*41757Smarc if (iscntrl(c)) { 96*41757Smarc *dst++ = '^'; 97*41757Smarc if (c == 0177) 98*41757Smarc *dst++ = '?'; 9939284Smarc else 100*41757Smarc *dst++ = c + '@'; 101*41757Smarc } else { 102*41757Smarc *dst++ = '-'; 103*41757Smarc *dst++ = c; 10439284Smarc } 10539284Smarc done: 106*41757Smarc *dst = '\0'; 107*41757Smarc return (dst); 10839284Smarc } 10939284Smarc 110*41757Smarc 11139284Smarc /* 11239284Smarc * decode driven by state machine 11339284Smarc */ 11439284Smarc #define S_NORMAL 1 /* haven't seen escape char */ 11539284Smarc #define S_START 2 /* start decoding special sequence */ 11639284Smarc #define S_META 3 /* metachar started (M) */ 11739284Smarc #define S_META1 4 /* metachar more, regular char (-) */ 11839284Smarc #define S_CTRL 5 /* control char started (^) */ 11939284Smarc #define S_OCTAL 6 /* octal number */ 12039284Smarc 12139284Smarc /* 12239284Smarc * 12339284Smarc */ 124*41757Smarc cunvis(c, cp, flags) 12539284Smarc char c; 12639284Smarc char *cp; 12739284Smarc { 12839284Smarc static int state = S_NORMAL; 129*41757Smarc static u_char buildchar; 130*41757Smarc static int octal; 13139284Smarc 132*41757Smarc if (flags&UNVIS_END) { 13339284Smarc int ostate = state; 13439284Smarc state = S_NORMAL; 13539284Smarc if (ostate == S_OCTAL) { 13639284Smarc *cp = buildchar; 137*41757Smarc return(UNVIS_OK); 13839284Smarc } else if (ostate == S_META1) { 13939284Smarc /* slightly forgiving, if not wrong */ 14039284Smarc *cp = ' ' | 0200; 141*41757Smarc return(UNVIS_OK); 14239284Smarc } else 143*41757Smarc return(ostate == S_NORMAL ? UNVIS_NOCHAR : CDEC_SYNBAD); 14439284Smarc } 14539284Smarc 14639284Smarc switch (state) { 14739284Smarc case S_NORMAL: 14839284Smarc buildchar = 0; 14939284Smarc if (c == '\\') { 15039284Smarc state = S_START; 151*41757Smarc return(UNVIS_NEEDMORE); 152*41757Smarc } else if (flags&UNVIS_HAT && c == '^') { 15339284Smarc state = S_CTRL; 154*41757Smarc return(UNVIS_NEEDMORE); 15539284Smarc } else { 15639284Smarc *cp = c; 157*41757Smarc return(UNVIS_OK); 15839284Smarc } 15939284Smarc break; 16039284Smarc case S_START: 16139284Smarc state = S_NORMAL; 16239284Smarc if (c == '\\') { 16339284Smarc *cp = c; 164*41757Smarc return(UNVIS_OK); 16539284Smarc } 16639284Smarc if (isoctal(c)) { 16739284Smarc buildchar = (c-'0'); 16839284Smarc octal = 1; 16939284Smarc state = S_OCTAL; 170*41757Smarc return(UNVIS_NEEDMORE); 17139284Smarc } 17239284Smarc switch(c) { 17339284Smarc case 'M': 17439284Smarc buildchar |= 0200; 17539284Smarc state = S_META; 176*41757Smarc return(UNVIS_NEEDMORE); 17739284Smarc case '^': 17839284Smarc state = S_CTRL; 179*41757Smarc return(UNVIS_NEEDMORE); 18039284Smarc case 'n': 18139284Smarc *cp = '\n'; 182*41757Smarc return(UNVIS_OK); 18339284Smarc case 'r': 18439284Smarc *cp = '\r'; 185*41757Smarc return(UNVIS_OK); 18639284Smarc case 'b': 18739284Smarc *cp = '\b'; 188*41757Smarc return(UNVIS_OK); 18939284Smarc case 'a': 19039284Smarc *cp = '\007'; 191*41757Smarc return(UNVIS_OK); 19239284Smarc case 'v': 19339284Smarc *cp = '\v'; 194*41757Smarc return(UNVIS_OK); 19539284Smarc case 't': 19639284Smarc *cp = '\t'; 197*41757Smarc return(UNVIS_OK); 19839284Smarc case 'f': 19939284Smarc *cp = '\f'; 200*41757Smarc return(UNVIS_OK); 20139284Smarc case 's': /* does anyone use this ? */ 20239284Smarc *cp = ' '; 203*41757Smarc return(UNVIS_OK); 20439284Smarc case 'E': 20539284Smarc *cp = '\033'; 206*41757Smarc return(UNVIS_OK); 20739284Smarc case '\n': 208*41757Smarc return(UNVIS_NOCHAR); /* hidden newline */ 20939284Smarc } 21039284Smarc state = S_NORMAL; 211*41757Smarc return(UNVIS_SYNBAD); 21239284Smarc case S_META: 21339284Smarc if (c == '-') 21439284Smarc state = S_META1; 21539284Smarc else if (c == '^') 21639284Smarc state = S_CTRL; 21739284Smarc else { 21839284Smarc state = S_NORMAL; 219*41757Smarc return(UNVIS_SYNBAD); 22039284Smarc } 221*41757Smarc return(UNVIS_NEEDMORE); 22239284Smarc case S_META1: 22339284Smarc state = S_NORMAL; 22439284Smarc *cp = c | buildchar; 225*41757Smarc return(UNVIS_OK); 22639284Smarc case S_CTRL: 22739284Smarc if (c == '?') 22839284Smarc buildchar |= 0177; 22939284Smarc else 23039284Smarc buildchar |= c&037; 23139284Smarc state = S_NORMAL; 23239284Smarc *cp = buildchar; 233*41757Smarc return(UNVIS_OK); 23439284Smarc case S_OCTAL: 23539284Smarc if (isoctal(c)) { 23639284Smarc buildchar = (buildchar<<3) + (c-'0'); 23739284Smarc if (++octal == 3) { 23839284Smarc state = S_NORMAL; 23939284Smarc *cp = buildchar; 240*41757Smarc return(UNVIS_OK); 24139284Smarc } else 242*41757Smarc return(UNVIS_NEEDMORE); 24339284Smarc } else { 24439284Smarc state = S_NORMAL; 24539284Smarc *cp = buildchar; 246*41757Smarc return(UNVIS_OKPUSH); 24739284Smarc } 24839284Smarc } 24939284Smarc } 250*41757Smarc 251*41757Smarc /* 252*41757Smarc * strvis - visually encode characters from src into dst 253*41757Smarc * 254*41757Smarc * If len >= 0, encodes exactly len chars from src (including NULL's). 255*41757Smarc * Otherwise, stops before first NULL in src. In all cases, dst is 256*41757Smarc * NULL terminated. 257*41757Smarc * 258*41757Smarc * Dst must be 4 times the size of src to account for possible 259*41757Smarc * expansion. The length of dst, not including the trailing NULL, 260*41757Smarc * is returned. 261*41757Smarc */ 262*41757Smarc strvis(dst, src, len, flag) 263*41757Smarc register char *dst, *src; 264*41757Smarc register int len; 265*41757Smarc { 266*41757Smarc char *start = dst; 267*41757Smarc 268*41757Smarc for (;;) { 269*41757Smarc if (len > 0) { 270*41757Smarc if (len-- == 0) 271*41757Smarc break; 272*41757Smarc } else if (!*src) 273*41757Smarc break; 274*41757Smarc dst = vis(dst, *src, flag | VIS_NEXTC, *(src+1)); 275*41757Smarc src++; 276*41757Smarc } 277*41757Smarc 278*41757Smarc return (dst - start); 279*41757Smarc } 280