Home | History | Annotate | Line # | Download | only in caesar
caesar.c revision 1.21
      1  1.21  christos /*	$NetBSD: caesar.c,v 1.21 2005/11/19 18:01:42 christos 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.5     lukem __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
     44   1.5     lukem 	The Regents of the University of California.  All rights reserved.\n");
     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.21  christos __RCSID("$NetBSD: caesar.c,v 1.21 2005/11/19 18:01:42 christos 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.15    rillig init_rottbl(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.16    rillig static 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.21  christos 	return (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.15    rillig 	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.16    rillig 	if (ferror(stdin)) {
    207  1.16    rillig 		errx(EXIT_FAILURE, "<stdin>");
    208  1.16    rillig 		/* NOTREACHED */
    209  1.16    rillig 	}
    210  1.16    rillig 
    211  1.16    rillig 	(void)fflush(stdout);
    212  1.16    rillig 	if (ferror(stdout)) {
    213  1.20    rillig 		errx(EXIT_FAILURE, "<stdout>");
    214  1.16    rillig 		/* NOTREACHED */
    215   1.1       cgd 	}
    216  1.16    rillig 
    217  1.16    rillig 	return 0;
    218   1.1       cgd }
    219