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 * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 3535773Scharnier#if 0 3636007Scharnierstatic char sccsid[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94"; 3735773Scharnier#endif 381556Srgrimes#endif /* not lint */ 3999109Sobrien#include <sys/cdefs.h> 4099109Sobrien__FBSDID("$FreeBSD$"); 411556Srgrimes 421556Srgrimes#include <sys/param.h> 431556Srgrimes 441556Srgrimes#include <err.h> 45111629Smarkm#include <inttypes.h> 461556Srgrimes#include <string.h> 471556Srgrimes 481556Srgrimes#include "dd.h" 491556Srgrimes#include "extern.h" 501556Srgrimes 511556Srgrimes/* 521556Srgrimes * def -- 531556Srgrimes * Copy input to output. Input is buffered until reaches obs, and then 541556Srgrimes * output until less than obs remains. Only a single buffer is used. 551556Srgrimes * Worst case buffer calculation is (ibs + obs - 1). 561556Srgrimes */ 571556Srgrimesvoid 5890108Simpdef(void) 591556Srgrimes{ 6051208Sgreen u_char *inp; 6151208Sgreen const u_char *t; 6251208Sgreen size_t cnt; 631556Srgrimes 6419720Sphk if ((t = ctab) != NULL) 651556Srgrimes for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) 661556Srgrimes *inp = t[*inp]; 671556Srgrimes 681556Srgrimes /* Make the output buffer look right. */ 691556Srgrimes out.dbp = in.dbp; 701556Srgrimes out.dbcnt = in.dbcnt; 711556Srgrimes 721556Srgrimes if (in.dbcnt >= out.dbsz) { 731556Srgrimes /* If the output buffer is full, write it. */ 741556Srgrimes dd_out(0); 751556Srgrimes 761556Srgrimes /* 771556Srgrimes * Ddout copies the leftover output to the beginning of 781556Srgrimes * the buffer and resets the output buffer. Reset the 791556Srgrimes * input buffer to match it. 801556Srgrimes */ 811556Srgrimes in.dbp = out.dbp; 821556Srgrimes in.dbcnt = out.dbcnt; 831556Srgrimes } 841556Srgrimes} 851556Srgrimes 861556Srgrimesvoid 8790108Simpdef_close(void) 881556Srgrimes{ 891556Srgrimes /* Just update the count, everything is already in the buffer. */ 901556Srgrimes if (in.dbcnt) 911556Srgrimes out.dbcnt = in.dbcnt; 921556Srgrimes} 931556Srgrimes 941556Srgrimes/* 951556Srgrimes * Copy variable length newline terminated records with a max size cbsz 961556Srgrimes * bytes to output. Records less than cbs are padded with spaces. 971556Srgrimes * 981556Srgrimes * max in buffer: MAX(ibs, cbsz) 991556Srgrimes * max out buffer: obs + cbsz 1001556Srgrimes */ 1011556Srgrimesvoid 10290108Simpblock(void) 1031556Srgrimes{ 10451208Sgreen u_char *inp, *outp; 10551208Sgreen const u_char *t; 10651208Sgreen size_t cnt, maxlen; 1071556Srgrimes static int intrunc; 10851249Sgreen int ch; 1091556Srgrimes 1101556Srgrimes /* 1111556Srgrimes * Record truncation can cross block boundaries. If currently in a 1121556Srgrimes * truncation state, keep tossing characters until reach a newline. 1131556Srgrimes * Start at the beginning of the buffer, as the input buffer is always 1141556Srgrimes * left empty. 1151556Srgrimes */ 1161556Srgrimes if (intrunc) { 11748026Sgreen for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt) 11848026Sgreen ; 1191556Srgrimes if (!cnt) { 1201556Srgrimes in.dbcnt = 0; 1211556Srgrimes in.dbp = in.db; 1221556Srgrimes return; 1231556Srgrimes } 1241556Srgrimes intrunc = 0; 1251556Srgrimes /* Adjust the input buffer numbers. */ 1261556Srgrimes in.dbcnt = cnt - 1; 1271556Srgrimes in.dbp = inp + cnt - 1; 1281556Srgrimes } 1291556Srgrimes 1301556Srgrimes /* 1311556Srgrimes * Copy records (max cbsz size chunks) into the output buffer. The 1321556Srgrimes * translation is done as we copy into the output buffer. 1331556Srgrimes */ 13420420Ssteve ch = 0; 1351556Srgrimes for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { 1361556Srgrimes maxlen = MIN(cbsz, in.dbcnt); 13719720Sphk if ((t = ctab) != NULL) 13848026Sgreen for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; 13948051Sgreen ++cnt) 1401556Srgrimes *outp++ = t[ch]; 1411556Srgrimes else 14248026Sgreen for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n'; 14348051Sgreen ++cnt) 1441556Srgrimes *outp++ = ch; 1451556Srgrimes /* 1461556Srgrimes * Check for short record without a newline. Reassemble the 1471556Srgrimes * input block. 1481556Srgrimes */ 1491556Srgrimes if (ch != '\n' && in.dbcnt < cbsz) { 15051208Sgreen (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 1511556Srgrimes break; 1521556Srgrimes } 1531556Srgrimes 1541556Srgrimes /* Adjust the input buffer numbers. */ 1551556Srgrimes in.dbcnt -= cnt; 1561556Srgrimes if (ch == '\n') 1571556Srgrimes --in.dbcnt; 1581556Srgrimes 1591556Srgrimes /* Pad short records with spaces. */ 1601556Srgrimes if (cnt < cbsz) 1611556Srgrimes (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); 1621556Srgrimes else { 1631556Srgrimes /* 1641556Srgrimes * If the next character wouldn't have ended the 1651556Srgrimes * block, it's a truncation. 1661556Srgrimes */ 1671556Srgrimes if (!in.dbcnt || *inp != '\n') 1681556Srgrimes ++st.trunc; 1691556Srgrimes 1701556Srgrimes /* Toss characters to a newline. */ 171111629Smarkm for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt) 172111629Smarkm ; 1731556Srgrimes if (!in.dbcnt) 1741556Srgrimes intrunc = 1; 1751556Srgrimes else 1761556Srgrimes --in.dbcnt; 1771556Srgrimes } 1781556Srgrimes 1791556Srgrimes /* Adjust output buffer numbers. */ 1801556Srgrimes out.dbp += cbsz; 1811556Srgrimes if ((out.dbcnt += cbsz) >= out.dbsz) 1821556Srgrimes dd_out(0); 1831556Srgrimes outp = out.dbp; 1841556Srgrimes } 1851556Srgrimes in.dbp = in.db + in.dbcnt; 1861556Srgrimes} 1871556Srgrimes 1881556Srgrimesvoid 18990108Simpblock_close(void) 1901556Srgrimes{ 1911556Srgrimes /* 1921556Srgrimes * Copy any remaining data into the output buffer and pad to a record. 1931556Srgrimes * Don't worry about truncation or translation, the input buffer is 1941556Srgrimes * always empty when truncating, and no characters have been added for 1951556Srgrimes * translation. The bottom line is that anything left in the input 1961556Srgrimes * buffer is a truncated record. Anything left in the output buffer 1971556Srgrimes * just wasn't big enough. 1981556Srgrimes */ 1991556Srgrimes if (in.dbcnt) { 2001556Srgrimes ++st.trunc; 20151208Sgreen (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt); 20248026Sgreen (void)memset(out.dbp + in.dbcnt, ctab ? ctab[' '] : ' ', 20348051Sgreen cbsz - in.dbcnt); 2041556Srgrimes out.dbcnt += cbsz; 2051556Srgrimes } 2061556Srgrimes} 2071556Srgrimes 2081556Srgrimes/* 2091556Srgrimes * Convert fixed length (cbsz) records to variable length. Deletes any 2101556Srgrimes * trailing blanks and appends a newline. 2111556Srgrimes * 2121556Srgrimes * max in buffer: MAX(ibs, cbsz) + cbsz 2131556Srgrimes * max out buffer: obs + cbsz 2141556Srgrimes */ 2151556Srgrimesvoid 21690108Simpunblock(void) 2171556Srgrimes{ 21851208Sgreen u_char *inp; 21951208Sgreen const u_char *t; 22051208Sgreen size_t cnt; 2211556Srgrimes 2221556Srgrimes /* Translation and case conversion. */ 22319720Sphk if ((t = ctab) != NULL) 224111629Smarkm for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) 225111629Smarkm *inp = t[*inp]; 2261556Srgrimes /* 2271556Srgrimes * Copy records (max cbsz size chunks) into the output buffer. The 2281556Srgrimes * translation has to already be done or we might not recognize the 2291556Srgrimes * spaces. 2301556Srgrimes */ 2311556Srgrimes for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) { 23248026Sgreen for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t) 23348026Sgreen ; 2341556Srgrimes if (t >= inp) { 2351556Srgrimes cnt = t - inp + 1; 23651208Sgreen (void)memmove(out.dbp, inp, cnt); 2371556Srgrimes out.dbp += cnt; 2381556Srgrimes out.dbcnt += cnt; 2391556Srgrimes } 2401556Srgrimes *out.dbp++ = '\n'; 24148026Sgreen if (++out.dbcnt >= out.dbsz) 2421556Srgrimes dd_out(0); 2431556Srgrimes } 2441556Srgrimes if (in.dbcnt) 24551208Sgreen (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 2461556Srgrimes in.dbp = in.db + in.dbcnt; 2471556Srgrimes} 2481556Srgrimes 2491556Srgrimesvoid 25090108Simpunblock_close(void) 2511556Srgrimes{ 2521556Srgrimes u_char *t; 25351208Sgreen size_t cnt; 2541556Srgrimes 2551556Srgrimes if (in.dbcnt) { 2561556Srgrimes warnx("%s: short input record", in.name); 25748026Sgreen for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t) 25848026Sgreen ; 2591556Srgrimes if (t >= in.db) { 2601556Srgrimes cnt = t - in.db + 1; 26151208Sgreen (void)memmove(out.dbp, in.db, cnt); 2621556Srgrimes out.dbp += cnt; 2631556Srgrimes out.dbcnt += cnt; 2641556Srgrimes } 2651556Srgrimes ++out.dbcnt; 2661556Srgrimes *out.dbp++ = '\n'; 2671556Srgrimes } 2681556Srgrimes} 269