1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Adams. 7 * 8 * Authors: 9 * Stan King, John Eldridge, based on algorithm suggested by 10 * Bob Morris 11 * 29-Sep-82 12 * 13 * Redistribution and use in source and binary forms are permitted 14 * provided that the above copyright notice and this paragraph are 15 * duplicated in all such forms and that any documentation, 16 * advertising materials, and other materials related to such 17 * distribution and use acknowledge that the software was developed 18 * by the University of California, Berkeley. The name of the 19 * University may not be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 24 */ 25 26 #ifndef lint 27 char copyright[] = 28 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 29 All rights reserved.\n"; 30 #endif /* not lint */ 31 32 #ifndef lint 33 static char sccsid[] = "@(#)caesar.c 5.3 (Berkeley) 09/05/89"; 34 #endif /* not lint */ 35 36 #include <math.h> 37 #include <stdio.h> 38 #include <ctype.h> 39 #include <unistd.h> 40 41 #define LINELENGTH 2048 42 #define ROTATE(ch, perm) \ 43 isupper(ch) ? ('A' + (ch - 'A' + perm) % 26) : \ 44 islower(ch) ? ('a' + (ch - 'a' + perm) % 26) : ch 45 46 /* 47 * letter frequencies (taken from some unix(tm) documentation) 48 * (unix is a trademark of Bell Laboratories) 49 */ 50 double stdf[26] = { 51 7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, 6.39, 0.04, 52 0.42, 3.81, 2.69, 5.92, 6.96, 2.91, 0.08, 6.63, 8.77, 9.68, 53 2.62, 0.81, 1.88, 0.23, 2.07, 0.06, 54 }; 55 56 main(argc, argv) 57 int argc; 58 char **argv; 59 { 60 extern int errno; 61 register int ch, dot, i, nread, winnerdot; 62 register char *inbuf; 63 int obs[26], try, winner; 64 char *malloc(), *strerror(); 65 66 if (argc > 1) 67 printit(argv[1]); 68 69 if (!(inbuf = malloc(LINELENGTH))) { 70 (void)fprintf(stderr, "caesar: out of memory.\n"); 71 exit(1); 72 } 73 74 /* adjust frequency table to weight low probs REAL low */ 75 for (i = 0; i < 26; ++i) 76 stdf[i] = log(stdf[i]) + log(26.0 / 100.0); 77 78 /* zero out observation table */ 79 bzero(obs, 26 * sizeof(int)); 80 81 if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) { 82 (void)fprintf(stderr, "caesar: %s\n", strerror(errno)); 83 exit(1); 84 } 85 for (i = nread; i--;) { 86 ch = inbuf[i]; 87 if (islower(ch)) 88 ++obs[ch - 'a']; 89 else if (isupper(ch)) 90 ++obs[ch - 'A']; 91 } 92 93 /* 94 * now "dot" the freqs with the observed letter freqs 95 * and keep track of best fit 96 */ 97 for (try = winner = 0; try < 26; ++try) { /* += 13) { */ 98 dot = 0; 99 for (i = 0; i < 26; i++) 100 dot += obs[i] * stdf[(i + try) % 26]; 101 /* initialize winning score */ 102 if (try == 0) 103 winnerdot = dot; 104 if (dot > winnerdot) { 105 /* got a new winner! */ 106 winner = try; 107 winnerdot = dot; 108 } 109 } 110 111 for (;;) { 112 for (i = 0; i < nread; ++i) { 113 ch = inbuf[i]; 114 putchar(ROTATE(ch, winner)); 115 } 116 if (nread < LINELENGTH) 117 break; 118 if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) { 119 (void)fprintf(stderr, "caesar: %s\n", strerror(errno)); 120 exit(1); 121 } 122 } 123 exit(0); 124 } 125 126 printit(arg) 127 char *arg; 128 { 129 register int ch, rot; 130 131 if ((rot = atoi(arg)) < 0) { 132 (void)fprintf(stderr, "caesar: bad rotation value.\n"); 133 exit(1); 134 } 135 while ((ch = getchar()) != EOF) 136 putchar(ROTATE(ch, rot)); 137 exit(0); 138 } 139