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=" + *_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     // used throughout parsing for line storage.
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       // need to read in the list of indices
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   // below is code for creating the list.
00083   enum fortune_states {
00084     chowing_separators,  // looking for the breaks between fortunes.
00085     adding_fortunes,     // saw the separator so get ready for a new fortune.
00086     chowing_fortunes,    // currently in a fortune accumulating lines.
00087     done_parsing         // finished parsing the fortune file.
00088   };
00089 
00090   _number_of_fortunes = 0;
00091   fortune_states state = chowing_separators;
00092 
00093   int posn;
00094   int_array fortune_posns;  // our list of fortunes.
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       // exit from the loop now...
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           // special casing is for when we see a separator on the line
00119           // by itself versus when it is the beginning of a line.  if the
00120           // beginning of a line, we currently take that to mean the rest
00121           // of the line is the fortune.
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   // make a new index file.
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;  // which position to read the chosen line at.
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 

Generated on Fri Nov 28 04:28:51 2008 for HOOPLE Libraries by  doxygen 1.5.1