#include "SoilMoistureIo.h" #include "apps.h" #include #include namespace trygvis { namespace apps { using namespace std; using namespace trygvis::apps; using namespace trygvis::soil_moisture; namespace po = boost::program_options; class TimestampFixingSampleOutputStream : public SampleOutputStream { public: TimestampFixingSampleOutputStream(shared_ptr output, KeyDictionary &dict, string timestamp_name, string now_name, time_t start_time) : timestamp_key(dict.indexOf(timestamp_name)), now_key(dict.indexOf(now_name)), start_time_(start_time), output_(output) { } virtual void write(SampleRecord sample) override { o relative_time_o = sample.lexical_at(now_key); if (!relative_time_o) { return; } long relative_time = relative_time_o.get(); string new_value = std::to_string(start_time_ + relative_time); sample.set(timestamp_key, new_value); output_->write(sample); }; private: const SampleKey* now_key, *timestamp_key; time_t start_time_; shared_ptr output_; }; class sample_timestamp : public app { private: string input_file, timestamp_name, now_name; SampleKey* now_key; public: sample_timestamp() : input_file("") { } void add_options(po::options_description_easy_init &options) override { options ("help", "produce this help message") ("input", po::value(&input_file)->required()) ("now-name", po::value(&now_name)->default_value("now")) ("timestamp-name", po::value(×tamp_name)->default_value("timestamp")); } int main(app_execution &execution) override { ifstream input(input_file, std::ifstream::in | std::ifstream::binary); if (input.fail()) { cerr << "Could not open file: " << input_file << endl; return EXIT_FAILURE; } const int buffer_size = 100; input.seekg(-buffer_size, ios_base::end); struct stat buf; if (stat(input_file.c_str(), &buf)) { cerr << "stat failed" << endl; return EXIT_FAILURE; } KeyDictionary dict; now_key = dict.indexOf(now_name); auto sample_buffer = make_shared(); auto parser = open_sample_input_stream(sample_buffer, dict); while (!input.fail()) { char buffer[buffer_size]; input.read(buffer, buffer_size); auto count = (size_t) input.gcount(); cerr << "eof? " << input.eof() << endl; mutable_buffers_1 b = boost::asio::buffer(buffer, count); parser->process(b); } if (sample_buffer->samples.empty()) { cerr << "Could not find any samples" << endl; return EXIT_FAILURE; } time_t end_time = buf.st_mtim.tv_sec; SampleRecord sample = *--sample_buffer->samples.end(); o s = sample.at(now_key); if (!s) { cerr << "Missing key '" + now_name + "'." << endl; cerr << "keys: " << sample.to_string() << endl; return EXIT_FAILURE; } long now; try { now = boost::lexical_cast(s.get()); } catch (const boost::bad_lexical_cast &e) { cerr << "Bad integer value '" + s.get() + "'." << endl; return EXIT_FAILURE; } time_t start_time = end_time - now; cerr << "end_time " << end_time << endl; cerr << "now " << now << endl; cerr << "start_time " << start_time << endl; // Restart the reading of the input file and add the adjusted timestamp input.clear(ios::eofbit); input.seekg(0); if(input.fail()) { cerr << "Coult not seek input file" << endl; return EXIT_FAILURE; } unique_ptr unique_output_stream = open_sample_output_stream(shared_ptr(&cout, noop_deleter), dict, parser->type()); shared_ptr output_stream{std::move(unique_output_stream)}; auto p = make_shared(output_stream, dict, timestamp_name, now_name, start_time); parser = open_sample_input_stream(p, dict, parser->type()); int recordCount = 0; while (!input.eof()) { char buffer[buffer_size]; input.read(buffer, buffer_size); size_t gcount = (size_t)input.gcount(); recordCount++; mutable_buffers_1 b = boost::asio::buffer(buffer, gcount); parser->process(b); } return EXIT_SUCCESS; }; }; } } using namespace trygvis::apps; int main(int argc, char *argv[]) { sample_timestamp app; return launch_app(argc, argv, app); }