1/*	$NetBSD: bcd.c,v 1.16 2009/07/26 03:02:38 dholland Exp $	*/
2
3/*
4 * Copyright (c) 1989, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Steve Hayman of the Indiana University Computer Science Dept.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36#ifndef lint
37__COPYRIGHT("@(#) Copyright (c) 1989, 1993\
38 The Regents of the University of California.  All rights reserved.");
39#endif /* not lint */
40
41#ifndef lint
42#if 0
43static char sccsid[] = "@(#)bcd.c	8.2 (Berkeley) 3/20/94";
44#else
45__RCSID("$NetBSD: bcd.c,v 1.16 2009/07/26 03:02:38 dholland Exp $");
46#endif
47#endif /* not lint */
48
49/*
50 * bcd --
51 *
52 * Read one line of standard input and produce something that looks like a
53 * punch card.  An attempt to reimplement /usr/games/bcd.  All I looked at
54 * was the man page.
55 *
56 * I couldn't find a BCD table handy so I wrote a shell script to deduce what
57 * the patterns were that the old bcd was using for each possible 8-bit
58 * character.  These are the results -- the low order 12 bits represent the
59 * holes.  (A 1 bit is a hole.)  These may be wrong, but they match the old
60 * program!
61 *
62 * Steve Hayman
63 * sahayman@iuvax.cs.indiana.edu
64 * 1989 11 30
65 *
66 *
67 * I found an error in the table. The same error is found in the SunOS 4.1.1
68 * version of bcd. It has apparently been around a long time. The error caused
69 * 'Q' and 'R' to have the same punch code. I only noticed the error due to
70 * someone pointing it out to me when the program was used to print a cover
71 * for an APA!  The table was wrong in 4 places. The other error was masked
72 * by the fact that the input is converted to upper case before lookup.
73 *
74 * Dyane Bruce
75 * db@diana.ocunix.on.ca
76 * Nov 5, 1993
77 */
78
79#include <sys/types.h>
80
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <ctype.h>
85#include <unistd.h>
86
87static const u_short holes[256] = {
88    0x0,	 0x0,	  0x0,	   0x0,	    0x0,     0x0,     0x0,     0x0,
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,	 0x206,	  0x20a,   0x042,   0x442,   0x222,   0x800,   0x406,
93    0x812,	 0x412,	  0x422,   0xa00,   0x242,   0x400,   0x842,   0x300,
94    0x200,	 0x100,	  0x080,   0x040,   0x020,   0x010,   0x008,   0x004,
95    0x002,	 0x001,	  0x012,   0x40a,   0x80a,   0x212,   0x00a,   0x006,
96    0x022,	 0x900,	  0x880,   0x840,   0x820,   0x810,   0x808,   0x804,
97    0x802,	 0x801,	  0x500,   0x480,   0x440,   0x420,   0x410,   0x408,
98    0x404,	 0x402,	  0x401,   0x280,   0x240,   0x220,   0x210,   0x208,
99    0x204,	 0x202,	  0x201,   0x082,   0x822,   0x600,   0x282,   0x30f,
100    0x900,	 0x880,	  0x840,   0x820,   0x810,   0x808,   0x804,   0x802,
101    0x801,	 0x500,	  0x480,   0x440,   0x420,   0x410,   0x408,   0x404,
102    0x402,	 0x401,	  0x280,   0x240,   0x220,   0x210,   0x208,   0x204,
103    0x202,	 0x201,	  0x082,   0x806,   0x822,   0x600,   0x282,   0x0,
104    0x0,	 0x0,	  0x0,	   0x0,	    0x0,     0x0,     0x0,     0x0,
105    0x0,	 0x0,	  0x0,	   0x0,	    0x0,     0x0,     0x0,     0x0,
106    0x0,	 0x0,	  0x0,	   0x0,	    0x0,     0x0,     0x0,     0x0,
107    0x0,	 0x0,	  0x0,	   0x0,	    0x0,     0x0,     0x0,     0x0,
108    0x206,	 0x20a,	  0x042,   0x442,   0x222,   0x800,   0x406,   0x812,
109    0x412,	 0x422,	  0xa00,   0x242,   0x400,   0x842,   0x300,   0x200,
110    0x100,	 0x080,	  0x040,   0x020,   0x010,   0x008,   0x004,   0x002,
111    0x001,	 0x012,	  0x40a,   0x80a,   0x212,   0x00a,   0x006,   0x022,
112    0x900,	 0x880,	  0x840,   0x820,   0x810,   0x808,   0x804,   0x802,
113    0x801,	 0x500,	  0x480,   0x440,   0x420,   0x410,   0x408,   0x404,
114    0x402,	 0x401,	  0x280,   0x240,   0x220,   0x210,   0x208,   0x204,
115    0x202,	 0x201,	  0x082,   0x806,   0x822,   0x600,   0x282,   0x30f,
116    0x900,	 0x880,	  0x840,   0x820,   0x810,   0x808,   0x804,   0x802,
117    0x801,	 0x500,	  0x480,   0x440,   0x420,   0x410,   0x408,   0x404,
118    0x402,	 0x401,	  0x280,   0x240,   0x220,   0x210,   0x208,   0x204,
119    0x202,	 0x201,	  0x082,   0x806,   0x822,   0x600,   0x282,   0x0
120};
121
122/*
123 * i'th bit of w.
124 */
125#define	bit(w,i)	((w)&(1<<(i)))
126
127static void printcard(char *);
128
129int
130main(int argc, char **argv)
131{
132	char cardline[80];
133
134	/* revoke setgid privileges */
135	setgid(getgid());
136
137	/*
138	 * The original bcd prompts with a "%" when reading from stdin,
139	 * but this seems kind of silly.  So this one doesn't.
140	 */
141
142	if (argc > 1) {
143		while (--argc)
144			printcard(*++argv);
145	} else
146		while (fgets(cardline, sizeof(cardline), stdin))
147			printcard(cardline);
148	exit(0);
149}
150
151#define	COLUMNS	48
152
153static void
154printcard(char *str)
155{
156	static const char rowchars[] = "   123456789";
157	int i, row;
158	char *p;
159
160	/* ruthlessly remove newlines and truncate at 48 characters. */
161	if ((p = strchr(str, '\n')))
162		*p = '\0';
163
164	if (strlen(str) > COLUMNS)
165		str[COLUMNS] = '\0';
166
167	/* make string upper case. */
168	for (p = str; *p; ++p)
169		if (isascii((unsigned char)*p) && islower((unsigned char)*p))
170			*p = toupper((unsigned char) *p);
171
172	 /* top of card */
173	putchar(' ');
174	for (i = 1; i <= COLUMNS; ++i)
175		putchar('_');
176	putchar('\n');
177
178	/*
179	 * line of text.  Leave a blank if the character doesn't have
180	 * a hole pattern.
181	 */
182	p = str;
183	putchar('/');
184	for (i = 1; *p; i++, p++)
185		if (holes[(unsigned char)*p])
186			putchar(*p);
187		else
188			putchar(' ');
189	while (i++ <= COLUMNS)
190		putchar(' ');
191	putchar('|');
192	putchar('\n');
193
194	/*
195	 * 12 rows of potential holes; output a ']', which looks kind of
196	 * like a hole, if the appropriate bit is set in the holes[] table.
197	 * The original bcd output a '[', a backspace, five control A's,
198	 * and then a ']'.  This seems a little excessive.
199	 */
200	for (row = 0; row <= 11; ++row) {
201		putchar('|');
202		for (i = 0, p = str; *p; i++, p++) {
203			if (bit(holes[(unsigned char)*p], 11 - row))
204				putchar(']');
205			else
206				putchar(rowchars[row]);
207		}
208		while (i++ < COLUMNS)
209			putchar(rowchars[row]);
210		putchar('|');
211		putchar('\n');
212	}
213
214	/* bottom of card */
215	putchar('|');
216	for (i = 1; i <= COLUMNS; i++)
217		putchar('_');
218	putchar('|');
219	putchar('\n');
220}
221