#include "inputcsv.hh" #include "posutil.hh" #include "posexcept.hh" #include "stock.hh" #include #include #include using namespace std ; using std::tr1::unordered_map ; #include #include using namespace boost ; /* *** Constructors *** */ /** * Prepares the InputCSV to read a CSV file. * @param filename The name of the file to open. * @throw error_opening_input_file if the file cannot be opened. */ InputCSV::InputCSV(const string &filename) { input_file_name = filename ; input_file.open(input_file_name.c_str()) ; if (! input_file) throw error_opening_input_file(input_file_name) ; read_next_line() ; } InputCSV::~InputCSV() { input_file.close() ; } /* *** Operations *** */ /** * Tests if #input_file is opened and there is something more to * read. If the end of file is reached, the stream is closed. * @return \em true if the end of file is reached or if the file is * already closed. * @return \em false if there is something more to read. */ bool InputCSV::eof_close() { if (! input_file) return false ; if (input_file.eof()) { input_file.close() ; return true ; } return false ; } /** * Read the next non-blank line. Tabs and spaces at the begining of a * line are skipped. * #current_line is set to empty string in case of error. */ void InputCSV::read_next_line() { if (eof_close()) { current_line.clear() ; return ; } string::size_type first_non_blank = 0 ; do { ++current_line_nb ; getline(input_file, current_line) ; } while (! input_file.eof() && (first_non_blank = current_line.find_first_not_of(" \t")) == string::npos) ; if (eof_close()) current_line.clear() ; else current_line.erase(0, first_non_blank) ; } /** * This function reads the next Request in the CSV input file. Blank * lines and lines containing only spaces are skipped. * * #input_file should be opened before proceeding requests; otherwise, * #current_request is \link Request::clear() cleared\endlink and a * blank Request is returned. The file must be valid, * semicolon-separated (\em not comma-separated). * * @return The read Request, or a blank Request in case of error (file * not opened, end of file, invalid field or wrong number of fields in * the line). */ const Request& InputCSV::get_next_request() { if (eof_close()) { // End of file or error: blank current request current_request->clear() ; return *current_request ; } // Split read string into fields (semicolon-separated) tokenizer > tok( current_line, escaped_list_separator('\\', ';', '\"')) ; tokenizer >::const_iterator ti(tok.begin()) ; // Read Mobile MAC field if (ti == tok.end()) { // Wrong number of fields: blank current request current_request->clear() ; return *current_request ; } // If the mobile did not exist, we create it try { Stock::get_mobile(*ti) ; } catch (element_not_found e) { Stock::getw_mobile(*ti).set_mac_addr(*ti) ; } current_request->set_mobile(&Stock::get_mobile(*ti)) ; // Read Timestamp field if (++ti == tok.end()) { // Wrong number of fields: blank current request current_request->clear() ; return *current_request ; } try { current_request->set_timestamp(Timestamp (lexical_cast(*ti))) ; } catch (bad_lexical_cast &e) { cerr << "InputCSV::get_next_request(): Bad value « " << *ti << " » at line " << current_line_nb << ", field « Timestamp », of input file « " << input_file_name << " »!" << endl ; current_request->clear() ; // Blank current request return *current_request ; } // Read position fields bool is_calibration_request = false ; float pos[3] ; for (int i = 0 ; i < 3 ; ++i) { if (++ti == tok.end()) { // Wrong number of fields: blank current request current_request->clear() ; return *current_request ; } try { pos[i] = lexical_cast(*ti) ; if (pos[i] != 0) is_calibration_request = true ; } catch (bad_lexical_cast &e) { cerr << "InputCSV::get_next_request(): Bad value « " << *ti << " » at line " << current_line_nb << ", position field #" << i << ", of input file « " << input_file_name << " »!" << endl ; current_request->clear() ; // Blank current request return *current_request ; } } // Read direction field int direction ; if (++ti == tok.end()) { // Wrong number of fields: blank current request current_request->clear() ; return *current_request ; } try { direction = lexical_cast(*ti) ; if (direction != 0) is_calibration_request = true ; } catch (bad_lexical_cast &e) { cerr << "InputCSV::get_next_request(): Bad value « " << *ti << " » at line " << current_line_nb << ", field « Direction », of input file « " << input_file_name << " »!" << endl ; current_request->clear() ; // Blank current request return *current_request ; } // Reading {MAC_AP;SS} couples unordered_map measurements ; for (++ti ; ti != tok.end() ; ++ti) { string mac_ap(*ti) ; if (++ti == tok.end()) { // Wrong number of fields: blank current request current_request->clear() ; return *current_request ; } int ss ; try { ss = lexical_cast(*ti) ; } catch (bad_lexical_cast &e) { cerr << "InputCSV::get_next_request(): Bad value « " << *ti << " » at line " << current_line_nb << " of input file « " << input_file_name << " »!" << endl ; current_request->clear() ; // Blank current request return *current_request ; } // If the AP did not exist, we create it try { Stock::get_ap(mac_ap) ; } catch (element_not_found e) { Stock::getw_ap(mac_ap).set_mac_addr(mac_ap) ; } measurements[mac_ap].set_ap(&Stock::get_ap(mac_ap)) ; // Adding value measurements[mac_ap].add_ss(ss) ; } current_request->set_measurements(measurements) ; read_next_line() ; if (is_calibration_request) {} // TODO return *current_request ; }