Coverage Report

Created: 2023-06-07 06:04

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