Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/bin/dd/conv.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1991, 1993, 1994
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Keith Muller of the University of California, San Diego and Lance
9
* Visser of Convex Computer Corporation.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
* 3. Neither the name of the University nor the names of its contributors
20
* may be used to endorse or promote products derived from this software
21
* without specific prior written permission.
22
*
23
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
* SUCH DAMAGE.
34
*/
35
36
#include <sys/param.h>
37
38
#include <err.h>
39
#include <inttypes.h>
40
#include <string.h>
41
42
#include "dd.h"
43
#include "extern.h"
44
45
/*
46
* def --
47
* Copy input to output. Input is buffered until reaches obs, and then
48
* output until less than obs remains. Only a single buffer is used.
49
* Worst case buffer calculation is (ibs + obs - 1).
50
*/
51
void
52
def(void)
53
{
54
u_char *inp;
55
const u_char *t;
56
size_t cnt;
57
58
if ((t = ctab) != NULL)
59
for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
60
*inp = t[*inp];
61
62
/* Make the output buffer look right. */
63
out.dbp = in.dbp;
64
out.dbcnt = in.dbcnt;
65
66
if (in.dbcnt >= out.dbsz) {
67
/* If the output buffer is full, write it. */
68
dd_out(0);
69
70
/*
71
* dd_out copies the leftover output to the beginning of
72
* the buffer and resets the output buffer. Reset the
73
* input buffer to match it.
74
*/
75
in.dbp = out.dbp;
76
in.dbcnt = out.dbcnt;
77
}
78
}
79
80
void
81
def_close(void)
82
{
83
/* Just update the count, everything is already in the buffer. */
84
if (in.dbcnt)
85
out.dbcnt = in.dbcnt;
86
}
87
88
/*
89
* Copy variable length newline terminated records with a max size cbsz
90
* bytes to output. Records less than cbs are padded with spaces.
91
*
92
* max in buffer: MAX(ibs, cbsz)
93
* max out buffer: obs + cbsz
94
*/
95
void
96
block(void)
97
{
98
u_char *inp, *outp;
99
const u_char *t;
100
size_t cnt, maxlen;
101
static int intrunc;
102
int ch;
103
104
/*
105
* Record truncation can cross block boundaries. If currently in a
106
* truncation state, keep tossing characters until reach a newline.
107
* Start at the beginning of the buffer, as the input buffer is always
108
* left empty.
109
*/
110
if (intrunc) {
111
for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt)
112
;
113
if (!cnt) {
114
in.dbcnt = 0;
115
in.dbp = in.db;
116
return;
117
}
118
intrunc = 0;
119
/* Adjust the input buffer numbers. */
120
in.dbcnt = cnt - 1;
121
in.dbp = inp + cnt - 1;
122
}
123
124
/*
125
* Copy records (max cbsz size chunks) into the output buffer. The
126
* translation is done as we copy into the output buffer.
127
*/
128
ch = 0;
129
for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
130
maxlen = MIN(cbsz, (size_t)in.dbcnt);
131
if ((t = ctab) != NULL)
132
for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n';
133
++cnt)
134
*outp++ = t[ch];
135
else
136
for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n';
137
++cnt)
138
*outp++ = ch;
139
/*
140
* Check for short record without a newline. Reassemble the
141
* input block.
142
*/
143
if (ch != '\n' && (size_t)in.dbcnt < cbsz) {
144
(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
145
break;
146
}
147
148
/* Adjust the input buffer numbers. */
149
in.dbcnt -= cnt;
150
if (ch == '\n')
151
--in.dbcnt;
152
153
/* Pad short records with spaces. */
154
if (cnt < cbsz)
155
(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
156
else {
157
/*
158
* If the next character wouldn't have ended the
159
* block, it's a truncation.
160
*/
161
if (!in.dbcnt || *inp != '\n')
162
++st.trunc;
163
164
/* Toss characters to a newline. */
165
for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt)
166
;
167
if (!in.dbcnt)
168
intrunc = 1;
169
else
170
--in.dbcnt;
171
}
172
173
/* Adjust output buffer numbers. */
174
out.dbp += cbsz;
175
if ((out.dbcnt += cbsz) >= out.dbsz)
176
dd_out(0);
177
outp = out.dbp;
178
}
179
in.dbp = in.db + in.dbcnt;
180
}
181
182
void
183
block_close(void)
184
{
185
/*
186
* Copy any remaining data into the output buffer and pad to a record.
187
* Don't worry about truncation or translation, the input buffer is
188
* always empty when truncating, and no characters have been added for
189
* translation. The bottom line is that anything left in the input
190
* buffer is a truncated record. Anything left in the output buffer
191
* just wasn't big enough.
192
*/
193
if (in.dbcnt) {
194
++st.trunc;
195
(void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
196
(void)memset(out.dbp + in.dbcnt, ctab ? ctab[' '] : ' ',
197
cbsz - in.dbcnt);
198
out.dbcnt += cbsz;
199
}
200
}
201
202
/*
203
* Convert fixed length (cbsz) records to variable length. Deletes any
204
* trailing blanks and appends a newline.
205
*
206
* max in buffer: MAX(ibs, cbsz) + cbsz
207
* max out buffer: obs + cbsz
208
*/
209
void
210
unblock(void)
211
{
212
u_char *inp;
213
const u_char *t;
214
size_t cnt;
215
216
/* Translation and case conversion. */
217
if ((t = ctab) != NULL)
218
for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
219
*inp = t[*inp];
220
/*
221
* Copy records (max cbsz size chunks) into the output buffer. The
222
* translation has to already be done or we might not recognize the
223
* spaces.
224
*/
225
for (inp = in.db; (size_t)in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
226
for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t)
227
;
228
if (t >= inp) {
229
cnt = t - inp + 1;
230
(void)memmove(out.dbp, inp, cnt);
231
out.dbp += cnt;
232
out.dbcnt += cnt;
233
}
234
*out.dbp++ = '\n';
235
if (++out.dbcnt >= out.dbsz)
236
dd_out(0);
237
}
238
if (in.dbcnt)
239
(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
240
in.dbp = in.db + in.dbcnt;
241
}
242
243
void
244
unblock_close(void)
245
{
246
u_char *t;
247
size_t cnt;
248
249
if (in.dbcnt) {
250
warnx("%s: short input record", in.name);
251
for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t)
252
;
253
if (t >= in.db) {
254
cnt = t - in.db + 1;
255
(void)memmove(out.dbp, in.db, cnt);
256
out.dbp += cnt;
257
out.dbcnt += cnt;
258
}
259
++out.dbcnt;
260
*out.dbp++ = '\n';
261
}
262
}
263
264