conv.c revision 20420
119370Spst/*-
298948Sobrien * Copyright (c) 1991, 1993, 1994
398948Sobrien *	The Regents of the University of California.  All rights reserved.
4130809Smarcel *
519370Spst * This code is derived from software contributed to Berkeley by
619370Spst * Keith Muller of the University of California, San Diego and Lance
798948Sobrien * Visser of Convex Computer Corporation.
819370Spst *
998948Sobrien * Redistribution and use in source and binary forms, with or without
1098948Sobrien * modification, are permitted provided that the following conditions
1198948Sobrien * are met:
1298948Sobrien * 1. Redistributions of source code must retain the above copyright
1319370Spst *    notice, this list of conditions and the following disclaimer.
1498948Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1598948Sobrien *    notice, this list of conditions and the following disclaimer in the
1698948Sobrien *    documentation and/or other materials provided with the distribution.
1798948Sobrien * 3. All advertising materials mentioning features or use of this software
1819370Spst *    must display the following acknowledgement:
1998948Sobrien *	This product includes software developed by the University of
2098948Sobrien *	California, Berkeley and its contributors.
2198948Sobrien * 4. Neither the name of the University nor the names of its contributors
2298948Sobrien *    may be used to endorse or promote products derived from this software
2319370Spst *    without specific prior written permission.
2419370Spst *
2519370Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2619370Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2798948Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2898948Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2998948Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30130809Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3119370Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3219370Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3398948Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3419370Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3519370Spst * SUCH DAMAGE.
3619370Spst *
3719370Spst *	$Id: conv.c,v 1.5 1996/11/13 19:59:56 phk Exp $
3819370Spst */
3919370Spst
4098948Sobrien#ifndef lint
4119370Spststatic char const sccsid[] = "@(#)conv.c	8.3 (Berkeley) 4/2/94";
4298948Sobrien#endif /* not lint */
4319370Spst
4498948Sobrien#include <sys/param.h>
4598948Sobrien
4698948Sobrien#include <err.h>
4798948Sobrien#include <string.h>
4819370Spst
4919370Spst#include "dd.h"
50130809Smarcel#include "extern.h"
51130809Smarcel
5219370Spst/*
5319370Spst * def --
5419370Spst * Copy input to output.  Input is buffered until reaches obs, and then
5519370Spst * output until less than obs remains.  Only a single buffer is used.
5619370Spst * Worst case buffer calculation is (ibs + obs - 1).
5719370Spst */
5898948Sobrienvoid
5998948Sobriendef()
6098948Sobrien{
6119370Spst	int cnt;
6219370Spst	u_char *inp, *t;
6319370Spst
6498948Sobrien	if ((t = ctab) != NULL)
6598948Sobrien		for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
6619370Spst			*inp = t[*inp];
6798948Sobrien
6819370Spst	/* Make the output buffer look right. */
6998948Sobrien	out.dbp = in.dbp;
7098948Sobrien	out.dbcnt = in.dbcnt;
7146283Sdfr
7246283Sdfr	if (in.dbcnt >= out.dbsz) {
7319370Spst		/* If the output buffer is full, write it. */
7419370Spst		dd_out(0);
7519370Spst
7619370Spst		/*
7719370Spst		 * Ddout copies the leftover output to the beginning of
7819370Spst		 * the buffer and resets the output buffer.  Reset the
7919370Spst		 * input buffer to match it.
8019370Spst	 	 */
8119370Spst		in.dbp = out.dbp;
8219370Spst		in.dbcnt = out.dbcnt;
8319370Spst	}
8419370Spst}
85130809Smarcel
8619370Spstvoid
8719370Spstdef_close()
8819370Spst{
8919370Spst	/* Just update the count, everything is already in the buffer. */
9019370Spst	if (in.dbcnt)
9198948Sobrien		out.dbcnt = in.dbcnt;
9219370Spst}
9319370Spst
9419370Spst/*
9546283Sdfr * Copy variable length newline terminated records with a max size cbsz
9619370Spst * bytes to output.  Records less than cbs are padded with spaces.
9719370Spst *
9819370Spst * max in buffer:  MAX(ibs, cbsz)
9919370Spst * max out buffer: obs + cbsz
10019370Spst */
10119370Spstvoid
10219370Spstblock()
10319370Spst{
10419370Spst	static int intrunc;
10519370Spst	int ch, cnt, maxlen;
10619370Spst	u_char *inp, *outp, *t;
10719370Spst
10819370Spst	/*
10919370Spst	 * Record truncation can cross block boundaries.  If currently in a
11098948Sobrien	 * truncation state, keep tossing characters until reach a newline.
11119370Spst	 * Start at the beginning of the buffer, as the input buffer is always
11219370Spst	 * left empty.
11319370Spst	 */
11419370Spst	if (intrunc) {
11519370Spst		for (inp = in.db, cnt = in.dbrcnt;
11698948Sobrien		    cnt && *inp++ != '\n'; --cnt);
11719370Spst		if (!cnt) {
11819370Spst			in.dbcnt = 0;
11919370Spst			in.dbp = in.db;
12019370Spst			return;
12119370Spst		}
12219370Spst		intrunc = 0;
12319370Spst		/* Adjust the input buffer numbers. */
12419370Spst		in.dbcnt = cnt - 1;
12598948Sobrien		in.dbp = inp + cnt - 1;
12619370Spst	}
12719370Spst
12819370Spst	/*
12919370Spst	 * Copy records (max cbsz size chunks) into the output buffer.  The
13019370Spst	 * translation is done as we copy into the output buffer.
13119370Spst	 */
13219370Spst	ch = 0;
13319370Spst	for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
13419370Spst		maxlen = MIN(cbsz, in.dbcnt);
13519370Spst		if ((t = ctab) != NULL)
13619370Spst			for (cnt = 0;
13719370Spst			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
13819370Spst				*outp++ = t[ch];
13946283Sdfr		else
14046283Sdfr			for (cnt = 0;
14198948Sobrien			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
14298948Sobrien				*outp++ = ch;
14398948Sobrien		/*
14498948Sobrien		 * Check for short record without a newline.  Reassemble the
14598948Sobrien		 * input block.
14646283Sdfr		 */
14798948Sobrien		if (ch != '\n' && in.dbcnt < cbsz) {
14898948Sobrien			memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
14998948Sobrien			break;
150130809Smarcel		}
15198948Sobrien
15298948Sobrien		/* Adjust the input buffer numbers. */
15398948Sobrien		in.dbcnt -= cnt;
15498948Sobrien		if (ch == '\n')
15598948Sobrien			--in.dbcnt;
15698948Sobrien
15798948Sobrien		/* Pad short records with spaces. */
15898948Sobrien		if (cnt < cbsz)
15998948Sobrien			(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
16098948Sobrien		else {
16119370Spst			/*
16219370Spst			 * If the next character wouldn't have ended the
16319370Spst			 * block, it's a truncation.
16419370Spst			 */
16598948Sobrien			if (!in.dbcnt || *inp != '\n')
16698948Sobrien				++st.trunc;
16798948Sobrien
16898948Sobrien			/* Toss characters to a newline. */
16998948Sobrien			for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
17098948Sobrien			if (!in.dbcnt)
17119370Spst				intrunc = 1;
17219370Spst			else
17319370Spst				--in.dbcnt;
174130809Smarcel		}
175130809Smarcel
176130809Smarcel		/* Adjust output buffer numbers. */
177130809Smarcel		out.dbp += cbsz;
178130809Smarcel		if ((out.dbcnt += cbsz) >= out.dbsz)
17919370Spst			dd_out(0);
18019370Spst		outp = out.dbp;
18119370Spst	}
18219370Spst	in.dbp = in.db + in.dbcnt;
18319370Spst}
18498948Sobrien
18519370Spstvoid
18619370Spstblock_close()
18719370Spst{
18819370Spst	/*
18919370Spst	 * Copy any remaining data into the output buffer and pad to a record.
19019370Spst	 * Don't worry about truncation or translation, the input buffer is
19198948Sobrien	 * always empty when truncating, and no characters have been added for
19219370Spst	 * translation.  The bottom line is that anything left in the input
19398948Sobrien	 * buffer is a truncated record.  Anything left in the output buffer
19498948Sobrien	 * just wasn't big enough.
19519370Spst	 */
19698948Sobrien	if (in.dbcnt) {
19719370Spst		++st.trunc;
19898948Sobrien		memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
19998948Sobrien		(void)memset(out.dbp + in.dbcnt,
20098948Sobrien		    ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
20119370Spst		out.dbcnt += cbsz;
20298948Sobrien	}
20319370Spst}
20498948Sobrien
20598948Sobrien/*
20619370Spst * Convert fixed length (cbsz) records to variable length.  Deletes any
20798948Sobrien * trailing blanks and appends a newline.
20819370Spst *
20919370Spst * max in buffer:  MAX(ibs, cbsz) + cbsz
21019370Spst * max out buffer: obs + cbsz
21119370Spst */
21298948Sobrienvoid
21398948Sobrienunblock()
21419370Spst{
21519370Spst	int cnt;
21698948Sobrien	u_char *inp, *t;
21719370Spst
21846283Sdfr	/* Translation and case conversion. */
21946283Sdfr	if ((t = ctab) != NULL)
22098948Sobrien		for (cnt = in.dbrcnt, inp = in.dbp; cnt--;)
22146283Sdfr			*--inp = t[*inp];
22246283Sdfr	/*
22346283Sdfr	 * Copy records (max cbsz size chunks) into the output buffer.  The
22446283Sdfr	 * translation has to already be done or we might not recognize the
22546283Sdfr	 * spaces.
22646283Sdfr	 */
22746283Sdfr	for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
22846283Sdfr		for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
22946283Sdfr		if (t >= inp) {
23046283Sdfr			cnt = t - inp + 1;
23146283Sdfr			memmove(out.dbp, inp, cnt);
23246283Sdfr			out.dbp += cnt;
23398948Sobrien			out.dbcnt += cnt;
23498948Sobrien		}
23598948Sobrien		++out.dbcnt;
23646283Sdfr		*out.dbp++ = '\n';
23719370Spst		if (out.dbcnt >= out.dbsz)
23819370Spst			dd_out(0);
23919370Spst	}
24098948Sobrien	if (in.dbcnt)
24198948Sobrien		memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
24298948Sobrien	in.dbp = in.db + in.dbcnt;
24319370Spst}
24498948Sobrien
24598948Sobrienvoid
24698948Sobrienunblock_close()
24798948Sobrien{
24898948Sobrien	int cnt;
24998948Sobrien	u_char *t;
25019370Spst
25119370Spst	if (in.dbcnt) {
25219370Spst		warnx("%s: short input record", in.name);
25398948Sobrien		for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
25419370Spst		if (t >= in.db) {
25519370Spst			cnt = t - in.db + 1;
25619370Spst			memmove(out.dbp, in.db, cnt);
25719370Spst			out.dbp += cnt;
25898948Sobrien			out.dbcnt += cnt;
25919370Spst		}
26046283Sdfr		++out.dbcnt;
26146283Sdfr		*out.dbp++ = '\n';
26298948Sobrien	}
26398948Sobrien}
26446283Sdfr