xref: /openbsd-src/games/caesar/caesar.c (revision ab9f6680fc0a599f08d58055c82af817019b03a3)
1*ab9f6680Sschwarze /*	$OpenBSD: caesar.c,v 1.21 2019/05/15 15:59:24 schwarze Exp $	*/
2df930be7Sderaadt 
3df930be7Sderaadt /*
4df930be7Sderaadt  * Copyright (c) 1989, 1993
5df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
6df930be7Sderaadt  *
7df930be7Sderaadt  * This code is derived from software contributed to Berkeley by
8df930be7Sderaadt  * Rick Adams.
9df930be7Sderaadt  *
10df930be7Sderaadt  * Authors:
11df930be7Sderaadt  *	Stan King, John Eldridge, based on algorithm suggested by
12df930be7Sderaadt  *	Bob Morris
13df930be7Sderaadt  * 29-Sep-82
14df930be7Sderaadt  *
15df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
16df930be7Sderaadt  * modification, are permitted provided that the following conditions
17df930be7Sderaadt  * are met:
18df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
19df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
20df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
21df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
22df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
237a09557bSmillert  * 3. Neither the name of the University nor the names of its contributors
24df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
25df930be7Sderaadt  *    without specific prior written permission.
26df930be7Sderaadt  *
27df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df930be7Sderaadt  * SUCH DAMAGE.
38df930be7Sderaadt  */
39df930be7Sderaadt 
40df930be7Sderaadt #include <ctype.h>
41986c0edfSderaadt #include <err.h>
42e0232237Sniklas #include <errno.h>
435dc4a87cSpjanzen #include <math.h>
445dc4a87cSpjanzen #include <stdio.h>
455dc4a87cSpjanzen #include <string.h>
465dc4a87cSpjanzen #include <stdlib.h>
475dc4a87cSpjanzen #include <unistd.h>
48df930be7Sderaadt 
49df930be7Sderaadt #define	LINELENGTH	2048
50df930be7Sderaadt #define	ROTATE(ch, perm) \
51df930be7Sderaadt 	isupper(ch) ? ('A' + (ch - 'A' + perm) % 26) : \
52df930be7Sderaadt 	    islower(ch) ? ('a' + (ch - 'a' + perm) % 26) : ch
53df930be7Sderaadt 
54df930be7Sderaadt /*
555b2e6243Stedu  * letter frequencies
56df930be7Sderaadt  */
57df930be7Sderaadt double stdf[26] = {
585b2e6243Stedu 	8.1, 1.4, 2.7, 3.8, 13.0, 2.9, 2.0, 5.2, 6.3, 0.13,
595b2e6243Stedu 	0.4, 3.4, 2.5, 7.1, 7.9, 1.9, 0.11, 6.8, 6.1, 10.5,
605b2e6243Stedu 	2.4, 0.9, 1.5, 0.15, 1.9, 0.07
61df930be7Sderaadt };
62df930be7Sderaadt 
63b9a3a871Sschwarze __dead void printit(int);
64986c0edfSderaadt 
65986c0edfSderaadt int
main(int argc,char * argv[])66a5ca3416Sderaadt main(int argc, char *argv[])
67df930be7Sderaadt {
6861f9e11aSotto 	int ch, i, nread;
69466e81dfStb 	extern char *__progname;
70dd8b6bb4Smestre 	const char *errstr;
71466e81dfStb 	char *inbuf;
72df930be7Sderaadt 	int obs[26], try, winner;
7361f9e11aSotto 	double dot, winnerdot;
74df930be7Sderaadt 
75673e924cSdoug 	if (pledge("stdio", NULL) == -1)
76673e924cSdoug 		err(1, "pledge");
77673e924cSdoug 
78986c0edfSderaadt 	/* check to see if we were called as rot13 */
79466e81dfStb 	if (strcmp(__progname, "rot13") == 0)
80986c0edfSderaadt 		printit(13);
81986c0edfSderaadt 
825dc4a87cSpjanzen 	if (argc > 1) {
83*ab9f6680Sschwarze 		i = strtonum(argv[1], -25, 25, &errstr);
84dd8b6bb4Smestre 		if (errstr)
85dd8b6bb4Smestre 			errx(1, "rotation is %s: %s", errstr, argv[1]);
865dc4a87cSpjanzen 		else
87dd8b6bb4Smestre 			printit(i);
885dc4a87cSpjanzen 	}
895dc4a87cSpjanzen 
90986c0edfSderaadt 	if (!(inbuf = malloc(LINELENGTH)))
915b71d505Spjanzen 		err(1, NULL);
92986c0edfSderaadt 
93df930be7Sderaadt 	/* adjust frequency table to weight low probs REAL low */
94df930be7Sderaadt 	for (i = 0; i < 26; ++i)
95df930be7Sderaadt 		stdf[i] = log(stdf[i]) + log(26.0 / 100.0);
96df930be7Sderaadt 
97df930be7Sderaadt 	/* zero out observation table */
98986c0edfSderaadt 	memset(obs, 0, 26 * sizeof(int));
99df930be7Sderaadt 
100986c0edfSderaadt 	nread = 0;
101986c0edfSderaadt 	while ((nread < LINELENGTH) && ((ch = getchar()) != EOF)) {
102986c0edfSderaadt 		inbuf[nread++] = ch;
103df930be7Sderaadt 		if (islower(ch))
104df930be7Sderaadt 			++obs[ch - 'a'];
105df930be7Sderaadt 		else if (isupper(ch))
106df930be7Sderaadt 			++obs[ch - 'A'];
107df930be7Sderaadt 	}
108df930be7Sderaadt 
109df930be7Sderaadt 	/*
110df930be7Sderaadt 	 * now "dot" the freqs with the observed letter freqs
111df930be7Sderaadt 	 * and keep track of best fit
112df930be7Sderaadt 	 */
1135dc4a87cSpjanzen 	winnerdot = 0;
114df930be7Sderaadt 	for (try = winner = 0; try < 26; ++try) { /* += 13) { */
115df930be7Sderaadt 		dot = 0;
116df930be7Sderaadt 		for (i = 0; i < 26; i++)
117df930be7Sderaadt 			dot += obs[i] * stdf[(i + try) % 26];
118df930be7Sderaadt 		if (dot > winnerdot) {
119df930be7Sderaadt 			/* got a new winner! */
120df930be7Sderaadt 			winner = try;
121df930be7Sderaadt 			winnerdot = dot;
122df930be7Sderaadt 		}
123df930be7Sderaadt 	}
124df930be7Sderaadt 
125986c0edfSderaadt 	/* dump the buffer before calling printit */
126df930be7Sderaadt 	for (i = 0; i < nread; ++i) {
127df930be7Sderaadt 		ch = inbuf[i];
128df930be7Sderaadt 		putchar(ROTATE(ch, winner));
129df930be7Sderaadt 	}
130986c0edfSderaadt 	printit(winner);
131df930be7Sderaadt }
132df930be7Sderaadt 
133986c0edfSderaadt void
printit(int rot)134a5ca3416Sderaadt printit(int rot)
135df930be7Sderaadt {
13697419aa0Spjanzen 	int ch;
137df930be7Sderaadt 
138*ab9f6680Sschwarze 	if (rot < 0)
139*ab9f6680Sschwarze 		rot = rot + 26;
140df930be7Sderaadt 	while ((ch = getchar()) != EOF)
141df930be7Sderaadt 		putchar(ROTATE(ch, rot));
142df930be7Sderaadt 	exit(0);
143df930be7Sderaadt }
144