conv.c revision 1.11 1 /* $NetBSD: conv.c,v 1.11 2001/04/28 22:47:23 ross 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.11 2001/04/28 22:47:23 ross 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
55 #include "dd.h"
56 #include "extern.h"
57
58 /*
59 * def --
60 * Copy input to output. Input is buffered until reaches obs, and then
61 * output until less than obs remains. Only a single buffer is used.
62 * Worst case buffer calculation is (ibs + obs - 1).
63 */
64 void
65 def()
66 {
67 int cnt;
68 u_char *inp;
69 const u_char *t;
70
71 if ((t = ctab) != NULL)
72 for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
73 *inp = t[*inp];
74
75 /* Make the output buffer look right. */
76 out.dbp = in.dbp;
77 out.dbcnt = in.dbcnt;
78
79 if (in.dbcnt >= out.dbsz) {
80 /* If the output buffer is full, write it. */
81 dd_out(0);
82
83 /*
84 * Ddout copies the leftover output to the beginning of
85 * the buffer and resets the output buffer. Reset the
86 * input buffer to match it.
87 */
88 in.dbp = out.dbp;
89 in.dbcnt = out.dbcnt;
90 }
91 }
92
93 void
94 def_close()
95 {
96 /* Just update the count, everything is already in the buffer. */
97 if (in.dbcnt)
98 out.dbcnt = in.dbcnt;
99 }
100
101 #ifdef NO_CONV
102 /* Build a smaller version (i.e. for a miniroot) */
103 /* These can not be called, but just in case... */
104 static char no_block[] = "unblock and -DNO_CONV?";
105 void block() { errx(1, "%s", no_block + 2); }
106 void block_close() { errx(1, "%s", no_block + 2); }
107 void unblock() { errx(1, "%s", no_block); }
108 void unblock_close() { errx(1, "%s", no_block); }
109 #else /* NO_CONV */
110
111 /*
112 * Copy variable length newline terminated records with a max size cbsz
113 * bytes to output. Records less than cbs are padded with spaces.
114 *
115 * max in buffer: MAX(ibs, cbsz)
116 * max out buffer: obs + cbsz
117 */
118 void
119 block()
120 {
121 static int intrunc;
122 int ch = 0; /* pacify gcc */
123 int cnt, maxlen;
124 u_char *inp, *outp;
125 const u_char *t;
126
127 /*
128 * Record truncation can cross block boundaries. If currently in a
129 * truncation state, keep tossing characters until reach a newline.
130 * Start at the beginning of the buffer, as the input buffer is always
131 * left empty.
132 */
133 if (intrunc) {
134 for (inp = in.db, cnt = in.dbrcnt;
135 cnt && *inp++ != '\n'; --cnt);
136 if (!cnt) {
137 in.dbcnt = 0;
138 in.dbp = in.db;
139 return;
140 }
141 intrunc = 0;
142 /* Adjust the input buffer numbers. */
143 in.dbcnt = cnt - 1;
144 in.dbp = inp + cnt - 1;
145 }
146
147 /*
148 * Copy records (max cbsz size chunks) into the output buffer. The
149 * translation is done as we copy into the output buffer.
150 */
151 for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
152 maxlen = MIN(cbsz, in.dbcnt);
153 if ((t = ctab) != NULL)
154 for (cnt = 0;
155 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
156 *outp++ = t[ch];
157 else
158 for (cnt = 0;
159 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
160 *outp++ = ch;
161 /*
162 * Check for short record without a newline. Reassemble the
163 * input block.
164 */
165 if (ch != '\n' && in.dbcnt < cbsz) {
166 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
167 break;
168 }
169
170 /* Adjust the input buffer numbers. */
171 in.dbcnt -= cnt;
172 if (ch == '\n')
173 --in.dbcnt;
174
175 /* Pad short records with spaces. */
176 if (cnt < cbsz)
177 (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
178 else {
179 /*
180 * If the next character wouldn't have ended the
181 * block, it's a truncation.
182 */
183 if (!in.dbcnt || *inp != '\n')
184 ++st.trunc;
185
186 /* Toss characters to a newline. */
187 for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
188 if (!in.dbcnt)
189 intrunc = 1;
190 else
191 --in.dbcnt;
192 }
193
194 /* Adjust output buffer numbers. */
195 out.dbp += cbsz;
196 if ((out.dbcnt += cbsz) >= out.dbsz)
197 dd_out(0);
198 outp = out.dbp;
199 }
200 in.dbp = in.db + in.dbcnt;
201 }
202
203 void
204 block_close()
205 {
206 /*
207 * Copy any remaining data into the output buffer and pad to a record.
208 * Don't worry about truncation or translation, the input buffer is
209 * always empty when truncating, and no characters have been added for
210 * translation. The bottom line is that anything left in the input
211 * buffer is a truncated record. Anything left in the output buffer
212 * just wasn't big enough.
213 */
214 if (in.dbcnt) {
215 ++st.trunc;
216 (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
217 (void)memset(out.dbp + in.dbcnt,
218 ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
219 out.dbcnt += cbsz;
220 }
221 }
222
223 /*
224 * Convert fixed length (cbsz) records to variable length. Deletes any
225 * trailing blanks and appends a newline.
226 *
227 * max in buffer: MAX(ibs, cbsz) + cbsz
228 * max out buffer: obs + cbsz
229 */
230 void
231 unblock()
232 {
233 int cnt;
234 u_char *inp;
235 const u_char *t;
236
237 /* Translation and case conversion. */
238 if ((t = ctab) != NULL)
239 for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
240 *inp = t[*inp];
241 /*
242 * Copy records (max cbsz size chunks) into the output buffer. The
243 * translation has to already be done or we might not recognize the
244 * spaces.
245 */
246 for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
247 for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
248 if (t >= inp) {
249 cnt = t - inp + 1;
250 (void)memmove(out.dbp, inp, cnt);
251 out.dbp += cnt;
252 out.dbcnt += cnt;
253 }
254 ++out.dbcnt;
255 *out.dbp++ = '\n';
256 if (out.dbcnt >= out.dbsz)
257 dd_out(0);
258 }
259 if (in.dbcnt)
260 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
261 in.dbp = in.db + in.dbcnt;
262 }
263
264 void
265 unblock_close()
266 {
267 int cnt;
268 u_char *t;
269
270 if (in.dbcnt) {
271 warnx("%s: short input record", in.name);
272 for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
273 if (t >= in.db) {
274 cnt = t - in.db + 1;
275 (void)memmove(out.dbp, in.db, cnt);
276 out.dbp += cnt;
277 out.dbcnt += cnt;
278 }
279 ++out.dbcnt;
280 *out.dbp++ = '\n';
281 }
282 }
283
284 #endif /* NO_CONV */
285