xref: /openbsd/games/bcd/bcd.c (revision cca36db2)
1 /*	$OpenBSD: bcd.c,v 1.13 2009/10/27 23:59:24 deraadt 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 <sys/types.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <ctype.h>
71 #include <unistd.h>
72 
73 u_short holes[256] = {
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,	 0x0,	  0x0,	   0x0,	    0x0,     0x0,     0x0,     0x0,
78     0x0,	 0x206,	  0x20a,   0x042,   0x442,   0x222,   0x800,   0x406,
79     0x812,	 0x412,	  0x422,   0xa00,   0x242,   0x400,   0x842,   0x300,
80     0x200,	 0x100,	  0x080,   0x040,   0x020,   0x010,   0x008,   0x004,
81     0x002,	 0x001,	  0x012,   0x40a,   0x80a,   0x212,   0x00a,   0x006,
82     0x022,	 0x900,	  0x880,   0x840,   0x820,   0x810,   0x808,   0x804,
83     0x802,	 0x801,	  0x500,   0x480,   0x440,   0x420,   0x410,   0x408,
84     0x404,	 0x402,	  0x401,   0x280,   0x240,   0x220,   0x210,   0x208,
85     0x204,	 0x202,	  0x201,   0x082,   0x822,   0x600,   0x282,   0x30f,
86     0x900,	 0x880,	  0x840,   0x820,   0x810,   0x808,   0x804,   0x802,
87     0x801,	 0x500,	  0x480,   0x440,   0x420,   0x410,   0x408,   0x404,
88     0x402,	 0x401,	  0x280,   0x240,   0x220,   0x210,   0x208,   0x204,
89     0x202,	 0x201,	  0x082,   0x806,   0x822,   0x600,   0x282,   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,	 0x0,	  0x0,	   0x0,	    0x0,     0x0,     0x0,     0x0,
94     0x206,	 0x20a,	  0x042,   0x442,   0x222,   0x800,   0x406,   0x812,
95     0x412,	 0x422,	  0xa00,   0x242,   0x400,   0x842,   0x300,   0x200,
96     0x100,	 0x080,	  0x040,   0x020,   0x010,   0x008,   0x004,   0x002,
97     0x001,	 0x012,	  0x40a,   0x80a,   0x212,   0x00a,   0x006,   0x022,
98     0x900,	 0x880,	  0x840,   0x820,   0x810,   0x808,   0x804,   0x802,
99     0x801,	 0x500,	  0x480,   0x440,   0x420,   0x410,   0x408,   0x404,
100     0x402,	 0x401,	  0x280,   0x240,   0x220,   0x210,   0x208,   0x204,
101     0x202,	 0x201,	  0x082,   0x806,   0x822,   0x600,   0x282,   0x30f,
102     0x900,	 0x880,	  0x840,   0x820,   0x810,   0x808,   0x804,   0x802,
103     0x801,	 0x500,	  0x480,   0x440,   0x420,   0x410,   0x408,   0x404,
104     0x402,	 0x401,	  0x280,   0x240,   0x220,   0x210,   0x208,   0x204,
105     0x202,	 0x201,	  0x082,   0x806,   0x822,   0x600,   0x282,   0x0
106 };
107 
108 /*
109  * i'th bit of w.
110  */
111 #define	bit(w,i)	((w)&(1<<(i)))
112 
113 void	printcard(char *);
114 
115 int
116 main(int argc, char *argv[])
117 {
118 	char cardline[80];
119 
120 	/*
121 	 * The original bcd prompts with a "%" when reading from stdin,
122 	 * but this seems kind of silly.  So this one doesn't.
123 	 */
124 
125 	if (argc > 1) {
126 		while (--argc)
127 			printcard(*++argv);
128 	} else
129 		while (fgets(cardline, sizeof(cardline), stdin))
130 			printcard(cardline);
131 	exit(0);
132 }
133 
134 #define	COLUMNS	48
135 
136 void
137 printcard(char *str)
138 {
139 	static const char rowchars[] = "   123456789";
140 	int	i, row;
141 	char	*p;
142 
143 	/* ruthlessly remove newlines and truncate at 48 characters. */
144 	str[strcspn(str, "\n")] = '\0';
145 
146 	if (strlen(str) > COLUMNS)
147 		str[COLUMNS] = '\0';
148 
149 	/* make string upper case. */
150 	for (p = str; *p; ++p)
151 		if (isascii(*p) && islower(*p))
152 			*p = toupper(*p);
153 
154 	 /* top of card */
155 	putchar(' ');
156 	for (i = 1; i <= COLUMNS; ++i)
157 		putchar('_');
158 	putchar('\n');
159 
160 	/*
161 	 * line of text.  Leave a blank if the character doesn't have
162 	 * a hole pattern.
163 	 */
164 	p = str;
165 	putchar('/');
166 	for (i = 1; *p; i++, p++)
167 		if (holes[(int)*p])
168 			putchar(*p);
169 		else
170 			putchar(' ');
171 	while (i++ <= COLUMNS)
172 		putchar(' ');
173 	putchar('|');
174 	putchar('\n');
175 
176 	/*
177 	 * 12 rows of potential holes; output a ']', which looks kind of
178 	 * like a hole, if the appropriate bit is set in the holes[] table.
179 	 * The original bcd output a '[', a backspace, five control A's,
180 	 * and then a ']'.  This seems a little excessive.
181 	 */
182 	for (row = 0; row <= 11; ++row) {
183 		putchar('|');
184 		for (i = 0, p = str; *p; i++, p++) {
185 			if (bit(holes[(int)*p], 11 - row))
186 				putchar(']');
187 			else
188 				putchar(rowchars[row]);
189 		}
190 		while (i++ < COLUMNS)
191 			putchar(rowchars[row]);
192 		putchar('|');
193 		putchar('\n');
194 	}
195 
196 	/* bottom of card */
197 	putchar('|');
198 	for (i = 1; i <= COLUMNS; i++)
199 		putchar('_');
200 	putchar('|');
201 	putchar('\n');
202 }
203