00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "nechung_oracle.h"
00016
00017 #include <basis/chaos.h>
00018 #include <basis/guards.h>
00019 #include <basis/istring.h>
00020 #include <opsystem/byte_filer.h>
00021 #include <loggers/console_logger.h>
00022 #include <opsystem/filetime.h>
00023 #include <textual/parser_bits.h>
00024
00025 #include <stdio.h>
00026 #include <string.h>
00027
00028 #undef LOG
00029 #define LOG(s) program_wide_logger().log(s)
00030
00031 const int MAX_LINE_LENGTH = 2048;
00032
00033 nechung_oracle::nechung_oracle(const istring &nechung_filename,
00034 const istring &index_filename)
00035 : _randomizer(new chaos),
00036 _filename_held(new istring(nechung_filename)),
00037 _index_held(new istring(index_filename)),
00038 _number_of_fortunes(0)
00039 { parse_file(); }
00040
00041 nechung_oracle::~nechung_oracle()
00042 {
00043 WHACK(_randomizer);
00044 WHACK(_filename_held);
00045 WHACK(_index_held);
00046 }
00047
00048 void nechung_oracle::parse_file()
00049 {
00050 FUNCDEF("parse_file");
00051
00052 byte_filer fortune_file(_filename_held->s(), "rb");
00053 #ifdef DEBUG_NECHUNG
00054 LOG(istring("filename=") + *_filename_held + " idx file=" + *_index_held);
00055 #endif
00056 if (!fortune_file.good())
00057 non_continuable_error(class_name(), func, "Cannot open fortune file.");
00058
00059 byte_array buffer(MAX_LINE_LENGTH + 1);
00060
00061
00062 byte_filer index_file(_index_held->observe(), "r");
00063 if (index_file.good()) {
00064 #ifdef DEBUG_NECHUNG
00065 LOG("index file exists");
00066 #endif
00067 file_time index_time((FILE *)index_file.file_handle());
00068 file_time fortune_time((FILE *)fortune_file.file_handle());
00069 if (index_time >= fortune_time) {
00070
00071 index_file.getline(buffer, MAX_LINE_LENGTH);
00072 sscanf((char *)buffer.access(), "%d", &_number_of_fortunes);
00073 #ifdef DEBUG_NECHUNG
00074 LOG(istring(istring::SPRINTF, "%d entries in index",
00075 _number_of_fortunes));
00076 #endif
00077 return;
00078 }
00079 }
00080 index_file.close();
00081
00082
00083 enum fortune_states {
00084 chowing_separators,
00085 adding_fortunes,
00086 chowing_fortunes,
00087 done_parsing
00088 };
00089
00090 _number_of_fortunes = 0;
00091 fortune_states state = chowing_separators;
00092
00093 int posn;
00094 int_array fortune_posns;
00095 while (state != done_parsing) {
00096 #ifdef DEBUG_NECHUNG
00097 LOG(istring(istring::SPRINTF, "#%d", _number_of_fortunes));
00098 #endif
00099 if (fortune_file.eof()) {
00100
00101 state = done_parsing;
00102 continue;
00103 }
00104 switch (state) {
00105 case chowing_separators: {
00106 #ifdef DEBUG_NECHUNG
00107 LOG("chowseps, ");
00108 #endif
00109 posn = int(fortune_file.tell());
00110 if (posn < 0)
00111 non_continuable_error(class_name(), func, "Cannot get file position.");
00112 fortune_file.getline(buffer, MAX_LINE_LENGTH);
00113 #ifdef DEBUG_NECHUNG
00114 LOG(istring("got a line: ") + buffer);
00115 #endif
00116 if (buffer[0] != NECHUNG_SEPARATION_CHARACTER) state = adding_fortunes;
00117 else {
00118
00119
00120
00121
00122 if (strlen((char *)buffer.access()) == 2) posn += 2;
00123 else posn++;
00124 state = adding_fortunes;
00125 }
00126 break;
00127 }
00128 case adding_fortunes: {
00129 #ifdef DEBUG_NECHUNG
00130 LOG("add forts, ");
00131 #endif
00132 fortune_posns += posn;
00133 _number_of_fortunes++;
00134 state = chowing_fortunes;
00135 break;
00136 }
00137 case chowing_fortunes: {
00138 #ifdef DEBUG_NECHUNG
00139 LOG("chow forts, ");
00140 #endif
00141 posn = int(fortune_file.tell());
00142 if (posn < 0)
00143 non_continuable_error(class_name(), func, "Cannot get file size.");
00144 fortune_file.getline(buffer, MAX_LINE_LENGTH);
00145 #ifdef DEBUG_NECHUNG
00146 LOG(istring(istring::SPRINTF, "got a line: %s", buffer.access()));
00147 LOG(istring(istring::SPRINTF, "len is %d", strlen((char *)buffer.access())));
00148 #endif
00149 if ( (buffer[0] == NECHUNG_SEPARATION_CHARACTER)
00150 && (strlen((char *)buffer.access()) == 2) )
00151 state = chowing_separators;
00152 else if (buffer[0] == NECHUNG_SEPARATION_CHARACTER) {
00153 posn++;
00154 state = adding_fortunes;
00155 }
00156 break;
00157 }
00158 case done_parsing: {
00159 non_continuable_error(class_name(), func, "Illegal state reached.");
00160 }
00161 }
00162 }
00163 fortune_file.close();
00164
00165
00166 index_file.open(_index_held->observe(), "w");
00167 if (!index_file.good())
00168 non_continuable_error(class_name(), func, "Cannot open index file.");
00169 istring to_write(istring::SPRINTF, "%d\n", _number_of_fortunes);
00170 index_file.write((byte *)to_write.s(), to_write.length());
00171 for (int j = 0; j < _number_of_fortunes; j++) {
00172 to_write.sprintf("%d\n", fortune_posns[j]);
00173 index_file.write((byte *)to_write.s(), to_write.length());
00174 }
00175 index_file.close();
00176 }
00177
00178 istring nechung_oracle::pick_random()
00179 {
00180 FUNCDEF("pick_random");
00181 #ifdef DEBUG_NECHUNG
00182 LOG(istring("got to ") + func);
00183 #endif
00184
00185 byte_filer fortune_file(_filename_held->s(), "rb");
00186 if (!fortune_file.good())
00187 non_continuable_error(class_name(), func, "Cannot open data file.");
00188 int to_display = _randomizer->inclusive(0, _number_of_fortunes - 1);
00189
00194 byte_filer index_file(_index_held->observe(), "r");
00195 int chosen_posn = 0;
00196 if (index_file.good()) {
00197 program_wide_logger().eol(log_base::NO_ENDING);
00198 byte_array buffer(MAX_LINE_LENGTH + 1);
00199 for (int i = 0; i <= to_display; i++) {
00200 #ifdef DEBUG_NECHUNG
00201 LOG(istring(istring::SPRINTF, "#%d: ", i));
00202 #endif
00203 index_file.getline(buffer, MAX_LINE_LENGTH);
00204 sscanf((char *)buffer.access(), "%d", &chosen_posn);
00205 #ifdef DEBUG_NECHUNG
00206 LOG(istring(istring::SPRINTF, "%d, ", chosen_posn));
00207 if ((i + 1) % 5 == 0) LOG(log_base::platform_ending());
00208 #endif
00209 }
00210 #ifdef DEBUG_NECHUNG
00211 program_wide_logger().eol(log_base::pick_ending_for_platform());
00212 LOG(log_base::platform_ending());
00213 #endif
00214
00215 } else {
00216 non_continuable_error(class_name(), func, \
00217 istring("Could not open the index file \"") + *_index_held + "\"");
00218 }
00219 index_file.close();
00221
00222 #ifdef DEBUG_NECHUNG
00223 LOG(istring(istring::SPRINTF, "about to seek @ num %d and "
00224 "index %d", to_display, chosen_posn);
00225 #endif
00226 if (!fortune_file.seek(chosen_posn, byte_filer::FROM_START))
00227 non_continuable_error(class_name(), func, "Cannot seek to indexed position.");
00228 #ifdef DEBUG_NECHUNG
00229 LOG("after seek");
00230 #endif
00231 istring to_return;
00232 byte_array temp(MAX_LINE_LENGTH + 1);
00233 while (!fortune_file.eof()) {
00234 int chars_read = fortune_file.getline(temp, MAX_LINE_LENGTH);
00235 if (!chars_read) {
00236 if (!fortune_file.eof())
00237 non_continuable_error(class_name(), func, "Error while reading fortune.");
00238 else break;
00239 }
00240 if (temp[0] == NECHUNG_SEPARATION_CHARACTER) break;
00241 else to_return += istring((char *)temp.access());
00242 }
00243 return to_return;
00244 }
00245
00246 void nechung_oracle::display_random()
00247 {
00248 istring to_show = pick_random();
00250 while (parser_bits::is_eol(to_show[to_show.end()]))
00251 to_show.zap(to_show.end(), to_show.end());
00252 LOG(to_show);
00254 }
00255