conv.c revision 19720
150276Speter/*-
2174993Srafan * Copyright (c) 1991, 1993, 1994
350276Speter *	The Regents of the University of California.  All rights reserved.
450276Speter *
550276Speter * This code is derived from software contributed to Berkeley by
650276Speter * Keith Muller of the University of California, San Diego and Lance
750276Speter * Visser of Convex Computer Corporation.
850276Speter *
950276Speter * Redistribution and use in source and binary forms, with or without
1050276Speter * modification, are permitted provided that the following conditions
1150276Speter * are met:
1250276Speter * 1. Redistributions of source code must retain the above copyright
1350276Speter *    notice, this list of conditions and the following disclaimer.
1450276Speter * 2. Redistributions in binary form must reproduce the above copyright
1550276Speter *    notice, this list of conditions and the following disclaimer in the
1650276Speter *    documentation and/or other materials provided with the distribution.
1750276Speter * 3. All advertising materials mentioning features or use of this software
1850276Speter *    must display the following acknowledgement:
1950276Speter *	This product includes software developed by the University of
2050276Speter *	California, Berkeley and its contributors.
2150276Speter * 4. Neither the name of the University nor the names of its contributors
2250276Speter *    may be used to endorse or promote products derived from this software
2350276Speter *    without specific prior written permission.
2450276Speter *
2550276Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2650276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2750276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2850276Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2950276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30166124Srafan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3150276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3250276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3350276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3450276Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35174993Srafan * SUCH DAMAGE.
3650276Speter *
37166124Srafan *	$Id: conv.c,v 1.4 1996/11/12 23:09:04 phk Exp $
38166124Srafan */
39166124Srafan
40166124Srafan#ifndef lint
41174993Srafanstatic char sccsid[] = "@(#)conv.c	8.3 (Berkeley) 4/2/94";
42166124Srafan#endif /* not lint */
43166124Srafan
44166124Srafan#include <sys/param.h>
45166124Srafan
4650276Speter#include <err.h>
47166124Srafan#include <string.h>
48166124Srafan
49166124Srafan#include "dd.h"
50166124Srafan#include "extern.h"
51166124Srafan
52166124Srafan/*
53166124Srafan * def --
54166124Srafan * Copy input to output.  Input is buffered until reaches obs, and then
55166124Srafan * output until less than obs remains.  Only a single buffer is used.
56166124Srafan * Worst case buffer calculation is (ibs + obs - 1).
57174993Srafan */
58174993Srafanvoid
59166124Srafandef()
60166124Srafan{
61166124Srafan	int cnt;
62166124Srafan	u_char *inp, *t;
63166124Srafan
64166124Srafan	if ((t = ctab) != NULL)
65166124Srafan		for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
66166124Srafan			*inp = t[*inp];
67166124Srafan
68166124Srafan	/* Make the output buffer look right. */
69166124Srafan	out.dbp = in.dbp;
70166124Srafan	out.dbcnt = in.dbcnt;
71166124Srafan
72166124Srafan	if (in.dbcnt >= out.dbsz) {
73166124Srafan		/* If the output buffer is full, write it. */
74166124Srafan		dd_out(0);
75166124Srafan
76166124Srafan		/*
77166124Srafan		 * Ddout copies the leftover output to the beginning of
78166124Srafan		 * the buffer and resets the output buffer.  Reset the
79166124Srafan		 * input buffer to match it.
80174993Srafan	 	 */
81166124Srafan		in.dbp = out.dbp;
82166124Srafan		in.dbcnt = out.dbcnt;
83166124Srafan	}
8450276Speter}
8550276Speter
8650276Spetervoid
8750276Speterdef_close()
8876726Speter{
8950276Speter	/* Just update the count, everything is already in the buffer. */
9050276Speter	if (in.dbcnt)
91166124Srafan		out.dbcnt = in.dbcnt;
9262449Speter}
93166124Srafan
9450276Speter/*
9550276Speter * Copy variable length newline terminated records with a max size cbsz
9662449Speter * bytes to output.  Records less than cbs are padded with spaces.
9762449Speter *
98166124Srafan * max in buffer:  MAX(ibs, cbsz)
99166124Srafan * max out buffer: obs + cbsz
100166124Srafan */
101166124Srafanvoid
102174993Srafanblock()
10350276Speter{
104174993Srafan	static int intrunc;
105174993Srafan	int ch, cnt, maxlen;
10662449Speter	u_char *inp, *outp, *t;
10750276Speter
10850276Speter	/*
10962449Speter	 * Record truncation can cross block boundaries.  If currently in a
11062449Speter	 * truncation state, keep tossing characters until reach a newline.
11150276Speter	 * Start at the beginning of the buffer, as the input buffer is always
11262449Speter	 * left empty.
11362449Speter	 */
11450276Speter	if (intrunc) {
11562449Speter		for (inp = in.db, cnt = in.dbrcnt;
11662449Speter		    cnt && *inp++ != '\n'; --cnt);
11762449Speter		if (!cnt) {
11850276Speter			in.dbcnt = 0;
11962449Speter			in.dbp = in.db;
12050276Speter			return;
12162449Speter		}
12262449Speter		intrunc = 0;
12362449Speter		/* Adjust the input buffer numbers. */
12450276Speter		in.dbcnt = cnt - 1;
12562449Speter		in.dbp = inp + cnt - 1;
12662449Speter	}
12762449Speter
12862449Speter	/*
12962449Speter	 * Copy records (max cbsz size chunks) into the output buffer.  The
13062449Speter	 * translation is done as we copy into the output buffer.
13162449Speter	 */
13262449Speter	ch = 0;			/* Help the compiler. */
13350276Speter	for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
13462449Speter		maxlen = MIN(cbsz, in.dbcnt);
135166124Srafan		if ((t = ctab) != NULL)
136166124Srafan			for (cnt = 0;
137166124Srafan			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
13862449Speter				*outp++ = t[ch];
139166124Srafan		else
140166124Srafan			for (cnt = 0;
141166124Srafan			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
14250276Speter				*outp++ = ch;
14362449Speter		/*
144166124Srafan		 * Check for short record without a newline.  Reassemble the
145166124Srafan		 * input block.
146166124Srafan		 */
14762449Speter		if (ch != '\n' && in.dbcnt < cbsz) {
148166124Srafan			memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
149166124Srafan			break;
15062449Speter		}
151166124Srafan
15250276Speter		/* Adjust the input buffer numbers. */
153166124Srafan		in.dbcnt -= cnt;
154166124Srafan		if (ch == '\n')
155166124Srafan			--in.dbcnt;
156166124Srafan
157166124Srafan		/* Pad short records with spaces. */
158166124Srafan		if (cnt < cbsz)
159166124Srafan			(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
160166124Srafan		else {
161166124Srafan			/*
162166124Srafan			 * If the next character wouldn't have ended the
163166124Srafan			 * block, it's a truncation.
164166124Srafan			 */
165166124Srafan			if (!in.dbcnt || *inp != '\n')
16697049Speter				++st.trunc;
167166124Srafan
168166124Srafan			/* Toss characters to a newline. */
169166124Srafan			for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
170166124Srafan			if (!in.dbcnt)
17162449Speter				intrunc = 1;
172166124Srafan			else
173166124Srafan				--in.dbcnt;
174166124Srafan		}
17550276Speter
176166124Srafan		/* Adjust output buffer numbers. */
177166124Srafan		out.dbp += cbsz;
178166124Srafan		if ((out.dbcnt += cbsz) >= out.dbsz)
179166124Srafan			dd_out(0);
180166124Srafan		outp = out.dbp;
181166124Srafan	}
18262449Speter	in.dbp = in.db + in.dbcnt;
183166124Srafan}
184166124Srafan
18562449Spetervoid
186166124Srafanblock_close()
18762449Speter{
188166124Srafan	/*
18950276Speter	 * Copy any remaining data into the output buffer and pad to a record.
190166124Srafan	 * Don't worry about truncation or translation, the input buffer is
19162449Speter	 * always empty when truncating, and no characters have been added for
19250276Speter	 * translation.  The bottom line is that anything left in the input
19362449Speter	 * buffer is a truncated record.  Anything left in the output buffer
194166124Srafan	 * just wasn't big enough.
195166124Srafan	 */
196166124Srafan	if (in.dbcnt) {
197166124Srafan		++st.trunc;
198166124Srafan		memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
199166124Srafan		(void)memset(out.dbp + in.dbcnt,
200166124Srafan		    ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
201166124Srafan		out.dbcnt += cbsz;
202166124Srafan	}
203166124Srafan}
204166124Srafan
205166124Srafan/*
206166124Srafan * Convert fixed length (cbsz) records to variable length.  Deletes any
207166124Srafan * trailing blanks and appends a newline.
208166124Srafan *
209166124Srafan * max in buffer:  MAX(ibs, cbsz) + cbsz
210166124Srafan * max out buffer: obs + cbsz
211166124Srafan */
21262449Spetervoid
21362449Speterunblock()
21462449Speter{
21562449Speter	int cnt;
21662449Speter	u_char *inp, *t;
21750276Speter
21862449Speter	/* Translation and case conversion. */
21962449Speter	if ((t = ctab) != NULL)
22062449Speter		for (cnt = in.dbrcnt, inp = in.dbp; cnt--;)
22162449Speter			*--inp = t[*inp];
22262449Speter	/*
22350276Speter	 * Copy records (max cbsz size chunks) into the output buffer.  The
22462449Speter	 * translation has to already be done or we might not recognize the
22562449Speter	 * spaces.
22662449Speter	 */
22762449Speter	for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
22850276Speter		for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
229166124Srafan		if (t >= inp) {
230166124Srafan			cnt = t - inp + 1;
231166124Srafan			memmove(out.dbp, inp, cnt);
232166124Srafan			out.dbp += cnt;
233166124Srafan			out.dbcnt += cnt;
234166124Srafan		}
23550276Speter		++out.dbcnt;
236166124Srafan		*out.dbp++ = '\n';
237166124Srafan		if (out.dbcnt >= out.dbsz)
238166124Srafan			dd_out(0);
239166124Srafan	}
240174993Srafan	if (in.dbcnt)
24162449Speter		memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
242174993Srafan	in.dbp = in.db + in.dbcnt;
243174993Srafan}
24450276Speter
24562449Spetervoid
24650276Speterunblock_close()
247{
248	int cnt;
249	u_char *t;
250
251	if (in.dbcnt) {
252		warnx("%s: short input record", in.name);
253		for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
254		if (t >= in.db) {
255			cnt = t - in.db + 1;
256			memmove(out.dbp, in.db, cnt);
257			out.dbp += cnt;
258			out.dbcnt += cnt;
259		}
260		++out.dbcnt;
261		*out.dbp++ = '\n';
262	}
263}
264