xref: /original-bsd/bin/dd/conv.c (revision f3f8e977)
1 /*-
2  * Copyright (c) 1991, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Keith Muller of the University of California, San Diego and Lance
7  * Visser of Convex Computer Corporation.
8  *
9  * %sccs.include.redist.c%
10  */
11 
12 #ifndef lint
13 static char sccsid[] = "@(#)conv.c	8.3 (Berkeley) 04/02/94";
14 #endif /* not lint */
15 
16 #include <sys/param.h>
17 
18 #include <err.h>
19 #include <string.h>
20 
21 #include "dd.h"
22 #include "extern.h"
23 
24 /*
25  * def --
26  * Copy input to output.  Input is buffered until reaches obs, and then
27  * output until less than obs remains.  Only a single buffer is used.
28  * Worst case buffer calculation is (ibs + obs - 1).
29  */
30 void
31 def()
32 {
33 	int cnt;
34 	u_char *inp, *t;
35 
36 	if (t = ctab)
37 		for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
38 			*inp = t[*inp];
39 
40 	/* Make the output buffer look right. */
41 	out.dbp = in.dbp;
42 	out.dbcnt = in.dbcnt;
43 
44 	if (in.dbcnt >= out.dbsz) {
45 		/* If the output buffer is full, write it. */
46 		dd_out(0);
47 
48 		/*
49 		 * Ddout copies the leftover output to the beginning of
50 		 * the buffer and resets the output buffer.  Reset the
51 		 * input buffer to match it.
52 	 	 */
53 		in.dbp = out.dbp;
54 		in.dbcnt = out.dbcnt;
55 	}
56 }
57 
58 void
59 def_close()
60 {
61 	/* Just update the count, everything is already in the buffer. */
62 	if (in.dbcnt)
63 		out.dbcnt = in.dbcnt;
64 }
65 
66 /*
67  * Copy variable length newline terminated records with a max size cbsz
68  * bytes to output.  Records less than cbs are padded with spaces.
69  *
70  * max in buffer:  MAX(ibs, cbsz)
71  * max out buffer: obs + cbsz
72  */
73 void
74 block()
75 {
76 	static int intrunc;
77 	int ch, cnt, maxlen;
78 	u_char *inp, *outp, *t;
79 
80 	/*
81 	 * Record truncation can cross block boundaries.  If currently in a
82 	 * truncation state, keep tossing characters until reach a newline.
83 	 * Start at the beginning of the buffer, as the input buffer is always
84 	 * left empty.
85 	 */
86 	if (intrunc) {
87 		for (inp = in.db, cnt = in.dbrcnt;
88 		    cnt && *inp++ != '\n'; --cnt);
89 		if (!cnt) {
90 			in.dbcnt = 0;
91 			in.dbp = in.db;
92 			return;
93 		}
94 		intrunc = 0;
95 		/* Adjust the input buffer numbers. */
96 		in.dbcnt = cnt - 1;
97 		in.dbp = inp + cnt - 1;
98 	}
99 
100 	/*
101 	 * Copy records (max cbsz size chunks) into the output buffer.  The
102 	 * translation is done as we copy into the output buffer.
103 	 */
104 	for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
105 		maxlen = MIN(cbsz, in.dbcnt);
106 		if (t = ctab)
107 			for (cnt = 0;
108 			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
109 				*outp++ = t[ch];
110 		else
111 			for (cnt = 0;
112 			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
113 				*outp++ = ch;
114 		/*
115 		 * Check for short record without a newline.  Reassemble the
116 		 * input block.
117 		 */
118 		if (ch != '\n' && in.dbcnt < cbsz) {
119 			memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
120 			break;
121 		}
122 
123 		/* Adjust the input buffer numbers. */
124 		in.dbcnt -= cnt;
125 		if (ch == '\n')
126 			--in.dbcnt;
127 
128 		/* Pad short records with spaces. */
129 		if (cnt < cbsz)
130 			(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
131 		else {
132 			/*
133 			 * If the next character wouldn't have ended the
134 			 * block, it's a truncation.
135 			 */
136 			if (!in.dbcnt || *inp != '\n')
137 				++st.trunc;
138 
139 			/* Toss characters to a newline. */
140 			for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
141 			if (!in.dbcnt)
142 				intrunc = 1;
143 			else
144 				--in.dbcnt;
145 		}
146 
147 		/* Adjust output buffer numbers. */
148 		out.dbp += cbsz;
149 		if ((out.dbcnt += cbsz) >= out.dbsz)
150 			dd_out(0);
151 		outp = out.dbp;
152 	}
153 	in.dbp = in.db + in.dbcnt;
154 }
155 
156 void
157 block_close()
158 {
159 	/*
160 	 * Copy any remaining data into the output buffer and pad to a record.
161 	 * Don't worry about truncation or translation, the input buffer is
162 	 * always empty when truncating, and no characters have been added for
163 	 * translation.  The bottom line is that anything left in the input
164 	 * buffer is a truncated record.  Anything left in the output buffer
165 	 * just wasn't big enough.
166 	 */
167 	if (in.dbcnt) {
168 		++st.trunc;
169 		memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
170 		(void)memset(out.dbp + in.dbcnt,
171 		    ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
172 		out.dbcnt += cbsz;
173 	}
174 }
175 
176 /*
177  * Convert fixed length (cbsz) records to variable length.  Deletes any
178  * trailing blanks and appends a newline.
179  *
180  * max in buffer:  MAX(ibs, cbsz) + cbsz
181  * max out buffer: obs + cbsz
182  */
183 void
184 unblock()
185 {
186 	int cnt;
187 	u_char *inp, *t;
188 
189 	/* Translation and case conversion. */
190 	if (t = ctab)
191 		for (cnt = in.dbrcnt, inp = in.dbp; cnt--;)
192 			*--inp = t[*inp];
193 	/*
194 	 * Copy records (max cbsz size chunks) into the output buffer.  The
195 	 * translation has to already be done or we might not recognize the
196 	 * spaces.
197 	 */
198 	for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
199 		for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
200 		if (t >= inp) {
201 			cnt = t - inp + 1;
202 			memmove(out.dbp, inp, cnt);
203 			out.dbp += cnt;
204 			out.dbcnt += cnt;
205 		}
206 		++out.dbcnt;
207 		*out.dbp++ = '\n';
208 		if (out.dbcnt >= out.dbsz)
209 			dd_out(0);
210 	}
211 	if (in.dbcnt)
212 		memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
213 	in.dbp = in.db + in.dbcnt;
214 }
215 
216 void
217 unblock_close()
218 {
219 	int cnt;
220 	u_char *t;
221 
222 	if (in.dbcnt) {
223 		warnx("%s: short input record", in.name);
224 		for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
225 		if (t >= in.db) {
226 			cnt = t - in.db + 1;
227 			memmove(out.dbp, in.db, cnt);
228 			out.dbp += cnt;
229 			out.dbcnt += cnt;
230 		}
231 		++out.dbcnt;
232 		*out.dbp++ = '\n';
233 	}
234 }
235