SHOGUN
v3.2.0
|
00001 /* 00002 * This program is free software; you can redistribute it and/or modify 00003 * it under the terms of the GNU General Public License as published by 00004 * the Free Software Foundation; either version 3 of the License, or 00005 * (at your option) any later version. 00006 * 00007 * Written (W) 1999-2009 Soeren Sonnenburg 00008 * Written (W) 1999-2009 Gunnar Raetsch 00009 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society 00010 */ 00011 00012 #include <shogun/lib/config.h> 00013 00014 #include <shogun/io/SGIO.h> 00015 #include <shogun/lib/ShogunException.h> 00016 #include <shogun/lib/Signal.h> 00017 #include <shogun/lib/common.h> 00018 #include <shogun/lib/Time.h> 00019 #include <shogun/mathematics/Math.h> 00020 #include <shogun/lib/RefCount.h> 00021 00022 #include <stdio.h> 00023 #include <stdarg.h> 00024 #include <ctype.h> 00025 00026 #include <stdlib.h> 00027 00028 using namespace shogun; 00029 00030 const EMessageType SGIO::levels[NUM_LOG_LEVELS]={MSG_GCDEBUG, MSG_DEBUG, MSG_INFO, MSG_NOTICE, 00031 MSG_WARN, MSG_ERROR, MSG_CRITICAL, MSG_ALERT, MSG_EMERGENCY, MSG_MESSAGEONLY}; 00032 00033 const char* SGIO::message_strings[NUM_LOG_LEVELS]={"[GCDEBUG] \0", "[DEBUG] \0", "[INFO] \0", 00034 "[NOTICE] \0", "[WARN] \0", "[ERROR] \0", 00035 "[CRITICAL] \0", "[ALERT] \0", "[EMERGENCY] \0", "\0"}; 00036 00037 const char* SGIO::message_strings_highlighted[NUM_LOG_LEVELS]={"[GCDEBUG] \0", "[DEBUG] \0", "[INFO] \0", 00038 "[NOTICE] \0", "\033[1;34m[WARN]\033[0m \0", "\033[1;31m[ERROR]\033[0m \0", 00039 "[CRITICAL] \0", "[ALERT] \0", "[EMERGENCY] \0", "\0"}; 00040 00042 char SGIO::file_buffer[FBUFSIZE]; 00043 00045 char SGIO::directory_name[FBUFSIZE]; 00046 00047 SGIO::SGIO() 00048 : target(stdout), last_progress_time(0), progress_start_time(0), 00049 last_progress(1), show_progress(false), location_info(MSG_NONE), 00050 syntax_highlight(true), loglevel(MSG_WARN) 00051 { 00052 m_refcount = new RefCount(); 00053 } 00054 00055 SGIO::SGIO(const SGIO& orig) 00056 : target(orig.get_target()), last_progress_time(0), 00057 progress_start_time(0), last_progress(1), 00058 show_progress(orig.get_show_progress()), 00059 location_info(orig.get_location_info()), 00060 syntax_highlight(orig.get_syntax_highlight()), 00061 loglevel(orig.get_loglevel()) 00062 { 00063 m_refcount = new RefCount(orig.m_refcount->ref_count()); 00064 } 00065 00066 void SGIO::message(EMessageType prio, const char* function, const char* file, 00067 int32_t line, const char *fmt, ... ) const 00068 { 00069 const char* msg_intro=get_msg_intro(prio); 00070 00071 if (msg_intro) 00072 { 00073 char str[4096]; 00074 snprintf(str, sizeof(str), "%s", msg_intro); 00075 int len=strlen(msg_intro); 00076 char* s=str+len; 00077 00078 /* file and line are shown for warnings and worse */ 00079 if (location_info==MSG_LINE_AND_FILE || prio==MSG_WARN || prio==MSG_ERROR) 00080 { 00081 snprintf(s, sizeof(str)-len, "In file %s line %d: ", file, line); 00082 len=strlen(str); 00083 s=str+len; 00084 } 00085 else if (location_info==MSG_FUNCTION) 00086 { 00087 snprintf(s, sizeof(str)-len, "%s: ", function); 00088 len=strlen(str); 00089 s=str+len; 00090 } 00091 else if (location_info==MSG_NONE) 00092 { 00093 ; 00094 } 00095 00096 va_list list; 00097 va_start(list,fmt); 00098 vsnprintf(s, sizeof(str)-len, fmt, list); 00099 va_end(list); 00100 00101 switch (prio) 00102 { 00103 case MSG_GCDEBUG: 00104 case MSG_DEBUG: 00105 case MSG_INFO: 00106 case MSG_NOTICE: 00107 case MSG_MESSAGEONLY: 00108 if (sg_print_message) 00109 sg_print_message(target, str); 00110 break; 00111 00112 case MSG_WARN: 00113 if (sg_print_warning) 00114 sg_print_warning(target, str); 00115 break; 00116 00117 case MSG_ERROR: 00118 case MSG_CRITICAL: 00119 case MSG_ALERT: 00120 case MSG_EMERGENCY: 00121 if (sg_print_error) 00122 sg_print_error(target, str); 00123 throw ShogunException(str); 00124 break; 00125 default: 00126 break; 00127 } 00128 00129 fflush(target); 00130 } 00131 } 00132 00133 void SGIO::buffered_message(EMessageType prio, const char *fmt, ... ) const 00134 { 00135 const char* msg_intro=get_msg_intro(prio); 00136 00137 if (msg_intro) 00138 { 00139 fprintf(target, "%s", msg_intro); 00140 va_list list; 00141 va_start(list,fmt); 00142 vfprintf(target,fmt,list); 00143 va_end(list); 00144 } 00145 } 00146 00147 void SGIO::progress( 00148 float64_t current_val, float64_t min_val, float64_t max_val, 00149 int32_t decimals, const char* prefix) 00150 { 00151 if (!show_progress) 00152 return; 00153 00154 float64_t runtime = CTime::get_curtime(); 00155 00156 char str[1000]; 00157 float64_t v=-1, estimate=0, total_estimate=0 ; 00158 00159 if (max_val-min_val>0.0) 00160 v=100*(current_val-min_val+1)/(max_val-min_val+1); 00161 00162 if (decimals < 1) 00163 decimals = 1; 00164 00165 if (last_progress>v) 00166 { 00167 last_progress_time = runtime; 00168 progress_start_time = runtime; 00169 last_progress = v; 00170 } 00171 else 00172 { 00173 v=CMath::clamp(v,1e-5,100.0); 00174 last_progress = v-1e-6; 00175 00176 if ((v!=100.0) && (runtime - last_progress_time<0.5)) 00177 return; 00178 00179 last_progress_time = runtime; 00180 estimate = (1-v/100)*(last_progress_time-progress_start_time)/(v/100); 00181 total_estimate = (last_progress_time-progress_start_time)/(v/100); 00182 } 00183 00184 if (estimate>120) 00185 { 00186 snprintf(str, sizeof(str), "%%s %%%d.%df%%%% %%1.1f minutes remaining %%1.1f minutes total \r",decimals+3, decimals); 00187 message(MSG_MESSAGEONLY, "", "", -1, str, prefix, v, estimate/60, total_estimate/60); 00188 } 00189 else 00190 { 00191 snprintf(str, sizeof(str), "%%s %%%d.%df%%%% %%1.1f seconds remaining %%1.1f seconds total \r",decimals+3, decimals); 00192 message(MSG_MESSAGEONLY, "", "", -1, str, prefix, v, estimate, total_estimate); 00193 } 00194 00195 fflush(target); 00196 } 00197 00198 void SGIO::absolute_progress( 00199 float64_t current_val, float64_t val, float64_t min_val, float64_t max_val, 00200 int32_t decimals, const char* prefix) 00201 { 00202 if (!show_progress) 00203 return; 00204 00205 float64_t runtime = CTime::get_curtime(); 00206 00207 char str[1000]; 00208 float64_t v=-1, estimate=0, total_estimate=0 ; 00209 00210 if (max_val-min_val>0) 00211 v=100*(val-min_val+1)/(max_val-min_val+1); 00212 00213 if (decimals < 1) 00214 decimals = 1; 00215 00216 if (last_progress>v) 00217 { 00218 last_progress_time = runtime; 00219 progress_start_time = runtime; 00220 last_progress = v; 00221 } 00222 else 00223 { 00224 v=CMath::clamp(v,1e-5,100.0); 00225 last_progress = v-1e-6; 00226 00227 if ((v!=100.0) && (runtime - last_progress_time<100)) 00228 return; 00229 00230 last_progress_time = runtime; 00231 estimate = (1-v/100)*(last_progress_time-progress_start_time)/(v/100); 00232 total_estimate = (last_progress_time-progress_start_time)/(v/100); 00233 } 00234 00235 if (estimate>120) 00236 { 00237 snprintf(str, sizeof(str), "%%s %%%d.%df %%1.1f minutes remaining %%1.1f minutes total \r",decimals+3, decimals); 00238 message(MSG_MESSAGEONLY, "", "", -1, str, prefix, current_val, estimate/60, total_estimate/60); 00239 } 00240 else 00241 { 00242 snprintf(str, sizeof(str), "%%s %%%d.%df %%1.1f seconds remaining %%1.1f seconds total \r",decimals+3, decimals); 00243 message(MSG_MESSAGEONLY, "", "", -1, str, prefix, current_val, estimate, total_estimate); 00244 } 00245 00246 fflush(target); 00247 } 00248 00249 void SGIO::done() 00250 { 00251 if (!show_progress) 00252 return; 00253 00254 message(MSG_INFO, "", "", -1, "done.\n"); 00255 } 00256 00257 char* SGIO::skip_spaces(char* str) 00258 { 00259 int32_t i=0; 00260 00261 if (str) 00262 { 00263 for (i=0; isspace(str[i]); i++); 00264 00265 return &str[i]; 00266 } 00267 else 00268 return str; 00269 } 00270 00271 char* SGIO::skip_blanks(char* str) 00272 { 00273 int32_t i=0; 00274 00275 if (str) 00276 { 00277 for (i=0; isblank(str[i]); i++); 00278 00279 return &str[i]; 00280 } 00281 else 00282 return str; 00283 } 00284 00285 EMessageType SGIO::get_loglevel() const 00286 { 00287 return loglevel; 00288 } 00289 00290 void SGIO::set_loglevel(EMessageType level) 00291 { 00292 loglevel=level; 00293 } 00294 00295 void SGIO::set_target(FILE* t) 00296 { 00297 target=t; 00298 } 00299 00300 const char* SGIO::get_msg_intro(EMessageType prio) const 00301 { 00302 for (int32_t i=NUM_LOG_LEVELS-1; i>=0; i--) 00303 { 00304 // ignore msg if prio's level is under loglevel, 00305 // but not if prio's level higher than MSG_WARN 00306 if (levels[i]<loglevel && prio<=MSG_WARN) 00307 return NULL; 00308 00309 if (levels[i]==prio) 00310 { 00311 if (syntax_highlight) 00312 return message_strings_highlighted[i]; 00313 else 00314 return message_strings[i]; 00315 } 00316 } 00317 00318 return NULL; 00319 } 00320 00321 char* SGIO::c_string_of_substring(substring s) 00322 { 00323 uint32_t len = s.end - s.start+1; 00324 char* ret = SG_CALLOC(char, len); 00325 memcpy(ret,s.start,len-1); 00326 return ret; 00327 } 00328 00329 void SGIO::print_substring(substring s) 00330 { 00331 char* c_string = c_string_of_substring(s); 00332 SG_SPRINT("%s\n", c_string) 00333 SG_FREE(c_string); 00334 } 00335 00336 float32_t SGIO::float_of_substring(substring s) 00337 { 00338 char* endptr = s.end; 00339 float32_t f = strtof(s.start,&endptr); 00340 if (endptr == s.start && s.start != s.end) 00341 SG_SERROR("error: %s is not a float!\n", c_string_of_substring(s)) 00342 00343 return f; 00344 } 00345 00346 float64_t SGIO::double_of_substring(substring s) 00347 { 00348 char* endptr = s.end; 00349 float64_t f = strtod(s.start,&endptr); 00350 if (endptr == s.start && s.start != s.end) 00351 SG_SERROR("Error!:%s is not a double!\n", c_string_of_substring(s)) 00352 00353 return f; 00354 } 00355 00356 int32_t SGIO::int_of_substring(substring s) 00357 { 00358 char* c_string = c_string_of_substring(s); 00359 int32_t int_val = atoi(c_string); 00360 SG_FREE(c_string); 00361 00362 return int_val; 00363 } 00364 00365 uint32_t SGIO::ulong_of_substring(substring s) 00366 { 00367 return strtoul(s.start,NULL,10); 00368 } 00369 00370 uint32_t SGIO::ss_length(substring s) 00371 { 00372 return (s.end - s.start); 00373 } 00374 00375 char* SGIO::concat_filename(const char* filename) 00376 { 00377 if (snprintf(file_buffer, FBUFSIZE, "%s/%s", directory_name, filename) > FBUFSIZE) 00378 SG_SERROR("filename too long") 00379 00380 SG_SDEBUG("filename=\"%s\"\n", file_buffer) 00381 return file_buffer; 00382 } 00383 00384 int SGIO::filter(CONST_DIRENT_T* d) 00385 { 00386 if (d) 00387 { 00388 char* fname=concat_filename(d->d_name); 00389 00390 if (!access(fname, R_OK)) 00391 { 00392 struct stat s; 00393 if (!stat(fname, &s) && S_ISREG(s.st_mode)) 00394 return 1; 00395 } 00396 } 00397 00398 return 0; 00399 } 00400 00401 SGIO::~SGIO() 00402 { 00403 delete m_refcount; 00404 } 00405 00406 int32_t SGIO::ref() 00407 { 00408 return m_refcount->ref(); 00409 } 00410 00411 int32_t SGIO::ref_count() const 00412 { 00413 return m_refcount->ref_count(); 00414 } 00415 00416 int32_t SGIO::unref() 00417 { 00418 int32_t rc = m_refcount->unref(); 00419 if (rc==0) 00420 { 00421 delete this; 00422 return 0; 00423 } 00424 00425 return rc; 00426 }