1 /* $OpenBSD: conv.c,v 1.8 2001/08/07 14:39:27 hugh Exp $ */ 2 /* $NetBSD: conv.c,v 1.6 1996/02/20 19:29:02 jtc Exp $ */ 3 4 /*- 5 * Copyright (c) 1991, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Keith Muller of the University of California, San Diego and Lance 10 * Visser of Convex Computer Corporation. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41 #ifndef lint 42 #if 0 43 static char sccsid[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94"; 44 #else 45 static char rcsid[] = "$OpenBSD: conv.c,v 1.8 2001/08/07 14:39:27 hugh Exp $"; 46 #endif 47 #endif /* not lint */ 48 49 #include <sys/param.h> 50 #include <sys/time.h> 51 52 #include <err.h> 53 #include <string.h> 54 55 #include "dd.h" 56 #include "extern.h" 57 58 /* 59 * def -- 60 * Copy input to output. Input is buffered until reaches obs, and then 61 * output until less than obs remains. Only a single buffer is used. 62 * Worst case buffer calculation is (ibs + obs - 1). 63 */ 64 void 65 def() 66 { 67 size_t cnt; 68 u_char *inp; 69 const u_char *t; 70 71 if ((t = ctab) != NULL) 72 for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp) 73 *inp = t[*inp]; 74 75 /* Make the output buffer look right. */ 76 out.dbp = in.dbp; 77 out.dbcnt = in.dbcnt; 78 79 if (in.dbcnt >= out.dbsz) { 80 /* If the output buffer is full, write it. */ 81 dd_out(0); 82 83 /* 84 * Ddout copies the leftover output to the beginning of 85 * the buffer and resets the output buffer. Reset the 86 * input buffer to match it. 87 */ 88 in.dbp = out.dbp; 89 in.dbcnt = out.dbcnt; 90 } 91 } 92 93 void 94 def_close() 95 { 96 /* Just update the count, everything is already in the buffer. */ 97 if (in.dbcnt) 98 out.dbcnt = in.dbcnt; 99 } 100 101 #ifdef NO_CONV 102 /* Build a smaller version (i.e. for a miniroot) */ 103 /* These can not be called, but just in case... */ 104 static char no_block[] = "unblock and -DNO_CONV?"; 105 void block() { errx(1, "%s", no_block + 2); } 106 void block_close() { errx(1, "%s", no_block + 2); } 107 void unblock() { errx(1, "%s", no_block); } 108 void unblock_close() { errx(1, "%s", no_block); } 109 #else /* NO_CONV */ 110 111 /* 112 * Copy variable length newline terminated records with a max size cbsz 113 * bytes to output. Records less than cbs are padded with spaces. 114 * 115 * max in buffer: MAX(ibs, cbsz) 116 * max out buffer: obs + cbsz 117 */ 118 void 119 block() 120 { 121 static int intrunc; 122 int ch = -1; 123 size_t cnt, maxlen; 124 u_char *inp, *outp; 125 const u_char *t; 126 127 /* 128 * Record truncation can cross block boundaries. If currently in a 129 * truncation state, keep tossing characters until reach a newline. 130 * Start at the beginning of the buffer, as the input buffer is always 131 * left empty. 132 */ 133 if (intrunc) { 134 for (inp = in.db, cnt = in.dbrcnt; 135 cnt && *inp++ != '\n'; --cnt); 136 if (!cnt) { 137 in.dbcnt = 0; 138 in.dbp = in.db; 139 return; 140 } 141 intrunc = 0; 142 /* Adjust the input buffer numbers. */ 143 in.dbcnt = cnt - 1; 144 in.dbp = inp + cnt - 1; 145 } 146 147 /* 148 * Copy records (max cbsz size chunks) into the output buffer. The 149 * translation is done as we copy into the output buffer. 150 */ 151 for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) { 152 maxlen = MIN(cbsz, in.dbcnt); 153 if ((t = ctab) != NULL) 154 for (cnt = 0; 155 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) 156 *outp++ = t[ch]; 157 else 158 for (cnt = 0; 159 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt) 160 *outp++ = ch; 161 /* 162 * Check for short record without a newline. Reassemble the 163 * input block. 164 */ 165 if (ch != '\n' && in.dbcnt < cbsz) { 166 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 167 break; 168 } 169 170 /* Adjust the input buffer numbers. */ 171 in.dbcnt -= cnt; 172 if (ch == '\n') 173 --in.dbcnt; 174 175 /* Pad short records with spaces. */ 176 if (cnt < cbsz) 177 (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt); 178 else { 179 /* 180 * If the next character wouldn't have ended the 181 * block, it's a truncation. 182 */ 183 if (!in.dbcnt || *inp != '\n') 184 ++st.trunc; 185 186 /* Toss characters to a newline. */ 187 for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt); 188 if (!in.dbcnt) 189 intrunc = 1; 190 else 191 --in.dbcnt; 192 } 193 194 /* Adjust output buffer numbers. */ 195 out.dbp += cbsz; 196 if ((out.dbcnt += cbsz) >= out.dbsz) 197 dd_out(0); 198 outp = out.dbp; 199 } 200 in.dbp = in.db + in.dbcnt; 201 } 202 203 void 204 block_close() 205 { 206 /* 207 * Copy any remaining data into the output buffer and pad to a record. 208 * Don't worry about truncation or translation, the input buffer is 209 * always empty when truncating, and no characters have been added for 210 * translation. The bottom line is that anything left in the input 211 * buffer is a truncated record. Anything left in the output buffer 212 * just wasn't big enough. 213 */ 214 if (in.dbcnt) { 215 ++st.trunc; 216 (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt); 217 (void)memset(out.dbp + in.dbcnt, 218 ctab ? ctab[' '] : ' ', cbsz - in.dbcnt); 219 out.dbcnt += cbsz; 220 } 221 } 222 223 /* 224 * Convert fixed length (cbsz) records to variable length. Deletes any 225 * trailing blanks and appends a newline. 226 * 227 * max in buffer: MAX(ibs, cbsz) + cbsz 228 * max out buffer: obs + cbsz 229 */ 230 void 231 unblock() 232 { 233 size_t cnt; 234 u_char *inp; 235 const u_char *t; 236 237 /* Translation and case conversion. */ 238 if ((t = ctab) != NULL) 239 for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--) 240 *inp = t[*inp]; 241 /* 242 * Copy records (max cbsz size chunks) into the output buffer. The 243 * translation has to already be done or we might not recognize the 244 * spaces. 245 */ 246 for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) { 247 for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t); 248 if (t >= inp) { 249 cnt = t - inp + 1; 250 (void)memmove(out.dbp, inp, cnt); 251 out.dbp += cnt; 252 out.dbcnt += cnt; 253 } 254 ++out.dbcnt; 255 *out.dbp++ = '\n'; 256 if (out.dbcnt >= out.dbsz) 257 dd_out(0); 258 } 259 if (in.dbcnt) 260 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt); 261 in.dbp = in.db + in.dbcnt; 262 } 263 264 void 265 unblock_close() 266 { 267 size_t cnt; 268 u_char *t; 269 270 if (in.dbcnt) { 271 warnx("%s: short input record", in.name); 272 for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t); 273 if (t >= in.db) { 274 cnt = t - in.db + 1; 275 (void)memmove(out.dbp, in.db, cnt); 276 out.dbp += cnt; 277 out.dbcnt += cnt; 278 } 279 ++out.dbcnt; 280 *out.dbp++ = '\n'; 281 } 282 } 283 284 #endif /* NO_CONV */ 285