ARB
arb_msg.cxx
Go to the documentation of this file.
1 // ================================================================ //
2 // //
3 // File : arb_msg.cxx //
4 // Purpose : //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in November 2010 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // ================================================================ //
11 
12 #include <arb_msg_fwd.h>
13 #include <arb_string.h>
14 #include <arb_backtrace.h>
15 #include <smartptr.h>
16 #include <arb_handlers.h>
17 #include <arb_defs.h>
18 #include "arb_strbuf.h"
19 
20 // AISC_MKPT_PROMOTE:#ifndef _GLIBCXX_CSTDLIB
21 // AISC_MKPT_PROMOTE:#include <cstdlib>
22 // AISC_MKPT_PROMOTE:#endif
23 // AISC_MKPT_PROMOTE:#ifndef ARB_CORE_H
24 // AISC_MKPT_PROMOTE:#include "arb_core.h"
25 // AISC_MKPT_PROMOTE:#endif
26 // AISC_MKPT_PROMOTE:#ifndef ARB_ASSERT_H
27 // AISC_MKPT_PROMOTE:#include "arb_assert.h"
28 // AISC_MKPT_PROMOTE:#endif
29 // AISC_MKPT_PROMOTE:
30 // AISC_MKPT_PROMOTE:// return error and ensure none is exported
31 // AISC_MKPT_PROMOTE:#define RETURN_ERROR(err) arb_assert(!GB_have_error()); return (err)
32 // AISC_MKPT_PROMOTE:
33 
34 #if defined(DEBUG)
35 #if defined(DEVEL_RALF)
36 // #define TRACE_BUFFER_USAGE
37 #endif // DEBUG
38 #endif // DEVEL_RALF
39 
40 #define GLOBAL_STRING_BUFFERS 4
41 
42 static size_t last_global_string_size = 0;
43 #define GBS_GLOBAL_STRING_SIZE 64000
44 
45 // --------------------------------------------------------------------------------
46 
47 #ifdef LINUX
48 # define HAVE_VSNPRINTF
49 #endif
50 
51 #ifdef HAVE_VSNPRINTF
52 # define PRINT2BUFFER(buffer, bufsize, templat, parg) vsnprintf(buffer, bufsize, templat, parg)
53 #else
54 # define PRINT2BUFFER(buffer, bufsize, templat, parg) vsprintf(buffer, templat, parg)
55 #endif
56 
57 #define PRINT2BUFFER_CHECKED(printed, buffer, bufsize, templat, parg) \
58  (printed) = PRINT2BUFFER(buffer, bufsize, templat, parg); \
59  if ((printed) < 0 || (size_t)(printed) >= (bufsize)) { \
60  GBK_terminatef("Internal buffer overflow (size=%zu, used=%i)\n", \
61  (bufsize), (printed)); \
62  }
63 
64 // --------------------------------------------------------------------------------
65 
67  char buffer[GLOBAL_STRING_BUFFERS][GBS_GLOBAL_STRING_SIZE+2]; // several buffers - used alternately
68  int idx;
69  char lifetime[GLOBAL_STRING_BUFFERS];
70  char nextIdx[GLOBAL_STRING_BUFFERS];
71 
72 public:
74  : idx(0)
75  {
76  for (int i = 0; i<GLOBAL_STRING_BUFFERS; ++i) {
77  nextIdx[i] = 0;
78  lifetime[i] = 0;
79  }
80  }
81 
82  __ATTR__VFORMAT_MEMBER(1) const char *vstrf(const char *templat, va_list parg, int allow_reuse);
83 };
84 
86 
87 const char *GlobalStringBuffers::vstrf(const char *templat, va_list parg, int allow_reuse) {
88  int my_idx;
89  int psize;
90 
91  if (nextIdx[0] == 0) { // initialize nextIdx
92  for (my_idx = 0; my_idx<GLOBAL_STRING_BUFFERS; my_idx++) {
93  nextIdx[my_idx] = (my_idx+1)%GLOBAL_STRING_BUFFERS;
94  }
95  }
96 
97  if (allow_reuse == -1) { // called from GBS_reuse_buffer
98  // buffer to reuse is passed in 'templat'
99 
100  for (my_idx = 0; my_idx<GLOBAL_STRING_BUFFERS; my_idx++) {
101  if (buffer[my_idx] == templat) {
102  lifetime[my_idx] = 0;
103 #if defined(TRACE_BUFFER_USAGE)
104  printf("Reusing buffer #%i\n", my_idx);
105 #endif // TRACE_BUFFER_USAGE
106  if (nextIdx[my_idx] == idx) idx = my_idx;
107  return NULp;
108  }
109 #if defined(TRACE_BUFFER_USAGE)
110  else {
111  printf("(buffer to reuse is not buffer #%i (%p))\n", my_idx, buffer[my_idx]);
112  }
113 #endif // TRACE_BUFFER_USAGE
114  }
115  for (my_idx = 0; my_idx<GLOBAL_STRING_BUFFERS; my_idx++) {
116  printf("buffer[%i]=%p\n", my_idx, buffer[my_idx]);
117  }
118  arb_assert(0); // GBS_reuse_buffer called with illegal buffer
119  return NULp;
120  }
121 
122  if (lifetime[idx] == 0) {
123  my_idx = idx;
124  }
125  else {
126  for (my_idx = nextIdx[idx]; lifetime[my_idx]>0; my_idx = nextIdx[my_idx]) {
127 #if defined(TRACE_BUFFER_USAGE)
128  printf("decreasing lifetime[%i] (%i->%i)\n", my_idx, lifetime[my_idx], lifetime[my_idx]-1);
129 #endif // TRACE_BUFFER_USAGE
130  lifetime[my_idx]--;
131  }
132  }
133 
134  PRINT2BUFFER_CHECKED(psize, buffer[my_idx], (size_t)GBS_GLOBAL_STRING_SIZE, templat, parg);
135 
136 #if defined(TRACE_BUFFER_USAGE)
137  printf("Printed into global buffer #%i ('%s')\n", my_idx, buffer[my_idx]);
138 #endif // TRACE_BUFFER_USAGE
139 
140  last_global_string_size = psize;
141 
142  if (!allow_reuse) {
143  idx = my_idx;
144  lifetime[idx] = 1;
145  }
146 #if defined(TRACE_BUFFER_USAGE)
147  else {
148  printf("Allow reuse of buffer #%i\n", my_idx);
149  }
150 #endif // TRACE_BUFFER_USAGE
151 
152  return buffer[my_idx];
153 }
154 
158  return stored;
159 }
160 
162  globBuf = *saved;
163  delete saved;
164 }
165 
166 const char *GBS_vglobal_string(const char *templat, va_list parg) {
167  // goes to header: __ATTR__VFORMAT(1)
168  return globBuf.vstrf(templat, parg, 0);
169 }
170 
171 char *GBS_vglobal_string_copy(const char *templat, va_list parg) {
172  // goes to header: __ATTR__VFORMAT(1)
173  const char *gstr = globBuf.vstrf(templat, parg, 1);
174  return ARB_strduplen(gstr, last_global_string_size);
175 }
176 
177 const char *GBS_global_string_to_buffer(char *buffer, size_t bufsize, const char *templat, ...) {
178  // goes to header: __ATTR__FORMAT(3)
179 
180  // @@@ search for '\b(sprintf)\b\s*\(' and replace by GBS_global_string_to_buffer
181 
182  va_list parg;
183  int psize;
184 
185  arb_assert(buffer);
186  va_start(parg, templat);
187  PRINT2BUFFER_CHECKED(psize, buffer, bufsize, templat, parg);
188  va_end(parg);
189 
190  return buffer;
191 }
192 
193 char *GBS_global_string_copy(const char *templat, ...) {
194  // goes to header: __ATTR__FORMAT(1)
195  va_list parg;
196  va_start(parg, templat);
197  char *result = GBS_vglobal_string_copy(templat, parg);
198  va_end(parg);
199  return result;
200 }
201 
202 const char *GBS_global_string(const char *templat, ...) {
203  // goes to header: __ATTR__FORMAT(1)
204  va_list parg;
205  va_start(parg, templat);
206  const char *result = globBuf.vstrf(templat, parg, 0);
207  va_end(parg);
208  return result;
209 }
210 
211 const char *GBS_static_string(const char *str) {
212  return GBS_global_string("%s", str);
213 }
214 
215 GB_ERROR GBK_assert_msg(const char *assertion, const char *file, int linenr) {
216 #define BUFSIZE 1000
217  static char *buffer = NULp;
218  const char *result = NULp;
219  int old_size = last_global_string_size;
220 
221  if (!buffer) ARB_alloc(buffer, BUFSIZE);
222  result = GBS_global_string_to_buffer(buffer, BUFSIZE, "assertion '%s' failed in %s #%i", assertion, file, linenr);
223 
224  last_global_string_size = old_size;
225 
226  return result;
227 #undef BUFSIZE
228 }
229 
230 // -------------------------
231 // Error "handling"
232 
233 
234 // @@@ redesign GB_export_error et al
235 
236 /* To clearly distinguish between the two ways of error handling
237  * (which are: return GB_ERROR
238  * and: export the error)
239  *
240  * GB_export_error() shall only export, not return the error message.
241  * if only used for formatting GBS_global_string shall be used
242  * (most cases where GB_export_errorf is used are candidates for this.
243  * GB_export_error was generally misused for this, before
244  * GBS_global_string was added!)
245  *
246  * GB_export_IO_error() shall not export and be renamed into GB_IO_error()
247  *
248  * GB_export_error() shall fail if there is already an exported error
249  * (maybe always remember a stack trace of last error export (try whether copy of backtrace-array works))
250  *
251  * use GB_get_error() to import AND clear the error
252  */
253 
254 static char *GB_error_buffer = NULp;
255 
256 GB_ERROR GB_export_error(const char *error) { // just a temp hack around format-warnings
257  arb_assert(error);
258  return GB_export_errorf("%s", error);
259 }
260 
261 GB_ERROR GB_export_errorf(const char *templat, ...) {
262  /* goes to header:
263  * __ATTR__FORMAT(1)
264  * __ATTR__DEPRECATED_LATER("use GB_export_error(GBS_global_string(...))")
265  * because it's misused (where GBS_global_string should be used)
266  * old functionality will remain available via 'GB_export_error(GBS_global_string(...))'
267  */
268 
269  char buffer[GBS_GLOBAL_STRING_SIZE];
270  char *p = buffer;
271  va_list parg;
272 
273  // @@@ dont prepend ARB ERROR here
274 
275  p += sprintf(buffer, "ARB ERROR: ");
276  va_start(parg, templat);
277 
278  vsprintf(p, templat, parg);
279 
280  freedup(GB_error_buffer, buffer);
281  return GB_error_buffer;
282 }
283 
284 GB_ERROR GB_IO_error(const char *action, const char *filename) {
291  GB_ERROR io_error;
292  if (errno) {
293  io_error = strerror(errno);
294  }
295  else {
296  arb_assert(0); // unhandled error (which is NOT an IO-Error)
297  io_error =
298  "Some unhandled error occurred, but it was not an IO-Error. "
299  "Please send detailed information about how the error occurred to devel@arb-home.de "
300  "or ignore this error (if possible).";
301  }
302 
303  GB_ERROR error;
304  if (action) {
305  if (filename) error = GBS_global_string("While %s '%s': %s", action, filename, io_error);
306  else error = GBS_global_string("While %s <unknown file>: %s", action, io_error);
307  }
308  else {
309  if (filename) error = GBS_global_string("Concerning '%s': %s", filename, io_error);
310  else error = io_error;
311  }
312 
313  return error;
314 }
315 
316 // @@@ replace GB_export_IO_error() by GB_IO_error() and then export it if really needed
317 GB_ERROR GB_export_IO_error(const char *action, const char *filename) {
318  // goes to header: __ATTR__DEPRECATED_TODO("use GB_export_error(GB_IO_error(...))")
319  return GB_export_error(GB_IO_error(action, filename));
320 }
321 
322 // @@@ reactivate deprecations below
324  // goes to header: __ATTR__DEPRECATED_TODO("will be removed completely")
325  if (GB_error_buffer) {
326  fflush(stdout);
327  fprintf(stderr, "%s\n", GB_error_buffer);
328  }
329  return GB_error_buffer;
330 }
331 
333  // goes to header: __ATTR__DEPRECATED_TODO("consider using either GB_await_error() or GB_incur_error()")
334  return GB_error_buffer;
335 }
336 
338  return GB_error_buffer;
339 }
340 
342  if (GB_error_buffer) {
343  static SmartCharPtr err;
344  err = GB_error_buffer;
345  GB_error_buffer = NULp;
346  return &*err;
347  }
348  arb_assert(0); // please correct error handling
349 
350  return "Program logic error: Something went wrong, but reason is unknown";
351 }
352 
353 void GB_clear_error() { // clears the error buffer
354  freenull(GB_error_buffer);
355 }
356 
357 // AISC_MKPT_PROMOTE:inline GB_ERROR GB_incur_error() {
358 // AISC_MKPT_PROMOTE: /*! Take over responsibility for any potential (exported) error.
359 // AISC_MKPT_PROMOTE: * @return NULp if no error was exported; the error otherwise
360 // AISC_MKPT_PROMOTE: * Postcondition: no error is exported
361 // AISC_MKPT_PROMOTE: */
362 // AISC_MKPT_PROMOTE: return GB_have_error() ? GB_await_error() : NULp;
363 // AISC_MKPT_PROMOTE:}
364 // AISC_MKPT_PROMOTE:inline GB_ERROR GB_incur_error_if(bool error_may_occur) {
365 // AISC_MKPT_PROMOTE: /*! similar to GB_incur_error.
366 // AISC_MKPT_PROMOTE: * Additionally asserts no error may occur if 'error_may_occur' is false!
367 // AISC_MKPT_PROMOTE: */
368 // AISC_MKPT_PROMOTE: arb_assert(implicated(!error_may_occur, !GB_have_error()));
369 // AISC_MKPT_PROMOTE: return error_may_occur ? GB_incur_error() : NULp;
370 // AISC_MKPT_PROMOTE:}
371 
372 // @@@ search for 'GBS_global_string.*error' and replace with GB_failedTo_error or GB_append_exportedError
373 
374 GB_ERROR GB_failedTo_error(const char *do_something, const char *special, GB_ERROR error) {
375  if (error) {
376  if (special) {
377  error = GBS_global_string("Failed to %s '%s'.\n(Reason: %s)", do_something, special, error);
378  }
379  else {
380  error = GBS_global_string("Failed to %s.\n(Reason: %s)", do_something, error);
381  }
382  }
383  return error;
384 }
385 
387  // If an error has been exported, it gets appended as reason to given 'error'.
388  // If error is NULp, the exported error is returned (if any)
389  //
390  // This is e.g. useful if you search for SOMETHING in the DB w/o success (i.e. get NULp as result).
391  // In that case you can't be sure, whether SOMETHING just does not exist or whether it was not
392  // found because some other error occurred.
393 
394  if (GB_have_error()) {
395  if (error) return GBS_global_string("%s (Reason: %s)", error, GB_await_error());
396  return GB_await_error();
397  }
398  return error;
399 }
400 
401 // ---------------------
402 // Backtracing
403 
404 class BackTraceInfo *GBK_get_backtrace(size_t skipFramesAtBottom) { // only used ifdef TRACE_ALLOCS
405  return new BackTraceInfo(skipFramesAtBottom);
406 }
407 void GBK_dump_former_backtrace(class BackTraceInfo *trace, FILE *out, const char *message) { // only used ifdef TRACE_ALLOCS
408  demangle_backtrace(*trace, out, message);
409 }
410 
411 void GBK_free_backtrace(class BackTraceInfo *trace) { // only used ifdef TRACE_ALLOCS
412  delete trace;
413 }
414 
415 void GBK_dump_backtrace(FILE *out, const char *message) {
416  demangle_backtrace(BackTraceInfo(1), out ? out : stderr, message);
417 }
418 
419 // -------------------------------------------
420 // Error/notification functions
421 
422 void GB_internal_error(const char *message) {
423  /* Use GB_internal_error, when something goes badly wrong
424  * but you want to give the user a chance to save his database
425  *
426  * Note: it's NOT recommended to use this function!
427  */
428 
429  char *full_message = GBS_global_string_copy("Internal ARB Error: %s", message);
430  active_arb_handlers->show_error(full_message);
431  active_arb_handlers->show_error("ARB is most likely unstable now (due to this error).\n"
432  "If you've made changes to the database, consider to save it using a different name.\n"
433  "Try to fix the cause of the error and restart ARB.");
434 
435 #ifdef ASSERTION_USED
436  fputs(full_message, stderr);
437  arb_assert(0); // internal errors shall not happen, go fix it
438 #else
439  GBK_dump_backtrace(stderr, full_message);
440 #endif
441 
442  free(full_message);
443 }
444 
445 void GB_internal_errorf(const char *templat, ...) {
446  // goes to header: __ATTR__FORMAT(1)
448 }
449 
450 void GBK_terminate(const char *error) { // goes to header __ATTR__NORETURN
451  /* GBK_terminate is the emergency exit!
452  * only used if no other way to recover
453  */
454 
455  fprintf(stderr, "Error: '%s'\n", error);
456  fputs("Can't continue - terminating..\n", stderr);
457  GBK_dump_backtrace(stderr, "GBK_terminate (reason above) ");
458 
459  fflush(stderr);
460  ARB_SIGSEGV(0); // GBK_terminate shall not be called, fix reason for call (this will crash in RELEASE version)
461  exit(ARB_CRASH_CODE(0)); // should not be reached..just ensure ARB really terminates if somebody changes ARB_SIGSEGV
462 }
463 
464 void GBK_terminatef(const char *templat, ...) {
465  // goes to header: __ATTR__FORMAT(1) __ATTR__NORETURN
467 }
468 
469 // AISC_MKPT_PROMOTE:inline void GBK_terminate_on_error(const char *error) { if (error) GBK_terminatef("Fatal error: %s", error); }
470 
471 void GB_warning(const char *message) {
472  /* If program uses GUI, the message is printed via aw_message, otherwise it goes to stdout
473  * see also : GB_information
474  */
476 }
477 void GB_warningf(const char *templat, ...) {
478  // goes to header: __ATTR__FORMAT(1)
479  FORWARD_FORMATTED(GB_warning, templat);
480 }
481 
482 void GB_information(const char *message) {
483  /* this message is always printed to stdout (regardless whether program uses GUI or not)
484  * (if it is not redirected using ARB_redirect_handlers_to)
485  * see also : GB_warning
486  */
488 }
489 void GB_informationf(const char *templat, ...) {
490  // goes to header: __ATTR__FORMAT(1)
492 }
493 
494 
495 #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
496 
497 void GBS_reuse_buffer(const char *global_buffer) {
498  // If you've just shortely used a buffer, you can put it back here
499  va_list empty;
500  globBuf.vstrf(global_buffer, empty, -1); // omg hax
501 }
502 
503 // @@@ search for '\b(system)\b\s*\(' and use GBK_system instead
504 
505 GB_ERROR GBK_system(const char *system_command) {
506  // goes to header: __ATTR__USERESULT
507  fflush(stdout);
508  fprintf(stderr, "[Action: `%s`]\n", system_command); fflush(stderr);
509 
510  int res = system(system_command);
511 
512  fflush(stdout);
513  fflush(stderr);
514 
515  GB_ERROR error = NULp;
516  if (res) {
517  if (res == -1) {
518  error = GB_IO_error("forking", system_command);
519  error = GBS_global_string("System call failed (Reason: %s)", error);
520  }
521  else {
522  error = GBS_global_string("System call failed (result=%i)", res);
523  }
524 
525  error = GBS_global_string("%s\n"
526  "System call was `%s`%s",
527  error, system_command,
528  res == -1 ? "" : "\n(Note: console window may contain additional information)");
529  }
530  return error;
531 }
532 
533 char *GBK_singlequote(const char *arg) {
537  if (!arg[0]) return ARB_strdup("''");
538 
539  GBS_strstruct out(500);
540  const char *existing_quote = strchr(arg, '\'');
541 
542  while (existing_quote) {
543  if (existing_quote>arg) {
544  out.put('\'');
545  out.ncat(arg, existing_quote-arg);
546  out.put('\'');
547  }
548  out.put('\\');
549  out.put('\'');
550  arg = existing_quote+1;
551  existing_quote = strchr(arg, '\'');
552  }
553 
554  if (arg[0]) {
555  out.put('\'');
556  out.cat(arg);
557  out.put('\'');
558  }
559  return out.release();
560 }
561 
562 char *GBK_doublequote(const char *arg) {
567  const char *charsToEscape = "\"\\";
568  const char *escape = arg+strcspn(arg, charsToEscape);
569  GBS_strstruct out(500);
570 
571  out.put('"');
572  while (escape[0]) {
573  out.ncat(arg, escape-arg);
574  out.put('\\');
575  out.put(escape[0]);
576  arg = escape+1;
577  escape = arg+strcspn(arg, charsToEscape);
578  }
579  out.cat(arg);
580  out.put('"');
581  return out.release();
582 }
583 
584 // --------------------------------------------------------------------------------
585 
586 #ifdef UNIT_TESTS
587 #ifndef TEST_UNIT_H
588 #include <test_unit.h>
589 #endif
590 
591 #include "FileContent.h"
592 #include <unistd.h>
593 
594 #define TEST_EXPECT_SQUOTE(plain,squote_expected) do { \
595  char *plain_squoted = GBK_singlequote(plain); \
596  TEST_EXPECT_EQUAL(plain_squoted, squote_expected); \
597  free(plain_squoted); \
598  } while(0)
599 
600 #define TEST_EXPECT_DQUOTE(plain,dquote_expected) do { \
601  char *plain_dquoted = GBK_doublequote(plain); \
602  TEST_EXPECT_EQUAL(plain_dquoted, dquote_expected); \
603  free(plain_dquoted); \
604  } while(0)
605 
606 #define TEST_EXPECT_ECHOED_EQUALS(echoarg,expected_echo) do { \
607  char *cmd = GBS_global_string_copy("echo %s > %s", echoarg, tmpfile); \
608  TEST_EXPECT_NO_ERROR(GBK_system(cmd)); \
609  FileContent out(tmpfile); \
610  TEST_EXPECT_NO_ERROR(out.has_error()); \
611  TEST_EXPECT_EQUAL(out.lines()[0], expected_echo); \
612  free(cmd); \
613  } while(0)
614 
615 #define TEST_EXPECT_SQUOTE_IDENTITY(plain) do { \
616  char *plain_squoted = GBK_singlequote(plain); \
617  TEST_EXPECT_ECHOED_EQUALS(plain_squoted,plain); \
618  free(plain_squoted); \
619  } while(0)
620 
621 #define TEST_EXPECT_DQUOTE_IDENTITY(plain) do { \
622  char *plain_dquoted = GBK_doublequote(plain); \
623  TEST_EXPECT_ECHOED_EQUALS(plain_dquoted,plain); \
624  free(plain_dquoted); \
625  } while(0)
626 
627 void TEST_quoting() {
628  const char *tmpfile = "quoted.output";
629 
630  struct quoting {
631  const char *plain;
632  const char *squoted;
633  const char *dquoted;
634  } args[] = {
635  { "", "''", "\"\"" }, // empty
636  { " ", "' '", "\" \"" }, // a space
637  { "unquoted", "'unquoted'", "\"unquoted\"" },
638  { "part 'is' squoted", "'part '\\''is'\\'' squoted'", "\"part 'is' squoted\"" },
639  { "part \"is\" dquoted", "'part \"is\" dquoted'", "\"part \\\"is\\\" dquoted\"" },
640  { "'squoted'", "\\''squoted'\\'", "\"'squoted'\"" },
641  { "\"dquoted\"", "'\"dquoted\"'", "\"\\\"dquoted\\\"\"" },
642  { "'", "\\'", "\"'\"" }, // a single quote
643  { "\"", "'\"'", "\"\\\"\"" }, // a double quote
644  { "\\", "'\\'", "\"\\\\\"" }, // a backslash
645  { "'\"'\"", "\\''\"'\\''\"'", "\"'\\\"'\\\"\"" }, // interleaved quotes
646  { "`wc -c <min_ascii.arb | tr -d ' '`",
647  "'`wc -c <min_ascii.arb | tr -d '\\'' '\\''`'",
648  "\"`wc -c <min_ascii.arb | tr -d ' '`\"" }, // interleaved quotes
649  };
650 
651  for (unsigned a = 0; a<ARRAY_ELEMS(args); ++a) {
652  TEST_ANNOTATE(GBS_global_string("a=%i", a));
653  const quoting& arg = args[a];
654 
655  TEST_EXPECT_SQUOTE(arg.plain, arg.squoted);
656  TEST_EXPECT_SQUOTE_IDENTITY(arg.plain);
657 
658  TEST_EXPECT_DQUOTE(arg.plain, arg.dquoted);
659  if (a != 11) {
660  TEST_EXPECT_DQUOTE_IDENTITY(arg.plain);
661  }
662  else { // backticked wc call
663  char *dquoted = GBK_doublequote(arg.plain);
664  TEST_EXPECT_ECHOED_EQUALS(dquoted, "16"); // 16 is number of chars in min_ascii.arb
665  free(dquoted);
666  }
667  }
668 
669  TEST_EXPECT_EQUAL(unlink(tmpfile), 0);
670 }
671 
672 #endif // UNIT_TESTS
673 
674 // --------------------------------------------------------------------------------
675 
GB_ERROR GB_get_error()
Definition: arb_msg.cxx:332
#define arb_assert(cond)
Definition: arb_assert.h:245
const char * GB_ERROR
Definition: arb_core.h:25
string result
void GBS_restore_global_buffers(GlobalStringBuffers *saved)
Definition: arb_msg.cxx:161
void GB_warning(const char *message)
Definition: arb_msg.cxx:471
const char * GBS_vglobal_string(const char *templat, va_list parg)
Definition: arb_msg.cxx:166
gb_warning_func_type show_warning
Definition: arb_handlers.h:39
static char * GB_error_buffer
Definition: arb_msg.cxx:254
GB_ERROR GBK_system(const char *system_command)
Definition: arb_msg.cxx:505
static size_t last_global_string_size
Definition: arb_msg.cxx:42
gb_information_func_type show_message
Definition: arb_handlers.h:40
GB_ERROR GB_append_exportedError(GB_ERROR error)
Definition: arb_msg.cxx:386
void demangle_backtrace(const class BackTraceInfo &trace, FILE *out, const char *message)
Definition: arb_backtrace.h:95
const char * GBS_global_string_to_buffer(char *buffer, size_t bufsize, const char *templat,...)
Definition: arb_msg.cxx:177
char * GBK_doublequote(const char *arg)
Definition: arb_msg.cxx:562
GB_ERROR GB_IO_error(const char *action, const char *filename)
Definition: arb_msg.cxx:284
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
#define ARB_CRASH_CODE(sig)
Definition: arb_backtrace.h:33
void GB_internal_errorf(const char *templat,...)
Definition: arb_msg.cxx:445
GB_ERROR GB_export_IO_error(const char *action, const char *filename)
Definition: arb_msg.cxx:317
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:202
#define FORWARD_FORMATTED(receiver, format)
Definition: arb_msg_fwd.h:19
bool GB_have_error()
Definition: arb_msg.cxx:337
void GBK_terminatef(const char *templat,...)
Definition: arb_msg.cxx:464
char * release()
Definition: arb_strbuf.h:80
#define ARB_SIGSEGV(backtrace)
Definition: arb_assert.h:174
void cat(const char *from)
Definition: arb_strbuf.h:158
char * GBS_vglobal_string_copy(const char *templat, va_list parg)
Definition: arb_msg.cxx:171
static GlobalStringBuffers globBuf
Definition: arb_msg.cxx:85
class BackTraceInfo * GBK_get_backtrace(size_t skipFramesAtBottom)
Definition: arb_msg.cxx:404
void GBK_dump_former_backtrace(class BackTraceInfo *trace, FILE *out, const char *message)
Definition: arb_msg.cxx:407
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
gb_error_handler_type show_error
Definition: arb_handlers.h:38
GB_ERROR GB_export_error(const char *error)
Definition: arb_msg.cxx:256
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:341
fflush(stdout)
char * ARB_strduplen(const char *p, unsigned len)
Definition: arb_string.h:33
void GB_warningf(const char *templat,...)
Definition: arb_msg.cxx:477
TYPE * ARB_alloc(size_t nelem)
Definition: arb_mem.h:56
arb_handlers * active_arb_handlers
void GB_clear_error()
Definition: arb_msg.cxx:353
void message(char *errortext)
static void error(const char *msg)
Definition: mkptypes.cxx:96
GB_ERROR GBK_assert_msg(const char *assertion, const char *file, int linenr)
Definition: arb_msg.cxx:215
__ATTR__VFORMAT_MEMBER(1) const char *vstrf(const char *templat
void GBS_reuse_buffer(const char *global_buffer)
Definition: arb_msg.cxx:497
#define BUFSIZE
va_end(argPtr)
GB_ERROR GB_print_error()
Definition: arb_msg.cxx:323
fputs(TRACE_PREFIX, stderr)
GB_ERROR GB_export_errorf(const char *templat,...)
Definition: arb_msg.cxx:261
void GB_internal_error(const char *message)
Definition: arb_msg.cxx:422
void ncat(const char *from, size_t count)
Definition: arb_strbuf.h:151
char * GBK_singlequote(const char *arg)
Definition: arb_msg.cxx:533
BackTraceInfo(size_t skipFramesAtBottom)
Definition: arb_backtrace.h:46
void GBK_free_backtrace(class BackTraceInfo *trace)
Definition: arb_msg.cxx:411
GB_ERROR GB_failedTo_error(const char *do_something, const char *special, GB_ERROR error)
Definition: arb_msg.cxx:374
va_start(argPtr, format)
const char * GBS_static_string(const char *str)
Definition: arb_msg.cxx:211
void GBK_dump_backtrace(FILE *out, const char *message)
Definition: arb_msg.cxx:415
#define PRINT2BUFFER_CHECKED(printed, buffer, bufsize, templat, parg)
Definition: arb_msg.cxx:57
GlobalStringBuffers * GBS_store_global_buffers()
Definition: arb_msg.cxx:155
#define NULp
Definition: cxxforward.h:114
void GB_information(const char *message)
Definition: arb_msg.cxx:482
void GBK_terminate(const char *error)
Definition: arb_msg.cxx:450
void GB_informationf(const char *templat,...)
Definition: arb_msg.cxx:489
#define FORWARD_FORMATTED_NORETURN(receiver, format)
Definition: arb_msg_fwd.h:29
va_list int allow_reuse
Definition: arb_msg.cxx:82
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1283
#define GBS_GLOBAL_STRING_SIZE
Definition: arb_msg.cxx:43
#define GLOBAL_STRING_BUFFERS
Definition: arb_msg.cxx:40
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:193
void put(char c)
Definition: arb_strbuf.h:138