001: #include <iostream>
002: #include <fstream>
003: #include <string>
004: #include <sstream>
006: using namespace std;
007:
008: /**
009: Prints usage instructions.
010: @param program_name the name of this program
011: */
012: void usage(string program_name)
013: { cout << "Usage: " << program_name
015: << " [-d] [-kn] infile outfile\n";
016: exit(1);
017: }
019: /**
020: Prints file opening error message
021: @param filename the name of the file that could not be opened
022: */
023: void open_file_error(string filename)
024: { cout << "Error opening file " << filename << "\n";
026: exit(1);
027: }
029: /**
030: Computes correct remainder for negative dividend.
031: @param a an integer
032: @param n an integer > 0
033: @return the mathematically correct remainder r such that
034: a - r is divisible by n and 0 <= r and r < n
035: */
036: int remainder(int a, int n)
037: { if (a >= 0) return a % n;
040: else return n - 1 - (-a - 1) % n;
042: }
044: /**
045: Encrypts a character using the Caesar cipher.
046: @param ch the character to encrypt
047: @param k the encryption key
048: @return the encrypted character
049: */
050: char encrypt(char ch, int k)
051: { const int NLETTER = 'Z' - 'A' + 1;
053: if ('A' <= ch && ch <= 'Z')
054: return static_cast<char>('A' + remainder(ch - 'A' + k, NLETTER));
056: if ('a' <= ch && ch <= 'z')
057: return static_cast<char>('a' + remainder(ch - 'a' + k, NLETTER));
059: return ch;
060: }
062: /**
063: Encrypts a stream using the Caesar cipher.
064: @param in the stream to read from
065: @param out the stream to write to
066: @param k the encryption key
067: */
068: void encrypt_file(istream& in, ostream& out, int k)
069: { char ch;
071: while (in.get(ch)) out.put(encrypt(ch, k));
073: }
075: /**
076: Converts a string to an integer, e.g. "3" -> 3.
077: @param s a string representing an integer
078: @return the equivalent integer
079: */
080: int string_to_int(string s)
081: { istringstream instr(s);
083: int n;
084: instr >> n;
085: return n;
086: }
087:
088: int main(int argc, char* argv[])
089: { bool decrypt = false;
091: int key = 3;
092: int nfile = 0; /* the number of files specified */
093: ifstream infile;
094: ofstream outfile;
095:
096: if (argc < 3 or argc > 5) usage(string(argv[0]));
097:
098: int i;
099: for (i = 1; i < argc; i++)
100: { string arg = string(argv[i]);
101: if (arg.length() >= 2 and arg[0] == '-')
102: /* it is a command line option */
103: { char option = arg[1];
105: if (option == 'd') decrypt = true;
107: else if (option == 'k')
108: key = string_to_int(arg.substr(2, arg.length() - 2));
109: }
110: else
111: { nfile++;
113: if (nfile == 1)
114: { infile.open(arg.c_str());
116: if (infile.fail()) open_file_error(arg);
117: }
118: else if (nfile == 2)
119: { outfile.open(arg.c_str());
121: if (outfile.fail()) open_file_error(arg);
122: }
123: }
124: }
125:
126: if(nfile != 2) usage(string(argv[0]));
127:
128: if (decrypt) key = -key;
129:
130: encrypt_file(infile, outfile, key);
131: infile.close();
132: outfile.close();
133: return 0;
134: }