xref: /original-bsd/games/caesar/caesar.c (revision 21b9697b)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Adams.
7  *
8  * Authors:
9  *	Stan King, John Eldridge, based on algorithm suggested by
10  *	Bob Morris
11  * 29-Sep-82
12  *
13  * Redistribution and use in source and binary forms are permitted
14  * provided that the above copyright notice and this paragraph are
15  * duplicated in all such forms and that any documentation,
16  * advertising materials, and other materials related to such
17  * distribution and use acknowledge that the software was developed
18  * by the University of California, Berkeley.  The name of the
19  * University may not be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24  */
25 
26 #ifndef lint
27 char copyright[] =
28 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
29  All rights reserved.\n";
30 #endif /* not lint */
31 
32 #ifndef lint
33 static char sccsid[] = "@(#)caesar.c	5.3 (Berkeley) 09/05/89";
34 #endif /* not lint */
35 
36 #include <math.h>
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <unistd.h>
40 
41 #define	LINELENGTH	2048
42 #define	ROTATE(ch, perm) \
43 	isupper(ch) ? ('A' + (ch - 'A' + perm) % 26) : \
44 	    islower(ch) ? ('a' + (ch - 'a' + perm) % 26) : ch
45 
46 /*
47  * letter frequencies (taken from some unix(tm) documentation)
48  * (unix is a trademark of Bell Laboratories)
49  */
50 double stdf[26] = {
51 	7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, 6.39, 0.04,
52 	0.42, 3.81, 2.69, 5.92,  6.96, 2.91, 0.08, 6.63, 8.77, 9.68,
53 	2.62, 0.81, 1.88, 0.23,  2.07, 0.06,
54 };
55 
56 main(argc, argv)
57 	int argc;
58 	char **argv;
59 {
60 	extern int errno;
61 	register int ch, dot, i, nread, winnerdot;
62 	register char *inbuf;
63 	int obs[26], try, winner;
64 	char *malloc(), *strerror();
65 
66 	if (argc > 1)
67 		printit(argv[1]);
68 
69 	if (!(inbuf = malloc(LINELENGTH))) {
70 		(void)fprintf(stderr, "caesar: out of memory.\n");
71 		exit(1);
72 	}
73 
74 	/* adjust frequency table to weight low probs REAL low */
75 	for (i = 0; i < 26; ++i)
76 		stdf[i] = log(stdf[i]) + log(26.0 / 100.0);
77 
78 	/* zero out observation table */
79 	bzero(obs, 26 * sizeof(int));
80 
81 	if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) {
82 		(void)fprintf(stderr, "caesar: %s\n", strerror(errno));
83 		exit(1);
84 	}
85 	for (i = nread; i--;) {
86 		ch = inbuf[i];
87 		if (islower(ch))
88 			++obs[ch - 'a'];
89 		else if (isupper(ch))
90 			++obs[ch - 'A'];
91 	}
92 
93 	/*
94 	 * now "dot" the freqs with the observed letter freqs
95 	 * and keep track of best fit
96 	 */
97 	for (try = winner = 0; try < 26; ++try) { /* += 13) { */
98 		dot = 0;
99 		for (i = 0; i < 26; i++)
100 			dot += obs[i] * stdf[(i + try) % 26];
101 		/* initialize winning score */
102 		if (try == 0)
103 			winnerdot = dot;
104 		if (dot > winnerdot) {
105 			/* got a new winner! */
106 			winner = try;
107 			winnerdot = dot;
108 		}
109 	}
110 
111 	for (;;) {
112 		for (i = 0; i < nread; ++i) {
113 			ch = inbuf[i];
114 			putchar(ROTATE(ch, winner));
115 		}
116 		if (nread < LINELENGTH)
117 			break;
118 		if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) {
119 			(void)fprintf(stderr, "caesar: %s\n", strerror(errno));
120 			exit(1);
121 		}
122 	}
123 	exit(0);
124 }
125 
126 printit(arg)
127 	char *arg;
128 {
129 	register int ch, rot;
130 
131 	if ((rot = atoi(arg)) < 0) {
132 		(void)fprintf(stderr, "caesar: bad rotation value.\n");
133 		exit(1);
134 	}
135 	while ((ch = getchar()) != EOF)
136 		putchar(ROTATE(ch, rot));
137 	exit(0);
138 }
139