conv.c revision 111629
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 111629 2003-02-27 18:04:54Z markm $"); 451556Srgrimes 461556Srgrimes#include <sys/param.h> 471556Srgrimes 481556Srgrimes#include <err.h> 49111629Smarkm#include <inttypes.h> 501556Srgrimes#include <string.h> 511556Srgrimes 521556Srgrimes#include "dd.h" 531556Srgrimes#include "extern.h" 541556Srgrimes 551556Srgrimes/* 561556Srgrimes * def -- 571556Srgrimes * Copy input to output. Input is buffered until reaches obs, and then 581556Srgrimes * output until less than obs remains. Only a single buffer is used. 591556Srgrimes * Worst case buffer calculation is (ibs + obs - 1). 601556Srgrimes */ 611556Srgrimesvoid 6290108Simpdef(void) 631556Srgrimes{ 6451208Sgreen u_char *inp; 6551208Sgreen const u_char *t; 6651208Sgreen size_t cnt; 671556Srgrimes 6819720Sphk if ((t = ctab) != NULL) 691556Srgrimes for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) 701556Srgrimes *inp = t[*inp]; 711556Srgrimes 721556Srgrimes /* Make the output buffer look right. */ 731556Srgrimes out.dbp = in.dbp; 741556Srgrimes out.dbcnt = in.dbcnt; 751556Srgrimes 761556Srgrimes if (in.dbcnt >= out.dbsz) { 771556Srgrimes /* If the output buffer is full, write it. */ 781556Srgrimes dd_out(0); 791556Srgrimes 801556Srgrimes /* 811556Srgrimes * Ddout copies the leftover output to the beginning of 821556Srgrimes * the buffer and resets the output buffer. Reset the 831556Srgrimes * input buffer to match it. 841556Srgrimes */ 851556Srgrimes in.dbp = out.dbp; 861556Srgrimes in.dbcnt = out.dbcnt; 871556Srgrimes } 881556Srgrimes} 891556Srgrimes 901556Srgrimesvoid 9190108Simpdef_close(void) 921556Srgrimes{ 931556Srgrimes /* Just update the count, everything is already in the buffer. */ 941556Srgrimes if (in.dbcnt) 951556Srgrimes out.dbcnt = in.dbcnt; 961556Srgrimes} 971556Srgrimes 981556Srgrimes/* 991556Srgrimes * Copy variable length newline terminated records with a max size cbsz 1001556Srgrimes * bytes to output. Records less than cbs are padded with spaces. 1011556Srgrimes * 1021556Srgrimes * max in buffer: MAX(ibs, cbsz) 1031556Srgrimes * max out buffer: obs + cbsz 1041556Srgrimes */ 1051556Srgrimesvoid 10690108Simpblock(void) 1071556Srgrimes{ 10851208Sgreen u_char *inp, *outp; 10951208Sgreen const u_char *t; 11051208Sgreen size_t cnt, maxlen; 1111556Srgrimes static int intrunc; 11251249Sgreen int ch; 1131556Srgrimes 1141556Srgrimes /* 1151556Srgrimes * Record truncation can cross block boundaries. If currently in a 1161556Srgrimes * truncation state, keep tossing characters until reach a newline. 1171556Srgrimes * Start at the beginning of the buffer, as the input buffer is always 1181556Srgrimes * left empty. 1191556Srgrimes */ 1201556Srgrimes if (intrunc) { 12148026Sgreen for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt) 12248026Sgreen ; 1231556Srgrimes if (!cnt) { 1241556Srgrimes in.dbcnt = 0; 1251556Srgrimes in.dbp = in.db; 1261556Srgrimes return; 1271556Srgrimes } 1281556Srgrimes intrunc = 0; 1291556Srgrimes /* Adjust the input buffer numbers. */ 1301556Srgrimes in.dbcnt = cnt - 1; 1311556Srgrimes in.dbp = inp + cnt - 1; 1321556Srgrimes } 1331556Srgrimes 1341556Srgrimes /* 1351556Srgrimes * Copy records (max cbsz size chunks) into the output buffer. The 1361556Srgrimes * translation is done as we copy into the output buffer. 1371556Srgrimes */ 13820420Ssteve ch = 0; 1391556Srgrimes for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { 1401556Srgrimes maxlen = MIN(cbsz, in.dbcnt); 14119720Sphk if ((t = ctab) != NULL) 14248026Sgreen for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; 14348051Sgreen ++cnt) 1441556Srgrimes *outp++ = t[ch]; 1451556Srgrimes else 14648026Sgreen for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; 14748051Sgreen ++cnt) 1481556Srgrimes *outp++ = ch; 1491556Srgrimes /* 1501556Srgrimes * Check for short record without a newline. Reassemble the 1511556Srgrimes * input block. 1521556Srgrimes */ 1531556Srgrimes if (ch != '\n' && in.dbcnt < cbsz) { 15451208Sgreen (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 1551556Srgrimes break; 1561556Srgrimes } 1571556Srgrimes 1581556Srgrimes /* Adjust the input buffer numbers. */ 1591556Srgrimes in.dbcnt -= cnt; 1601556Srgrimes if (ch == '\n') 1611556Srgrimes --in.dbcnt; 1621556Srgrimes 1631556Srgrimes /* Pad short records with spaces. */ 1641556Srgrimes if (cnt < cbsz) 1651556Srgrimes (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); 1661556Srgrimes else { 1671556Srgrimes /* 1681556Srgrimes * If the next character wouldn't have ended the 1691556Srgrimes * block, it's a truncation. 1701556Srgrimes */ 1711556Srgrimes if (!in.dbcnt || *inp != '\n') 1721556Srgrimes ++st.trunc; 1731556Srgrimes 1741556Srgrimes /* Toss characters to a newline. */ 175111629Smarkm for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt) 176111629Smarkm ; 1771556Srgrimes if (!in.dbcnt) 1781556Srgrimes intrunc = 1; 1791556Srgrimes else 1801556Srgrimes --in.dbcnt; 1811556Srgrimes } 1821556Srgrimes 1831556Srgrimes /* Adjust output buffer numbers. */ 1841556Srgrimes out.dbp += cbsz; 1851556Srgrimes if ((out.dbcnt += cbsz) >= out.dbsz) 1861556Srgrimes dd_out(0); 1871556Srgrimes outp = out.dbp; 1881556Srgrimes } 1891556Srgrimes in.dbp = in.db + in.dbcnt; 1901556Srgrimes} 1911556Srgrimes 1921556Srgrimesvoid 19390108Simpblock_close(void) 1941556Srgrimes{ 1951556Srgrimes /* 1961556Srgrimes * Copy any remaining data into the output buffer and pad to a record. 1971556Srgrimes * Don't worry about truncation or translation, the input buffer is 1981556Srgrimes * always empty when truncating, and no characters have been added for 1991556Srgrimes * translation. The bottom line is that anything left in the input 2001556Srgrimes * buffer is a truncated record. Anything left in the output buffer 2011556Srgrimes * just wasn't big enough. 2021556Srgrimes */ 2031556Srgrimes if (in.dbcnt) { 2041556Srgrimes ++st.trunc; 20551208Sgreen (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt); 20648026Sgreen (void)memset(out.dbp + in.dbcnt, ctab ? ctab[' '] : ' ', 20748051Sgreen cbsz - in.dbcnt); 2081556Srgrimes out.dbcnt += cbsz; 2091556Srgrimes } 2101556Srgrimes} 2111556Srgrimes 2121556Srgrimes/* 2131556Srgrimes * Convert fixed length (cbsz) records to variable length. Deletes any 2141556Srgrimes * trailing blanks and appends a newline. 2151556Srgrimes * 2161556Srgrimes * max in buffer: MAX(ibs, cbsz) + cbsz 2171556Srgrimes * max out buffer: obs + cbsz 2181556Srgrimes */ 2191556Srgrimesvoid 22090108Simpunblock(void) 2211556Srgrimes{ 22251208Sgreen u_char *inp; 22351208Sgreen const u_char *t; 22451208Sgreen size_t cnt; 2251556Srgrimes 2261556Srgrimes /* Translation and case conversion. */ 22719720Sphk if ((t = ctab) != NULL) 228111629Smarkm for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) 229111629Smarkm *inp = t[*inp]; 2301556Srgrimes /* 2311556Srgrimes * Copy records (max cbsz size chunks) into the output buffer. The 2321556Srgrimes * translation has to already be done or we might not recognize the 2331556Srgrimes * spaces. 2341556Srgrimes */ 2351556Srgrimes for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) { 23648026Sgreen for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t) 23748026Sgreen ; 2381556Srgrimes if (t >= inp) { 2391556Srgrimes cnt = t - inp + 1; 24051208Sgreen (void)memmove(out.dbp, inp, cnt); 2411556Srgrimes out.dbp += cnt; 2421556Srgrimes out.dbcnt += cnt; 2431556Srgrimes } 2441556Srgrimes *out.dbp++ = '\n'; 24548026Sgreen if (++out.dbcnt >= out.dbsz) 2461556Srgrimes dd_out(0); 2471556Srgrimes } 2481556Srgrimes if (in.dbcnt) 24951208Sgreen (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 2501556Srgrimes in.dbp = in.db + in.dbcnt; 2511556Srgrimes} 2521556Srgrimes 2531556Srgrimesvoid 25490108Simpunblock_close(void) 2551556Srgrimes{ 2561556Srgrimes u_char *t; 25751208Sgreen size_t cnt; 2581556Srgrimes 2591556Srgrimes if (in.dbcnt) { 2601556Srgrimes warnx("%s: short input record", in.name); 26148026Sgreen for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t) 26248026Sgreen ; 2631556Srgrimes if (t >= in.db) { 2641556Srgrimes cnt = t - in.db + 1; 26551208Sgreen (void)memmove(out.dbp, in.db, cnt); 2661556Srgrimes out.dbp += cnt; 2671556Srgrimes out.dbcnt += cnt; 2681556Srgrimes } 2691556Srgrimes ++out.dbcnt; 2701556Srgrimes *out.dbp++ = '\n'; 2711556Srgrimes } 2721556Srgrimes} 273