1/* $NetBSD: strunvis.c,v 1.5 2005/06/01 11:48:49 lukem Exp $ */ 2/* from NetBSD: unvis.c,v 1.27 2005/05/16 11:42:04 lukem Exp */ 3 4/*- 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include "tnftp.h" 34 35/* 36 * decode driven by state machine 37 */ 38#define S_GROUND 0 /* haven't seen escape char */ 39#define S_START 1 /* start decoding special sequence */ 40#define S_META 2 /* metachar started (M) */ 41#define S_META1 3 /* metachar more, regular char (-) */ 42#define S_CTRL 4 /* control char started (^) */ 43#define S_OCTAL2 5 /* octal digit 2 */ 44#define S_OCTAL3 6 /* octal digit 3 */ 45#define S_HEX1 7 /* hex digit */ 46#define S_HEX2 8 /* hex digit 2 */ 47 48#define isoctal(c) (((unsigned char)(c)) >= '0' && ((unsigned char)(c)) <= '7') 49#define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10)) 50 51/* 52 * unvis - decode characters previously encoded by vis 53 */ 54int 55unvis(char *cp, int c, int *astate, int flag) 56{ 57 unsigned char uc = (unsigned char)c; 58 59 if (flag & UNVIS_END) { 60 if (*astate == S_OCTAL2 || *astate == S_OCTAL3 61 || *astate == S_HEX2) { 62 *astate = S_GROUND; 63 return (UNVIS_VALID); 64 } 65 return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD); 66 } 67 68 switch (*astate) { 69 70 case S_GROUND: 71 *cp = 0; 72 if (c == '\\') { 73 *astate = S_START; 74 return (0); 75 } 76 if ((flag & VIS_HTTPSTYLE) && c == '%') { 77 *astate = S_HEX1; 78 return (0); 79 } 80 *cp = c; 81 return (UNVIS_VALID); 82 83 case S_START: 84 switch(c) { 85 case '\\': 86 *cp = c; 87 *astate = S_GROUND; 88 return (UNVIS_VALID); 89 case '0': case '1': case '2': case '3': 90 case '4': case '5': case '6': case '7': 91 *cp = (c - '0'); 92 *astate = S_OCTAL2; 93 return (0); 94 case 'M': 95 *cp = (char)0200; 96 *astate = S_META; 97 return (0); 98 case '^': 99 *astate = S_CTRL; 100 return (0); 101 case 'n': 102 *cp = '\n'; 103 *astate = S_GROUND; 104 return (UNVIS_VALID); 105 case 'r': 106 *cp = '\r'; 107 *astate = S_GROUND; 108 return (UNVIS_VALID); 109 case 'b': 110 *cp = '\b'; 111 *astate = S_GROUND; 112 return (UNVIS_VALID); 113 case 'a': 114 *cp = '\007'; 115 *astate = S_GROUND; 116 return (UNVIS_VALID); 117 case 'v': 118 *cp = '\v'; 119 *astate = S_GROUND; 120 return (UNVIS_VALID); 121 case 't': 122 *cp = '\t'; 123 *astate = S_GROUND; 124 return (UNVIS_VALID); 125 case 'f': 126 *cp = '\f'; 127 *astate = S_GROUND; 128 return (UNVIS_VALID); 129 case 's': 130 *cp = ' '; 131 *astate = S_GROUND; 132 return (UNVIS_VALID); 133 case 'E': 134 *cp = '\033'; 135 *astate = S_GROUND; 136 return (UNVIS_VALID); 137 case '\n': 138 /* 139 * hidden newline 140 */ 141 *astate = S_GROUND; 142 return (UNVIS_NOCHAR); 143 case '$': 144 /* 145 * hidden marker 146 */ 147 *astate = S_GROUND; 148 return (UNVIS_NOCHAR); 149 } 150 *astate = S_GROUND; 151 return (UNVIS_SYNBAD); 152 153 case S_META: 154 if (c == '-') 155 *astate = S_META1; 156 else if (c == '^') 157 *astate = S_CTRL; 158 else { 159 *astate = S_GROUND; 160 return (UNVIS_SYNBAD); 161 } 162 return (0); 163 164 case S_META1: 165 *astate = S_GROUND; 166 *cp |= c; 167 return (UNVIS_VALID); 168 169 case S_CTRL: 170 if (c == '?') 171 *cp |= 0177; 172 else 173 *cp |= c & 037; 174 *astate = S_GROUND; 175 return (UNVIS_VALID); 176 177 case S_OCTAL2: /* second possible octal digit */ 178 if (isoctal(uc)) { 179 /* 180 * yes - and maybe a third 181 */ 182 *cp = (*cp << 3) + (c - '0'); 183 *astate = S_OCTAL3; 184 return (0); 185 } 186 /* 187 * no - done with current sequence, push back passed char 188 */ 189 *astate = S_GROUND; 190 return (UNVIS_VALIDPUSH); 191 192 case S_OCTAL3: /* third possible octal digit */ 193 *astate = S_GROUND; 194 if (isoctal(uc)) { 195 *cp = (*cp << 3) + (c - '0'); 196 return (UNVIS_VALID); 197 } 198 /* 199 * we were done, push back passed char 200 */ 201 return (UNVIS_VALIDPUSH); 202 203 case S_HEX1: 204 if (isxdigit(uc)) { 205 *cp = xtod(uc); 206 *astate = S_HEX2; 207 return (0); 208 } 209 /* 210 * no - done with current sequence, push back passed char 211 */ 212 *astate = S_GROUND; 213 return (UNVIS_VALIDPUSH); 214 215 case S_HEX2: 216 *astate = S_GROUND; 217 if (isxdigit(uc)) { 218 *cp = xtod(uc) | (*cp << 4); 219 return (UNVIS_VALID); 220 } 221 return (UNVIS_VALIDPUSH); 222 223 default: 224 /* 225 * decoder in unknown state - (probably uninitialized) 226 */ 227 *astate = S_GROUND; 228 return (UNVIS_SYNBAD); 229 } 230} 231 232/* 233 * strunvis - decode src into dst 234 * 235 * Number of chars decoded into dst is returned, -1 on error. 236 * Dst is null terminated. 237 */ 238 239int 240strunvisx(char *dst, const char *src, int flag) 241{ 242 char c; 243 char *start = dst; 244 int state = 0; 245 246 while ((c = *src++) != '\0') { 247 again: 248 switch (unvis(dst, c, &state, flag)) { 249 case UNVIS_VALID: 250 dst++; 251 break; 252 case UNVIS_VALIDPUSH: 253 dst++; 254 goto again; 255 case 0: 256 case UNVIS_NOCHAR: 257 break; 258 default: 259 return (-1); 260 } 261 } 262 if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID) 263 dst++; 264 *dst = '\0'; 265 return (dst - start); 266} 267 268int 269strunvis(char *dst, const char *src) 270{ 271 return strunvisx(dst, src, 0); 272} 273