1 /*****************************************************************************\
3 * Name : nechung_oracle *
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 1991-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 *****************************************************************************/
15 #include "nechung_oracle.h"
17 #include <basis/astring.h>
18 #include <filesystem/byte_filer.h>
19 #include <filesystem/file_time.h>
20 #include <loggers/critical_events.h>
21 #include <loggers/program_wide_logger.h>
26 //using namespace application;
27 using namespace basis;
28 using namespace filesystem;
29 using namespace loggers;
32 #define LOG(s) program_wide_logger::get().log(s, 0)
33 ///hmmm: fix filter value to be ALWAYS_PRINT!
35 const int MAX_LINE_LENGTH = 2048;
37 nechung_oracle::nechung_oracle(const astring &nechung_filename,
38 const astring &index_filename)
40 c_filename_held(nechung_filename),
41 c_index_held(index_filename),
42 c_number_of_fortunes(0)
45 nechung_oracle::~nechung_oracle() {}
47 void nechung_oracle::parse_file()
49 FUNCDEF("parse_file");
50 // below is code for comparing dates on the fortune file and the index file.
51 byte_filer fortune_file(c_filename_held.s(), "rb");
53 LOG(astring("filename=") + c_filename_held + " idx file=" + c_index_held);
55 if (!fortune_file.good())
56 non_continuable_error(class_name(), func, "Cannot open fortune file.");
58 byte_array buffer(MAX_LINE_LENGTH + 1);
59 // used throughout parsing for line storage.
61 byte_filer index_file(c_index_held.observe(), "r");
62 if (index_file.good()) {
64 LOG("index file exists");
66 file_time index_time((FILE *)index_file.file_handle());
67 file_time fortune_time((FILE *)fortune_file.file_handle());
68 if (index_time >= fortune_time) {
69 // need to read in the list of indices
70 index_file.getline(buffer, MAX_LINE_LENGTH);
71 sscanf((char *)buffer.access(), "%d", &c_number_of_fortunes);
73 LOG(astring(astring::SPRINTF, "%d entries in index",
74 c_number_of_fortunes));
81 // below is code for creating the list.
83 chowing_separators, // looking for the breaks between fortunes.
84 adding_fortunes, // saw the separator so get ready for a new fortune.
85 chowing_fortunes, // currently in a fortune accumulating lines.
86 done_parsing // finished parsing the fortune file.
89 c_number_of_fortunes = 0;
90 fortune_states state = chowing_separators;
93 int_array fortune_posns; // our list of fortunes.
94 while (state != done_parsing) {
96 LOG(astring(astring::SPRINTF, "#%d", c_number_of_fortunes));
98 if (fortune_file.eof()) {
99 // exit from the loop now...
100 state = done_parsing;
104 case chowing_separators: {
108 posn = int(fortune_file.tell());
110 non_continuable_error(class_name(), func, "Cannot get file position.");
111 fortune_file.getline(buffer, MAX_LINE_LENGTH);
113 LOG(astring("got a line: ") + buffer);
115 if (buffer[0] != NECHUNG_SEPARATION_CHARACTER) state = adding_fortunes;
117 // special casing is for when we see a separator on the line
118 // by itself versus when it is the beginning of a line. if the
119 // beginning of a line, we currently take that to mean the rest
120 // of the line is the fortune.
121 if (strlen((char *)buffer.access()) == 2) posn += 2;
123 state = adding_fortunes;
127 case adding_fortunes: {
131 fortune_posns += posn;
132 c_number_of_fortunes++;
133 state = chowing_fortunes;
136 case chowing_fortunes: {
140 posn = int(fortune_file.tell());
142 non_continuable_error(class_name(), func, "Cannot get file size.");
143 fortune_file.getline(buffer, MAX_LINE_LENGTH);
145 LOG(astring(astring::SPRINTF, "got a line: %s", buffer.access()));
146 LOG(astring(astring::SPRINTF, "len is %d", strlen((char *)buffer.access())));
148 if ( (buffer[0] == NECHUNG_SEPARATION_CHARACTER)
149 && (strlen((char *)buffer.access()) == 2) )
150 state = chowing_separators;
151 else if (buffer[0] == NECHUNG_SEPARATION_CHARACTER) {
153 state = adding_fortunes;
158 non_continuable_error(class_name(), func, "Illegal state reached.");
162 fortune_file.close();
164 // make a new index file.
165 index_file.open(c_index_held.observe(), "w");
166 if (!index_file.good())
167 non_continuable_error(class_name(), func, astring("Cannot open index file: ") + c_index_held);
168 astring to_write(astring::SPRINTF, "%d\n", c_number_of_fortunes);
169 index_file.write((abyte *)to_write.s(), to_write.length());
170 for (int j = 0; j < c_number_of_fortunes; j++) {
171 to_write.sprintf("%d\n", fortune_posns[j]);
172 index_file.write((abyte *)to_write.s(), to_write.length());
177 astring nechung_oracle::pick_random()
179 FUNCDEF("pick_random");
181 LOG(astring("got to ") + func);
184 byte_filer fortune_file(c_filename_held.s(), "rb");
186 ///printf("num forts = %d\n", c_number_of_fortunes );
188 if (!fortune_file.good())
189 non_continuable_error(class_name(), func, "Cannot open data file.");
190 int to_display = c_randomizer.inclusive(0, c_number_of_fortunes - 1);
192 ///printf("rand chose= %d\n", to_display);
195 ///hmmm: this bit could be more efficient by just jumping to the Nth line
196 /// instead of reading through up to the Nth line.
198 byte_filer index_file(c_index_held.observe(), "r");
199 int chosen_posn = 0; // which position to read the chosen line at.
200 if (index_file.good()) {
201 astring accumulated_text;
202 byte_array buffer(MAX_LINE_LENGTH + 1);
203 for (int i = 0; i <= to_display; i++) {
205 accumulated_text += astring(astring::SPRINTF, "#%d: ", i);
207 index_file.getline(buffer, MAX_LINE_LENGTH);
208 sscanf((char *)buffer.access(), "%d", &chosen_posn);
210 accumulated_text += astring(astring::SPRINTF, "%d, ", chosen_posn);
211 if ((i + 1) % 5 == 0) accumulated_text += "\n";
215 LOG(accumulated_text);
219 non_continuable_error(class_name(), func, \
220 astring("Could not open the index file \"") + c_index_held + "\"");
224 LOG(astring(astring::SPRINTF, "about to seek @ num %d and "
225 "index %d", to_display, chosen_posn));
227 if (!fortune_file.seek(chosen_posn, byte_filer::FROM_START))
228 non_continuable_error(class_name(), func, "Cannot seek to indexed position.");
234 byte_array temp(MAX_LINE_LENGTH + 1);
235 while (!fortune_file.eof()) {
236 int chars_read = fortune_file.getline(temp, MAX_LINE_LENGTH);
238 if (!fortune_file.eof()) {
239 non_continuable_error(class_name(), func, "Error while reading fortune.");
242 if (temp[0] == NECHUNG_SEPARATION_CHARACTER) break;
243 else to_return += astring((char *)temp.access());
248 //hmmm: stolen from parser bits. reconnect when available.
249 bool is_eol(char to_check)
250 { return (to_check == '\n') || (to_check == '\r'); }
252 void nechung_oracle::display_random()
254 astring to_show = pick_random();
255 while (is_eol(to_show[to_show.end()]))
256 to_show.zap(to_show.end(), to_show.end());