/* rotx.cc
Sun May 22 15:18:35 CEST 2005, jochem@vorm.net
See http://vorm.net/foucaultspendulum */
#include <iostream>
#include <iomanip>
#include <fstream>
#include <iterator>
#include <vector>
#include <map>
using namespace std;
string shift_word(string word, int shift) {
unsigned char tmp[4096];
int size = word.size()+1;
memcpy(tmp, word.c_str(), size);
for (int j=0; j < size; ++j) {
if ((tmp[j] >= 'a' and tmp[j] <= 'z')) {
tmp[j] += (unsigned char) shift;
if (tmp[j] > 'z') --tmp[j] -= 'z'-'a';
if (tmp[j] < 'a') ++tmp[j] += 'z'-'a';
}
}
return string(reinterpret_cast<char *>(tmp));
}
void grow(vector<string> &in, multimap<string,short> &all, short shift) {
string word;
for (vector<string>::iterator i = in.begin(); i != in.end(); ++i) {
word = shift_word(*i, shift);
all.insert(make_pair(word, shift));
}
}
void print_dups(multimap<string,short> &all) {
string prev;
string orig;
string last_printed;
multimap<string,short>::iterator i;
for (i = all.begin(); i != all.end(); ++i) {
if (i->second == 0) {
prev = i->first;
} else if (i->first == prev) {
if (i->first != last_printed) {
orig = shift_word(i->first, -i->second);
cout << setw(2) << i->second << " " << orig << " " << i->first
<< endl;
last_printed = i->first;
}
}
}
}
void strtolower(string *in) {
char tmp[4096];
int s = (*in).size()+1;
memcpy(tmp,(*in).c_str(),s);
for (int i=0; i < s; i++)
tmp[i] = tolower(tmp[i]);
(*in) = tmp;
}
int main (int argc, char* argv[]) {
string filename;
string word;
vector<string> wordlist;
multimap<string,short> memhog;
if (argc == 2) {
// Set filename
filename = argv[1];
if (filename == "-") {
filename = "/dev/stdin";
}
// Read wordlist
ifstream fh(filename.c_str());
while (fh >> word) {
if (word.length() > 2)
if (word.find("'",0) == string::npos) {
strtolower(&word);
wordlist.push_back(word);
}
}
fh.close();
// Loop through alphabet (half, problem is symmetric) add to memhog
for (short i=0; i < 14; i++) {
grow(wordlist, memhog, i);
}
// Print matches
print_dups(memhog);
} else {
cerr << "Syntax: rotx wordfile.txt" << endl;
}
return 0;
}