144303Smarc /*- 241932Smarc * Copyright (c) 1989 The Regents of the University of California. 341932Smarc * All rights reserved. 441932Smarc * 544303Smarc * %sccs.include.redist.c% 641932Smarc */ 741932Smarc 841932Smarc #if defined(LIBC_SCCS) && !defined(lint) 9*46597Sdonn static char sccsid[] = "@(#)unvis.c 1.4 (Berkeley) 02/23/91"; 1041932Smarc #endif /* LIBC_SCCS and not lint */ 1141932Smarc 1241932Smarc #include <sys/types.h> 1341932Smarc #include <ctype.h> 1441932Smarc #include <vis.h> 1541932Smarc 1641932Smarc /* 1741932Smarc * decode driven by state machine 1841932Smarc */ 1941932Smarc #define S_GROUND 0 /* haven't seen escape char */ 2041932Smarc #define S_START 1 /* start decoding special sequence */ 2141932Smarc #define S_META 2 /* metachar started (M) */ 2241932Smarc #define S_META1 3 /* metachar more, regular char (-) */ 2341932Smarc #define S_CTRL 4 /* control char started (^) */ 2441932Smarc #define S_OCTAL2 5 /* octal digit 2 */ 2541932Smarc #define S_OCTAL3 6 /* octal digit 3 */ 2641932Smarc 2744303Smarc #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') 2844303Smarc 2941932Smarc /* 3041932Smarc * unvis - decode characters previously encoded by vis 3141932Smarc */ 32*46597Sdonn int 33*46597Sdonn #if __STDC__ 34*46597Sdonn unvis(char *cp, char c, int *astate, int flag) 35*46597Sdonn #else 3641932Smarc unvis(cp, c, astate, flag) 37*46597Sdonn char *cp, c; 3841932Smarc int *astate, flag; 39*46597Sdonn #endif 4041932Smarc { 4141932Smarc 4241932Smarc if (flag & UNVIS_END) { 4341932Smarc if (*astate == S_OCTAL2 || *astate == S_OCTAL3) { 4441932Smarc *astate = S_GROUND; 4541932Smarc return (UNVIS_VALID); 4641932Smarc } 4741932Smarc return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD); 4841932Smarc } 4941932Smarc 5041932Smarc switch (*astate) { 5141932Smarc 5241932Smarc case S_GROUND: 5341932Smarc *cp = 0; 5441932Smarc if (c == '\\') { 5541932Smarc *astate = S_START; 5641932Smarc return (0); 5741932Smarc } 5841932Smarc *cp = c; 5941932Smarc return (UNVIS_VALID); 6041932Smarc 6141932Smarc case S_START: 6241932Smarc switch(c) { 6341932Smarc case '\\': 6441932Smarc *cp = c; 6541932Smarc *astate = S_GROUND; 6641932Smarc return (UNVIS_VALID); 6741932Smarc case '0': case '1': case '2': case '3': 6841932Smarc case '4': case '5': case '6': case '7': 6941932Smarc *cp = (c - '0'); 7041932Smarc *astate = S_OCTAL2; 7141932Smarc return (0); 7241932Smarc case 'M': 7341932Smarc *cp = 0200; 7441932Smarc *astate = S_META; 7541932Smarc return (0); 7641932Smarc case '^': 7741932Smarc *astate = S_CTRL; 7841932Smarc return (0); 7941932Smarc case 'n': 8041932Smarc *cp = '\n'; 8141932Smarc *astate = S_GROUND; 8241932Smarc return (UNVIS_VALID); 8341932Smarc case 'r': 8441932Smarc *cp = '\r'; 8541932Smarc *astate = S_GROUND; 8641932Smarc return (UNVIS_VALID); 8741932Smarc case 'b': 8841932Smarc *cp = '\b'; 8941932Smarc *astate = S_GROUND; 9041932Smarc return (UNVIS_VALID); 9141932Smarc case 'a': 9241932Smarc *cp = '\007'; 9341932Smarc *astate = S_GROUND; 9441932Smarc return (UNVIS_VALID); 9541932Smarc case 'v': 9641932Smarc *cp = '\v'; 9741932Smarc *astate = S_GROUND; 9841932Smarc return (UNVIS_VALID); 9941932Smarc case 't': 10041932Smarc *cp = '\t'; 10141932Smarc *astate = S_GROUND; 10241932Smarc return (UNVIS_VALID); 10341932Smarc case 'f': 10441932Smarc *cp = '\f'; 10541932Smarc *astate = S_GROUND; 10641932Smarc return (UNVIS_VALID); 10741932Smarc case 's': 10841932Smarc *cp = ' '; 10941932Smarc *astate = S_GROUND; 11041932Smarc return (UNVIS_VALID); 11141932Smarc case 'E': 11241932Smarc *cp = '\033'; 11341932Smarc *astate = S_GROUND; 11441932Smarc return (UNVIS_VALID); 11541932Smarc case '\n': 11641932Smarc /* 11741932Smarc * hidden newline 11841932Smarc */ 11941932Smarc *astate = S_GROUND; 12041932Smarc return (UNVIS_NOCHAR); 12144303Smarc case '$': 12244303Smarc /* 12344303Smarc * hidden marker 12444303Smarc */ 12544303Smarc *astate = S_GROUND; 12644303Smarc return (UNVIS_NOCHAR); 12741932Smarc } 12841932Smarc *astate = S_GROUND; 12941932Smarc return (UNVIS_SYNBAD); 13041932Smarc 13141932Smarc case S_META: 13241932Smarc if (c == '-') 13341932Smarc *astate = S_META1; 13441932Smarc else if (c == '^') 13541932Smarc *astate = S_CTRL; 13641932Smarc else { 13741932Smarc *astate = S_GROUND; 13841932Smarc return (UNVIS_SYNBAD); 13941932Smarc } 14041932Smarc return (0); 14141932Smarc 14241932Smarc case S_META1: 14341932Smarc *astate = S_GROUND; 14441932Smarc *cp |= c; 14541932Smarc return (UNVIS_VALID); 14641932Smarc 14741932Smarc case S_CTRL: 14841932Smarc if (c == '?') 14941932Smarc *cp |= 0177; 15041932Smarc else 15141932Smarc *cp |= c & 037; 15241932Smarc *astate = S_GROUND; 15341932Smarc return (UNVIS_VALID); 15441932Smarc 15541932Smarc case S_OCTAL2: /* second possible octal digit */ 15641932Smarc if (isoctal(c)) { 15741932Smarc /* 15841932Smarc * yes - and maybe a third 15941932Smarc */ 16041932Smarc *cp = (*cp << 3) + (c - '0'); 16141932Smarc *astate = S_OCTAL3; 16241932Smarc return (0); 16341932Smarc } 16441932Smarc /* 16541932Smarc * no - done with current sequence, push back passed char 16641932Smarc */ 16741932Smarc *astate = S_GROUND; 16841932Smarc return (UNVIS_VALIDPUSH); 16941932Smarc 17041932Smarc case S_OCTAL3: /* third possible octal digit */ 17141932Smarc *astate = S_GROUND; 17241932Smarc if (isoctal(c)) { 17341932Smarc *cp = (*cp << 3) + (c - '0'); 17441932Smarc return (UNVIS_VALID); 17541932Smarc } 17641932Smarc /* 17741932Smarc * we were done, push back passed char 17841932Smarc */ 17941932Smarc return (UNVIS_VALIDPUSH); 18041932Smarc 18141932Smarc default: 18241932Smarc /* 18341932Smarc * decoder in unknown state - (probably uninitialized) 18441932Smarc */ 18544333Smarc *astate = S_GROUND; 18644333Smarc return (UNVIS_SYNBAD); 18741932Smarc } 18841932Smarc } 18941932Smarc 19041932Smarc /* 19144303Smarc * strunvis - decode src into dst 19241932Smarc * 19344303Smarc * Number of chars decoded into dst is returned, -1 on error. 19444303Smarc * Dst is null terminated. 19541932Smarc */ 19644303Smarc 197*46597Sdonn int 19844303Smarc strunvis(dst, src) 199*46597Sdonn register char *dst; 200*46597Sdonn register const char *src; 20141932Smarc { 20244303Smarc register char c; 20341932Smarc char *start = dst; 20444333Smarc int state = 0; 20541932Smarc 20644303Smarc while (c = *src++) { 20744303Smarc again: 20844303Smarc switch (unvis(dst, c, &state, 0)) { 20944303Smarc case UNVIS_VALID: 21044303Smarc dst++; 21141932Smarc break; 21244303Smarc case UNVIS_VALIDPUSH: 21344303Smarc dst++; 21444303Smarc goto again; 21544303Smarc case 0: 21644303Smarc case UNVIS_NOCHAR: 21744303Smarc break; 21844303Smarc default: 21944303Smarc return (-1); 22044303Smarc } 22141932Smarc } 22244333Smarc if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID) 22344333Smarc dst++; 22444303Smarc *dst = '\0'; 22541932Smarc return (dst - start); 22641932Smarc } 227