ARB
arb_misc.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : arb_misc.cxx //
4 // Purpose : misc that doesnt fit elsewhere //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in October 2012 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // =============================================================== //
11 
12 #include "arb_misc.h"
13 #include "arb_msg.h"
14 #include "arb_file.h"
15 #include "arb_string.h"
16 
17 #include <cmath>
18 
19 // AISC_MKPT_PROMOTE:#ifndef _GLIBCXX_CSTDLIB
20 // AISC_MKPT_PROMOTE:#include <cstdlib>
21 // AISC_MKPT_PROMOTE:#endif
22 
23 const char *GBS_readable_size(unsigned long long size, const char *unit_suffix) {
24  // return human readable size information
25  // returned string is maximal 6+strlen(unit_suffix) characters long
26  // (using "b" as 'unit_suffix' produces '### b', '### Mb' etc)
27 
28  if (size<1000) return GBS_global_string("%llu %s", size, unit_suffix);
29 
30  const char *units = "kMGTPEZY"; // kilo, Mega, Giga, Tera, ... should be enough forever
31  int i;
32 
33  for (i = 0; units[i]; ++i) {
34  char unit = units[i];
35  if (size<1000*1024) {
36  double amount = size/(double)1024;
37  if (amount<10.0) return GBS_global_string("%4.2f %c%s", amount+0.005, unit, unit_suffix);
38  if (amount<100.0) return GBS_global_string("%4.1f %c%s", amount+0.05, unit, unit_suffix);
39  return GBS_global_string("%i %c%s", (int)(amount+0.5), unit, unit_suffix);
40  }
41  size /= 1024; // next unit
42  }
43  return GBS_global_string("MUCH %s", unit_suffix);
44 }
45 
46 const char *GBS_readable_timediff(size_t seconds) {
47  size_t mins = seconds/60; seconds -= mins * 60;
48  size_t hours = mins/60; mins -= hours * 60;
49  size_t days = hours/24; hours -= days * 24;
50 
51  const int MAXPRINT = 40;
52  int printed = 0;
53  static char buffer[MAXPRINT+1];
54 
55  if (days>0) printed += sprintf(buffer+printed, "%zud", days);
56  if (printed || hours>0) printed += sprintf(buffer+printed, "%zuh", hours);
57  if (printed || mins>0) printed += sprintf(buffer+printed, "%zum", mins);
58 
59  printed += sprintf(buffer+printed, "%zus", seconds);
60 
61  arb_assert(printed>0 && printed<MAXPRINT);
62 
63  return buffer;
64 }
65 
66 const char *ARB_float_2_ascii(const float f) {
72  const int MAXSIZE = 50;
73  static char result[MAXSIZE];
74  char buffer[MAXSIZE];
75 
76  int printed_e = snprintf(result, MAXSIZE, "%e", f); arb_assert(printed_e<MAXSIZE);
77  float back_e = strtof(result, NULp);
78  float diff_e = fabsf(f-back_e);
79 
80  int printed_g = snprintf(buffer, MAXSIZE, "%g", f); arb_assert(printed_g<MAXSIZE);
81  float back_g = strtof(buffer, NULp);
82  float diff_g = fabsf(f-back_g);
83 
84  if (diff_g<diff_e || (diff_g == diff_e && printed_g<printed_e)) {
85  printed_e = printed_g;
86  back_e = back_g;
87  diff_e = diff_g;
88  memcpy(result, buffer, printed_g+1);
89  }
90 
91  int printed_f = snprintf(buffer, MAXSIZE, "%f", f); arb_assert(printed_f<MAXSIZE);
92  float back_f = strtof(buffer, NULp);
93  float diff_f = fabsf(f-back_f);
94 
95  if (diff_f<diff_e || (diff_f == diff_e && printed_f<printed_e)) {
96  memcpy(result, buffer, printed_f+1);
97  }
98 
99  return result;
100 }
101 
102 const char *ARB_getenv_ignore_empty(const char *envvar) {
103  const char *result = getenv(envvar);
104  return (result && result[0]) ? result : NULp;
105 }
106 
107 char *ARB_executable(const char *exe_name, const char *path) {
115  char *buffer = ARB_alloc<char>(strlen(path)+1+strlen(exe_name)+1);
116  const char *start = path;
117  bool found = false;
118 
119  while (!found && start) {
120  const char *colon = strchr(start, ':');
121  int len = colon ? (colon-start) : (int)strlen(start);
122 
123  memcpy(buffer, start, len);
124  buffer[len] = '/';
125  strcpy(buffer+len+1, exe_name);
126 
127  found = GB_is_executablefile(buffer);
128  start = colon ? colon+1 : NULp;
129  }
130 
131  if (!found && GB_is_executablefile(exe_name)) { // accept 'exe_name' specified with full path
132  strcpy(buffer, exe_name);
133  found = true;
134  }
135 
136  char *executable = found ? ARB_strdup(buffer) : NULp;
137  free(buffer);
138  return executable;
139 }
140 
141 // --------------------------------------------------------------------------------
142 
143 char ARB_path_contains_unwanted_chars(const char *path) {
144  if (strchr(path, ' ') != NULp) {
145  return ' ';
146  }
147  return 0;
148 }
149 
150 void ARB_warn_about_unwanted_chars(const char *path, const char *path_description) {
151  // annoy user with warnings if paths contain unwanted characters.
152  //
153  // motivation: I tried to fix some scripts to correctly handle the case
154  // where arb is installed in a path containing spaces.
155  //
156  // Since that is a bottomless pit, I decided to deny spaces there.
157 
158  char unwantedChar = ARB_path_contains_unwanted_chars(path);
159  if (unwantedChar) {
160  GB_warningf(
161  "arb may not work as expected, because\n"
162  "%s\n"
163  " (='%s')\n"
164  "contains an unwanted character ('%c').",
165  path_description,
166  path,
167  unwantedChar);
168  }
169 }
170 
171 // --------------------------------------------------------------------------------
172 
173 #ifdef UNIT_TESTS
174 #ifndef TEST_UNIT_H
175 #include <test_unit.h>
176 #endif
177 
178 #if 0
179 // simple test
180 #define TEST_EXPECT_FLOAT_2_ASCII(f,a) TEST_EXPECT_EQUAL(ARB_float_2_ascii(f), a)
181 #else
182 // also test back-conversion (ascii->float->ascii) is stable
183 #define TEST_EXPECT_FLOAT_2_ASCII(f,a) do{ \
184  TEST_EXPECT_EQUAL(ARB_float_2_ascii(f), a); \
185  TEST_EXPECT_EQUAL(ARB_float_2_ascii(strtof(a, NULp)), a); \
186  }while(0)
187 #endif
188 
189 __ATTR__REDUCED_OPTIMIZE void TEST_float_2_ascii() {
190  TEST_EXPECT_FLOAT_2_ASCII(3.141592e+00, "3.141592");
191  TEST_EXPECT_FLOAT_2_ASCII(3.141592, "3.141592");
192  TEST_EXPECT_FLOAT_2_ASCII(3.14159, "3.14159");
193 
194  TEST_EXPECT_FLOAT_2_ASCII(0.1, "0.1");
195  TEST_EXPECT_FLOAT_2_ASCII(0.01, "0.01");
196  TEST_EXPECT_FLOAT_2_ASCII(0.001, "0.001");
197  TEST_EXPECT_FLOAT_2_ASCII(0.0001, "0.0001");
198  TEST_EXPECT_FLOAT_2_ASCII(0.00001, "1e-05");
199  TEST_EXPECT_FLOAT_2_ASCII(0.000001, "1e-06");
200  TEST_EXPECT_FLOAT_2_ASCII(0.0000001, "1e-07");
201  TEST_EXPECT_FLOAT_2_ASCII(0.00000001, "1e-08");
202  TEST_EXPECT_FLOAT_2_ASCII(0.000000001, "1e-09");
203  TEST_EXPECT_FLOAT_2_ASCII(0.0000000001, "1e-10");
204  TEST_EXPECT_FLOAT_2_ASCII(0.00000000001, "1e-11");
205 
206  TEST_EXPECT_FLOAT_2_ASCII(10, "10");
207  TEST_EXPECT_FLOAT_2_ASCII(100, "100");
208  TEST_EXPECT_FLOAT_2_ASCII(1000, "1000");
209  TEST_EXPECT_FLOAT_2_ASCII(10000, "10000");
210  TEST_EXPECT_FLOAT_2_ASCII(100000, "100000");
211  TEST_EXPECT_FLOAT_2_ASCII(1000000, "1e+06");
212  TEST_EXPECT_FLOAT_2_ASCII(10000000, "1e+07");
213  TEST_EXPECT_FLOAT_2_ASCII(100000000, "1e+08");
214  TEST_EXPECT_FLOAT_2_ASCII(1000000000, "1e+09");
215 
216  TEST_EXPECT_FLOAT_2_ASCII(3141592, "3.141592e+06");
217  TEST_EXPECT_FLOAT_2_ASCII(314159.2, "3.141592e+05");
218  TEST_EXPECT_FLOAT_2_ASCII(31415.92, "3.141592e+04");
219  TEST_EXPECT_FLOAT_2_ASCII(3141.592, "3141.592041");
220  TEST_EXPECT_FLOAT_2_ASCII(3141.592041, "3141.592041");
221  TEST_EXPECT_FLOAT_2_ASCII(314.1592, "314.159210");
222  TEST_EXPECT_FLOAT_2_ASCII(314.159210, "314.159210");
223  TEST_EXPECT_FLOAT_2_ASCII(31.41592, "31.415920");
224  TEST_EXPECT_FLOAT_2_ASCII(3.141592, "3.141592");
225  TEST_EXPECT_FLOAT_2_ASCII(.3141592, "3.141592e-01");
226  TEST_EXPECT_FLOAT_2_ASCII(.03141592, "3.141592e-02");
227  TEST_EXPECT_FLOAT_2_ASCII(.003141592, "3.141592e-03");
228  TEST_EXPECT_FLOAT_2_ASCII(.0003141592, "3.141592e-04");
229  TEST_EXPECT_FLOAT_2_ASCII(.00003141592, "3.141592e-05");
230  TEST_EXPECT_FLOAT_2_ASCII(M_PI, "3.141593");
231 
232  TEST_EXPECT_FLOAT_2_ASCII(1/2.0, "0.5");
233  TEST_EXPECT_FLOAT_2_ASCII(1/3.0, "3.333333e-01");
234  TEST_EXPECT_FLOAT_2_ASCII(1/4.0, "0.25");
235  TEST_EXPECT_FLOAT_2_ASCII(1/5.0, "0.2");
236  TEST_EXPECT_FLOAT_2_ASCII(1/6.0, "1.666667e-01");
237 
238  TEST_EXPECT_FLOAT_2_ASCII(37550000.0, "3.755e+07");
239  TEST_EXPECT_FLOAT_2_ASCII(3755000.0, "3.755e+06");
240  TEST_EXPECT_FLOAT_2_ASCII(375500.0, "375500");
241  TEST_EXPECT_FLOAT_2_ASCII(37550.0, "37550");
242  TEST_EXPECT_FLOAT_2_ASCII(3755.0, "3755");
243  TEST_EXPECT_FLOAT_2_ASCII(375.5, "375.5");
244  TEST_EXPECT_FLOAT_2_ASCII(37.55, "37.55");
245  TEST_EXPECT_FLOAT_2_ASCII(3.755, "3.755");
246  TEST_EXPECT_FLOAT_2_ASCII(0.3755, "0.3755");
247  TEST_EXPECT_FLOAT_2_ASCII(0.03755, "0.03755");
248  TEST_EXPECT_FLOAT_2_ASCII(0.003755, "0.003755");
249  TEST_EXPECT_FLOAT_2_ASCII(0.0003755, "0.0003755");
250  TEST_EXPECT_FLOAT_2_ASCII(0.00003755, "3.755e-05");
251  TEST_EXPECT_FLOAT_2_ASCII(0.000003755, "3.755e-06");
252 
253  TEST_EXPECT_FLOAT_2_ASCII(1000.0*1000.0*1000.0, "1e+09");
254  TEST_EXPECT_FLOAT_2_ASCII(25000.0*25000.0*25000.0, "1.5625e+13");
255 }
256 
257 // ------------------------------------------------------------
258 // test to ensure sanitizers work as expected
259 
260 #if 0
261 void TEST_fail_address_sanitizer() {
262  static int array[5];
263  array[2] = 1;
264  array[5] = 1; // <- fails with AddressSanitizer
265 
266  printf("array[5]=%i\n", array[5]);
267 }
268 #endif
269 
270 #if 0
271 void TEST_fail_undef_sanitizer() {
272  // error below are not reported if AddressSanitizer bails out (TEST_fail_address_sanitizer)
273  int x = 7;
274  int y1 = -1;
275 
276  int s = x<<y1; // runtime error with ubsan: shift exponent -1 is negative (does not terminate)
277  printf("s=%i\n", s);
278 
279  int o = INT_MAX;
280  int u = INT_MIN;
281  o++; // runtime error: signed integer overflow
282  u--; // runtime error: signed integer overflow
283  printf("o=%i u=%i\n", o, u);
284 
285 #if 0
286  int y2 = 0;
287  int z1 = x/y1;
288  int z2 = x/y2; // runtime error with ubsan: division by zero (terminates with SEGV; also w/o sanitizers)
289  printf("z1=%i z2=%i\n", z1, z2);
290 #endif
291 }
292 #endif
293 
294 #if 0
295 void TEST_fail_leak_sanitizer() {
296  int *p = new int[5]; // <- fails with LeakSanitizer (only reported if AddressSanitizer does not bail out (TEST_fail_address_sanitizer))
297  printf("p[3]=%i\n", p[3]);
298 }
299 #endif
300 
301 // ------------------------------------------------------------
302 
303 #include "StrUniquifier.h"
304 
305 void TEST_StrUniquifier() {
306  StrUniquifier uniq("->");
307  TEST_EXPECT_EQUAL(uniq.make_unique_key("hey"), "hey");
308  TEST_EXPECT_EQUAL(uniq.make_unique_key("hey"), "hey->2");
309  TEST_EXPECT_EQUAL(uniq.make_unique_key("Hey"), "Hey");
310  TEST_EXPECT_EQUAL(uniq.make_unique_key("Hey"), "Hey->2");
311 
312  TEST_EXPECT_EQUAL(uniq.make_unique_key(""), "");
313  TEST_EXPECT_EQUAL(uniq.make_unique_key(""), "->2");
314 
315  StrUniquifier fresh(".");
316  TEST_EXPECT_EQUAL(fresh.make_unique_key(""), "");
317  TEST_EXPECT_EQUAL(fresh.make_unique_key(""), ".2");
318 }
319 
320 // ------------------------------------------------------------
321 
322 #endif // UNIT_TESTS
323 
324 // --------------------------------------------------------------------------------
325 
#define arb_assert(cond)
Definition: arb_assert.h:245
string result
bool GB_is_executablefile(const char *path)
Definition: arb_file.cxx:101
void ARB_warn_about_unwanted_chars(const char *path, const char *path_description)
Definition: arb_misc.cxx:150
const char * ARB_getenv_ignore_empty(const char *envvar)
Definition: arb_misc.cxx:102
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
const char * ARB_float_2_ascii(const float f)
Definition: arb_misc.cxx:66
#define M_PI
static HelixNrInfo * start
char * ARB_executable(const char *exe_name, const char *path)
Definition: arb_misc.cxx:107
void GB_warningf(const char *templat,...)
Definition: arb_msg.cxx:536
const char * GBS_readable_size(unsigned long long size, const char *unit_suffix)
Definition: arb_misc.cxx:23
const char * GBS_readable_timediff(size_t seconds)
Definition: arb_misc.cxx:46
#define __ATTR__REDUCED_OPTIMIZE
Definition: test_unit.h:83
char ARB_path_contains_unwanted_chars(const char *path)
Definition: arb_misc.cxx:143
#define NULp
Definition: cxxforward.h:116
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1294
GB_write_int const char s
Definition: AW_awar.cxx:154