conv.c revision 99109
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993, 1994 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Keith Muller of the University of California, San Diego and Lance 71556Srgrimes * Visser of Convex Computer Corporation. 81556Srgrimes * 91556Srgrimes * Redistribution and use in source and binary forms, with or without 101556Srgrimes * modification, are permitted provided that the following conditions 111556Srgrimes * are met: 121556Srgrimes * 1. Redistributions of source code must retain the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer. 141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer in the 161556Srgrimes * documentation and/or other materials provided with the distribution. 171556Srgrimes * 3. All advertising materials mentioning features or use of this software 181556Srgrimes * must display the following acknowledgement: 191556Srgrimes * This product includes software developed by the University of 201556Srgrimes * California, Berkeley and its contributors. 211556Srgrimes * 4. Neither the name of the University nor the names of its contributors 221556Srgrimes * may be used to endorse or promote products derived from this software 231556Srgrimes * without specific prior written permission. 241556Srgrimes * 251556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351556Srgrimes * SUCH DAMAGE. 361556Srgrimes */ 371556Srgrimes 381556Srgrimes#ifndef lint 3935773Scharnier#if 0 4036007Scharnierstatic char sccsid[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94"; 4135773Scharnier#endif 421556Srgrimes#endif /* not lint */ 4399109Sobrien#include <sys/cdefs.h> 4499109Sobrien__FBSDID("$FreeBSD: head/bin/dd/conv.c 99109 2002-06-30 05:13:54Z obrien $"); 451556Srgrimes 461556Srgrimes#include <sys/param.h> 471556Srgrimes 481556Srgrimes#include <err.h> 491556Srgrimes#include <string.h> 501556Srgrimes 511556Srgrimes#include "dd.h" 521556Srgrimes#include "extern.h" 531556Srgrimes 541556Srgrimes/* 551556Srgrimes * def -- 561556Srgrimes * Copy input to output. Input is buffered until reaches obs, and then 571556Srgrimes * output until less than obs remains. Only a single buffer is used. 581556Srgrimes * Worst case buffer calculation is (ibs + obs - 1). 591556Srgrimes */ 601556Srgrimesvoid 6190108Simpdef(void) 621556Srgrimes{ 6351208Sgreen u_char *inp; 6451208Sgreen const u_char *t; 6551208Sgreen size_t cnt; 661556Srgrimes 6719720Sphk if ((t = ctab) != NULL) 681556Srgrimes for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) 691556Srgrimes *inp = t[*inp]; 701556Srgrimes 711556Srgrimes /* Make the output buffer look right. */ 721556Srgrimes out.dbp = in.dbp; 731556Srgrimes out.dbcnt = in.dbcnt; 741556Srgrimes 751556Srgrimes if (in.dbcnt >= out.dbsz) { 761556Srgrimes /* If the output buffer is full, write it. */ 771556Srgrimes dd_out(0); 781556Srgrimes 791556Srgrimes /* 801556Srgrimes * Ddout copies the leftover output to the beginning of 811556Srgrimes * the buffer and resets the output buffer. Reset the 821556Srgrimes * input buffer to match it. 831556Srgrimes */ 841556Srgrimes in.dbp = out.dbp; 851556Srgrimes in.dbcnt = out.dbcnt; 861556Srgrimes } 871556Srgrimes} 881556Srgrimes 891556Srgrimesvoid 9090108Simpdef_close(void) 911556Srgrimes{ 921556Srgrimes /* Just update the count, everything is already in the buffer. */ 931556Srgrimes if (in.dbcnt) 941556Srgrimes out.dbcnt = in.dbcnt; 951556Srgrimes} 961556Srgrimes 971556Srgrimes/* 981556Srgrimes * Copy variable length newline terminated records with a max size cbsz 991556Srgrimes * bytes to output. Records less than cbs are padded with spaces. 1001556Srgrimes * 1011556Srgrimes * max in buffer: MAX(ibs, cbsz) 1021556Srgrimes * max out buffer: obs + cbsz 1031556Srgrimes */ 1041556Srgrimesvoid 10590108Simpblock(void) 1061556Srgrimes{ 10751208Sgreen u_char *inp, *outp; 10851208Sgreen const u_char *t; 10951208Sgreen size_t cnt, maxlen; 1101556Srgrimes static int intrunc; 11151249Sgreen int ch; 1121556Srgrimes 1131556Srgrimes /* 1141556Srgrimes * Record truncation can cross block boundaries. If currently in a 1151556Srgrimes * truncation state, keep tossing characters until reach a newline. 1161556Srgrimes * Start at the beginning of the buffer, as the input buffer is always 1171556Srgrimes * left empty. 1181556Srgrimes */ 1191556Srgrimes if (intrunc) { 12048026Sgreen for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt) 12148026Sgreen ; 1221556Srgrimes if (!cnt) { 1231556Srgrimes in.dbcnt = 0; 1241556Srgrimes in.dbp = in.db; 1251556Srgrimes return; 1261556Srgrimes } 1271556Srgrimes intrunc = 0; 1281556Srgrimes /* Adjust the input buffer numbers. */ 1291556Srgrimes in.dbcnt = cnt - 1; 1301556Srgrimes in.dbp = inp + cnt - 1; 1311556Srgrimes } 1321556Srgrimes 1331556Srgrimes /* 1341556Srgrimes * Copy records (max cbsz size chunks) into the output buffer. The 1351556Srgrimes * translation is done as we copy into the output buffer. 1361556Srgrimes */ 13720420Ssteve ch = 0; 1381556Srgrimes for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { 1391556Srgrimes maxlen = MIN(cbsz, in.dbcnt); 14019720Sphk if ((t = ctab) != NULL) 14148026Sgreen for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; 14248051Sgreen ++cnt) 1431556Srgrimes *outp++ = t[ch]; 1441556Srgrimes else 14548026Sgreen for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; 14648051Sgreen ++cnt) 1471556Srgrimes *outp++ = ch; 1481556Srgrimes /* 1491556Srgrimes * Check for short record without a newline. Reassemble the 1501556Srgrimes * input block. 1511556Srgrimes */ 1521556Srgrimes if (ch != '\n' && in.dbcnt < cbsz) { 15351208Sgreen (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 1541556Srgrimes break; 1551556Srgrimes } 1561556Srgrimes 1571556Srgrimes /* Adjust the input buffer numbers. */ 1581556Srgrimes in.dbcnt -= cnt; 1591556Srgrimes if (ch == '\n') 1601556Srgrimes --in.dbcnt; 1611556Srgrimes 1621556Srgrimes /* Pad short records with spaces. */ 1631556Srgrimes if (cnt < cbsz) 1641556Srgrimes (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); 1651556Srgrimes else { 1661556Srgrimes /* 1671556Srgrimes * If the next character wouldn't have ended the 1681556Srgrimes * block, it's a truncation. 1691556Srgrimes */ 1701556Srgrimes if (!in.dbcnt || *inp != '\n') 1711556Srgrimes ++st.trunc; 1721556Srgrimes 1731556Srgrimes /* Toss characters to a newline. */ 1741556Srgrimes for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt); 1751556Srgrimes if (!in.dbcnt) 1761556Srgrimes intrunc = 1; 1771556Srgrimes else 1781556Srgrimes --in.dbcnt; 1791556Srgrimes } 1801556Srgrimes 1811556Srgrimes /* Adjust output buffer numbers. */ 1821556Srgrimes out.dbp += cbsz; 1831556Srgrimes if ((out.dbcnt += cbsz) >= out.dbsz) 1841556Srgrimes dd_out(0); 1851556Srgrimes outp = out.dbp; 1861556Srgrimes } 1871556Srgrimes in.dbp = in.db + in.dbcnt; 1881556Srgrimes} 1891556Srgrimes 1901556Srgrimesvoid 19190108Simpblock_close(void) 1921556Srgrimes{ 1931556Srgrimes /* 1941556Srgrimes * Copy any remaining data into the output buffer and pad to a record. 1951556Srgrimes * Don't worry about truncation or translation, the input buffer is 1961556Srgrimes * always empty when truncating, and no characters have been added for 1971556Srgrimes * translation. The bottom line is that anything left in the input 1981556Srgrimes * buffer is a truncated record. Anything left in the output buffer 1991556Srgrimes * just wasn't big enough. 2001556Srgrimes */ 2011556Srgrimes if (in.dbcnt) { 2021556Srgrimes ++st.trunc; 20351208Sgreen (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt); 20448026Sgreen (void)memset(out.dbp + in.dbcnt, ctab ? ctab[' '] : ' ', 20548051Sgreen cbsz - in.dbcnt); 2061556Srgrimes out.dbcnt += cbsz; 2071556Srgrimes } 2081556Srgrimes} 2091556Srgrimes 2101556Srgrimes/* 2111556Srgrimes * Convert fixed length (cbsz) records to variable length. Deletes any 2121556Srgrimes * trailing blanks and appends a newline. 2131556Srgrimes * 2141556Srgrimes * max in buffer: MAX(ibs, cbsz) + cbsz 2151556Srgrimes * max out buffer: obs + cbsz 2161556Srgrimes */ 2171556Srgrimesvoid 21890108Simpunblock(void) 2191556Srgrimes{ 22051208Sgreen u_char *inp; 22151208Sgreen const u_char *t; 22251208Sgreen size_t cnt; 2231556Srgrimes 2241556Srgrimes /* Translation and case conversion. */ 22519720Sphk if ((t = ctab) != NULL) 2261556Srgrimes for (cnt = in.dbrcnt, inp = in.dbp; cnt--;) 2271556Srgrimes *--inp = t[*inp]; 2281556Srgrimes /* 2291556Srgrimes * Copy records (max cbsz size chunks) into the output buffer. The 2301556Srgrimes * translation has to already be done or we might not recognize the 2311556Srgrimes * spaces. 2321556Srgrimes */ 2331556Srgrimes for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) { 23448026Sgreen for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t) 23548026Sgreen ; 2361556Srgrimes if (t >= inp) { 2371556Srgrimes cnt = t - inp + 1; 23851208Sgreen (void)memmove(out.dbp, inp, cnt); 2391556Srgrimes out.dbp += cnt; 2401556Srgrimes out.dbcnt += cnt; 2411556Srgrimes } 2421556Srgrimes *out.dbp++ = '\n'; 24348026Sgreen if (++out.dbcnt >= out.dbsz) 2441556Srgrimes dd_out(0); 2451556Srgrimes } 2461556Srgrimes if (in.dbcnt) 24751208Sgreen (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 2481556Srgrimes in.dbp = in.db + in.dbcnt; 2491556Srgrimes} 2501556Srgrimes 2511556Srgrimesvoid 25290108Simpunblock_close(void) 2531556Srgrimes{ 2541556Srgrimes u_char *t; 25551208Sgreen size_t cnt; 2561556Srgrimes 2571556Srgrimes if (in.dbcnt) { 2581556Srgrimes warnx("%s: short input record", in.name); 25948026Sgreen for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t) 26048026Sgreen ; 2611556Srgrimes if (t >= in.db) { 2621556Srgrimes cnt = t - in.db + 1; 26351208Sgreen (void)memmove(out.dbp, in.db, cnt); 2641556Srgrimes out.dbp += cnt; 2651556Srgrimes out.dbcnt += cnt; 2661556Srgrimes } 2671556Srgrimes ++out.dbcnt; 2681556Srgrimes *out.dbp++ = '\n'; 2691556Srgrimes } 2701556Srgrimes} 271