caesar.c revision 1.24 1 1.24 rillig /* $NetBSD: caesar.c,v 1.24 2021/11/16 20:42:47 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.22 lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993\
44 1.22 lukem The Regents of the University of California. All rights reserved.");
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.24 rillig __RCSID("$NetBSD: caesar.c,v 1.24 2021/11/16 20:42:47 rillig Exp $");
52 1.3 cgd #endif
53 1.1 cgd #endif /* not lint */
54 1.1 cgd
55 1.6 lukem #include <err.h>
56 1.5 lukem #include <errno.h>
57 1.15 rillig #include <limits.h>
58 1.1 cgd #include <math.h>
59 1.1 cgd #include <stdio.h>
60 1.5 lukem #include <string.h>
61 1.5 lukem #include <stdlib.h>
62 1.1 cgd
63 1.15 rillig #define NCHARS (1 << CHAR_BIT)
64 1.15 rillig #define LETTERS (26)
65 1.1 cgd
66 1.1 cgd /*
67 1.1 cgd * letter frequencies (taken from some unix(tm) documentation)
68 1.1 cgd * (unix is a trademark of Bell Laboratories)
69 1.1 cgd */
70 1.15 rillig static const unsigned char upper[LETTERS] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
71 1.15 rillig static const unsigned char lower[LETTERS] = "abcdefghijklmnopqrstuvwxyz";
72 1.15 rillig static double stdf[LETTERS] = {
73 1.1 cgd 7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, 6.39, 0.04,
74 1.1 cgd 0.42, 3.81, 2.69, 5.92, 6.96, 2.91, 0.08, 6.63, 8.77, 9.68,
75 1.15 rillig 2.62, 0.81, 1.88, 0.23, 2.07, 0.06
76 1.1 cgd };
77 1.1 cgd
78 1.15 rillig static unsigned char rottbl[NCHARS];
79 1.5 lukem
80 1.15 rillig
81 1.15 rillig static void
82 1.23 rillig init_rottbl(unsigned int rot)
83 1.15 rillig {
84 1.15 rillig size_t i;
85 1.15 rillig
86 1.16 rillig rot %= LETTERS; /* prevent integer overflow */
87 1.15 rillig
88 1.15 rillig for (i = 0; i < NCHARS; i++)
89 1.15 rillig rottbl[i] = (unsigned char)i;
90 1.15 rillig
91 1.15 rillig for (i = 0; i < LETTERS; i++)
92 1.15 rillig rottbl[upper[i]] = upper[(i + rot) % LETTERS];
93 1.15 rillig
94 1.15 rillig for (i = 0; i < LETTERS; i++)
95 1.15 rillig rottbl[lower[i]] = lower[(i + rot) % LETTERS];
96 1.15 rillig }
97 1.15 rillig
98 1.16 rillig static void
99 1.16 rillig print_file(void)
100 1.15 rillig {
101 1.15 rillig int ch;
102 1.16 rillig
103 1.16 rillig while ((ch = getchar()) != EOF) {
104 1.16 rillig if (putchar(rottbl[ch]) == EOF) {
105 1.16 rillig err(EXIT_FAILURE, "<stdout>");
106 1.16 rillig /* NOTREACHED */
107 1.16 rillig }
108 1.16 rillig }
109 1.16 rillig }
110 1.16 rillig
111 1.16 rillig static void
112 1.16 rillig print_array(const unsigned char *a, size_t len)
113 1.16 rillig {
114 1.16 rillig size_t i;
115 1.16 rillig
116 1.16 rillig for (i = 0; i < len; i++) {
117 1.16 rillig if (putchar(rottbl[a[i]]) == EOF) {
118 1.16 rillig err(EXIT_FAILURE, "<stdout>");
119 1.16 rillig /* NOTREACHED */
120 1.16 rillig }
121 1.16 rillig }
122 1.16 rillig }
123 1.16 rillig
124 1.23 rillig static unsigned int
125 1.16 rillig get_rotation(const char *arg)
126 1.16 rillig {
127 1.15 rillig long rot;
128 1.15 rillig char *endp;
129 1.15 rillig
130 1.15 rillig errno = 0;
131 1.15 rillig rot = strtol(arg, &endp, 10);
132 1.21 christos if (errno == 0 && (arg[0] == '\0' || *endp != '\0'))
133 1.21 christos errno = EINVAL;
134 1.21 christos if (errno == 0 && (rot < 0 || rot > INT_MAX))
135 1.21 christos errno = ERANGE;
136 1.21 christos if (errno)
137 1.21 christos err(EXIT_FAILURE, "Bad rotation value `%s'", arg);
138 1.23 rillig return (unsigned int)rot;
139 1.15 rillig }
140 1.5 lukem
141 1.16 rillig static void
142 1.16 rillig guess_and_rotate(void)
143 1.1 cgd {
144 1.16 rillig unsigned char inbuf[2048];
145 1.16 rillig unsigned int obs[NCHARS];
146 1.16 rillig size_t i, nread;
147 1.13 jsm double dot, winnerdot;
148 1.23 rillig unsigned int try, winner;
149 1.16 rillig int ch;
150 1.1 cgd
151 1.1 cgd /* adjust frequency table to weight low probs REAL low */
152 1.15 rillig for (i = 0; i < LETTERS; i++)
153 1.15 rillig stdf[i] = log(stdf[i]) + log(LETTERS / 100.0);
154 1.1 cgd
155 1.1 cgd /* zero out observation table */
156 1.15 rillig (void)memset(obs, 0, sizeof(obs));
157 1.1 cgd
158 1.16 rillig for (nread = 0; nread < sizeof(inbuf); nread++) {
159 1.16 rillig if ((ch = getchar()) == EOF)
160 1.15 rillig break;
161 1.16 rillig inbuf[nread] = (unsigned char) ch;
162 1.1 cgd }
163 1.1 cgd
164 1.16 rillig for (i = 0; i < nread; i++)
165 1.15 rillig obs[inbuf[i]]++;
166 1.15 rillig
167 1.1 cgd /*
168 1.1 cgd * now "dot" the freqs with the observed letter freqs
169 1.1 cgd * and keep track of best fit
170 1.1 cgd */
171 1.15 rillig winner = 0;
172 1.15 rillig winnerdot = 0.0;
173 1.15 rillig for (try = 0; try < LETTERS; try++) {
174 1.15 rillig dot = 0.0;
175 1.15 rillig for (i = 0; i < LETTERS; i++)
176 1.15 rillig dot += (obs[upper[i]] + obs[lower[i]])
177 1.15 rillig * stdf[(i + try) % LETTERS];
178 1.15 rillig
179 1.15 rillig if (try == 0 || dot > winnerdot) {
180 1.1 cgd /* got a new winner! */
181 1.1 cgd winner = try;
182 1.1 cgd winnerdot = dot;
183 1.1 cgd }
184 1.1 cgd }
185 1.16 rillig
186 1.15 rillig init_rottbl(winner);
187 1.16 rillig print_array(inbuf, nread);
188 1.16 rillig print_file();
189 1.16 rillig }
190 1.1 cgd
191 1.16 rillig int
192 1.16 rillig main(int argc, char **argv)
193 1.16 rillig {
194 1.18 rillig
195 1.16 rillig if (argc == 1) {
196 1.16 rillig guess_and_rotate();
197 1.16 rillig } else if (argc == 2) {
198 1.16 rillig init_rottbl(get_rotation(argv[1]));
199 1.16 rillig print_file();
200 1.16 rillig } else {
201 1.17 rillig (void)fprintf(stderr, "usage: caesar [rotation]\n");
202 1.16 rillig exit(EXIT_FAILURE);
203 1.16 rillig /* NOTREACHED */
204 1.16 rillig }
205 1.16 rillig
206 1.24 rillig if (ferror(stdin) != 0) {
207 1.24 rillig errx(EXIT_FAILURE, "<stdin>: read error");
208 1.16 rillig /* NOTREACHED */
209 1.16 rillig }
210 1.16 rillig
211 1.16 rillig (void)fflush(stdout);
212 1.24 rillig if (ferror(stdout) != 0) {
213 1.24 rillig errx(EXIT_FAILURE, "<stdout>: write error");
214 1.16 rillig /* NOTREACHED */
215 1.1 cgd }
216 1.16 rillig
217 1.16 rillig return 0;
218 1.1 cgd }
219