nechung_oracle.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : nechung_oracle                                                    *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *******************************************************************************
00007 * Copyright (c) 1991-$now By Author.  This program is free software; you can  *
00008 * redistribute it and/or modify it under the terms of the GNU General Public  *
00009 * License as published by the Free Software Foundation; either version 2 of   *
00010 * the License or (at your option) any later version.  This is online at:      *
00011 *     http://www.fsf.org/copyleft/gpl.html                                    *
00012 * Please send any updates to: fred@gruntose.com                               *
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   // below is code for comparing dates on the fortune file and the index file.
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     // used throughout parsing for line storage.
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       // need to read in the list of indices
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   // below is code for creating the list.
00084   enum fortune_states {
00085     chowing_separators,  // looking for the breaks between fortunes.
00086     adding_fortunes,     // saw the separator so get ready for a new fortune.
00087     chowing_fortunes,    // currently in a fortune accumulating lines.
00088     done_parsing         // finished parsing the fortune file.
00089   };
00090 
00091   _number_of_fortunes = 0;
00092   fortune_states state = chowing_separators;
00093 
00094   int posn;
00095   int_array fortune_posns;  // our list of fortunes.
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       // exit from the loop now...
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           // special casing is for when we see a separator on the line
00120           // by itself versus when it is the beginning of a line.  if the
00121           // beginning of a line, we currently take that to mean the rest
00122           // of the line is the fortune.
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   // make a new index file.
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;  // which position to read the chosen line at.
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 

Generated on Fri Sep 5 04:28:19 2008 for HOOPLE Libraries by  doxygen 1.5.1