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) {
108  char *buffer = ARB_alloc<char>(strlen(path)+1+strlen(exe_name)+1);
109  const char *start = path;
110  int found = 0;
111 
112  while (!found && start) {
113  const char *colon = strchr(start, ':');
114  int len = colon ? (colon-start) : (int)strlen(start);
115 
116  memcpy(buffer, start, len);
117  buffer[len] = '/';
118  strcpy(buffer+len+1, exe_name);
119 
120  found = GB_is_executablefile(buffer);
121  start = colon ? colon+1 : NULp;
122  }
123 
124  char *executable = found ? ARB_strdup(buffer) : NULp;
125  free(buffer);
126  return executable;
127 }
128 
129 // --------------------------------------------------------------------------------
130 
131 char ARB_path_contains_unwanted_chars(const char *path) {
132  if (strchr(path, ' ') != NULp) {
133  return ' ';
134  }
135  return 0;
136 }
137 
138 void ARB_warn_about_unwanted_chars(const char *path, const char *path_description) {
139  // annoy user with warnings if paths contain unwanted characters.
140  //
141  // motivation: I tried to fix some scripts to correctly handle the case
142  // where arb is installed in a path containing spaces.
143  //
144  // Since that is a bottomless pit, I decided to deny spaces there.
145 
146  char unwantedChar = ARB_path_contains_unwanted_chars(path);
147  if (unwantedChar) {
148  GB_warningf(
149  "arb may not work as expected, because\n"
150  "%s\n"
151  " (='%s')\n"
152  "contains an unwanted character ('%c').",
153  path_description,
154  path,
155  unwantedChar);
156  }
157 }
158 
159 // --------------------------------------------------------------------------------
160 
161 #ifdef UNIT_TESTS
162 #ifndef TEST_UNIT_H
163 #include <test_unit.h>
164 #endif
165 
166 #if 0
167 // simple test
168 #define TEST_EXPECT_FLOAT_2_ASCII(f,a) TEST_EXPECT_EQUAL(ARB_float_2_ascii(f), a)
169 #else
170 // also test back-conversion (ascii->float->ascii) is stable
171 #define TEST_EXPECT_FLOAT_2_ASCII(f,a) do{ \
172  TEST_EXPECT_EQUAL(ARB_float_2_ascii(f), a); \
173  TEST_EXPECT_EQUAL(ARB_float_2_ascii(strtof(a, NULp)), a); \
174  }while(0)
175 #endif
176 
177 __ATTR__REDUCED_OPTIMIZE void TEST_float_2_ascii() {
178  TEST_EXPECT_FLOAT_2_ASCII(3.141592e+00, "3.141592");
179  TEST_EXPECT_FLOAT_2_ASCII(3.141592, "3.141592");
180  TEST_EXPECT_FLOAT_2_ASCII(3.14159, "3.14159");
181 
182  TEST_EXPECT_FLOAT_2_ASCII(0.1, "0.1");
183  TEST_EXPECT_FLOAT_2_ASCII(0.01, "0.01");
184  TEST_EXPECT_FLOAT_2_ASCII(0.001, "0.001");
185  TEST_EXPECT_FLOAT_2_ASCII(0.0001, "0.0001");
186  TEST_EXPECT_FLOAT_2_ASCII(0.00001, "1e-05");
187  TEST_EXPECT_FLOAT_2_ASCII(0.000001, "1e-06");
188  TEST_EXPECT_FLOAT_2_ASCII(0.0000001, "1e-07");
189  TEST_EXPECT_FLOAT_2_ASCII(0.00000001, "1e-08");
190  TEST_EXPECT_FLOAT_2_ASCII(0.000000001, "1e-09");
191  TEST_EXPECT_FLOAT_2_ASCII(0.0000000001, "1e-10");
192  TEST_EXPECT_FLOAT_2_ASCII(0.00000000001, "1e-11");
193 
194  TEST_EXPECT_FLOAT_2_ASCII(10, "10");
195  TEST_EXPECT_FLOAT_2_ASCII(100, "100");
196  TEST_EXPECT_FLOAT_2_ASCII(1000, "1000");
197  TEST_EXPECT_FLOAT_2_ASCII(10000, "10000");
198  TEST_EXPECT_FLOAT_2_ASCII(100000, "100000");
199  TEST_EXPECT_FLOAT_2_ASCII(1000000, "1e+06");
200  TEST_EXPECT_FLOAT_2_ASCII(10000000, "1e+07");
201  TEST_EXPECT_FLOAT_2_ASCII(100000000, "1e+08");
202  TEST_EXPECT_FLOAT_2_ASCII(1000000000, "1e+09");
203 
204  TEST_EXPECT_FLOAT_2_ASCII(3141592, "3.141592e+06");
205  TEST_EXPECT_FLOAT_2_ASCII(314159.2, "3.141592e+05");
206  TEST_EXPECT_FLOAT_2_ASCII(31415.92, "3.141592e+04");
207  TEST_EXPECT_FLOAT_2_ASCII(3141.592, "3141.592041");
208  TEST_EXPECT_FLOAT_2_ASCII(3141.592041, "3141.592041");
209  TEST_EXPECT_FLOAT_2_ASCII(314.1592, "314.159210");
210  TEST_EXPECT_FLOAT_2_ASCII(314.159210, "314.159210");
211  TEST_EXPECT_FLOAT_2_ASCII(31.41592, "31.415920");
212  TEST_EXPECT_FLOAT_2_ASCII(3.141592, "3.141592");
213  TEST_EXPECT_FLOAT_2_ASCII(.3141592, "3.141592e-01");
214  TEST_EXPECT_FLOAT_2_ASCII(.03141592, "3.141592e-02");
215  TEST_EXPECT_FLOAT_2_ASCII(.003141592, "3.141592e-03");
216  TEST_EXPECT_FLOAT_2_ASCII(.0003141592, "3.141592e-04");
217  TEST_EXPECT_FLOAT_2_ASCII(.00003141592, "3.141592e-05");
218  TEST_EXPECT_FLOAT_2_ASCII(M_PI, "3.141593");
219 
220  TEST_EXPECT_FLOAT_2_ASCII(1/2.0, "0.5");
221  TEST_EXPECT_FLOAT_2_ASCII(1/3.0, "3.333333e-01");
222  TEST_EXPECT_FLOAT_2_ASCII(1/4.0, "0.25");
223  TEST_EXPECT_FLOAT_2_ASCII(1/5.0, "0.2");
224  TEST_EXPECT_FLOAT_2_ASCII(1/6.0, "1.666667e-01");
225 
226  TEST_EXPECT_FLOAT_2_ASCII(37550000.0, "3.755e+07");
227  TEST_EXPECT_FLOAT_2_ASCII(3755000.0, "3.755e+06");
228  TEST_EXPECT_FLOAT_2_ASCII(375500.0, "375500");
229  TEST_EXPECT_FLOAT_2_ASCII(37550.0, "37550");
230  TEST_EXPECT_FLOAT_2_ASCII(3755.0, "3755");
231  TEST_EXPECT_FLOAT_2_ASCII(375.5, "375.5");
232  TEST_EXPECT_FLOAT_2_ASCII(37.55, "37.55");
233  TEST_EXPECT_FLOAT_2_ASCII(3.755, "3.755");
234  TEST_EXPECT_FLOAT_2_ASCII(0.3755, "0.3755");
235  TEST_EXPECT_FLOAT_2_ASCII(0.03755, "0.03755");
236  TEST_EXPECT_FLOAT_2_ASCII(0.003755, "0.003755");
237  TEST_EXPECT_FLOAT_2_ASCII(0.0003755, "0.0003755");
238  TEST_EXPECT_FLOAT_2_ASCII(0.00003755, "3.755e-05");
239  TEST_EXPECT_FLOAT_2_ASCII(0.000003755, "3.755e-06");
240 
241  TEST_EXPECT_FLOAT_2_ASCII(1000.0*1000.0*1000.0, "1e+09");
242  TEST_EXPECT_FLOAT_2_ASCII(25000.0*25000.0*25000.0, "1.5625e+13");
243 }
244 
245 // ------------------------------------------------------------
246 // test to ensure sanitizers work as expected
247 
248 #if 0
249 void TEST_fail_address_sanitizer() {
250  static int array[5];
251  array[2] = 1;
252  array[5] = 1; // <- fails with AddressSanitizer
253 
254  printf("array[5]=%i\n", array[5]);
255 }
256 #endif
257 
258 #if 0
259 void TEST_fail_undef_sanitizer() {
260  // error below are not reported if AddressSanitizer bails out (TEST_fail_address_sanitizer)
261  int x = 7;
262  int y1 = -1;
263 
264  int s = x<<y1; // runtime error with ubsan: shift exponent -1 is negative (does not terminate)
265  printf("s=%i\n", s);
266 
267  int o = INT_MAX;
268  int u = INT_MIN;
269  o++; // runtime error: signed integer overflow
270  u--; // runtime error: signed integer overflow
271  printf("o=%i u=%i\n", o, u);
272 
273 #if 0
274  int y2 = 0;
275  int z1 = x/y1;
276  int z2 = x/y2; // runtime error with ubsan: division by zero (terminates with SEGV; also w/o sanitizers)
277  printf("z1=%i z2=%i\n", z1, z2);
278 #endif
279 }
280 #endif
281 
282 #if 0
283 void TEST_fail_leak_sanitizer() {
284  int *p = new int[5]; // <- fails with LeakSanitizer (only reported if AddressSanitizer does not bail out (TEST_fail_address_sanitizer))
285  printf("p[3]=%i\n", p[3]);
286 }
287 #endif
288 
289 // ------------------------------------------------------------
290 
291 #include "StrUniquifier.h"
292 
293 void TEST_StrUniquifier() {
294  StrUniquifier uniq("->");
295  TEST_EXPECT_EQUAL(uniq.make_unique_key("hey"), "hey");
296  TEST_EXPECT_EQUAL(uniq.make_unique_key("hey"), "hey->2");
297  TEST_EXPECT_EQUAL(uniq.make_unique_key("Hey"), "Hey");
298  TEST_EXPECT_EQUAL(uniq.make_unique_key("Hey"), "Hey->2");
299 
300  TEST_EXPECT_EQUAL(uniq.make_unique_key(""), "");
301  TEST_EXPECT_EQUAL(uniq.make_unique_key(""), "->2");
302 
303  StrUniquifier fresh(".");
304  TEST_EXPECT_EQUAL(fresh.make_unique_key(""), "");
305  TEST_EXPECT_EQUAL(fresh.make_unique_key(""), ".2");
306 }
307 
308 #endif // UNIT_TESTS
309 
310 // --------------------------------------------------------------------------------
311 
#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:138
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:204
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:490
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:131
#define NULp
Definition: cxxforward.h:97
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1283
GB_write_int const char s
Definition: AW_awar.cxx:156