caesar.c revision 1.18 1 1.18 rillig /* $NetBSD: caesar.c,v 1.18 2005/10/08 18:18:18 rillig Exp $ */
2 1.3 cgd
3 1.1 cgd /*
4 1.3 cgd * Copyright (c) 1989, 1993
5 1.3 cgd * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * This code is derived from software contributed to Berkeley by
8 1.1 cgd * Rick Adams.
9 1.1 cgd *
10 1.1 cgd * Authors:
11 1.1 cgd * Stan King, John Eldridge, based on algorithm suggested by
12 1.1 cgd * Bob Morris
13 1.1 cgd * 29-Sep-82
14 1.15 rillig * Roland Illig, 2005
15 1.1 cgd *
16 1.1 cgd * Redistribution and use in source and binary forms, with or without
17 1.1 cgd * modification, are permitted provided that the following conditions
18 1.1 cgd * are met:
19 1.1 cgd * 1. Redistributions of source code must retain the above copyright
20 1.1 cgd * notice, this list of conditions and the following disclaimer.
21 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
22 1.1 cgd * notice, this list of conditions and the following disclaimer in the
23 1.1 cgd * documentation and/or other materials provided with the distribution.
24 1.12 agc * 3. Neither the name of the University nor the names of its contributors
25 1.1 cgd * may be used to endorse or promote products derived from this software
26 1.1 cgd * without specific prior written permission.
27 1.1 cgd *
28 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 1.1 cgd * SUCH DAMAGE.
39 1.1 cgd */
40 1.1 cgd
41 1.5 lukem #include <sys/cdefs.h>
42 1.1 cgd #ifndef lint
43 1.5 lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
44 1.5 lukem The Regents of the University of California. All rights reserved.\n");
45 1.1 cgd #endif /* not lint */
46 1.1 cgd
47 1.1 cgd #ifndef lint
48 1.3 cgd #if 0
49 1.3 cgd static char sccsid[] = "@(#)caesar.c 8.1 (Berkeley) 5/31/93";
50 1.3 cgd #else
51 1.18 rillig __RCSID("$NetBSD: caesar.c,v 1.18 2005/10/08 18:18:18 rillig Exp $");
52 1.3 cgd #endif
53 1.1 cgd #endif /* not lint */
54 1.1 cgd
55 1.5 lukem #include <ctype.h>
56 1.6 lukem #include <err.h>
57 1.5 lukem #include <errno.h>
58 1.15 rillig #include <limits.h>
59 1.1 cgd #include <math.h>
60 1.1 cgd #include <stdio.h>
61 1.5 lukem #include <string.h>
62 1.5 lukem #include <stdlib.h>
63 1.1 cgd
64 1.15 rillig #define NCHARS (1 << CHAR_BIT)
65 1.15 rillig #define LETTERS (26)
66 1.1 cgd
67 1.1 cgd /*
68 1.1 cgd * letter frequencies (taken from some unix(tm) documentation)
69 1.1 cgd * (unix is a trademark of Bell Laboratories)
70 1.1 cgd */
71 1.15 rillig static const unsigned char upper[LETTERS] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
72 1.15 rillig static const unsigned char lower[LETTERS] = "abcdefghijklmnopqrstuvwxyz";
73 1.15 rillig static double stdf[LETTERS] = {
74 1.1 cgd 7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, 6.39, 0.04,
75 1.1 cgd 0.42, 3.81, 2.69, 5.92, 6.96, 2.91, 0.08, 6.63, 8.77, 9.68,
76 1.15 rillig 2.62, 0.81, 1.88, 0.23, 2.07, 0.06
77 1.1 cgd };
78 1.1 cgd
79 1.15 rillig static unsigned char rottbl[NCHARS];
80 1.5 lukem
81 1.15 rillig
82 1.15 rillig static void
83 1.15 rillig init_rottbl(int rot)
84 1.15 rillig {
85 1.15 rillig size_t i;
86 1.15 rillig
87 1.16 rillig rot %= LETTERS; /* prevent integer overflow */
88 1.15 rillig
89 1.15 rillig for (i = 0; i < NCHARS; i++)
90 1.15 rillig rottbl[i] = (unsigned char)i;
91 1.15 rillig
92 1.15 rillig for (i = 0; i < LETTERS; i++)
93 1.15 rillig rottbl[upper[i]] = upper[(i + rot) % LETTERS];
94 1.15 rillig
95 1.15 rillig for (i = 0; i < LETTERS; i++)
96 1.15 rillig rottbl[lower[i]] = lower[(i + rot) % LETTERS];
97 1.15 rillig }
98 1.15 rillig
99 1.16 rillig static void
100 1.16 rillig print_file(void)
101 1.15 rillig {
102 1.15 rillig int ch;
103 1.16 rillig
104 1.16 rillig while ((ch = getchar()) != EOF) {
105 1.16 rillig if (putchar(rottbl[ch]) == EOF) {
106 1.16 rillig err(EXIT_FAILURE, "<stdout>");
107 1.16 rillig /* NOTREACHED */
108 1.16 rillig }
109 1.16 rillig }
110 1.16 rillig }
111 1.16 rillig
112 1.16 rillig static void
113 1.16 rillig print_array(const unsigned char *a, size_t len)
114 1.16 rillig {
115 1.16 rillig size_t i;
116 1.16 rillig
117 1.16 rillig for (i = 0; i < len; i++) {
118 1.16 rillig if (putchar(rottbl[a[i]]) == EOF) {
119 1.16 rillig err(EXIT_FAILURE, "<stdout>");
120 1.16 rillig /* NOTREACHED */
121 1.16 rillig }
122 1.16 rillig }
123 1.16 rillig }
124 1.16 rillig
125 1.16 rillig static int
126 1.16 rillig get_rotation(const char *arg)
127 1.16 rillig {
128 1.15 rillig long rot;
129 1.15 rillig char *endp;
130 1.15 rillig
131 1.15 rillig errno = 0;
132 1.15 rillig rot = strtol(arg, &endp, 10);
133 1.16 rillig if (!(errno == 0 && *endp == '\0' && 0 <= rot && rot <= INT_MAX)) {
134 1.15 rillig errx(EXIT_FAILURE, "bad rotation value: %s", arg);
135 1.15 rillig /* NOTREACHED */
136 1.15 rillig }
137 1.16 rillig return (int) rot;
138 1.15 rillig }
139 1.5 lukem
140 1.16 rillig static void
141 1.16 rillig guess_and_rotate(void)
142 1.1 cgd {
143 1.16 rillig unsigned char inbuf[2048];
144 1.16 rillig unsigned int obs[NCHARS];
145 1.16 rillig size_t i, nread;
146 1.13 jsm double dot, winnerdot;
147 1.15 rillig int try, winner;
148 1.16 rillig int ch;
149 1.1 cgd
150 1.1 cgd /* adjust frequency table to weight low probs REAL low */
151 1.15 rillig for (i = 0; i < LETTERS; i++)
152 1.15 rillig stdf[i] = log(stdf[i]) + log(LETTERS / 100.0);
153 1.1 cgd
154 1.1 cgd /* zero out observation table */
155 1.15 rillig (void)memset(obs, 0, sizeof(obs));
156 1.1 cgd
157 1.16 rillig for (nread = 0; nread < sizeof(inbuf); nread++) {
158 1.16 rillig if ((ch = getchar()) == EOF)
159 1.15 rillig break;
160 1.16 rillig inbuf[nread] = (unsigned char) ch;
161 1.1 cgd }
162 1.1 cgd
163 1.16 rillig for (i = 0; i < nread; i++)
164 1.15 rillig obs[inbuf[i]]++;
165 1.15 rillig
166 1.1 cgd /*
167 1.1 cgd * now "dot" the freqs with the observed letter freqs
168 1.1 cgd * and keep track of best fit
169 1.1 cgd */
170 1.15 rillig winner = 0;
171 1.15 rillig winnerdot = 0.0;
172 1.15 rillig for (try = 0; try < LETTERS; try++) {
173 1.15 rillig dot = 0.0;
174 1.15 rillig for (i = 0; i < LETTERS; i++)
175 1.15 rillig dot += (obs[upper[i]] + obs[lower[i]])
176 1.15 rillig * stdf[(i + try) % LETTERS];
177 1.15 rillig
178 1.15 rillig if (try == 0 || dot > winnerdot) {
179 1.1 cgd /* got a new winner! */
180 1.1 cgd winner = try;
181 1.1 cgd winnerdot = dot;
182 1.1 cgd }
183 1.1 cgd }
184 1.16 rillig
185 1.15 rillig init_rottbl(winner);
186 1.16 rillig print_array(inbuf, nread);
187 1.16 rillig print_file();
188 1.16 rillig }
189 1.1 cgd
190 1.16 rillig int
191 1.16 rillig main(int argc, char **argv)
192 1.16 rillig {
193 1.18 rillig
194 1.16 rillig if (argc == 1) {
195 1.16 rillig guess_and_rotate();
196 1.16 rillig } else if (argc == 2) {
197 1.16 rillig init_rottbl(get_rotation(argv[1]));
198 1.16 rillig print_file();
199 1.16 rillig } else {
200 1.17 rillig (void)fprintf(stderr, "usage: caesar [rotation]\n");
201 1.16 rillig exit(EXIT_FAILURE);
202 1.16 rillig /* NOTREACHED */
203 1.16 rillig }
204 1.16 rillig
205 1.16 rillig if (ferror(stdin)) {
206 1.16 rillig errx(EXIT_FAILURE, "<stdin>");
207 1.16 rillig /* NOTREACHED */
208 1.16 rillig }
209 1.16 rillig
210 1.16 rillig (void)fflush(stdout);
211 1.16 rillig if (ferror(stdout)) {
212 1.16 rillig err(EXIT_FAILURE, "<stdout>");
213 1.16 rillig /* NOTREACHED */
214 1.1 cgd }
215 1.16 rillig
216 1.16 rillig return 0;
217 1.1 cgd }
218