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