xref: /openbsd-src/games/bcd/bcd.c (revision c60fd96debf7bbccf863fc27c3aa05452a41feaf)
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