conv.c revision 51208
1223313Snwhitehorn/*-
2223313Snwhitehorn * Copyright (c) 1991, 1993, 1994
3223313Snwhitehorn *	The Regents of the University of California.  All rights reserved.
4223313Snwhitehorn *
5223313Snwhitehorn * This code is derived from software contributed to Berkeley by
6223313Snwhitehorn * Keith Muller of the University of California, San Diego and Lance
7223313Snwhitehorn * Visser of Convex Computer Corporation.
8223313Snwhitehorn *
9223313Snwhitehorn * Redistribution and use in source and binary forms, with or without
10223313Snwhitehorn * modification, are permitted provided that the following conditions
11223313Snwhitehorn * are met:
12223313Snwhitehorn * 1. Redistributions of source code must retain the above copyright
13223313Snwhitehorn *    notice, this list of conditions and the following disclaimer.
14223313Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
15223313Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
16223313Snwhitehorn *    documentation and/or other materials provided with the distribution.
17223313Snwhitehorn * 3. All advertising materials mentioning features or use of this software
18223313Snwhitehorn *    must display the following acknowledgement:
19223313Snwhitehorn *	This product includes software developed by the University of
20223313Snwhitehorn *	California, Berkeley and its contributors.
21223313Snwhitehorn * 4. Neither the name of the University nor the names of its contributors
22223313Snwhitehorn *    may be used to endorse or promote products derived from this software
23223313Snwhitehorn *    without specific prior written permission.
24223313Snwhitehorn *
25223313Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26223313Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27223313Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28223313Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29223313Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30223313Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31223313Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32223313Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33223313Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34223313Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35223313Snwhitehorn * SUCH DAMAGE.
36223313Snwhitehorn */
37223313Snwhitehorn
38223313Snwhitehorn#ifndef lint
39223313Snwhitehorn#if 0
40223313Snwhitehornstatic char sccsid[] = "@(#)conv.c	8.3 (Berkeley) 4/2/94";
41223313Snwhitehorn#endif
42223313Snwhitehornstatic const char rcsid[] =
43223313Snwhitehorn  "$FreeBSD: head/bin/dd/conv.c 51208 1999-09-12 16:51:53Z green $";
44223313Snwhitehorn#endif /* not lint */
45223313Snwhitehorn
46223313Snwhitehorn#include <sys/param.h>
47223313Snwhitehorn
48223313Snwhitehorn#include <err.h>
49223313Snwhitehorn#include <string.h>
50223313Snwhitehorn
51223313Snwhitehorn#include "dd.h"
52223313Snwhitehorn#include "extern.h"
53223313Snwhitehorn
54223313Snwhitehorn/*
55223313Snwhitehorn * def --
56223313Snwhitehorn * Copy input to output.  Input is buffered until reaches obs, and then
57223313Snwhitehorn * output until less than obs remains.  Only a single buffer is used.
58223313Snwhitehorn * Worst case buffer calculation is (ibs + obs - 1).
59223313Snwhitehorn */
60223313Snwhitehornvoid
61223313Snwhitehorndef()
62223313Snwhitehorn{
63223313Snwhitehorn	u_char *inp;
64223313Snwhitehorn	const u_char *t;
65223313Snwhitehorn	size_t cnt;
66223313Snwhitehorn
67223313Snwhitehorn	if ((t = ctab) != NULL)
68223313Snwhitehorn		for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
69223313Snwhitehorn			*inp = t[*inp];
70227309Sed
71227309Sed	/* Make the output buffer look right. */
72223313Snwhitehorn	out.dbp = in.dbp;
73223313Snwhitehorn	out.dbcnt = in.dbcnt;
74223313Snwhitehorn
75223313Snwhitehorn	if (in.dbcnt >= out.dbsz) {
76223313Snwhitehorn		/* If the output buffer is full, write it. */
77223313Snwhitehorn		dd_out(0);
78223313Snwhitehorn
79223313Snwhitehorn		/*
80223313Snwhitehorn		 * Ddout copies the leftover output to the beginning of
81223313Snwhitehorn		 * the buffer and resets the output buffer.  Reset the
82223313Snwhitehorn		 * input buffer to match it.
83223313Snwhitehorn	 	 */
84223313Snwhitehorn		in.dbp = out.dbp;
85223313Snwhitehorn		in.dbcnt = out.dbcnt;
86223313Snwhitehorn	}
87223313Snwhitehorn}
88223313Snwhitehorn
89223313Snwhitehornvoid
90223313Snwhitehorndef_close()
91223313Snwhitehorn{
92223313Snwhitehorn	/* Just update the count, everything is already in the buffer. */
93223313Snwhitehorn	if (in.dbcnt)
94223313Snwhitehorn		out.dbcnt = in.dbcnt;
95223313Snwhitehorn}
96223313Snwhitehorn
97223313Snwhitehorn/*
98223313Snwhitehorn * Copy variable length newline terminated records with a max size cbsz
99223313Snwhitehorn * bytes to output.  Records less than cbs are padded with spaces.
100223313Snwhitehorn *
101223313Snwhitehorn * max in buffer:  MAX(ibs, cbsz)
102223313Snwhitehorn * max out buffer: obs + cbsz
103223313Snwhitehorn */
104223313Snwhitehornvoid
105223313Snwhitehornblock()
106223313Snwhitehorn{
107223313Snwhitehorn	u_char *inp, *outp;
108223313Snwhitehorn	const u_char *t;
109223313Snwhitehorn	size_t cnt, maxlen;
110223313Snwhitehorn	static int intrunc;
111223313Snwhitehorn	int ch = -1;
112223313Snwhitehorn
113223313Snwhitehorn	/*
114223313Snwhitehorn	 * Record truncation can cross block boundaries.  If currently in a
115223313Snwhitehorn	 * truncation state, keep tossing characters until reach a newline.
116223313Snwhitehorn	 * Start at the beginning of the buffer, as the input buffer is always
117223313Snwhitehorn	 * left empty.
118223313Snwhitehorn	 */
119223313Snwhitehorn	if (intrunc) {
120223461Snwhitehorn		for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt)
121223461Snwhitehorn			;
122223313Snwhitehorn		if (!cnt) {
123223461Snwhitehorn			in.dbcnt = 0;
124223313Snwhitehorn			in.dbp = in.db;
125223313Snwhitehorn			return;
126223313Snwhitehorn		}
127223313Snwhitehorn		intrunc = 0;
128223313Snwhitehorn		/* Adjust the input buffer numbers. */
129223313Snwhitehorn		in.dbcnt = cnt - 1;
130223313Snwhitehorn		in.dbp = inp + cnt - 1;
131223313Snwhitehorn	}
132223461Snwhitehorn
133223313Snwhitehorn	/*
134223313Snwhitehorn	 * Copy records (max cbsz size chunks) into the output buffer.  The
135223313Snwhitehorn	 * translation is done as we copy into the output buffer.
136223313Snwhitehorn	 */
137223461Snwhitehorn	ch = 0;
138223461Snwhitehorn	for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
139223313Snwhitehorn		maxlen = MIN(cbsz, in.dbcnt);
140223313Snwhitehorn		if ((t = ctab) != NULL)
141223313Snwhitehorn			for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n';
142223313Snwhitehorn			    ++cnt)
143223313Snwhitehorn				*outp++ = t[ch];
144223313Snwhitehorn		else
145223313Snwhitehorn			for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n';
146223313Snwhitehorn			    ++cnt)
147223313Snwhitehorn				*outp++ = ch;
148223313Snwhitehorn		/*
149223313Snwhitehorn		 * Check for short record without a newline.  Reassemble the
150223313Snwhitehorn		 * input block.
151223313Snwhitehorn		 */
152223313Snwhitehorn		if (ch != '\n' && in.dbcnt < cbsz) {
153223313Snwhitehorn			(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
154223313Snwhitehorn			break;
155223313Snwhitehorn		}
156223313Snwhitehorn
157223313Snwhitehorn		/* Adjust the input buffer numbers. */
158223313Snwhitehorn		in.dbcnt -= cnt;
159223313Snwhitehorn		if (ch == '\n')
160223313Snwhitehorn			--in.dbcnt;
161223313Snwhitehorn
162223461Snwhitehorn		/* Pad short records with spaces. */
163223313Snwhitehorn		if (cnt < cbsz)
164223313Snwhitehorn			(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
165223313Snwhitehorn		else {
166223313Snwhitehorn			/*
167223313Snwhitehorn			 * If the next character wouldn't have ended the
168223313Snwhitehorn			 * block, it's a truncation.
169223313Snwhitehorn			 */
170223313Snwhitehorn			if (!in.dbcnt || *inp != '\n')
171223313Snwhitehorn				++st.trunc;
172223313Snwhitehorn
173223313Snwhitehorn			/* Toss characters to a newline. */
174223313Snwhitehorn			for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
175223313Snwhitehorn			if (!in.dbcnt)
176223313Snwhitehorn				intrunc = 1;
177223313Snwhitehorn			else
178223313Snwhitehorn				--in.dbcnt;
179223313Snwhitehorn		}
180223313Snwhitehorn
181223313Snwhitehorn		/* Adjust output buffer numbers. */
182223313Snwhitehorn		out.dbp += cbsz;
183223313Snwhitehorn		if ((out.dbcnt += cbsz) >= out.dbsz)
184223313Snwhitehorn			dd_out(0);
185223313Snwhitehorn		outp = out.dbp;
186223313Snwhitehorn	}
187223313Snwhitehorn	in.dbp = in.db + in.dbcnt;
188223313Snwhitehorn}
189223313Snwhitehorn
190223313Snwhitehornvoid
191223313Snwhitehornblock_close()
192223313Snwhitehorn{
193223313Snwhitehorn	/*
194223313Snwhitehorn	 * Copy any remaining data into the output buffer and pad to a record.
195223313Snwhitehorn	 * Don't worry about truncation or translation, the input buffer is
196223313Snwhitehorn	 * always empty when truncating, and no characters have been added for
197223313Snwhitehorn	 * translation.  The bottom line is that anything left in the input
198223313Snwhitehorn	 * buffer is a truncated record.  Anything left in the output buffer
199223313Snwhitehorn	 * just wasn't big enough.
200223313Snwhitehorn	 */
201223313Snwhitehorn	if (in.dbcnt) {
202223313Snwhitehorn		++st.trunc;
203223313Snwhitehorn		(void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
204223313Snwhitehorn		(void)memset(out.dbp + in.dbcnt, ctab ? ctab[' '] : ' ',
205223313Snwhitehorn		    cbsz - in.dbcnt);
206223313Snwhitehorn		out.dbcnt += cbsz;
207223461Snwhitehorn	}
208223313Snwhitehorn}
209223313Snwhitehorn
210223313Snwhitehorn/*
211223313Snwhitehorn * Convert fixed length (cbsz) records to variable length.  Deletes any
212223313Snwhitehorn * trailing blanks and appends a newline.
213223313Snwhitehorn *
214223461Snwhitehorn * max in buffer:  MAX(ibs, cbsz) + cbsz
215223313Snwhitehorn * max out buffer: obs + cbsz
216223313Snwhitehorn */
217223461Snwhitehornvoid
218223461Snwhitehornunblock()
219223313Snwhitehorn{
220223461Snwhitehorn	u_char *inp;
221223313Snwhitehorn	const u_char *t;
222223313Snwhitehorn	size_t cnt;
223223313Snwhitehorn
224223313Snwhitehorn	/* Translation and case conversion. */
225223313Snwhitehorn	if ((t = ctab) != NULL)
226223313Snwhitehorn		for (cnt = in.dbrcnt, inp = in.dbp; cnt--;)
227223313Snwhitehorn			*--inp = t[*inp];
228223313Snwhitehorn	/*
229223313Snwhitehorn	 * Copy records (max cbsz size chunks) into the output buffer.  The
230223313Snwhitehorn	 * translation has to already be done or we might not recognize the
231223313Snwhitehorn	 * spaces.
232223461Snwhitehorn	 */
233223313Snwhitehorn	for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
234223313Snwhitehorn		for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t)
235223313Snwhitehorn			;
236223316Snwhitehorn		if (t >= inp) {
237223316Snwhitehorn			cnt = t - inp + 1;
238223313Snwhitehorn			(void)memmove(out.dbp, inp, cnt);
239223313Snwhitehorn			out.dbp += cnt;
240223313Snwhitehorn			out.dbcnt += cnt;
241223313Snwhitehorn		}
242223313Snwhitehorn		*out.dbp++ = '\n';
243223313Snwhitehorn		if (++out.dbcnt >= out.dbsz)
244223461Snwhitehorn			dd_out(0);
245223313Snwhitehorn	}
246223313Snwhitehorn	if (in.dbcnt)
247223313Snwhitehorn		(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
248223313Snwhitehorn	in.dbp = in.db + in.dbcnt;
249223313Snwhitehorn}
250223313Snwhitehorn
251223313Snwhitehornvoid
252223313Snwhitehornunblock_close()
253223313Snwhitehorn{
254223313Snwhitehorn	u_char *t;
255223313Snwhitehorn	size_t cnt;
256223313Snwhitehorn
257223316Snwhitehorn	if (in.dbcnt) {
258223316Snwhitehorn		warnx("%s: short input record", in.name);
259223461Snwhitehorn		for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t)
260223316Snwhitehorn			;
261223461Snwhitehorn		if (t >= in.db) {
262223461Snwhitehorn			cnt = t - in.db + 1;
263223313Snwhitehorn			(void)memmove(out.dbp, in.db, cnt);
264223461Snwhitehorn			out.dbp += cnt;
265223316Snwhitehorn			out.dbcnt += cnt;
266223313Snwhitehorn		}
267223316Snwhitehorn		++out.dbcnt;
268223313Snwhitehorn		*out.dbp++ = '\n';
269223313Snwhitehorn	}
270223461Snwhitehorn}
271223461Snwhitehorn