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
main(int argc,char * argv[])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
printcard(char * str)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
printonecard(char * str,size_t len)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
decode(char * buf)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