/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1991, 1993, 19944* The Regents of the University of California. All rights reserved.5*6* This code is derived from software contributed to Berkeley by7* Keith Muller of the University of California, San Diego and Lance8* Visser of Convex Computer Corporation.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18* 3. Neither the name of the University nor the names of its contributors19* may be used to endorse or promote products derived from this software20* without specific prior written permission.21*22* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND23* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE24* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE25* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE26* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL27* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS28* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)29* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT30* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY31* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF32* SUCH DAMAGE.33*/3435#include <sys/param.h>3637#include <err.h>38#include <inttypes.h>39#include <string.h>4041#include "dd.h"42#include "extern.h"4344/*45* def --46* Copy input to output. Input is buffered until reaches obs, and then47* output until less than obs remains. Only a single buffer is used.48* Worst case buffer calculation is (ibs + obs - 1).49*/50void51def(void)52{53u_char *inp;54const u_char *t;55size_t cnt;5657if ((t = ctab) != NULL)58for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)59*inp = t[*inp];6061/* Make the output buffer look right. */62out.dbp = in.dbp;63out.dbcnt = in.dbcnt;6465if (in.dbcnt >= out.dbsz) {66/* If the output buffer is full, write it. */67dd_out(0);6869/*70* dd_out copies the leftover output to the beginning of71* the buffer and resets the output buffer. Reset the72* input buffer to match it.73*/74in.dbp = out.dbp;75in.dbcnt = out.dbcnt;76}77}7879void80def_close(void)81{82/* Just update the count, everything is already in the buffer. */83if (in.dbcnt)84out.dbcnt = in.dbcnt;85}8687/*88* Copy variable length newline terminated records with a max size cbsz89* bytes to output. Records less than cbs are padded with spaces.90*91* max in buffer: MAX(ibs, cbsz)92* max out buffer: obs + cbsz93*/94void95block(void)96{97u_char *inp, *outp;98const u_char *t;99size_t cnt, maxlen;100static int intrunc;101int ch;102103/*104* Record truncation can cross block boundaries. If currently in a105* truncation state, keep tossing characters until reach a newline.106* Start at the beginning of the buffer, as the input buffer is always107* left empty.108*/109if (intrunc) {110for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt)111;112if (!cnt) {113in.dbcnt = 0;114in.dbp = in.db;115return;116}117intrunc = 0;118/* Adjust the input buffer numbers. */119in.dbcnt = cnt - 1;120in.dbp = inp + cnt - 1;121}122123/*124* Copy records (max cbsz size chunks) into the output buffer. The125* translation is done as we copy into the output buffer.126*/127ch = 0;128for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {129maxlen = MIN(cbsz, (size_t)in.dbcnt);130if ((t = ctab) != NULL)131for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n';132++cnt)133*outp++ = t[ch];134else135for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n';136++cnt)137*outp++ = ch;138/*139* Check for short record without a newline. Reassemble the140* input block.141*/142if (ch != '\n' && (size_t)in.dbcnt < cbsz) {143(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);144break;145}146147/* Adjust the input buffer numbers. */148in.dbcnt -= cnt;149if (ch == '\n')150--in.dbcnt;151152/* Pad short records with spaces. */153if (cnt < cbsz)154(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);155else {156/*157* If the next character wouldn't have ended the158* block, it's a truncation.159*/160if (!in.dbcnt || *inp != '\n')161++st.trunc;162163/* Toss characters to a newline. */164for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt)165;166if (!in.dbcnt)167intrunc = 1;168else169--in.dbcnt;170}171172/* Adjust output buffer numbers. */173out.dbp += cbsz;174if ((out.dbcnt += cbsz) >= out.dbsz)175dd_out(0);176outp = out.dbp;177}178in.dbp = in.db + in.dbcnt;179}180181void182block_close(void)183{184/*185* Copy any remaining data into the output buffer and pad to a record.186* Don't worry about truncation or translation, the input buffer is187* always empty when truncating, and no characters have been added for188* translation. The bottom line is that anything left in the input189* buffer is a truncated record. Anything left in the output buffer190* just wasn't big enough.191*/192if (in.dbcnt) {193++st.trunc;194(void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);195(void)memset(out.dbp + in.dbcnt, ctab ? ctab[' '] : ' ',196cbsz - in.dbcnt);197out.dbcnt += cbsz;198}199}200201/*202* Convert fixed length (cbsz) records to variable length. Deletes any203* trailing blanks and appends a newline.204*205* max in buffer: MAX(ibs, cbsz) + cbsz206* max out buffer: obs + cbsz207*/208void209unblock(void)210{211u_char *inp;212const u_char *t;213size_t cnt;214215/* Translation and case conversion. */216if ((t = ctab) != NULL)217for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)218*inp = t[*inp];219/*220* Copy records (max cbsz size chunks) into the output buffer. The221* translation has to already be done or we might not recognize the222* spaces.223*/224for (inp = in.db; (size_t)in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {225for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t)226;227if (t >= inp) {228cnt = t - inp + 1;229(void)memmove(out.dbp, inp, cnt);230out.dbp += cnt;231out.dbcnt += cnt;232}233*out.dbp++ = '\n';234if (++out.dbcnt >= out.dbsz)235dd_out(0);236}237if (in.dbcnt)238(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);239in.dbp = in.db + in.dbcnt;240}241242void243unblock_close(void)244{245u_char *t;246size_t cnt;247248if (in.dbcnt) {249warnx("%s: short input record", in.name);250for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t)251;252if (t >= in.db) {253cnt = t - in.db + 1;254(void)memmove(out.dbp, in.db, cnt);255out.dbp += cnt;256out.dbcnt += cnt;257}258++out.dbcnt;259*out.dbp++ = '\n';260}261}262263264