ARB
adsocket.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : adsocket.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include <unistd.h>
12 
13 #include <climits>
14 #include <cstdarg>
15 #include <cctype>
16 
17 #include <netdb.h>
18 #include <netinet/tcp.h>
19 #include <signal.h>
20 #include <sys/mman.h>
21 #include <sys/socket.h>
22 #include <sys/stat.h>
23 #include <sys/time.h>
24 #include <sys/un.h>
25 
26 #if defined(DARWIN)
27 # include <sys/sysctl.h>
28 #endif // DARWIN
29 
30 #include <arb_cs.h>
31 #include <arb_str.h>
32 #include <arb_strbuf.h>
33 #include <arb_file.h>
34 #include <arb_sleep.h>
35 #include <arb_pathlen.h>
36 
37 #include "gb_comm.h"
38 #include "gb_data.h"
39 #include "gb_localdata.h"
40 #include "arbdbt.h"
41 
42 #include <SigHandler.h>
43 
44 #include <algorithm>
45 #include <arb_misc.h>
46 #include <arb_defs.h>
47 
48 // ------------------------------------------------
49 // private read and write socket functions
50 
54 }
55 
56 static long gbcm_read_buffered(int socket, char *ptr, long size) {
57  /* write_ptr ptr to not read data
58  write_free = write_bufsize-size of non read data;
59  */
60  long holding;
62  if (holding <= 0) {
63  holding = read(socket, gb_local->write_buffer, (size_t)gb_local->write_bufsize);
64 
65  if (holding < 0) {
66  fprintf(stderr, "Cannot read data from client: len=%li (%s, errno %i)\n",
67  holding, strerror(errno), errno);
68  return 0;
69  }
71  gb_local->write_free-=holding;
72  }
73  if (size>holding) size = holding;
74  memcpy(ptr, gb_local->write_ptr, (int)size);
75  gb_local->write_ptr += size;
76  gb_local->write_free += size;
77  return size;
78 }
79 
80 long gbcm_read(int socket, char *ptr, long size) {
81  long leftsize = size;
82  while (leftsize) {
83  long readsize = gbcm_read_buffered(socket, ptr, leftsize);
84  if (readsize<=0) return 0;
85  ptr += readsize;
86  leftsize -= readsize;
87  }
88 
89  return size;
90 }
91 
93  long leftsize = gb_local->write_ptr - gb_local->write_buffer;
94  ssize_t writesize;
95  char *ptr = gb_local->write_buffer;
96 
97  // once we're done, the buffer will be free
100 
101  while (leftsize) {
102 #ifdef MSG_NOSIGNAL
103  // Linux has MSG_NOSIGNAL, but not SO_NOSIGPIPE
104  // prevent SIGPIPE here
105  writesize = send(socket, ptr, leftsize, MSG_NOSIGNAL);
106 #else
107  writesize = write(socket, ptr, leftsize);
108 #endif
109 
110  if (writesize<0) {
111  if (gb_local->iamclient) {
112  fprintf(stderr,
113  "Client (pid=%i) terminating after failure to contact database (%s).",
114  getpid(), strerror(errno));
115  exit(EXIT_SUCCESS);
116  }
117  else {
118  fprintf(stderr, "Error sending data to client (%s).", strerror(errno));
119  return GBCM_SERVER_FAULT;
120  }
121  }
122  ptr += writesize;
123  leftsize -= writesize;
124  }
125 
126  return GBCM_SERVER_OK;
127 }
128 
129 GBCM_ServerResult gbcm_write(int socket, const char *ptr, long size) {
130  while (size >= gb_local->write_free) {
131  memcpy(gb_local->write_ptr, ptr, (int)gb_local->write_free);
133  size -= gb_local->write_free;
134  ptr += gb_local->write_free;
135 
136  gb_local->write_free = 0;
137  if (gbcm_write_flush(socket)) return GBCM_SERVER_FAULT;
138  }
139  memcpy(gb_local->write_ptr, ptr, (int)size);
140  gb_local->write_ptr += size;
141  gb_local->write_free -= size;
142  return GBCM_SERVER_OK;
143 }
144 
145 GB_ERROR gbcm_open_socket(const char *path, bool do_connect, int *psocket, char **unix_name) {
146  if (path && strcmp(path, ":") == 0) {
147  path = GBS_read_arb_tcp("ARB_DB_SERVER");
148  if (!path) {
149  return GB_await_error();
150  }
151  }
152 
153  return arb_open_socket(path, do_connect, psocket, unix_name);
154 }
155 
156 #if 0
157 // never used code
158 // (similar is done in GBCMS_shutdown, called e.g. from nt_disconnect_from_db)
159 long gbcms_close(gbcmc_comm *link) {
160  if (link->socket) {
161  close(link->socket);
162  link->socket = 0;
163  if (link->unix_name) {
164  unlink(link->unix_name);
165  }
166  }
167  return 0;
168 }
169 #endif
170 
171 gbcmc_comm *gbcmc_open(const char *path) {
172  gbcmc_comm *link = ARB_calloc<gbcmc_comm>(1);
173  GB_ERROR err = gbcm_open_socket(path, true, &link->socket, &link->unix_name);
174 
175  if (err) {
176  if (link->unix_name) free(link->unix_name); // @@@
177  free(link);
178  if (*err) {
179  GB_internal_errorf("ARB_DB_CLIENT_OPEN\n(Reason: %s)", err);
180  }
181  return NULp;
182  }
183  gb_local->iamclient = true;
184  return link;
185 }
186 
187 long gbcm_write_two(int socket, long a, long c) {
188  long ia[3];
189  ia[0] = a;
190  ia[1] = 3;
191  ia[2] = c;
192  if (!socket) return 1;
193  return gbcm_write(socket, (const char *)ia, sizeof(long)*3);
194 }
195 
196 
197 GBCM_ServerResult gbcm_read_two(int socket, long a, long *b, long *c) {
204  long ia[3];
205  long size;
206  size = gbcm_read(socket, (char *)&(ia[0]), sizeof(long)*3);
207  if (size != sizeof(long) * 3) {
208  GB_internal_errorf("receive failed: %zu bytes expected, %li got, keyword %lX",
209  sizeof(long) * 3, size, a);
210  return GBCM_SERVER_FAULT;
211  }
212  if (ia[0] != a) {
213  GB_internal_errorf("received keyword failed %lx != %lx\n", ia[0], a);
214  return GBCM_SERVER_FAULT;
215  }
216  if (b) {
217  *b = ia[1];
218  }
219  else {
220  if (ia[1]!=3) {
221  GB_internal_error("receive failed: size not 3\n");
222  return GBCM_SERVER_FAULT;
223  }
224  }
225  *c = ia[2];
226  return GBCM_SERVER_OK;
227 }
228 
229 GBCM_ServerResult gbcm_write_string(int socket, const char *key) {
230  if (key) {
231  size_t len = strlen(key);
232  gbcm_write_long(socket, len);
233  if (len) gbcm_write(socket, key, len);
234  }
235  else {
236  gbcm_write_long(socket, -1);
237  }
238  return GBCM_SERVER_OK;
239 }
240 
241 char *gbcm_read_string(int socket) {
242  char *key;
243  long len = gbcm_read_long(socket);
244 
245  if (len) {
246  if (len>0) {
247  ARB_calloc(key, len+1);
248  gbcm_read(socket, key, len);
249  }
250  else {
251  key = NULp;
252  }
253  }
254  else {
255  key = ARB_strdup("");
256  }
257 
258  return key;
259 }
260 
261 GBCM_ServerResult gbcm_write_long(int socket, long data) {
262  gbcm_write(socket, (char*)&data, sizeof(data));
263  return GBCM_SERVER_OK;
264 }
265 
266 long gbcm_read_long(int socket) {
267  long data;
268  gbcm_read(socket, (char*)&data, sizeof(data));
269  return data;
270 }
271 
272 char *GB_read_fp(FILE *in) {
279  GBS_strstruct buf(4096);
280 
281  int c;
282  while (EOF != (c = getc(in))) {
283  buf.put(c);
284  }
285  return buf.release_memfriendly();
286 }
287 
288 char *GB_read_file(const char *path) { // consider using class FileContent instead
295  char *result = NULp;
296 
297  if (strcmp(path, "-") == 0) {
298  result = GB_read_fp(stdin);
299  }
300  else {
301  char *epath = GBS_eval_env(path);
302 
303  if (epath) {
304  FILE *in = fopen(epath, "rt");
305 
306  if (!in) GB_export_error(GB_IO_error("reading", epath));
307  else {
308  long data_size = GB_size_of_file(epath);
309 
310  if (data_size >= 0) {
311  result = ARB_alloc<char>(data_size+1);
312 
313  data_size = fread(result, 1, data_size, in);
314  result[data_size] = 0;
315  }
316  fclose(in);
317  }
318  }
319  free(epath);
320  }
321  return result;
322 }
323 
324 char *GB_map_FILE(FILE *in, int writeable) {
325  int fi = fileno(in);
326  size_t size = GB_size_of_FILE(in);
327  char *buffer;
328  if (size<=0) {
329  GB_export_error("GB_map_file: sorry file not found");
330  return NULp;
331  }
332  if (writeable) {
333  buffer = (char*)mmap(NULp, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fi, 0);
334  }
335  else {
336  buffer = (char*)mmap(NULp, size, PROT_READ, MAP_SHARED, fi, 0);
337  }
338  if (buffer == MAP_FAILED) {
339  GB_export_errorf("GB_map_file: Error: Out of Memory: mmap failed (errno: %i)", errno);
340  return NULp;
341  }
342  return buffer;
343 }
344 
345 char *GB_map_file(const char *path, int writeable) {
346  FILE *in;
347  char *buffer;
348  in = fopen(path, "r");
349  if (!in) {
350  GB_export_errorf("GB_map_file: sorry file '%s' not readable", path);
351  return NULp;
352  }
353  buffer = GB_map_FILE(in, writeable);
354  fclose(in);
355  return buffer;
356 }
357 
359  timeval tp;
360  if (gettimeofday(&tp, NULp)) return 0;
361  return tp.tv_sec;
362 }
363 
364 GB_ERROR GB_textprint(const char *path) {
365  // goes to header: __ATTR__USERESULT
366  char *fpath = GBS_eval_env(path);
367  char *quoted_fpath = GBK_singlequote(fpath);
368  const char *command = GBS_global_string("arb_textprint %s &", quoted_fpath);
369  GB_ERROR error = GBK_system(command);
370  error = GB_failedTo_error("print textfile", fpath, error);
371  free(quoted_fpath);
372  free(fpath);
373  return error;
374 }
375 
376 // --------------------------------------------------------------------------------
377 
379  static const char *path = NULp;
380  if (!path) {
381  path = ARB_getenv_ignore_empty("PATH");
382  if (!path) {
383  path = GBS_eval_env("/bin:/usr/bin:$(ARBHOME)/bin");
384  GB_informationf("Your PATH variable is empty - using '%s' as search path.", path);
385  }
386  else {
387  char *arbbin = GBS_eval_env("$(ARBHOME)/bin");
388  if (!strstr(path, arbbin)) {
389  GB_warningf("Your PATH variable does not contain '%s'. Things may not work as expected.", arbbin);
390  }
391  free(arbbin);
392  }
393  }
394  return path;
395 }
396 
397 // --------------------------------------------------------------------------------
398 // Functions to find an executable
399 
400 static char *GB_find_executable(GB_CSTR description_of_executable, ...) {
401  // goes to header: __ATTR__SENTINEL
402  /* search the path for an executable with any of the given names (...)
403  * if any is found, it's full path is returned
404  * if none is found, a warning call is returned (which can be executed without harm)
405  */
406 
407  GB_CSTR name;
408  char *found = NULp;
409  va_list args;
410 
411  va_start(args, description_of_executable);
412  while (!found && (name = va_arg(args, GB_CSTR))) found = ARB_executable(name, GB_getenvPATH());
413  va_end(args);
414 
415  if (!found) { // none of the executables has been found
416  char *looked_for;
417  char *msg;
418  {
419  GBS_strstruct buf(100);
420  bool first = true;
421 
422  va_start(args, description_of_executable);
423  while ((name = va_arg(args, GB_CSTR))) {
424  if (!first) buf.cat(", ");
425  first = false;
426  buf.cat(name);
427  }
428  va_end(args);
429  looked_for = buf.release();
430  }
431 
432  msg = GBS_global_string_copy("Could not find a %s (looked for: %s)", description_of_executable, looked_for);
433  GB_warning(msg);
434  found = GBS_global_string_copy("echo \"%s\" ; arb_ign Parameters", msg);
435  free(msg);
436  free(looked_for);
437  }
438  else {
440  char *description = GBS_global_string_copy("the %s derived from environment variable PATH", description_of_executable);
441  ARB_warn_about_unwanted_chars(found, description);
442  free(description);
443  }
444  GB_informationf("Using %s '%s' ('%s')", description_of_executable, name, found);
445  }
446  return found;
447 }
448 
449 // --------------------------------------------------------------------------------
450 // Functions to access the environment variables used by ARB:
451 
452 static char *getenv_executable(GB_CSTR envvar) {
453  // get full path of executable defined by 'envvar'
454  // returns 0 if
455  // - envvar not defined or
456  // - not defining an executable (warns about that)
457 
458  char *result = NULp;
459  const char *exe_name = ARB_getenv_ignore_empty(envvar);
460 
461  if (exe_name) {
462 #if defined(DARWIN)
463  // On MacOS, the open command can be used to open files with MacOS
464  // applications. The open command fails the ARB executable test. If no
465  // application is passed to the open command, the default application
466  // for the file type is used or the user is presented with a dialog to
467  // chose an application if no default application is used. This is very
468  // hard to test from within ARB. Therefore, commands that start with
469  // open are considered to be valid applications and the executable test
470  // is not run.
471  if (!strncasecmp(exe_name, "open", 4)) {
472  return ARB_strdup(exe_name);
473  }
474 #endif
475 
476  result = ARB_executable(exe_name, GB_getenvPATH());
477  if (!result) {
478  GB_warningf("Environment variable '%s' contains '%s' (which is not an executable)", envvar, exe_name);
479  }
480 
481  if (ARB_path_contains_unwanted_chars(result)) {
482  char *description = GBS_global_string_copy("the executable derived from environment variables '%s' and PATH", envvar);
483  ARB_warn_about_unwanted_chars(result, description);
484  free(description);
485  }
486  }
487 
488  return result;
489 }
490 
491 static char *getenv_existing_directory(GB_CSTR envvar) {
492  // get full path of directory defined by 'envvar'
493  // return 0 if
494  // - envvar is not defined or
495  // - does not point to a directory (warns about that)
496 
497  char *result = NULp;
498  const char *dir_name = ARB_getenv_ignore_empty(envvar);
499 
500  if (dir_name) {
501  if (GB_is_directory(dir_name)) {
502  result = ARB_strdup(dir_name);
503  if (ARB_path_contains_unwanted_chars(result)) {
504  char *description = GBS_global_string_copy("the directory derived from environment variable '%s'", envvar);
505  ARB_warn_about_unwanted_chars(result, description);
506  free(description);
507  }
508  }
509  else {
510  GB_warningf("Environment variable '%s' should contain the path of an existing directory.\n"
511  "(current content '%s' has been ignored.)", envvar, dir_name);
512  }
513  }
514  return result;
515 }
516 
517 void GB_setenv(const char *var, const char *value) {
518  if (setenv(var, value, 1) != 0) {
519  GB_warningf("Could not set environment variable '%s'. This might cause problems in subprocesses.\n"
520  "(Reason: %s)", var, strerror(errno));
521  }
522 }
523 
525  static const char *xterm = NULp;
526  if (!xterm) {
527  xterm = ARB_getenv_ignore_empty("ARB_XTERM"); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARB_XTERM
528  if (!xterm) xterm = "xterm -sl 1000 -sb -geometry 150x60";
529  }
530  return xterm;
531 }
532 
534  static const char *xcmd = NULp;
535  if (!xcmd) {
536  xcmd = ARB_getenv_ignore_empty("ARB_XCMD"); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARB_XCMD
537  if (!xcmd) {
538  const char *xterm = GB_getenvARB_XTERM();
539  gb_assert(xterm);
540  xcmd = GBS_global_string_copy("%s -e", xterm);
541  }
542  }
543  return xcmd;
544 }
545 
547  static const char *user = NULp;
548  if (!user) {
549  user = ARB_getenv_ignore_empty("USER");
550  if (!user) user = ARB_getenv_ignore_empty("LOGNAME");
551  if (!user) {
552  user = ARB_getenv_ignore_empty("HOME");
553  if (user && strrchr(user, '/')) user = strrchr(user, '/')+1;
554  }
555  if (!user) {
556  fprintf(stderr, "WARNING: Cannot identify user: environment variables USER, LOGNAME and HOME not set\n");
557  user = "UnknownUser";
558  }
559  }
560  return user;
561 }
562 
563 
565  static SmartCharPtr Home;
566  if (Home.isNull()) {
567  char *home = getenv_existing_directory("HOME");
568  if (!home) {
569  home = nulldup(GB_getcwd());
570  if (!home) home = ARB_strdup(".");
571  fprintf(stderr, "WARNING: Cannot identify user's home directory: environment variable HOME not set\n"
572  "Using current directory (%s) as home.\n", home);
573  }
574  gb_assert(home);
575  Home = home;
576  }
577  return &*Home;
578 }
579 
581  static SmartCharPtr Arbhome;
582  if (Arbhome.isNull()) {
583  char *arbhome = getenv_existing_directory("ARBHOME"); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARBHOME
584  if (!arbhome) {
585  fprintf(stderr, "Fatal ERROR: Environment Variable ARBHOME not found !!!\n"
586  " Please set 'ARBHOME' to the installation path of ARB\n");
587  exit(EXIT_FAILURE);
588  }
589  Arbhome = arbhome;
590  }
591  return &*Arbhome;
592 }
593 
595  static const char *am = NULp;
596  if (!am) {
597  am = getenv_existing_directory("ARBMACRO"); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARBMACRO
598  if (!am) am = ARB_strdup(GB_path_in_ARBLIB("macros"));
599  }
600  return am;
601 }
602 
603 static char *getenv_autodirectory(const char *envvar, const char *defaultDirectory) {
604  // if environment variable 'envvar' contains an existing directory -> use that
605  // otherwise fallback to 'defaultDirectory' (create if not existing)
606  // return heap-copy of full directory name
607  char *dir = getenv_existing_directory(envvar);
608  if (!dir) {
609  dir = GBS_eval_env(defaultDirectory);
611  char *description = GBS_global_string_copy("the default directory expanded from expression '%s'", defaultDirectory);
612  ARB_warn_about_unwanted_chars(dir, description);
613  free(description);
614  }
615  if (!GB_is_directory(dir)) {
617  if (error) GB_warning(error);
618  }
619  }
620  return dir;
621 }
622 
624  static SmartCharPtr ArbProps;
625  if (ArbProps.isNull()) ArbProps = getenv_autodirectory("ARB_PROP", GB_path_in_HOME(".arb_prop")); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARB_PROP
626  return &*ArbProps;
627 }
628 
630  static SmartCharPtr ArbMacroHome;
631  if (ArbMacroHome.isNull()) ArbMacroHome = getenv_autodirectory("ARBMACROHOME", GB_path_in_arbprop("macros")); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARBMACROHOME
632  return &*ArbMacroHome;
633 }
634 
636  static SmartCharPtr ArbConfig;
637  if (ArbConfig.isNull()) ArbConfig = getenv_autodirectory("ARBCONFIG", GB_path_in_arbprop("cfgSave")); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARBCONFIG
638  return &*ArbConfig;
639 }
640 
642  static const char *gs = NULp;
643  if (!gs) {
644  gs = getenv_executable("ARB_GS"); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARB_GS
645  if (!gs) {
646 #if defined(DARWIN)
647  // use default application for PS files on MacOS if envvar is not
648  // set - defaults to Apple Preview application
649  // -W waits until the user has deleted the application this is
650  // required
651  gs = ARB_strdup("open -W");
652 #else
653  gs = GB_find_executable("Postscript viewer", "xreader", "gv", "ghostview", NULp);
654 #endif
655  }
656  }
657  return gs;
658 }
659 
661  static const char *pdfview = NULp;
662  if (!pdfview) {
663  pdfview = getenv_executable("ARB_PDFVIEW"); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARB_PDFVIEW
664  if (!pdfview) {
665 #if defined(DARWIN)
666  // use default application for PDF files on MacOS if envvar is not
667  // set - defaults to Apple Preview application
668  pdfview = ARB_strdup("open -W");
669 #else
670  pdfview = GB_find_executable("PDF viewer", "xreader", "epdfview", "xpdf", "kpdf", "acroread", "gv", NULp);
671 #endif
672  }
673  }
674  return pdfview;
675 }
676 
678  static const char *dp = NULp;
679  if (!dp) {
680  char *res = getenv_existing_directory("ARB_DOC"); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARB_DOC
681  if (res) dp = res;
682  else dp = ARB_strdup(GB_path_in_ARBLIB("help"));
683  }
684  return dp;
685 }
686 
688  static const char *dp = NULp;
689  if (!dp) {
690  char *res = getenv_existing_directory("ARB_HTMLDOC"); // doc in ../HELP_SOURCE/source/arb_envar.hlp@ARB_HTMLDOC
691  if (res) dp = res;
692  else dp = ARB_strdup(GB_path_in_ARBLIB("help_html"));
693  }
694  return dp;
695 
696 }
697 
699 
701  // Install 'hook' to be called by GB_getenv().
702  // If the 'hook' returns NULp, normal expansion takes place.
703  // Otherwise GB_getenv() returns result from 'hook'
704 
705  gb_getenv_hook oldHook = getenv_hook;
706  getenv_hook = hook;
707  return oldHook;
708 }
709 
710 GB_CSTR GB_getenv(const char *env) {
711  if (getenv_hook) {
712  const char *result = getenv_hook(env);
713  if (result) return result;
714  }
715  if (strncmp(env, "ARB", 3) == 0) {
716  // doc in ../HELP_SOURCE/source/arb_envar.hlp
717 
718  if (strcmp(env, "ARBHOME") == 0) return GB_getenvARBHOME();
719  if (strcmp(env, "ARB_PROP") == 0) return GB_getenvARB_PROP();
720  if (strcmp(env, "ARBCONFIG") == 0) return GB_getenvARBCONFIG();
721  if (strcmp(env, "ARBMACROHOME") == 0) return GB_getenvARBMACROHOME();
722  if (strcmp(env, "ARBMACRO") == 0) return GB_getenvARBMACRO();
723 
724  if (strcmp(env, "ARB_GS") == 0) return GB_getenvARB_GS();
725  if (strcmp(env, "ARB_PDFVIEW") == 0) return GB_getenvARB_PDFVIEW();
726  if (strcmp(env, "ARB_DOC") == 0) return GB_getenvDOCPATH();
727  if (strcmp(env, "ARB_XTERM") == 0) return GB_getenvARB_XTERM();
728  if (strcmp(env, "ARB_XCMD") == 0) return GB_getenvARB_XCMD();
729  }
730  else {
731  if (strcmp(env, "HOME") == 0) return GB_getenvHOME();
732  if (strcmp(env, "USER") == 0) return GB_getenvUSER();
733  }
734 
735  return ARB_getenv_ignore_empty(env);
736 }
737 
740  // set all variables needed in ARB subprocesses
741  GB_setenv("ARB_XCMD", GB_getenvARB_XCMD());
742  }
743 };
744 
746 
747 bool GB_host_is_local(const char *hostname) {
748  // returns true if host is local
749 
750  arb_assert(hostname);
751  arb_assert(hostname[0]);
752 
753  return
754  ARB_stricmp(hostname, "localhost") == 0 ||
755  ARB_strBeginsWith(hostname, "127.0.0.") ||
756  ARB_stricmp(hostname, arb_gethostname()) == 0;
757 }
758 
760  // Returns the physical available memory size in k available for one process
761  static GB_ULONG physical_memsize = 0;
762  if (!physical_memsize) {
763  GB_ULONG memsize; // real existing memory in k
764 #if defined(LINUX)
765  {
766  long pagesize = sysconf(_SC_PAGESIZE);
767  long pages = sysconf(_SC_PHYS_PAGES);
768 
769  memsize = (pagesize/1024) * pages;
770  }
771 #elif defined(DARWIN)
772 #warning memsize detection needs to be tested for Darwin
773  {
774  int mib[2];
775  uint64_t bytes;
776  size_t len;
777 
778  mib[0] = CTL_HW;
779  mib[1] = HW_MEMSIZE; // uint64_t: physical ram size
780  len = sizeof(bytes);
781  sysctl(mib, 2, &bytes, &len, NULp, 0);
782 
783  memsize = bytes/1024;
784  }
785 #else
786  memsize = 1024*1024; // assume 1 Gb
787  printf("\n"
788  "Warning: ARB is not prepared to detect the memory size on your system!\n"
789  " (it assumes you have %ul Mb, but does not use more)\n\n", memsize/1024);
790 #endif
791 
792  GB_ULONG net_memsize = memsize - 10240; // reduce by 10Mb
793 
794  // detect max allocateable memory by ... allocating
795  GB_ULONG max_malloc_try = net_memsize*1024;
796  GB_ULONG max_malloc = 0;
797  {
798  GB_ULONG step_size = 4096;
799  void *head = NULp;
800 
801  do {
802  void **tmp;
803  while ((tmp=(void**)malloc(step_size))) { // do NOT use ARB_alloc here!
804  *tmp = head;
805  head = tmp;
806  max_malloc += step_size;
807  if (max_malloc >= max_malloc_try) break;
808  step_size *= 2;
809  }
810  } while ((step_size=step_size/2) > sizeof(void*));
811 
812  while (head) freeset(head, *(void**)head);
813  max_malloc /= 1024;
814  }
815 
816  physical_memsize = std::min(net_memsize, max_malloc);
817 
818 #if defined(DEBUG) && 0
819  printf("- memsize(real) = %20lu k\n", memsize);
820  printf("- memsize(net) = %20lu k\n", net_memsize);
821  printf("- memsize(max_malloc) = %20lu k\n", max_malloc);
822 #endif // DEBUG
823 
824  GB_informationf("Visible memory: %s", GBS_readable_size(physical_memsize*1024, "b"));
825  }
826 
827  arb_assert(physical_memsize>0);
828  return physical_memsize;
829 }
830 
831 static GB_ULONG parse_env_mem_definition(const char *env_override, GB_ERROR& error) {
832  const char *end;
833  GB_ULONG num = strtoul(env_override, const_cast<char**>(&end), 10);
834 
835  error = NULp;
836 
837  bool valid = num>0 || env_override[0] == '0';
838  if (valid) {
839  const char *formatSpec = end;
840  double factor = 1;
841 
842  switch (tolower(formatSpec[0])) {
843  case 0:
844  num = GB_ULONG(num/1024.0+0.5); // byte->kb
845  break; // no format given
846 
847  case 'g': factor *= 1024; FALLTHROUGH;
848  case 'm': factor *= 1024; FALLTHROUGH;
849  case 'k': break;
850 
851  case '%':
852  factor = num/100.0;
853  num = get_physical_memory();
854  break;
855 
856  default: valid = false; break;
857  }
858 
859  if (valid) return GB_ULONG(num*factor+0.5);
860  }
861 
862  error = "expected digits (optionally followed by k, M, G or %)";
863  return 0;
864 }
865 
867  // memory allowed to be used by a single ARB process (in kbyte)
868 
869  static GB_ULONG useable_memory = 0;
870  if (!useable_memory) {
871  bool allow_fallback = true;
872  const char *env_override = GB_getenv("ARB_MEMORY");
873  const char *via_whom;
874  if (env_override) {
875  via_whom = "via envar ARB_MEMORY";
876  }
877  else {
878  FALLBACK:
879  env_override = "90%"; // ARB processes do not use more than 90% of physical memory
880  via_whom = "by internal default";
881  allow_fallback = false;
882  }
883 
884  gb_assert(env_override);
885 
886  GB_ERROR env_error;
887  GB_ULONG env_memory = parse_env_mem_definition(env_override, env_error);
888  if (env_error) {
889  GB_warningf("Ignoring invalid setting '%s' %s (%s)", env_override, via_whom, env_error);
890  if (allow_fallback) goto FALLBACK;
891  GBK_terminate("failed to detect usable memory");
892  }
893 
894  GB_informationf("Restricting used memory (%s '%s') to %s", via_whom, env_override, GBS_readable_size(env_memory*1024, "b"));
895  if (!allow_fallback) {
896  GB_informationf("Note: Setting envar ARB_MEMORY will override that restriction (percentage or absolute memsize)");
897  }
898  useable_memory = env_memory;
899  gb_assert(useable_memory>0 && useable_memory<get_physical_memory());
900  }
901  return useable_memory;
902 }
903 
904 // ---------------------------------
905 // process synchronisation
906 
908  gb_assert(!GB_have_error()); // illegal to enter this function when an error is exported!
909 
910  GBDATA *gb_sync_data = GB_entry(gb_main, "sync_data");
911  if (!gb_sync_data) {
912  gb_sync_data = GBT_create(gb_main, "sync_data", 0); // has to use security level 0 (otherwise GB_set_temporary does fail)
913  GB_ERROR error = GB_set_temporary(gb_sync_data);
914  if (error) {
915  GB_export_error(error);
916  gb_sync_data = NULp;
917  }
918  }
919 
920  gb_assert(contradicted(gb_sync_data, GB_have_error())); // either result or error!
921  return gb_sync_data;
922 }
923 static GBDATA *find_or_create_sync_value(GBDATA *gb_main, const char *id) {
924  gb_assert(!GB_have_error()); // illegal to enter this function when an error is exported!
925 
926  GBDATA *gb_value = NULp;
927  GBDATA *gb_sync_data = find_or_create_sync_data(gb_main);
928  if (gb_sync_data) {
929  GBDATA *gb_sync = GBT_find_or_create_item_rel_item_data(gb_sync_data, "sync", "id", id, false);
930  if (gb_sync) {
931  gb_value = GB_searchOrCreate_string(gb_sync, "value", "");
932  }
933  }
934 
935  gb_assert(contradicted(gb_value, GB_have_error())); // either result or error!
936  return gb_value;
937 }
938 
939 GB_ERROR GB_write_sync_value(GBDATA *gb_main, const char *id, const char *value) {
940  GB_ERROR error = NULp;
941  GBDATA *gb_syncValue = find_or_create_sync_value(gb_main, id);
942  if (gb_syncValue) {
943  error = GB_write_string(gb_syncValue, value);
944  }
945  else {
946  error = GB_await_error();
947  }
948  return error;
949 }
950 
952  GB_CSTR value = NULp;
953  GBDATA *gb_syncValue = find_or_create_sync_value(gb_main, id);
954 
955  if (gb_syncValue) {
956  value = GB_read_char_pntr(gb_syncValue);
957  }
958 
959  gb_assert(contradicted(value, GB_have_error())); // either result or error!
960  return value;
961 }
962 
963 // ---------------------------------------------
964 // path completion (parts former located in AWT)
965 // @@@ whole section (+ corresponding tests) should move to adfile.cxx
966 
967 static int path_toggle = 0;
968 static char path_buf[2][ARB_PATH_MAX];
969 
970 static char *use_other_path_buf() {
971  path_toggle = 1-path_toggle;
972  return path_buf[path_toggle];
973 }
974 
975 GB_CSTR GB_append_suffix(const char *name, const char *suffix) {
976  // if suffix isnt NULp -> append .suffix
977  // (automatically removes duplicated '.'s)
978  //
979  // Note: see also GB_split_full_path
980 
981  GB_CSTR result = name;
982  if (suffix) {
983  while (suffix[0] == '.') suffix++;
984  if (suffix[0]) {
985  result = GBS_global_string_to_buffer(use_other_path_buf(), ARB_PATH_MAX, "%s.%s", name, suffix);
986  }
987  }
988  return result;
989 }
990 
991 GB_CSTR GB_canonical_path(const char *anypath) {
992  // expands '~' '..' symbolic links etc in 'anypath'.
993  //
994  // Never returns NULp (if called correctly)
995  // Instead might return non-canonical path (when a directory
996  // in 'anypath' does not exist)
997 
998  GB_CSTR result = NULp;
999  if (!anypath) {
1000  GB_export_error("NULp path (internal error)");
1001  }
1002  else if (!anypath[0]) {
1003  result = "/";
1004  }
1005  else if (strlen(anypath) >= ARB_PATH_MAX) {
1006  GB_export_errorf("Path too long (> %i chars)", ARB_PATH_MAX-1);
1007  }
1008  else {
1009  if (anypath[0] == '~' && (!anypath[1] || anypath[1] == '/')) {
1010  GB_CSTR home = GB_getenvHOME();
1011  GB_CSTR homeexp = GBS_global_string("%s%s", home, anypath+1);
1012  result = GB_canonical_path(homeexp);
1013  GBS_reuse_buffer(homeexp);
1014  }
1015  else {
1016  result = realpath(anypath, path_buf[1-path_toggle]);
1017  if (result) {
1018  path_toggle = 1-path_toggle;
1019  }
1020  else { // realpath failed (happens e.g. when using a non-existing path, e.g. if user entered the name of a new file)
1021  // => content of path_buf[path_toggle] is UNDEFINED!
1022  char *dir, *fullname;
1023  GB_split_full_path(anypath, &dir, &fullname, NULp, NULp);
1024 
1025  const char *canonical_dir = NULp;
1026  if (!dir) {
1027  gb_assert(!strchr(anypath, '/'));
1028  canonical_dir = GB_canonical_path("."); // use working directory
1029  }
1030  else {
1031  gb_assert(strcmp(dir, anypath) != 0); // avoid deadlock
1032  canonical_dir = GB_canonical_path(dir);
1033  }
1034  gb_assert(canonical_dir);
1035 
1036  // manually resolve '.' and '..' in non-existing parent directories
1037  if (strcmp(fullname, "..") == 0) {
1038  char *parent;
1039  GB_split_full_path(canonical_dir, &parent, NULp, NULp, NULp);
1040  if (parent) {
1041  result = strcpy(use_other_path_buf(), parent);
1042  free(parent);
1043  }
1044  }
1045  else if (strcmp(fullname, ".") == 0) {
1046  result = canonical_dir;
1047  }
1048 
1049  if (!result) result = GB_concat_path(canonical_dir, fullname);
1050 
1051  free(dir);
1052  free(fullname);
1053  }
1054  }
1055  gb_assert(result);
1056  }
1057  return result;
1058 }
1059 
1060 GB_CSTR GB_concat_path(GB_CSTR anypath_left, GB_CSTR anypath_right) {
1061  // concats left and right part of a path.
1062  // '/' is inserted in-between
1063  //
1064  // if one of the arguments is NULp => returns the other argument
1065  // if both arguments are NULp => return NULp (@@@ maybe forbid?)
1066  //
1067  // Note: see also GB_split_full_path
1068 
1069  GB_CSTR result = NULp;
1070 
1071  if (anypath_right) {
1072  if (anypath_right[0] == '/') {
1073  result = GB_concat_path(anypath_left, anypath_right+1);
1074  }
1075  else if (anypath_left && anypath_left[0]) {
1076  if (anypath_left[strlen(anypath_left)-1] == '/') {
1077  result = GBS_global_string_to_buffer(use_other_path_buf(), sizeof(path_buf[0]), "%s%s", anypath_left, anypath_right);
1078  }
1079  else {
1080  result = GBS_global_string_to_buffer(use_other_path_buf(), sizeof(path_buf[0]), "%s/%s", anypath_left, anypath_right);
1081  }
1082  }
1083  else {
1084  result = anypath_right;
1085  }
1086  }
1087  else {
1088  result = anypath_left;
1089  }
1090 
1091  return result;
1092 }
1093 
1094 GB_CSTR GB_concat_full_path(const char *anypath_left, const char *anypath_right) {
1095  // like GB_concat_path(), but returns the canonical path
1096  GB_CSTR result = GB_concat_path(anypath_left, anypath_right);
1097 
1098  gb_assert(result != anypath_left); // consider using GB_canonical_path() directly
1099  gb_assert(result != anypath_right);
1100 
1101  if (result) result = GB_canonical_path(result);
1102  return result;
1103 }
1104 
1105 inline bool is_absolute_path(const char *path) { return path[0] == '/' || path[0] == '~'; }
1106 inline bool is_name_of_envvar(const char *name) {
1107  for (int i = 0; name[i]; ++i) {
1108  if (isalnum(name[i]) || name[i] == '_') continue;
1109  return false;
1110  }
1111  return true;
1112 }
1113 
1114 GB_CSTR GB_unfold_in_directory(const char *relative_directory, const char *path) {
1115  // If 'path' is an absolute path, return canonical path.
1116  //
1117  // Otherwise unfolds relative 'path' using 'relative_directory' as start directory.
1118 
1119  if (is_absolute_path(path)) return GB_canonical_path(path);
1120  return GB_concat_full_path(relative_directory, path);
1121 }
1122 
1123 GB_CSTR GB_unfold_path(const char *pwd_envar, const char *path) {
1124  // If 'path' is an absolute path, return canonical path.
1125  //
1126  // Otherwise unfolds relative 'path' using content of environment
1127  // variable 'pwd_envar' as start directory.
1128  // If environment variable is not defined, fall-back to current directory
1129 
1130  gb_assert(is_name_of_envvar(pwd_envar));
1131  if (is_absolute_path(path)) {
1132  return GB_canonical_path(path);
1133  }
1134 
1135  const char *pwd = GB_getenv(pwd_envar);
1136  if (!pwd) pwd = GB_getcwd(); // @@@ really wanted ?
1137  return GB_concat_full_path(pwd, path);
1138 }
1139 
1140 GB_CSTR GB_path_in_ARBHOME(const char *relative_path) {
1141  return GB_unfold_path("ARBHOME", relative_path);
1142 }
1143 static GB_CSTR GB_concat_path_in_ARBHOME(const char *relative_path_left, const char *anypath_right) {
1144  return GB_path_in_ARBHOME(GB_concat_path(relative_path_left, anypath_right));
1145 }
1146 
1147 GB_CSTR GB_path_in_ARBLIB(const char *relative_path) {
1148  return GB_concat_path_in_ARBHOME("lib", relative_path);
1149 }
1150 GB_CSTR GB_concat_path_in_ARBLIB(const char *relative_path_left, const char *anypath_right) {
1151  return GB_path_in_ARBLIB(GB_concat_path(relative_path_left, anypath_right));
1152 }
1153 
1154 GB_CSTR GB_path_in_HOME(const char *relative_path) {
1155  return GB_unfold_path("HOME", relative_path);
1156 }
1157 GB_CSTR GB_path_in_arbprop(const char *relative_path) {
1158  return GB_unfold_path("ARB_PROP", relative_path);
1159 }
1160 static GB_CSTR GB_path_in_arb_temp(const char *relative_path) {
1161  return GB_path_in_HOME(GB_concat_path(".arb_tmp", relative_path));
1162 }
1163 
1164 
1165 #define GB_PATH_TMP GB_path_in_arb_temp("tmp") // = "~/.arb_tmp/tmp" (used wherever '/tmp' was used in the past)
1166 
1167 FILE *GB_fopen_tempfile(const char *filename, const char *fmode, char **res_fullname) {
1168  // fopens a tempfile
1169  //
1170  // Returns
1171  // - NULp in case of error (which is exported then)
1172  // - otherwise returns open filehandle
1173  //
1174  // Always sets
1175  // - heap-copy of used filename in 'res_fullname' (if res_fullname isnt NULp)
1176  // (even if fopen failed)
1177 
1178  char *file = ARB_strdup(GB_concat_path(GB_PATH_TMP, filename));
1180  FILE *fp = NULp;
1181 
1182  if (!error) {
1183  bool write = strpbrk(fmode, "wa");
1184 
1185  fp = fopen(file, fmode);
1186  if (fp) {
1187  // make file private
1188  if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) != 0) {
1189  error = GB_IO_error("changing permissions of", file);
1190  }
1191  }
1192  else {
1193  error = GB_IO_error(GBS_global_string("opening(%s) tempfile", write ? "write" : "read"), file);
1194  }
1195 
1196  if (res_fullname) {
1197  *res_fullname = file ? ARB_strdup(file) : NULp;
1198  }
1199  }
1200 
1201  if (error) {
1202  // don't care if anything fails here..
1203  if (fp) { fclose(fp); fp = NULp; }
1204  if (file) unlink(file);
1205  GB_export_error(error);
1206  }
1207 
1208  free(file);
1209 
1210  return fp;
1211 }
1212 
1213 char *GB_create_tempfile(const char *name) {
1214  // creates a tempfile and returns full name of created file
1215  // returns NULp in case of error (which is exported then)
1216 
1217  char *fullname;
1218  FILE *out = GB_fopen_tempfile(name, "wt", &fullname);
1219 
1220  if (out) fclose(out);
1221  return fullname;
1222 }
1223 
1224 char *GB_unique_filename(const char *name_prefix, const char *suffix) {
1225  // generates a unique (enough) filename
1226  //
1227  // scheme: name_prefix_USER_PID_COUNT.suffix
1228 
1229  static int counter = 0;
1230  return GBS_global_string_copy("%s_%s_%i_%i.%s",
1231  name_prefix,
1232  GB_getenvUSER(), getpid(), counter++,
1233  suffix);
1234 }
1235 
1237 static void exit_remove_file(const char *file, long, void *) {
1238  if (unlink(file) != 0) {
1239  fprintf(stderr, "Warning: %s\n", GB_IO_error("removing", file));
1240  }
1241 }
1242 static void exit_removal() {
1243  if (files_to_remove_on_exit) {
1244  GBS_hash_do_const_loop(files_to_remove_on_exit, exit_remove_file, NULp);
1245  GBS_free_hash(files_to_remove_on_exit);
1246  files_to_remove_on_exit = NULp;
1247  }
1248 }
1249 void GB_remove_on_exit(const char *filename) {
1250  // mark a file for removal on exit
1251 
1252  if (!files_to_remove_on_exit) {
1253  files_to_remove_on_exit = GBS_create_hash(20, GB_MIND_CASE);
1255  }
1256  GBS_write_hash(files_to_remove_on_exit, filename, 1);
1257 }
1258 
1259 void GB_split_full_path(const char *fullpath, char **res_dir, char **res_fullname, char **res_name_only, char **res_suffix) {
1260  // Takes a file (or directory) name and splits it into "path/name.suffix".
1261  // If result pointers (res_*) are non-NULp, they'll get assigned heap-copies of the splitted parts:
1262  // "path" -> res_dir
1263  // "name.suffix" -> res_fullname
1264  // "name" -> res_name_only
1265  // "suffix" -> res_suffix
1266  //
1267  // If parts are not valid (e.g. cause 'fullpath' doesn't have a .suffix) the corresponding result pointer
1268  // is set to NULp.
1269  //
1270  // The '/' and '.' characters at the split-positions will be removed (not included in the results-strings).
1271  // Exceptions:
1272  // - the '.' in 'res_fullname'
1273  // - the '/' if directory part is the rootdir
1274  //
1275  // Note:
1276  // - if the filename starts with '.' (and that is the only '.' in the filename, an empty filename is returned: "")
1277  //
1278  // Reverse functionality is provided by GB_concat_path and GB_append_suffix.
1279 
1280  if (fullpath && fullpath[0]) {
1281  const char *lslash = strrchr(fullpath, '/');
1282  const char *name_start = lslash ? lslash+1 : fullpath;
1283  const char *ldot = strrchr(lslash ? lslash : fullpath, '.');
1284  const char *terminal = strchr(name_start, 0);
1285 
1286  gb_assert(terminal);
1287  gb_assert(name_start);
1288  gb_assert(terminal > fullpath); // ensure (terminal-1) is a valid character position in path
1289 
1290  if (!lslash && fullpath[0] == '.' && (fullpath[1] == 0 || (fullpath[1] == '.' && fullpath[2] == 0))) { // '.' and '..'
1291  if (res_dir) *res_dir = ARB_strdup(fullpath);
1292  if (res_fullname) *res_fullname = NULp;
1293  if (res_name_only) *res_name_only = NULp;
1294  if (res_suffix) *res_suffix = NULp;
1295  }
1296  else {
1297  if (res_dir) *res_dir = lslash ? ARB_strpartdup(fullpath, lslash == fullpath ? lslash : lslash-1) : NULp;
1298  if (res_fullname) *res_fullname = ARB_strpartdup(name_start, terminal-1);
1299  if (res_name_only) *res_name_only = ARB_strpartdup(name_start, ldot ? ldot-1 : terminal-1);
1300  if (res_suffix) *res_suffix = ldot ? ARB_strpartdup(ldot+1, terminal-1) : NULp;
1301  }
1302  }
1303  else {
1304  if (res_dir) *res_dir = NULp;
1305  if (res_fullname) *res_fullname = NULp;
1306  if (res_name_only) *res_name_only = NULp;
1307  if (res_suffix) *res_suffix = NULp;
1308  }
1309 }
1310 
1311 
1312 // --------------------------------------------------------------------------------
1313 
1314 #ifdef UNIT_TESTS
1315 
1316 #include <test_unit.h>
1317 
1318 #define TEST_EXPECT_IS_CANONICAL(file) \
1319  do { \
1320  char *dup = ARB_strdup(file); \
1321  TEST_EXPECT_EQUAL(GB_canonical_path(dup), dup); \
1322  free(dup); \
1323  } while(0)
1324 
1325 #define TEST_EXPECT_CANONICAL_TO(not_cano,cano) \
1326  do { \
1327  char *arb_not_cano = ARB_strdup(GB_concat_path(arbhome, not_cano)); \
1328  char *arb_cano = ARB_strdup(GB_concat_path(arbhome, cano)); \
1329  TEST_EXPECT_EQUAL(GB_canonical_path(arb_not_cano), arb_cano); \
1330  free(arb_cano); \
1331  free(arb_not_cano); \
1332  } while (0)
1333 
1334 static arb_test::match_expectation path_splits_into(const char *path, const char *Edir, const char *Enameext, const char *Ename, const char *Eext) {
1335  using namespace arb_test;
1336  expectation_group expected;
1337 
1338  char *Sdir,*Snameext,*Sname,*Sext;
1339  GB_split_full_path(path, &Sdir, &Snameext, &Sname, &Sext);
1340 
1341  expected.add(that(Sdir).is_equal_to(Edir));
1342  expected.add(that(Snameext).is_equal_to(Enameext));
1343  expected.add(that(Sname).is_equal_to(Ename));
1344  expected.add(that(Sext).is_equal_to(Eext));
1345 
1346  free(Sdir);
1347  free(Snameext);
1348  free(Sname);
1349  free(Sext);
1350 
1351  return all().ofgroup(expected);
1352 }
1353 
1354 #define TEST_EXPECT_PATH_SPLITS_INTO(path,dir,nameext,name,ext) TEST_EXPECTATION(path_splits_into(path,dir,nameext,name,ext))
1355 #define TEST_EXPECT_PATH_SPLITS_INTO__BROKEN(path,dir,nameext,name,ext) TEST_EXPECTATION__BROKEN(path_splits_into(path,dir,nameext,name,ext))
1356 
1357 static arb_test::match_expectation path_splits_reversible(const char *path) {
1358  using namespace arb_test;
1359  expectation_group expected;
1360 
1361  char *Sdir,*Snameext,*Sname,*Sext;
1362  GB_split_full_path(path, &Sdir, &Snameext, &Sname, &Sext);
1363 
1364  expected.add(that(GB_append_suffix(Sname, Sext)).is_equal_to(Snameext)); // GB_append_suffix should reverse name.ext-split
1365  expected.add(that(GB_concat_path(Sdir, Snameext)).is_equal_to(path)); // GB_concat_path should reverse dir/file-split
1366 
1367  free(Sdir);
1368  free(Snameext);
1369  free(Sname);
1370  free(Sext);
1371 
1372  return all().ofgroup(expected);
1373 }
1374 
1375 #define TEST_SPLIT_REVERSIBILITY(path) TEST_EXPECTATION(path_splits_reversible(path))
1376 #define TEST_SPLIT_REVERSIBILITY__BROKEN(path) TEST_EXPECTATION__BROKEN(path_splits_reversible(path))
1377 
1378 void TEST_paths() {
1379  // test GB_concat_path
1382  TEST_EXPECT_EQUAL(GB_concat_path("a", "b"), "a/b");
1383 
1384  TEST_EXPECT_EQUAL(GB_concat_path("/", "test.fig"), "/test.fig");
1385 
1386  // test GB_split_full_path
1387  TEST_EXPECT_PATH_SPLITS_INTO("dir/sub/.ext", "dir/sub", ".ext", "", "ext");
1388  TEST_EXPECT_PATH_SPLITS_INTO("/root/sub/file.notext.ext", "/root/sub", "file.notext.ext", "file.notext", "ext");
1389 
1390  TEST_EXPECT_PATH_SPLITS_INTO("./file.ext", ".", "file.ext", "file", "ext");
1391  TEST_EXPECT_PATH_SPLITS_INTO("/file", "/", "file", "file", NULp);
1392  TEST_EXPECT_PATH_SPLITS_INTO(".", ".", NULp, NULp, NULp);
1393 
1394  // test reversibility of GB_split_full_path and GB_concat_path/GB_append_suffix
1395  {
1396  const char *prefix[] = {
1397  "",
1398  "dir/",
1399  "dir/sub/",
1400  "/dir/",
1401  "/dir/sub/",
1402  "/",
1403  "./",
1404  "../",
1405  };
1406 
1407  for (size_t d = 0; d<ARRAY_ELEMS(prefix); ++d) {
1408  TEST_ANNOTATE(GBS_global_string("prefix='%s'", prefix[d]));
1409 
1410  TEST_SPLIT_REVERSIBILITY(GBS_global_string("%sfile.ext", prefix[d]));
1411  TEST_SPLIT_REVERSIBILITY(GBS_global_string("%sfile", prefix[d]));
1412  TEST_SPLIT_REVERSIBILITY(GBS_global_string("%s.ext", prefix[d]));
1413  if (prefix[d][0]) { // empty string "" reverts to NULp
1414  TEST_SPLIT_REVERSIBILITY(prefix[d]);
1415  }
1416  }
1417  }
1418 
1419  // GB_canonical_path basics
1420  TEST_EXPECT_CONTAINS(GB_canonical_path("./bla"), "UNIT_TESTER/run/bla");
1421  TEST_EXPECT_CONTAINS(GB_canonical_path("bla"), "UNIT_TESTER/run/bla");
1422 
1423  {
1424  char *arbhome = ARB_strdup(GB_getenvARBHOME());
1425  const char* nosuchfile = "nosuchfile";
1426  const char* somefile = "arb_README.txt";
1427 
1428  char *somefile_in_arbhome = ARB_strdup(GB_concat_path(arbhome, somefile));
1429  char *nosuchfile_in_arbhome = ARB_strdup(GB_concat_path(arbhome, nosuchfile));
1430  char *nosuchpath_in_arbhome = ARB_strdup(GB_concat_path(arbhome, "nosuchpath"));
1431  char *somepath_in_arbhome = ARB_strdup(GB_concat_path(arbhome, "lib"));
1432  char *file_in_nosuchpath = ARB_strdup(GB_concat_path(nosuchpath_in_arbhome, "whatever"));
1433 
1434  TEST_REJECT(GB_is_directory(nosuchpath_in_arbhome));
1435 
1436  // test GB_get_full_path
1437  TEST_EXPECT_IS_CANONICAL(somefile_in_arbhome);
1438  TEST_EXPECT_IS_CANONICAL(nosuchpath_in_arbhome);
1439  TEST_EXPECT_IS_CANONICAL(file_in_nosuchpath);
1440 
1441  TEST_EXPECT_IS_CANONICAL("/usr"); // existing (most likely)
1442 #if !defined(DARWIN)
1443  // TEST_DISABLED_OSX: fails for darwin on jenkins (/tmp seems to be a symbolic link there)
1444  TEST_EXPECT_IS_CANONICAL("/tmp/arbtest.fig");
1445 #endif
1446  TEST_EXPECT_IS_CANONICAL("/arbtest.fig"); // not existing (most likely)
1447 
1448  TEST_EXPECT_CANONICAL_TO("./PARSIMONY/./../ARBDB/./arbdb.h", "ARBDB/arbdb.h"); // test parent-path
1449  TEST_EXPECT_CANONICAL_TO("INCLUDE/arbdb.h", "ARBDB/arbdb.h"); // test symbolic link to file
1450  TEST_EXPECT_CANONICAL_TO("NAMES_COM/AISC/aisc.pa", "AISC_COM/AISC/aisc.pa"); // test symbolic link to directory
1451  TEST_EXPECT_CANONICAL_TO("./NAMES_COM/AISC/..", "AISC_COM"); // test parent-path through links
1452 
1453  TEST_EXPECT_CANONICAL_TO("./PARSIMONY/./../ARBDB/../nosuchpath", "nosuchpath"); // nosuchpath does not exist, but involved parent dirs do
1454  // test resolving of non-existent parent dirs:
1455  TEST_EXPECT_CANONICAL_TO("./PARSIMONY/./../nosuchpath/../ARBDB", "ARBDB");
1456  TEST_EXPECT_CANONICAL_TO("./nosuchpath/./../ARBDB", "ARBDB");
1457 
1458  // test GB_unfold_path
1459  TEST_EXPECT_EQUAL(GB_unfold_path("ARBHOME", somefile), somefile_in_arbhome);
1460  TEST_EXPECT_EQUAL(GB_unfold_path("ARBHOME", nosuchfile), nosuchfile_in_arbhome);
1461 
1462  char *inhome = ARB_strdup(GB_unfold_path("HOME", "whatever"));
1463  TEST_EXPECT_EQUAL(inhome, GB_canonical_path("~/whatever"));
1464  free(inhome);
1465 
1466  // test GB_unfold_in_directory
1467  TEST_EXPECT_EQUAL(GB_unfold_in_directory(arbhome, somefile), somefile_in_arbhome);
1468  TEST_EXPECT_EQUAL(GB_unfold_in_directory(nosuchpath_in_arbhome, somefile_in_arbhome), somefile_in_arbhome);
1469  TEST_EXPECT_EQUAL(GB_unfold_in_directory(arbhome, nosuchfile), nosuchfile_in_arbhome);
1470  TEST_EXPECT_EQUAL(GB_unfold_in_directory(nosuchpath_in_arbhome, "whatever"), file_in_nosuchpath);
1471  TEST_EXPECT_EQUAL(GB_unfold_in_directory(somepath_in_arbhome, "../nosuchfile"), nosuchfile_in_arbhome);
1472 
1473  // test unfolding absolute paths (HOME is ignored)
1474  TEST_EXPECT_EQUAL(GB_unfold_path("HOME", arbhome), arbhome);
1475  TEST_EXPECT_EQUAL(GB_unfold_path("HOME", somefile_in_arbhome), somefile_in_arbhome);
1476  TEST_EXPECT_EQUAL(GB_unfold_path("HOME", nosuchfile_in_arbhome), nosuchfile_in_arbhome);
1477 
1478  // test GB_path_in_ARBHOME
1479  TEST_EXPECT_EQUAL(GB_path_in_ARBHOME(somefile), somefile_in_arbhome);
1480  TEST_EXPECT_EQUAL(GB_path_in_ARBHOME(nosuchfile), nosuchfile_in_arbhome);
1481 
1482  free(file_in_nosuchpath);
1483  free(somepath_in_arbhome);
1484  free(nosuchpath_in_arbhome);
1485  free(nosuchfile_in_arbhome);
1486  free(somefile_in_arbhome);
1487  free(arbhome);
1488  }
1489 
1491 
1492 }
1493 
1494 // ----------------------------------------
1495 
1496 class TestFile : virtual Noncopyable {
1497  const char *name;
1498  bool open(const char *mode) {
1499  FILE *out = fopen(name, mode);
1500  if (out) fclose(out);
1501  return out;
1502  }
1503  void create() { ASSERT_RESULT(bool, true, open("w")); }
1504  void unlink() { ::unlink(name); }
1505 public:
1506  TestFile(const char *name_) : name(name_) { create(); }
1507  ~TestFile() { if (exists()) unlink(); }
1508  const char *get_name() const { return name; }
1509  bool exists() { return open("r"); }
1510 };
1511 
1512 void TEST_GB_remove_on_exit() {
1513  {
1514  // first test class TestFile
1515  TestFile file("test1");
1516  TEST_EXPECT(file.exists());
1517  TEST_EXPECT(TestFile(file.get_name()).exists()); // removes the file
1518  TEST_REJECT(file.exists());
1519  }
1520 
1521  TestFile t("test1");
1522  {
1523  GB_shell shell;
1524  GBDATA *gb_main = GB_open("no.arb", "c");
1525 
1526  GB_remove_on_exit(t.get_name());
1527  GB_close(gb_main);
1528  }
1529  TEST_REJECT(t.exists());
1530 }
1531 
1532 void TEST_some_paths() {
1533  gb_getenv_hook old = GB_install_getenv_hook(arb_test::fakeenv);
1534  {
1535  // ../UNIT_TESTER/run/homefake
1536 
1537  TEST_EXPECT_CONTAINS__BROKEN(GB_getenvHOME(), "/UNIT_TESTER/run/homefake"); // GB_getenvHOME() ignores the hook
1538  // @@@ this is a general problem - unit tested code cannot use GB_getenvHOME() w/o problems
1539 
1540  TEST_EXPECT_CONTAINS(GB_getenvARB_PROP(), "/UNIT_TESTER/run/homefake/.arb_prop");
1541  TEST_EXPECT_CONTAINS(GB_getenvARBMACRO(), "/lib/macros");
1542 
1543  TEST_EXPECT_CONTAINS(GB_getenvARBCONFIG(), "/UNIT_TESTER/run/homefake/.arb_prop/cfgSave");
1544  TEST_EXPECT_CONTAINS(GB_getenvARBMACROHOME(), "/UNIT_TESTER/run/homefake/.arb_prop/macros"); // works in [11068]
1545  }
1546  TEST_EXPECT_EQUAL((void*)arb_test::fakeenv, (void*)GB_install_getenv_hook(old));
1547 }
1548 
1549 void TEST_sync() {
1550  const char *db_save_name = "saved_after_sync.arb";
1551 
1552  GB_shell shell;
1553  {
1554  GBDATA *gb_main = GB_open("nosuch.arb", "cw");
1555 
1556  {
1557  GB_transaction ta(gb_main);
1558  GB_CSTR value;
1559 
1560  TEST_EXPECT_RESULT__NOERROREXPORTED(value = GB_read_sync_value(gb_main, "neverUsedId"));
1561  TEST_EXPECT_EQUAL(value, ""); // unused IDs have empty string as (default) value
1562 
1563 #define SYNCID "myId"
1564 
1565  // write new value:
1566  TEST_EXPECT_NO_ERROR(GB_write_sync_value(gb_main, SYNCID, "eins"));
1567  // read written value:
1568  TEST_EXPECT_RESULT__NOERROREXPORTED(value = GB_read_sync_value(gb_main, SYNCID));
1569  TEST_EXPECT_EQUAL(value, "eins");
1570 
1571  // change value:
1572  TEST_EXPECT_NO_ERROR(GB_write_sync_value(gb_main, SYNCID, "zwei"));
1573  // read written value:
1574  TEST_EXPECT_RESULT__NOERROREXPORTED(value = GB_read_sync_value(gb_main, SYNCID));
1575  TEST_EXPECT_EQUAL(value, "zwei");
1576  }
1577 
1578  // save database (for test below)
1579  TEST_EXPECT_NO_ERROR(GB_save_as(gb_main, db_save_name, "b"));
1580  GB_close(gb_main);
1581  }
1582 
1583  {
1584  // reload database
1585  GBDATA *gb_main = GB_open(db_save_name, "r");
1586 
1587  {
1588  GB_transaction ta(gb_main);
1589  GB_CSTR value;
1590 
1591  TEST_EXPECT_RESULT__NOERROREXPORTED(value = GB_read_sync_value(gb_main, SYNCID));
1592  TEST_EXPECT_EQUAL(value, ""); // test value of used sync entry has vanished
1593  }
1594 
1595  GB_close(gb_main);
1596  }
1597 
1598  // delete saved database
1600 }
1601 
1602 #endif // UNIT_TESTS
1603 
static GB_CSTR GB_getenvARB_PROP()
Definition: adsocket.cxx:623
char * gbcm_read_string(int socket)
Definition: adsocket.cxx:241
GB_CSTR GB_path_in_HOME(const char *relative_path)
Definition: adsocket.cxx:1154
GB_ULONG GB_get_usable_memory()
Definition: adsocket.cxx:866
GB_ERROR GBK_system(const char *system_command)
Definition: arb_msg.cxx:571
#define arb_assert(cond)
Definition: arb_assert.h:245
const char * GB_ERROR
Definition: arb_core.h:25
long GB_size_of_FILE(FILE *in)
Definition: arb_file.cxx:34
GB_CSTR GB_unfold_in_directory(const char *relative_directory, const char *path)
Definition: adsocket.cxx:1114
string result
GBDATA * GB_open(const char *path, const char *opent)
Definition: ad_load.cxx:1363
static GBDATA * find_or_create_sync_value(GBDATA *gb_main, const char *id)
Definition: adsocket.cxx:923
GBCM_ServerResult gbcm_write_flush(int socket)
Definition: adsocket.cxx:92
GB_CSTR GB_concat_full_path(const char *anypath_left, const char *anypath_right)
Definition: adsocket.cxx:1094
void GB_warning(const char *message)
Definition: arb_msg.cxx:530
#define ARB_PATH_MAX
Definition: arb_pathlen.h:31
group_matcher all()
Definition: test_unit.h:1011
#define TEST_EXPECT_CONTAINS__BROKEN(str, part)
Definition: test_unit.h:1317
void gbcm_read_flush()
Definition: adsocket.cxx:51
GB_CSTR GB_unfold_path(const char *pwd_envar, const char *path)
Definition: adsocket.cxx:1123
long GBS_write_hash(GB_HASH *hs, const char *key, long val)
Definition: adhash.cxx:454
void GB_split_full_path(const char *fullpath, char **res_dir, char **res_fullname, char **res_name_only, char **res_suffix)
Definition: adsocket.cxx:1259
static GB_ULONG get_physical_memory()
Definition: adsocket.cxx:759
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
Definition: arbdb.cxx:1387
GBDATA * GB_searchOrCreate_string(GBDATA *gb_container, const char *fieldpath, const char *default_value)
Definition: adquery.cxx:546
NOT4PERL gb_getenv_hook GB_install_getenv_hook(gb_getenv_hook hook)
Definition: adsocket.cxx:700
const char * GBS_global_string_to_buffer(char *buffer, size_t bufsize, const char *templat,...)
Definition: arb_msg.cxx:178
GB_CSTR GB_getenvHTMLDOCPATH()
Definition: adsocket.cxx:687
void ARB_warn_about_unwanted_chars(const char *path, const char *path_description)
Definition: arb_misc.cxx:150
char * GB_read_file(const char *path)
Definition: adsocket.cxx:288
const char * arb_gethostname()
Definition: arb_cs.cxx:51
GB_CSTR GB_path_in_ARBLIB(const char *relative_path)
Definition: adsocket.cxx:1147
int ARB_stricmp(const char *s1, const char *s2)
Definition: arb_str.h:28
#define ASSERT_RESULT(Type, Expected, Expr)
Definition: arb_assert.h:336
const char * ARB_getenv_ignore_empty(const char *envvar)
Definition: arb_misc.cxx:102
GB_ERROR GB_delete_database(GB_CSTR filename)
GB_ERROR GB_IO_error(const char *action, const char *filename)
Definition: arb_msg.cxx:285
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
static GB_CSTR GB_getenvARBCONFIG()
Definition: adsocket.cxx:635
void GB_internal_errorf(const char *templat,...)
Definition: arb_msg.cxx:504
GB_ERROR arb_open_socket(const char *name, bool do_connect, int *fd, char **filename_out)
Definition: arb_cs.cxx:124
GB_CSTR GB_getenvARBHOME()
Definition: adsocket.cxx:580
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
GB_CSTR GB_getenv(const char *env)
Definition: adsocket.cxx:710
GB_CSTR GB_getenvUSER()
Definition: adsocket.cxx:546
GB_ERROR GB_textprint(const char *path)
Definition: adsocket.cxx:364
bool GB_have_error()
Definition: arb_msg.cxx:338
static void exit_remove_file(const char *file, long, void *)
Definition: adsocket.cxx:1237
char * release()
Definition: arb_strbuf.h:129
static char * getenv_executable(GB_CSTR envvar)
Definition: adsocket.cxx:452
void GBS_free_hash(GB_HASH *hs)
Definition: adhash.cxx:538
void cat(const char *from)
Definition: arb_strbuf.h:199
GBCM_ServerResult gbcm_write(int socket, const char *ptr, long size)
Definition: adsocket.cxx:129
char * ARB_strpartdup(const char *start, const char *end)
Definition: arb_string.h:51
GB_ERROR GB_create_parent_directory(const char *path)
#define EXIT_SUCCESS
Definition: arb_a2ps.c:154
GBCM_ServerResult gbcm_write_long(int socket, long data)
Definition: adsocket.cxx:261
void GB_setenv(const char *var, const char *value)
Definition: adsocket.cxx:517
char * unix_name
Definition: gb_comm.h:16
long GB_size_of_file(const char *path)
Definition: arb_file.cxx:28
static GB_CSTR GB_getenvPATH()
Definition: adsocket.cxx:378
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
static char * getenv_autodirectory(const char *envvar, const char *defaultDirectory)
Definition: adsocket.cxx:603
unsigned long GB_ULONG
Definition: arbdb_base.h:42
#define NOT4PERL
Definition: arbdb_base.h:23
static char path_buf[2][ARB_PATH_MAX]
Definition: adsocket.cxx:968
GB_ULONG GB_time_of_day()
Definition: adsocket.cxx:358
char * ARB_executable(const char *exe_name, const char *path)
Definition: arb_misc.cxx:107
#define TEST_EXPECT_CONTAINS(str, part)
Definition: test_unit.h:1316
GB_ERROR GB_export_error(const char *error)
Definition: arb_msg.cxx:257
static long gbcm_read_buffered(int socket, char *ptr, long size)
Definition: adsocket.cxx:56
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
#define TEST_EXPECT(cond)
Definition: test_unit.h:1328
const char * GBS_read_arb_tcp(const char *env)
Definition: adtcp.cxx:325
GBCM_ServerResult gbcm_read_two(int socket, long a, long *b, long *c)
Definition: adsocket.cxx:197
GBCM_ServerResult
Definition: gb_local.h:93
void GB_warningf(const char *templat,...)
Definition: arb_msg.cxx:536
GB_CSTR GB_append_suffix(const char *name, const char *suffix)
Definition: adsocket.cxx:975
static char * use_other_path_buf()
Definition: adsocket.cxx:970
static GB_CSTR GB_getenvHOME()
Definition: adsocket.cxx:564
void GBS_hash_do_const_loop(const GB_HASH *hs, gb_hash_const_loop_type func, void *client_data)
Definition: adhash.cxx:559
GB_CSTR GB_read_sync_value(GBDATA *gb_main, const char *id)
Definition: adsocket.cxx:951
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:509
char * GB_unique_filename(const char *name_prefix, const char *suffix)
Definition: adsocket.cxx:1224
long gbcm_read(int socket, char *ptr, long size)
Definition: adsocket.cxx:80
GB_ERROR GB_save_as(GBDATA *gbd, const char *path, const char *savetype)
GB_ERROR GB_write_sync_value(GBDATA *gb_main, const char *id, const char *value)
Definition: adsocket.cxx:939
GB_ERROR gbcm_open_socket(const char *path, bool do_connect, int *psocket, char **unix_name)
Definition: adsocket.cxx:145
const char * GBS_readable_size(unsigned long long size, const char *unit_suffix)
Definition: arb_misc.cxx:23
static char * GB_find_executable(GB_CSTR description_of_executable,...)
Definition: adsocket.cxx:400
#define TEST_REJECT(cond)
Definition: test_unit.h:1330
void GB_atexit(void(*exitfun)())
Definition: arbdb.cxx:402
long gbcm_read_long(int socket)
Definition: adsocket.cxx:266
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define GB_PATH_TMP
Definition: adsocket.cxx:1165
static int path_toggle
Definition: adsocket.cxx:967
expectation_group & add(const expectation &e)
Definition: test_unit.h:812
char * GB_create_tempfile(const char *name)
Definition: adsocket.cxx:1213
GB_CSTR GB_getenvARBMACRO()
Definition: adsocket.cxx:594
#define that(thing)
Definition: test_unit.h:1043
static GB_CSTR GB_path_in_arb_temp(const char *relative_path)
Definition: adsocket.cxx:1160
GB_CSTR GB_concat_path(GB_CSTR anypath_left, GB_CSTR anypath_right)
Definition: adsocket.cxx:1060
bool is_name_of_envvar(const char *name)
Definition: adsocket.cxx:1106
static char * getenv_existing_directory(GB_CSTR envvar)
Definition: adsocket.cxx:491
static GB_CSTR GB_concat_path_in_ARBHOME(const char *relative_path_left, const char *anypath_right)
Definition: adsocket.cxx:1143
GBCM_ServerResult gbcm_write_string(int socket, const char *key)
Definition: adsocket.cxx:229
bool GB_host_is_local(const char *hostname)
Definition: adsocket.cxx:747
const char *(* gb_getenv_hook)(const char *varname)
Definition: arbdb.h:126
static gb_getenv_hook getenv_hook
Definition: adsocket.cxx:698
int socket
Definition: gb_comm.h:15
CONSTEXPR_INLINE bool valid(SpeciesCreationMode m)
Definition: ed4_class.hxx:2247
static GBDATA * find_or_create_sync_data(GBDATA *gb_main)
Definition: adsocket.cxx:907
long gbcm_write_two(int socket, long a, long c)
Definition: adsocket.cxx:187
FILE * GB_fopen_tempfile(const char *filename, const char *fmode, char **res_fullname)
Definition: adsocket.cxx:1167
GB_CSTR GB_getcwd(void)
Definition: adfile.cxx:24
void GBS_reuse_buffer(const char *global_buffer)
Definition: arb_msg.cxx:563
va_end(argPtr)
#define EXIT_FAILURE
Definition: arb_a2ps.c:157
#define is_equal_to(val)
Definition: test_unit.h:1025
GB_CSTR GB_getenvDOCPATH()
Definition: adsocket.cxx:677
char * write_buffer
Definition: gb_localdata.h:52
char * write_ptr
Definition: gb_localdata.h:53
GB_CSTR GB_getenvARB_GS()
Definition: adsocket.cxx:641
GB_ERROR GB_set_temporary(GBDATA *gbd) __ATTR__USERESULT
Definition: arbdb.cxx:2282
long write_bufsize
Definition: gb_localdata.h:54
GB_ERROR GB_export_errorf(const char *templat,...)
Definition: arb_msg.cxx:262
void GB_internal_error(const char *message)
Definition: arb_msg.cxx:481
GB_CSTR GB_getenvARB_XTERM()
Definition: adsocket.cxx:524
TYPE * ARB_calloc(size_t nelem)
Definition: arb_mem.h:81
static void exit_removal()
Definition: adsocket.cxx:1242
#define gb_assert(cond)
Definition: arbdbt.h:11
char * GBK_singlequote(const char *arg)
Definition: arb_msg.cxx:599
GB_CSTR GB_concat_path_in_ARBLIB(const char *relative_path_left, const char *anypath_right)
Definition: adsocket.cxx:1150
void GB_remove_on_exit(const char *filename)
Definition: adsocket.cxx:1249
aisc_com * link
bool GB_is_directory(const char *path)
Definition: arb_file.cxx:176
char ARB_path_contains_unwanted_chars(const char *path)
Definition: arb_misc.cxx:143
GB_ERROR GB_failedTo_error(const char *do_something, const char *special, GB_ERROR error)
Definition: arb_msg.cxx:375
char * GB_map_FILE(FILE *in, int writeable)
Definition: adsocket.cxx:324
GB_CSTR GB_canonical_path(const char *anypath)
Definition: adsocket.cxx:991
GBDATA * GBT_create(GBDATA *father, const char *key, long delete_level)
Definition: adtools.cxx:26
static int pages
Definition: arb_a2ps.c:298
va_start(argPtr, format)
static GB_HASH * files_to_remove_on_exit
Definition: adsocket.cxx:1236
#define TEST_EXPECT_NO_ERROR(call)
Definition: test_unit.h:1118
char * GBS_eval_env(GB_CSTR p)
Definition: adstring.cxx:212
static export_environment expenv
Definition: adsocket.cxx:745
#define NULp
Definition: cxxforward.h:116
void GB_informationf(const char *templat,...)
Definition: arb_msg.cxx:555
gbcmc_comm * gbcmc_open(const char *path)
Definition: adsocket.cxx:171
static char * command
Definition: arb_a2ps.c:319
bool ARB_strBeginsWith(const char *str, const char *with)
Definition: arb_str.h:42
static GB_ULONG parse_env_mem_definition(const char *env_override, GB_ERROR &error)
Definition: adsocket.cxx:831
GB_CSTR GB_getenvARBMACROHOME()
Definition: adsocket.cxx:629
#define FALLTHROUGH
Definition: cxxforward.h:136
char * GB_map_file(const char *path, int writeable)
Definition: adsocket.cxx:345
GB_transaction ta(gb_var)
GB_CSTR GB_path_in_ARBHOME(const char *relative_path)
Definition: adsocket.cxx:1140
bool is_absolute_path(const char *path)
Definition: adsocket.cxx:1105
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
Definition: arbdb.cxx:904
GBDATA * gb_main
Definition: adname.cxx:32
GB_CSTR GB_getenvARB_XCMD()
Definition: adsocket.cxx:533
char * GB_read_fp(FILE *in)
Definition: adsocket.cxx:272
#define min(a, b)
Definition: f2c.h:153
GBDATA * GBT_find_or_create_item_rel_item_data(GBDATA *gb_item_data, const char *itemname, const char *id_field, const char *id, bool markCreated)
Definition: aditem.cxx:18
const char * GB_CSTR
Definition: arbdb_base.h:25
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1294
gb_local_data * gb_local
Definition: arbdb.cxx:33
char * release_memfriendly()
Definition: arb_strbuf.h:133
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
GB_ERROR GB_create_directory(const char *path)
long gbcms_close(gbcmc_comm *link)
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:655
GB_CSTR GB_getenvARB_PDFVIEW()
Definition: adsocket.cxx:660
GB_CSTR GB_path_in_arbprop(const char *relative_path)
Definition: adsocket.cxx:1157
GB_HASH * GBS_create_hash(long estimated_elements, GB_CASE case_sens)
Definition: adhash.cxx:253
void put(char c)
Definition: arb_strbuf.h:174