Home | History | Annotate | Line # | Download | only in caesar
      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