ARPDAS_QNX6 1.0
csv_file.cc
Go to the documentation of this file.
00001 /**
00002  * \file csv_file.cc
00003  * These classes definee the runtime for extraction to CSV output
00004  */
00005 #include <malloc.h>
00006 #include <ctype.h>
00007 #include <signal.h>
00008 #include <stdlib.h>
00009 #include "csv_file.h"
00010 #include "nortlib.h"
00011 #include "nl_assert.h"
00012 
00013 csv_col::csv_col(const char *colname, const char *fmt) {
00014   cname = colname;
00015   format = fmt;
00016   dsval = 0;
00017   dsval_size = 0;
00018   warned = false;
00019 }
00020 
00021 csv_col::~csv_col() {
00022   if (dsval) free(dsval);
00023 }
00024 
00025 const char *csv_col::output() {
00026   return dsval ? dsval : "";
00027 }
00028 
00029 const char *csv_col::header() {
00030   return cname ? cname : "";
00031 }
00032 
00033 void csv_col::dsval_resize(int newsize) {
00034   char *newbuf;
00035   dsval_size = newsize;
00036   newbuf = (char *)realloc(dsval, dsval_size);
00037   if (newbuf == NULL) {
00038     nl_error(3, "Memory allocation failure in csv_col::set(double)");
00039   }
00040   dsval = newbuf;
00041 }
00042 
00043 void csv_col::set(double dval) {
00044   nl_assert(format);
00045   int sz = snprintf(dsval, dsval_size, format, dval);
00046   if (sz >= dsval_size) {
00047     dsval_resize(sz+5);
00048     sz = snprintf(dsval, dsval_size, format, dval);
00049     nl_assert(sz < dsval_size);
00050   }
00051 }
00052 
00053 void csv_col::set(const char *tval) {
00054   int sz;
00055   const char *s = tval;
00056   bool is_num = true;
00057   // Check tval for numeric. If non, warn once, and replace text with nan
00058   while ( isspace(*s) ) ++s;
00059   if ( *s == '-' || *s == '+') ++s;
00060   if ( isdigit(*s) ) {
00061     while (isdigit(*s)) ++s;
00062     if ( *s == '.' ) {
00063       ++s;
00064       while (isdigit(*s)) ++s;
00065     }
00066   } else if (*s == '.') {
00067     ++s;
00068     if (isdigit(*s)) {
00069       while (isdigit(*s)) ++s;
00070     } else {
00071       is_num = false;
00072     }
00073   }
00074   if (is_num && tolower(*s) == 'e') {
00075     ++s;
00076     if ( *s == '-' || *s == '+') ++s;
00077     if (isdigit(*s)) {
00078       while (isdigit(*s)) ++s;
00079     } else is_num = false;
00080   }
00081   if (is_num && *s != '\0')
00082     is_num = false;
00083   if (!is_num) {
00084     if (!warned) {
00085       nl_error(1,"Column '%s' reported at least one non-numeric value: '%s'",
00086         cname, tval);
00087       warned = true;
00088     }
00089     tval = csv_file::nan;
00090   }
00091   sz = snprintf(dsval, dsval_size, "%s", tval);
00092   if (sz >= dsval_size) {
00093     dsval_resize(sz+5);
00094     sz = snprintf(dsval, dsval_size, "%s", tval);
00095     nl_assert(sz < dsval_size);
00096   }
00097 }
00098 
00099 void csv_col::reset() {
00100   if (dsval) dsval[0] = '\0';
00101 }
00102 
00103 
00104 csv_file::csv_file(const char *name, unsigned int n_cols,
00105       const char *nan_text, int json_fmt) {
00106   filename = name;
00107   cols.resize(n_cols);
00108   time_set = false;
00109   if (nan_text)
00110     nan = nan_text;
00111   json = json_fmt ? true : false;
00112 }
00113 
00114 void csv_file::init() {
00115   signal(SIGPIPE, &terminate_on_write_err);
00116   if (json) {
00117     fp = stdout;
00118   } else {
00119     fp = fopen( filename, "w" );
00120     if (fp == NULL)
00121       nl_error(3, "Cannot open output file %s", filename);
00122   }
00123 }
00124 
00125 void csv_file::terminate_on_write_err(int sig) {
00126   nl_error(0, "Received signal %d: Terminating", sig);
00127   exit(0);
00128 }
00129 
00130 const char *csv_file::nan = "";
00131 
00132 csv_file::~csv_file() {
00133   unsigned int i;
00134   if (time_set) flush_row();
00135   fclose(fp);
00136   for (i = 0; i < cols.size(); ++i) {
00137     if ( cols[i] ) delete cols[i];
00138   }
00139 }
00140 
00141 void csv_file::init_col(unsigned int col_num, const char *colname,
00142           const char *fmt) {
00143   if (time_set)
00144     nl_error(3, "csv_file::init_col() after time_set");
00145   if (col_num >= cols.size())
00146     nl_error(3, "col_num %d out of range in csv_file::init_col", col_num);
00147   if (cols[col_num])
00148     nl_error(3, "Illegal redefinition of column %d in csv_file::init_col",
00149       col_num);
00150   if (col_num == 0 && fmt == 0) fmt = "%.0lf";
00151   cols[col_num] = new csv_col(colname, fmt);
00152 }
00153 
00154 void csv_file::set_time(double T) {
00155   if (cols[0] == 0)
00156     cols[0] = new csv_col("Time", "%.0lf");
00157   if (time_set) {
00158     if (T != cur_time) flush_row();
00159   } else {
00160     flush_headers();
00161   }
00162   time_set = true;
00163   cur_time = T;
00164   cols[0]->set(T);
00165 }
00166 
00167 void csv_file::flush_headers() {
00168   unsigned int i;
00169   nl_assert(cols[0]);
00170   if (!json) {
00171     fprintf(fp, "%s", cols[0]->header());
00172     for (i = 1; i < cols.size(); ++i) {
00173       fprintf(fp, ",%s", cols[i] ? cols[i]->header() : "");
00174     }
00175     fprintf(fp, "\n");
00176   }
00177 }
00178 
00179 void csv_file::flush_row() {
00180   unsigned int i;
00181   if (json) {
00182     fprintf(fp, "{\n  \"Record\": \"%s\",\n  \"%s\": %s",
00183       filename, cols[0]->header(), cols[0]->output() );
00184     for (i = 1; i < cols.size(); ++i) {
00185       if (cols[i]) {
00186         fprintf(fp, ",\n  \"%s\": %s", cols[i]->header(), cols[i]->output() );
00187         cols[i]->reset();
00188       }
00189     }
00190     fprintf(fp, "\n}\n");
00191     fflush(fp);
00192   } else {
00193     fprintf(fp, "%s", cols[0]->output() );
00194     for (i = 1; i < cols.size(); ++i) {
00195       fprintf(fp, ",");
00196       if (cols[i]) {
00197         fprintf(fp, "%s", cols[i]->output() );
00198         cols[i]->reset();
00199       }
00200     }
00201     fprintf(fp, "\n");
00202   }
00203 }
00204 
00205 /**
00206  * This interface is not for column zero (Time)
00207  */
00208 void csv_file::set_col(unsigned int col_num, double dval) {
00209   if (col_num < 1 || col_num >= cols.size()) {
00210     nl_error(3, "col_num %u out of range in csv_file::set_col", col_num);
00211   } else if (cols[col_num] == NULL) {
00212     nl_error(3, "column %u undefined in csv_file::set_col", col_num);
00213   } else cols[col_num]->set(dval);
00214 }
00215 
00216 void csv_file::set_col(unsigned int col_num, const char *sval) {
00217   if (col_num < 1 || col_num >= cols.size()) {
00218     nl_error(3, "col_num %u out of range in csv_file::set_col", col_num);
00219   } else if (cols[col_num] == NULL) {
00220     nl_error(3, "column %u undefined in csv_file::set_col", col_num);
00221   } else cols[col_num]->set(sval);
00222 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines