ARPDAS_QNX6 1.0
|
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 }