1 /* $OpenBSD: bcd.c,v 1.26 2018/01/23 07:06:55 otto Exp $ */ 2 /* $NetBSD: bcd.c,v 1.6 1995/04/24 12:22:23 cgd Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Steve Hayman of the Indiana University Computer Science Dept. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 /* 37 * bcd -- 38 * 39 * Read one line of standard input and produce something that looks like a 40 * punch card. An attempt to reimplement /usr/games/bcd. All I looked at 41 * was the man page. 42 * 43 * I couldn't find a BCD table handy so I wrote a shell script to deduce what 44 * the patterns were that the old bcd was using for each possible 8-bit 45 * character. These are the results -- the low order 12 bits represent the 46 * holes. (A 1 bit is a hole.) These may be wrong, but they match the old 47 * program! 48 * 49 * Steve Hayman 50 * sahayman@iuvax.cs.indiana.edu 51 * 1989 11 30 52 * 53 * 54 * I found an error in the table. The same error is found in the SunOS 4.1.1 55 * version of bcd. It has apparently been around a long time. The error caused 56 * 'Q' and 'R' to have the same punch code. I only noticed the error due to 57 * someone pointing it out to me when the program was used to print a cover 58 * for an APA! The table was wrong in 4 places. The other error was masked 59 * by the fact that the input is converted to upper case before lookup. 60 * 61 * Dyane Bruce 62 * db@diana.ocunix.on.ca 63 * Nov 5, 1993 64 */ 65 66 #include <err.h> 67 #include <ctype.h> 68 #include <stdio.h> 69 #include <string.h> 70 #include <unistd.h> 71 72 u_short holes[256] = { 73 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 74 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 75 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 76 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 77 0x0, 0x206, 0x20a, 0x042, 0x442, 0x222, 0x800, 0x406, 78 0x812, 0x412, 0x422, 0xa00, 0x242, 0x400, 0x842, 0x300, 79 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 80 0x002, 0x001, 0x012, 0x40a, 0x80a, 0x212, 0x00a, 0x006, 81 0x022, 0x900, 0x880, 0x840, 0x820, 0x810, 0x808, 0x804, 82 0x802, 0x801, 0x500, 0x480, 0x440, 0x420, 0x410, 0x408, 83 0x404, 0x402, 0x401, 0x280, 0x240, 0x220, 0x210, 0x208, 84 0x204, 0x202, 0x201, 0x082, 0x806, 0x822, 0x600, 0x282, 85 0x022, 0x900, 0x880, 0x840, 0x820, 0x810, 0x808, 0x804, 86 0x802, 0x801, 0x500, 0x480, 0x440, 0x420, 0x410, 0x408, 87 0x404, 0x402, 0x401, 0x280, 0x240, 0x220, 0x210, 0x208, 88 0x204, 0x202, 0x201, 0x082, 0x806, 0x822, 0x600, 0x282, 89 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 90 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 91 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 92 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 93 0x0, 0x206, 0x20a, 0x042, 0x442, 0x222, 0x800, 0x406, 94 0x812, 0x412, 0x422, 0xa00, 0x242, 0x400, 0x842, 0x300, 95 0x200, 0x100, 0x080, 0x040, 0x020, 0x010, 0x008, 0x004, 96 0x002, 0x001, 0x012, 0x40a, 0x80a, 0x212, 0x00a, 0x006, 97 0x022, 0x900, 0x880, 0x840, 0x820, 0x810, 0x808, 0x804, 98 0x802, 0x801, 0x500, 0x480, 0x440, 0x420, 0x410, 0x408, 99 0x404, 0x402, 0x401, 0x280, 0x240, 0x220, 0x210, 0x208, 100 0x204, 0x202, 0x201, 0x082, 0x806, 0x822, 0x600, 0x282, 101 0x022, 0x900, 0x880, 0x840, 0x820, 0x810, 0x808, 0x804, 102 0x802, 0x801, 0x500, 0x480, 0x440, 0x420, 0x410, 0x408, 103 0x404, 0x402, 0x401, 0x280, 0x240, 0x220, 0x210, 0x208, 104 0x204, 0x202, 0x201, 0x082, 0x806, 0x822, 0x600, 0x282, 105 }; 106 107 /* 108 * i'th bit of w. 109 */ 110 #define bit(w,i) ((w)&(1<<(i))) 111 112 void printonecard(char *, size_t); 113 void printcard(char *); 114 int decode(char *buf); 115 116 int columns = 48; 117 118 int 119 main(int argc, char *argv[]) 120 { 121 char cardline[1024]; 122 extern char *__progname; 123 int dflag = 0; 124 int ch; 125 126 if (pledge("stdio", NULL) == -1) 127 err(1, "pledge"); 128 129 while ((ch = getopt(argc, argv, "dl")) != -1) { 130 switch (ch) { 131 case 'd': 132 dflag = 1; 133 break; 134 case 'l': 135 columns = 80; 136 break; 137 default: 138 fprintf(stderr, "usage: %s [-l] [string ...]\n", 139 __progname); 140 fprintf(stderr, "usage: %s -d [-l]\n", __progname); 141 return 1; 142 } 143 } 144 argc -= optind; 145 argv += optind; 146 147 if (dflag) { 148 while (decode(cardline) == 0) { 149 printf("%s\n", cardline); 150 } 151 return 0; 152 } 153 154 155 /* 156 * The original bcd prompts with a "%" when reading from stdin, 157 * but this seems kind of silly. So this one doesn't. 158 */ 159 if (argc > 0) { 160 while (argc--) { 161 printcard(*argv); 162 argv++; 163 } 164 } else { 165 while (fgets(cardline, sizeof(cardline), stdin)) 166 printcard(cardline); 167 } 168 return 0; 169 } 170 171 void 172 printcard(char *str) 173 { 174 size_t len = strlen(str); 175 176 while (len > 0) { 177 size_t amt = len > columns ? columns : len; 178 printonecard(str, amt); 179 str += amt; 180 len -= amt; 181 } 182 } 183 184 void 185 printonecard(char *str, size_t len) 186 { 187 static const char rowchars[] = " 123456789"; 188 int i, row; 189 char *p, *end; 190 191 end = str + len; 192 193 /* make string upper case. */ 194 for (p = str; p < end; ++p) 195 *p = toupper((unsigned char)*p); 196 197 /* top of card */ 198 putchar(' '); 199 for (i = 1; i <= columns; ++i) 200 putchar('_'); 201 putchar('\n'); 202 203 /* 204 * line of text. Leave a blank if the character doesn't have 205 * a hole pattern. 206 */ 207 p = str; 208 putchar('/'); 209 for (i = 1; p < end; i++, p++) 210 if (holes[(unsigned char)*p]) 211 putchar(*p); 212 else 213 putchar(' '); 214 while (i++ <= columns) 215 putchar(' '); 216 putchar('|'); 217 putchar('\n'); 218 219 /* 220 * 12 rows of potential holes; output a ']', which looks kind of 221 * like a hole, if the appropriate bit is set in the holes[] table. 222 * The original bcd output a '[', a backspace, five control A's, 223 * and then a ']'. This seems a little excessive. 224 */ 225 for (row = 0; row <= 11; ++row) { 226 putchar('|'); 227 for (i = 0, p = str; p < end; i++, p++) { 228 if (bit(holes[(unsigned char)*p], 11 - row)) 229 putchar(']'); 230 else 231 putchar(rowchars[row]); 232 } 233 while (i++ < columns) 234 putchar(rowchars[row]); 235 putchar('|'); 236 putchar('\n'); 237 } 238 239 /* bottom of card */ 240 putchar('|'); 241 for (i = 1; i <= columns; i++) 242 putchar('_'); 243 putchar('|'); 244 putchar('\n'); 245 } 246 247 #define LINES 12 248 249 int 250 decode(char *buf) 251 { 252 int col, i; 253 char lines[LINES][1024]; 254 char tmp[1024]; 255 256 /* top of card; if missing signal no more input */ 257 if (fgets(tmp, sizeof(tmp), stdin) == NULL) 258 return 1; 259 /* text line, ignored */ 260 if (fgets(tmp, sizeof(tmp), stdin) == NULL) 261 return -1; 262 /* twelve lines of data */ 263 for (i = 0; i < LINES; i++) 264 if (fgets(lines[i], sizeof(lines[i]), stdin) == NULL) 265 return -1; 266 /* bottom of card */ 267 if (fgets(tmp, sizeof(tmp), stdin) == NULL) 268 return -1; 269 270 for (i = 0; i < LINES; i++) { 271 if (strlen(lines[i]) < columns + 2) 272 return -1; 273 if (lines[i][0] != '|' || lines[i][columns + 1] != '|') 274 return -1; 275 memmove(&lines[i][0], &lines[i][1], columns); 276 lines[i][columns] = 0; 277 } 278 for (col = 0; col < columns; col++) { 279 unsigned int val = 0; 280 for (i = 0; i < LINES; i++) 281 if (lines[i][col] == ']') 282 val |= 1 << (11 - i); 283 buf[col] = ' '; 284 for (i = 0; i < 256; i++) 285 if (holes[i] == val && holes[i]) { 286 buf[col] = i; 287 break; 288 } 289 } 290 buf[col] = 0; 291 for (col = columns - 1; col >= 0; col--) { 292 if (buf[col] == ' ') 293 buf[col] = '\0'; 294 else 295 break; 296 } 297 return 0; 298 } 299