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