From 3c48fe193d2fb7c927c2c9d1dbf76707e657a9fd Mon Sep 17 00:00:00 2001 From: rillig Date: Mon, 23 May 2005 23:02:30 +0000 Subject: * fixed bugs * removed ASCII dependency * added input data validation * added bounds checking * added error checking * handle short reads (from pipes or sockets) correctly when trying to decode an encoded stream * added lint(1) directives --- caesar/caesar.c | 172 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 106 insertions(+), 66 deletions(-) (limited to 'caesar') diff --git a/caesar/caesar.c b/caesar/caesar.c index b1b3ad98..3423602f 100644 --- a/caesar/caesar.c +++ b/caesar/caesar.c @@ -1,4 +1,4 @@ -/* $NetBSD: caesar.c,v 1.14 2004/01/27 20:30:29 jsm Exp $ */ +/* $NetBSD: caesar.c,v 1.15 2005/05/23 23:02:30 rillig Exp $ */ /* * Copyright (c) 1989, 1993 @@ -11,6 +11,7 @@ * Stan King, John Eldridge, based on algorithm suggested by * Bob Morris * 29-Sep-82 + * Roland Illig, 2005 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -47,115 +48,154 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\ #if 0 static char sccsid[] = "@(#)caesar.c 8.1 (Berkeley) 5/31/93"; #else -__RCSID("$NetBSD: caesar.c,v 1.14 2004/01/27 20:30:29 jsm Exp $"); +__RCSID("$NetBSD: caesar.c,v 1.15 2005/05/23 23:02:30 rillig Exp $"); #endif #endif /* not lint */ #include #include #include +#include #include #include #include #include #include -#define LINELENGTH 2048 -#define ROTATE(ch, perm) \ - isupper(ch) ? ('A' + (ch - 'A' + perm) % 26) : \ - islower(ch) ? ('a' + (ch - 'a' + perm) % 26) : ch +#define NCHARS (1 << CHAR_BIT) +#define LETTERS (26) /* * letter frequencies (taken from some unix(tm) documentation) * (unix is a trademark of Bell Laboratories) */ -double stdf[26] = { +static const unsigned char upper[LETTERS] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static const unsigned char lower[LETTERS] = "abcdefghijklmnopqrstuvwxyz"; +static double stdf[LETTERS] = { 7.97, 1.35, 3.61, 4.78, 12.37, 2.01, 1.46, 4.49, 6.39, 0.04, 0.42, 3.81, 2.69, 5.92, 6.96, 2.91, 0.08, 6.63, 8.77, 9.68, - 2.62, 0.81, 1.88, 0.23, 2.07, 0.06, + 2.62, 0.81, 1.88, 0.23, 2.07, 0.06 }; +static unsigned char rottbl[NCHARS]; -int main(int, char *[]); -void printit(const char *) __attribute__((__noreturn__)); + +static void +init_rottbl(int rot) +{ + size_t i; + + rot %= LETTERS; + + for (i = 0; i < NCHARS; i++) + rottbl[i] = (unsigned char)i; + + for (i = 0; i < LETTERS; i++) + rottbl[upper[i]] = upper[(i + rot) % LETTERS]; + + for (i = 0; i < LETTERS; i++) + rottbl[lower[i]] = lower[(i + rot) % LETTERS]; +} + +static void __attribute__((__noreturn__)) +printrot(const char *arg) +{ + int ch; + long rot; + char *endp; + + errno = 0; + rot = strtol(arg, &endp, 10); + if (*endp != '\0') { + errx(EXIT_FAILURE, "bad rotation value: %s", arg); + /* NOTREACHED */ + } + if (errno == ERANGE || rot < 0 || rot > INT_MAX) { + errx(EXIT_FAILURE, "rotation value out of range: %s", arg); + /* NOTREACHED */ + } + init_rottbl((int)rot); + + while ((ch = getchar()) != EOF) { + if (putchar(rottbl[ch]) == EOF) { + err(EXIT_FAILURE, "writing to stdout"); + /* NOTREACHED */ + } + } + exit(EXIT_SUCCESS); + /* NOTREACHED */ +} int -main(argc, argv) - int argc; - char **argv; +main(int argc, char **argv) { - int ch, i, nread; + ssize_t i, nread, ntotal; double dot, winnerdot; - char *inbuf; - int obs[26], try, winner; + int try, winner; + unsigned char inbuf[2048]; + unsigned int obs[NCHARS]; /* revoke setgid privileges */ - setgid(getgid()); - - winnerdot = 0; - if (argc > 1) - printit(argv[1]); + (void)setgid(getgid()); - if (!(inbuf = malloc(LINELENGTH))) - err(1, NULL); + if (argc > 1) { + printrot(argv[1]); + /* NOTREACHED */ + } /* adjust frequency table to weight low probs REAL low */ - for (i = 0; i < 26; ++i) - stdf[i] = log(stdf[i]) + log(26.0 / 100.0); + for (i = 0; i < LETTERS; i++) + stdf[i] = log(stdf[i]) + log(LETTERS / 100.0); /* zero out observation table */ - memset(obs, 0, 26 * sizeof(int)); - - if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) - err(1, "reading from stdin"); - for (i = nread; i--;) { - ch = inbuf[i]; - if (islower(ch)) - ++obs[ch - 'a']; - else if (isupper(ch)) - ++obs[ch - 'A']; + (void)memset(obs, 0, sizeof(obs)); + + for (ntotal = 0; (size_t) ntotal < sizeof(inbuf); ntotal += nread) { + nread = read(STDIN_FILENO, &inbuf[ntotal], + sizeof(inbuf) - ntotal); + if (nread < 0) { + err(EXIT_FAILURE, "reading from stdin"); + /* NOTREACHED */ + } + if (nread == 0) + break; } + for (i = 0; i < ntotal; i++) + obs[inbuf[i]]++; + /* * now "dot" the freqs with the observed letter freqs * and keep track of best fit */ - for (try = winner = 0; try < 26; ++try) { /* += 13) { */ - dot = 0; - for (i = 0; i < 26; i++) - dot += obs[i] * stdf[(i + try) % 26]; - /* initialize winning score */ - if (try == 0) - winnerdot = dot; - if (dot > winnerdot) { + winner = 0; + winnerdot = 0.0; + for (try = 0; try < LETTERS; try++) { + dot = 0.0; + for (i = 0; i < LETTERS; i++) + dot += (obs[upper[i]] + obs[lower[i]]) + * stdf[(i + try) % LETTERS]; + + if (try == 0 || dot > winnerdot) { /* got a new winner! */ winner = try; winnerdot = dot; } } - - for (;;) { - for (i = 0; i < nread; ++i) { - ch = inbuf[i]; - putchar(ROTATE(ch, winner)); + init_rottbl(winner); + + while (ntotal > 0) { + for (i = 0; i < ntotal; i++) { + if (putchar(rottbl[inbuf[i]]) == EOF) { + err(EXIT_FAILURE, "writing to stdout"); + /* NOTREACHED */ + } + } + if ((ntotal = read(STDIN_FILENO, inbuf, sizeof(inbuf))) < 0) { + err(EXIT_FAILURE, "reading from stdin"); + /* NOTREACHED */ } - if (nread < LINELENGTH) - break; - if ((nread = read(STDIN_FILENO, inbuf, LINELENGTH)) < 0) - err(1, "reading from stdin"); } - exit(0); -} - -void -printit(arg) - const char *arg; -{ - int ch, rot; - - if ((rot = atoi(arg)) < 0) - errx(1, "bad rotation value."); - while ((ch = getchar()) != EOF) - putchar(ROTATE(ch, rot)); - exit(0); + exit(EXIT_FAILURE); + /* NOTREACHED */ } -- cgit v1.2.3-56-ge451