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="
00055 + *_index_held);
00056 #endif
00057 if (!fortune_file.good())
00058 non_continuable_error(class_name(), func, "Cannot open fortune file.");
00059
00060 byte_array buffer(MAX_LINE_LENGTH + 1);
00061
00062
00063 byte_filer index_file(_index_held->observe(), "r");
00064 if (index_file.good()) {
00065 #ifdef DEBUG_NECHUNG
00066 LOG("index file exists");
00067 #endif
00068 file_time index_time((FILE *)index_file.file_handle());
00069 file_time fortune_time((FILE *)fortune_file.file_handle());
00070 if (index_time >= fortune_time) {
00071
00072 index_file.getline(buffer, MAX_LINE_LENGTH);
00073 sscanf((char *)buffer.access(), "%d", &_number_of_fortunes);
00074 #ifdef DEBUG_NECHUNG
00075 LOG(istring(istring::SPRINTF, "%d entries in index",
00076 _number_of_fortunes));
00077 #endif
00078 return;
00079 }
00080 }
00081 index_file.close();
00082
00083
00084 enum fortune_states {
00085 chowing_separators,
00086 adding_fortunes,
00087 chowing_fortunes,
00088 done_parsing
00089 };
00090
00091 _number_of_fortunes = 0;
00092 fortune_states state = chowing_separators;
00093
00094 int posn;
00095 int_array fortune_posns;
00096 while (state != done_parsing) {
00097 #ifdef DEBUG_NECHUNG
00098 LOG(istring(istring::SPRINTF, "#%d", _number_of_fortunes));
00099 #endif
00100 if (fortune_file.eof()) {
00101
00102 state = done_parsing;
00103 continue;
00104 }
00105 switch (state) {
00106 case chowing_separators: {
00107 #ifdef DEBUG_NECHUNG
00108 LOG("chowseps, ");
00109 #endif
00110 posn = int(fortune_file.tell());
00111 if (posn < 0)
00112 non_continuable_error(class_name(), func, "Cannot get file position.");
00113 fortune_file.getline(buffer, MAX_LINE_LENGTH);
00114 #ifdef DEBUG_NECHUNG
00115 LOG(istring("got a line: ") + buffer);
00116 #endif
00117 if (buffer[0] != NECHUNG_SEPARATION_CHARACTER) state = adding_fortunes;
00118 else {
00119
00120
00121
00122
00123 if (strlen((char *)buffer.access()) == 2) posn += 2;
00124 else posn++;
00125 state = adding_fortunes;
00126 }
00127 break;
00128 }
00129 case adding_fortunes: {
00130 #ifdef DEBUG_NECHUNG
00131 LOG("add forts, ");
00132 #endif
00133 fortune_posns += posn;
00134 _number_of_fortunes++;
00135 state = chowing_fortunes;
00136 break;
00137 }
00138 case chowing_fortunes: {
00139 #ifdef DEBUG_NECHUNG
00140 LOG("chow forts, ");
00141 #endif
00142 posn = int(fortune_file.tell());
00143 if (posn < 0)
00144 non_continuable_error(class_name(), func, "Cannot get file size.");
00145 fortune_file.getline(buffer, MAX_LINE_LENGTH);
00146 #ifdef DEBUG_NECHUNG
00147 LOG(istring(istring::SPRINTF, "got a line: %s", buffer.access()));
00148 LOG(istring(istring::SPRINTF, "len is %d", strlen((char *)buffer.access())));
00149 #endif
00150 if ( (buffer[0] == NECHUNG_SEPARATION_CHARACTER)
00151 && (strlen((char *)buffer.access()) == 2) )
00152 state = chowing_separators;
00153 else if (buffer[0] == NECHUNG_SEPARATION_CHARACTER) {
00154 posn++;
00155 state = adding_fortunes;
00156 }
00157 break;
00158 }
00159 case done_parsing: {
00160 non_continuable_error(class_name(), func, "Illegal state reached.");
00161 }
00162 }
00163 }
00164 fortune_file.close();
00165
00166
00167 index_file.open(_index_held->observe(), "w");
00168 if (!index_file.good())
00169 non_continuable_error(class_name(), func, "Cannot open index file.");
00170 istring to_write(istring::SPRINTF, "%dn", _number_of_fortunes);
00171 index_file.write((byte *)to_write.s(), to_write.length());
00172 for (int j = 0; j < _number_of_fortunes; j++) {
00173 to_write.sprintf("%dn", fortune_posns[j]);
00174 index_file.write((byte *)to_write.s(), to_write.length());
00175 }
00176 index_file.close();
00177 }
00178
00179 istring nechung_oracle::pick_random()
00180 {
00181 FUNCDEF("pick_random");
00182 #ifdef DEBUG_NECHUNG
00183 LOG(istring("got to ") + func);
00184 #endif
00185
00186 byte_filer fortune_file(_filename_held->s(), "rb");
00187 if (!fortune_file.good())
00188 non_continuable_error(class_name(), func, "Cannot open data file.");
00189 int to_display = _randomizer->inclusive(0, _number_of_fortunes - 1);
00190
00195 byte_filer index_file(_index_held->observe(), "r");
00196 int chosen_posn = 0;
00197 if (index_file.good()) {
00198 program_wide_logger().eol(log_base::NO_ENDING);
00199 byte_array buffer(MAX_LINE_LENGTH + 1);
00200 for (int i = 0; i <= to_display; i++) {
00201 #ifdef DEBUG_NECHUNG
00202 LOG(istring(istring::SPRINTF, "#%d: ", i));
00203 #endif
00204 index_file.getline(buffer, MAX_LINE_LENGTH);
00205 sscanf((char *)buffer.access(), "%d", &chosen_posn);
00206 #ifdef DEBUG_NECHUNG
00207 LOG(istring(istring::SPRINTF, "%d, ", chosen_posn));
00208 if ((i + 1) % 5 == 0) LOG(log_base::platform_ending());
00209 #endif
00210 }
00211 #ifdef DEBUG_NECHUNG
00212 program_wide_logger().eol(log_base::pick_ending_for_platform());
00213 LOG(log_base::platform_ending());
00214 #endif
00215
00216 } else {
00217 non_continuable_error(class_name(), func, \
00218 istring("Could not open the index file \"") + *_index_held + "\"");
00219 }
00220 index_file.close();
00222
00223 #ifdef DEBUG_NECHUNG
00224 LOG(istring(istring::SPRINTF, "about to seek @ num %d and "
00225 "index %d", to_display, chosen_posn);
00226 #endif
00227 if (!fortune_file.seek(chosen_posn, byte_filer::FROM_START))
00228 non_continuable_error(class_name(), func, "Cannot seek to indexed position.");
00229 #ifdef DEBUG_NECHUNG
00230 LOG("after seek");
00231 #endif
00232 istring to_return;
00233 byte_array temp(MAX_LINE_LENGTH + 1);
00234 while (!fortune_file.eof()) {
00235 int chars_read = fortune_file.getline(temp, MAX_LINE_LENGTH);
00236 if (!chars_read) {
00237 if (!fortune_file.eof())
00238 non_continuable_error(class_name(), func, "Error while reading fortune.");
00239 else break;
00240 }
00241 if (temp[0] == NECHUNG_SEPARATION_CHARACTER) break;
00242 else to_return += istring((char *)temp.access());
00243 }
00244 return to_return;
00245 }
00246
00247 void nechung_oracle::display_random()
00248 {
00249 istring to_show = pick_random();
00251 while (parser_bits::is_eol(to_show[to_show.end()]))
00252 to_show.zap(to_show.end(), to_show.end());
00253 LOG(to_show);
00255 }
00256