conv.c revision 1.16 1 /* $NetBSD: conv.c,v 1.16 2003/08/05 14:55:03 erh Exp $ */
2
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. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40 #include <sys/cdefs.h>
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94";
44 #else
45 __RCSID("$NetBSD: conv.c,v 1.16 2003/08/05 14:55:03 erh Exp $");
46 #endif
47 #endif /* not lint */
48
49 #include <sys/param.h>
50 #include <sys/time.h>
51
52 #include <err.h>
53 #include <string.h>
54 #include <stdlib.h>
55
56 #include "dd.h"
57 #include "extern.h"
58
59 /*
60 * def --
61 * Copy input to output. Input is buffered until reaches obs, and then
62 * output until less than obs remains. Only a single buffer is used.
63 * Worst case buffer calculation is (ibs + obs - 1).
64 */
65 void
66 def(void)
67 {
68 uint64_t cnt;
69 u_char *inp;
70 const u_char *t;
71
72 if ((t = ctab) != NULL)
73 for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
74 *inp = t[*inp];
75
76 /* Make the output buffer look right. */
77 out.dbp = in.dbp;
78 out.dbcnt = in.dbcnt;
79
80 if (in.dbcnt >= out.dbsz) {
81 /* If the output buffer is full, write it. */
82 dd_out(0);
83
84 /*
85 * Ddout copies the leftover output to the beginning of
86 * the buffer and resets the output buffer. Reset the
87 * input buffer to match it.
88 */
89 in.dbp = out.dbp;
90 in.dbcnt = out.dbcnt;
91 }
92 }
93
94 void
95 def_close(void)
96 {
97
98 /* Just update the count, everything is already in the buffer. */
99 if (in.dbcnt)
100 out.dbcnt = in.dbcnt;
101 }
102
103 #ifdef NO_CONV
104 /* Build a smaller version (i.e. for a miniroot) */
105 /* These can not be called, but just in case... */
106 static const char no_block[] = "unblock and -DNO_CONV?";
107 void block(void) { errx(EXIT_FAILURE, "%s", no_block + 2); }
108 void block_close(void) { errx(EXIT_FAILURE, "%s", no_block + 2); }
109 void unblock(void) { errx(EXIT_FAILURE, "%s", no_block); }
110 void unblock_close(void) { errx(EXIT_FAILURE, "%s", no_block); }
111 #else /* NO_CONV */
112
113 /*
114 * Copy variable length newline terminated records with a max size cbsz
115 * bytes to output. Records less than cbs are padded with spaces.
116 *
117 * max in buffer: MAX(ibs, cbsz)
118 * max out buffer: obs + cbsz
119 */
120 void
121 block(void)
122 {
123 static int intrunc;
124 int ch = 0; /* pacify gcc */
125 uint64_t cnt, maxlen;
126 u_char *inp, *outp;
127 const u_char *t;
128
129 /*
130 * Record truncation can cross block boundaries. If currently in a
131 * truncation state, keep tossing characters until reach a newline.
132 * Start at the beginning of the buffer, as the input buffer is always
133 * left empty.
134 */
135 if (intrunc) {
136 for (inp = in.db, cnt = in.dbrcnt;
137 cnt && *inp++ != '\n'; --cnt);
138 if (!cnt) {
139 in.dbcnt = 0;
140 in.dbp = in.db;
141 return;
142 }
143 intrunc = 0;
144 /* Adjust the input buffer numbers. */
145 in.dbcnt = cnt - 1;
146 in.dbp = inp + cnt - 1;
147 }
148
149 /*
150 * Copy records (max cbsz size chunks) into the output buffer. The
151 * translation is done as we copy into the output buffer.
152 */
153 for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
154 maxlen = MIN(cbsz, in.dbcnt);
155 if ((t = ctab) != NULL)
156 for (cnt = 0;
157 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
158 *outp++ = t[ch];
159 else
160 for (cnt = 0;
161 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
162 *outp++ = ch;
163 /*
164 * Check for short record without a newline. Reassemble the
165 * input block.
166 */
167 if (ch != '\n' && in.dbcnt < cbsz) {
168 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
169 break;
170 }
171
172 /* Adjust the input buffer numbers. */
173 in.dbcnt -= cnt;
174 if (ch == '\n')
175 --in.dbcnt;
176
177 /* Pad short records with spaces. */
178 if (cnt < cbsz)
179 (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
180 else {
181 /*
182 * If the next character wouldn't have ended the
183 * block, it's a truncation.
184 */
185 if (!in.dbcnt || *inp != '\n')
186 ++st.trunc;
187
188 /* Toss characters to a newline. */
189 for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
190 if (!in.dbcnt)
191 intrunc = 1;
192 else
193 --in.dbcnt;
194 }
195
196 /* Adjust output buffer numbers. */
197 out.dbp += cbsz;
198 if ((out.dbcnt += cbsz) >= out.dbsz)
199 dd_out(0);
200 outp = out.dbp;
201 }
202 in.dbp = in.db + in.dbcnt;
203 }
204
205 void
206 block_close(void)
207 {
208
209 /*
210 * Copy any remaining data into the output buffer and pad to a record.
211 * Don't worry about truncation or translation, the input buffer is
212 * always empty when truncating, and no characters have been added for
213 * translation. The bottom line is that anything left in the input
214 * buffer is a truncated record. Anything left in the output buffer
215 * just wasn't big enough.
216 */
217 if (in.dbcnt) {
218 ++st.trunc;
219 (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
220 (void)memset(out.dbp + in.dbcnt,
221 ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
222 out.dbcnt += cbsz;
223 }
224 }
225
226 /*
227 * Convert fixed length (cbsz) records to variable length. Deletes any
228 * trailing blanks and appends a newline.
229 *
230 * max in buffer: MAX(ibs, cbsz) + cbsz
231 * max out buffer: obs + cbsz
232 */
233 void
234 unblock(void)
235 {
236 uint64_t cnt;
237 u_char *inp;
238 const u_char *t;
239
240 /* Translation and case conversion. */
241 if ((t = ctab) != NULL)
242 for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
243 *inp = t[*inp];
244 /*
245 * Copy records (max cbsz size chunks) into the output buffer. The
246 * translation has to already be done or we might not recognize the
247 * spaces.
248 */
249 for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
250 for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
251 if (t >= inp) {
252 cnt = t - inp + 1;
253 (void)memmove(out.dbp, inp, cnt);
254 out.dbp += cnt;
255 out.dbcnt += cnt;
256 }
257 ++out.dbcnt;
258 *out.dbp++ = '\n';
259 if (out.dbcnt >= out.dbsz)
260 dd_out(0);
261 }
262 if (in.dbcnt)
263 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
264 in.dbp = in.db + in.dbcnt;
265 }
266
267 void
268 unblock_close(void)
269 {
270 uint64_t cnt;
271 u_char *t;
272
273 if (in.dbcnt) {
274 warnx("%s: short input record", in.name);
275 for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
276 if (t >= in.db) {
277 cnt = t - in.db + 1;
278 (void)memmove(out.dbp, in.db, cnt);
279 out.dbp += cnt;
280 out.dbcnt += cnt;
281 }
282 ++out.dbcnt;
283 *out.dbp++ = '\n';
284 }
285 }
286
287 #endif /* NO_CONV */
288