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