#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(string timestamp_name, string now_name, time_t start_time, shared_ptr output) : timestamp_name_(timestamp_name), now_name_(now_name), start_time_(start_time), output_(output) { } virtual void write(Sample sample) override { long relative_time = sample.lexical_at(now_name_); string new_value = std::to_string(start_time_ + relative_time); sample.set(timestamp_name_, new_value); output_->write(sample); }; private: string now_name_, timestamp_name_; time_t start_time_; shared_ptr output_; }; class sample_timestamp : public app { private: string input_file, timestamp_name, now_name; 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; } auto sample_buffer = make_shared(); unique_ptr parser = open_sample_input_stream(sample_buffer); while (!input.eof()) { char buffer[buffer_size]; input.read(buffer, buffer_size); if (input.bad()) { cerr << "Error reading input" << endl; return EXIT_FAILURE; } size_t count = (size_t) input.gcount(); 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; Sample sample = *--sample_buffer->samples.end(); string s; try { s = sample.at(now_name); } catch (out_of_range &e) { cerr << "Missing key '" + now_name + "'." << endl; return EXIT_FAILURE; } long now; try { now = boost::lexical_cast(s); } catch (const boost::bad_lexical_cast &e) { cerr << "Bad integer value '" + s + "'." << 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; } auto output_stream = open_sample_output_stream(parser->type(), unique_ptr(&cout)); auto p = make_shared("timestamp", now_name, start_time, move(output_stream)); parser = open_sample_input_stream(p, parser->type()); int recordCount = 0; while (!input.eof()) { char buffer[buffer_size]; size_t gcount = (size_t)input.readsome(buffer, buffer_size); 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); }