ARB
NT_main.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : NT_main.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include "NT_local.h"
12 
13 #include <mg_merge.hxx>
14 #include <awti_import.hxx>
15 #include <insdel.h>
16 #include <macros.hxx>
17 #include <mod_rlimit.h>
18 #include <TreeDisplay.hxx>
19 
20 #include <awt.hxx>
21 #include <awt_misc.hxx>
22 #include <awt_sel_boxes.hxx>
23 #include <awt_TreeAwars.hxx>
24 
25 #include <aw_advice.hxx>
26 #include <aw_question.hxx>
27 #include <aw_awars.hxx>
28 #include <aw_edit.hxx>
29 #include <aw_file.hxx>
30 #include <aw_msg.hxx>
31 #include <aw_root.hxx>
32 
33 #include <adGene.h>
34 
35 #include <arb_version.h>
36 #include <arb_progress.h>
37 #include <arb_file.h>
38 
39 #include <signal.h>
40 
41 using namespace std;
42 
44 
46 
47 // NT_format_all_alignments may be called after any operation which causes
48 // unformatted alignments (e.g importing sequences)
49 //
50 // It tests all alignments whether they need to be formatted
51 // and asks the user if they should be formatted.
52 
54  GB_ERROR err = NULp;
55  GB_transaction ta(gb_main);
56  GB_topSecurityLevel unsecured(gb_main);
57 
58  long ali_count = GBT_count_alignments(gb_main);
59  if (ali_count) {
60  arb_progress progress("Formatting alignments", ali_count);
61  err = GBT_check_data(gb_main, NULp);
62 
63  AW_repeated_question question;
64  question.add_help("prompt/format_alignments.hlp");
65 
66  GBDATA *gb_presets = GBT_get_presets(gb_main);
67  for (GBDATA *gb_ali = GB_entry(gb_presets, "alignment");
68  gb_ali && !err;
69  gb_ali = GB_nextEntry(gb_ali))
70  {
71  GBDATA *gb_aligned = GB_search(gb_ali, "aligned", GB_INT);
72 
73  if (GB_read_int(gb_aligned) == 0) { // sequences in alignment are not formatted
74  enum FormatAction {
75  FA_ASK_USER = 0, // ask user
76  FA_FORMAT_ALL = 1, // format automatically w/o asking
77  FA_SKIP_ALL = 2, // skip automatically w/o asking
78  };
79  FormatAction format_action = FA_ASK_USER;
80  GBDATA *gb_ali_name = GB_entry(gb_ali, "alignment_name");
81  const char *ali_name = GB_read_char_pntr(gb_ali_name);
82 
83  {
84  bool is_ali_genom = strcmp(ali_name, GENOM_ALIGNMENT) == 0;
85  GBDATA *gb_auto_format = GB_entry(gb_ali, "auto_format");
86 
87  if (gb_auto_format) {
88  format_action = FormatAction(GB_read_int(gb_auto_format));
89  if (is_ali_genom) {
90  if (format_action != FA_SKIP_ALL) {
91  format_action = FA_SKIP_ALL; // always skip ali_genom
92  err = GB_write_int(gb_auto_format, FA_SKIP_ALL);
93  }
94  }
95  }
96  else if (is_ali_genom) {
97  format_action = FA_SKIP_ALL;
98  err = GBT_write_int(gb_ali, "auto_format", FA_SKIP_ALL); // always skip
99  }
100  }
101 
102  bool perform_format = false;
103  if (!err) {
104  switch (format_action) {
105  case FA_FORMAT_ALL: perform_format = true; break;
106  case FA_SKIP_ALL: perform_format = false; break;
107  default: {
108  char *qtext = GBS_global_string_copy("Alignment '%s' is not formatted. Format?", ali_name);
109  int answer = question.get_answer("format_alignments", qtext, "Format,Skip,Always format,Always skip", "all", false);
110 
111  switch (answer) {
112  case 2:
113  err = GBT_write_int(gb_ali, "auto_format", FA_FORMAT_ALL);
114  // fall-through
115  case 0:
116  perform_format = true;
117  break;
118 
119  case 3:
120  err = GBT_write_int(gb_ali, "auto_format", FA_SKIP_ALL);
121  break;
122  }
123 
124  free(qtext);
125  break;
126  }
127  }
128  }
129  if (!err && perform_format) {
130  err = ARB_format_alignment(gb_main, ali_name);
131  }
132  }
133  progress.inc_and_check_user_abort(err);
134  }
135 
136  if (err) progress.done();
137  }
138 
139  err = ta.close(err);
140  return err;
141 }
142 
143 
144 // --------------------------------------------------------------------------------
145 
146 
148  // called once on ARB_NTREE startup
149  arb_progress cons_progress("Checking consistency");
150 
152  if (!err) err = NT_repair_DB(GLOBAL.gb_main);
153 
154  return err;
155 }
156 
157 __ATTR__USERESULT static GB_ERROR startup_mainwindow_and_dbserver(AW_root *aw_root, const char *autorun_macro, TREE_canvas*& result_ntw) {
159 
160  GB_ERROR error = configure_macro_recording(aw_root, "ARB_NT", GLOBAL.gb_main); // @@@ problematic if called from startup-importer
161  if (!error) {
162  result_ntw = NT_create_main_window(aw_root);
163  if (GB_is_server(GLOBAL.gb_main)) {
165  if (!error) NT_repair_userland_problems();
166  }
167  }
168 
169  if (!error) error = GBK_system("arb_macro_compatibility.sh &"); // run async to avoid (DB) lock problems
170 
171  if (!error && autorun_macro) execute_macro(aw_root, autorun_macro); // @@@ triggering execution here is ok, but its a bad place to pass 'autorun_macro'. Should be handled more generally
172 
173  return error;
174 }
175 
176 static ARB_ERROR load_and_startup_main_window(AW_root *aw_root, const char *autorun_macro) {
177  char *db_server = aw_root->awar(AWAR_DB_PATH)->read_string();
178  GLOBAL.gb_main = GBT_open(db_server, "rw");
179 
181  if (!GLOBAL.gb_main) {
182  error = GB_await_error();
183  }
184  else {
185  aw_root->awar(AWAR_DB_PATH)->write_string(db_server);
186 
187 #define MAXNAMELEN 35
188  int len = strlen(db_server);
189  if (len>MAXNAMELEN) {
190  char *nameOnly = strrchr(db_server, '/');
191  if (nameOnly) {
192  nameOnly++;
193  len -= (nameOnly-db_server);
194  memmove(db_server, nameOnly, len+1);
195  if (len>MAXNAMELEN) {
196  strcpy(db_server+MAXNAMELEN-3, "...");
197  }
198  }
199  }
200 #if defined(DEBUG)
201  AWT_announce_db_to_browser(GLOBAL.gb_main, GBS_global_string("ARB database (%s)", db_server));
202 #endif // DEBUG
203 
204  TREE_canvas *dummy = NULp;
205  GB_ERROR problem = startup_mainwindow_and_dbserver(aw_root, autorun_macro, dummy);
206  aw_message_if(problem); // no need to terminate ARB
207  }
208 
209  free(db_server);
210  return error;
211 }
212 
213 #define AWAR_DB_FILTER AWAR_DBBASE "/filter"
214 #define AWAR_DB_DIRECTORY AWAR_DBBASE "/directory"
215 
217  AW_root *aw_root = aww->get_root();
218  char *db_server = aw_root->awar(AWAR_DB_PATH)->read_string();
219 
220  if (strlen(db_server)) {
221  if (aw_ask_sure(NULp, GBS_global_string("Are you sure to delete database %s\nNote: there is no way to undelete it afterwards", db_server))) {
222  GB_ERROR error = GB_delete_database(db_server);
223  if (error) {
224  aw_message(error);
225  }
226  else {
227  aw_root->awar(AWAR_DB_FILTER)->touch();
228  }
229  }
230  }
231  else {
232  aw_message("No database selected");
233  }
234  free(db_server);
235 }
236 
238  GLOBAL.aw_root = aw_root;
239 
241  nt_assert(gb_imported == GLOBAL.gb_main); // import-DB should already be used as main-DB
242  GLOBAL.gb_main = gb_imported;
243 
244  TREE_canvas *ntw = NULp;
246 
247  if (aw_root->awar(AWAR_IMPORT_AUTOCONF)->read_int()) {
249  }
250 
251  aw_root->awar(AWAR_TREE_REFRESH)->touch();
252 }
253 
254 static void nt_intro_start_existing(AW_window *aw_intro) {
255  aw_intro->hide();
257  nt_assert(contradicted(error, got_macro_ability(aw_intro->get_root())));
258  if (error) {
259  aw_intro->show();
260  aw_popup_ok(error.deliver());
261  }
262  else {
263  error.expect_no_error();
264  }
265 }
266 
267 static void nt_intro_start_merge(AW_window *aw_intro) {
268  AW_root *aw_root = aw_intro->get_root();
269  const char *dir = aw_root->awar(AWAR_DB_DIRECTORY)->read_char_pntr();
270  char *merge_args = GBS_global_string_copy("'%s' '%s'", dir, dir);
271 
272  NT_restart(aw_root, merge_args); // call arb_ntree as merge-tool on exit
273 }
274 
275 static void nt_intro_start_import(AW_window *aw_intro) {
276  aw_intro->hide();
277 
278  AW_root *aw_root = aw_intro->get_root();
279  aw_root->awar_string(AWAR_DB_PATH)->write_string("noname.arb");
280 
281  AWTI_open_import_window(aw_root, NULp, true, NULp, makeRootCallback(start_main_window_after_import));
283 
284  nt_assert(got_macro_ability(aw_root));
285 }
286 
288  AW_window_simple *aws = new AW_window_simple;
289  aws->init(awr, "ARB_INTRO", "ARB INTRO");
290  aws->load_xfig("arb_intro.fig");
291 
292  aws->callback(makeWindowCallback(NT_exit, EXIT_SUCCESS));
293  aws->at("close");
294  aws->create_button("EXIT", "Exit", "x");
295 
296  aws->at("help");
297  aws->callback(makeHelpCallback("arb_intro.hlp"));
298  aws->create_button("HELP", "HELP", "H");
299 
301 
302  aws->button_length(0);
303 
304  aws->at("logo");
305  aws->create_button(NULp, "#logo.xpm");
306 
307  aws->at("version");
308  aws->create_button(NULp, GBS_global_string("Version " ARB_VERSION "\n(" ARB_BUILD_DATE ")")); // version + date
309 
310  aws->at("copyright");
311  aws->create_button(NULp, GBS_global_string("(C) 1993-" ARB_BUILD_YEAR));
312 
313  aws->at("old");
314  aws->callback(nt_intro_start_existing);
315  aws->create_autosize_button("OPEN_SELECTED", "OPEN SELECTED", "O");
316 
317  aws->at("del");
318  aws->callback(nt_delete_database);
319  aws->create_autosize_button("DELETE_SELECTED", "DELETE SELECTED");
320 
321  aws->at("new_complex");
322  aws->callback(nt_intro_start_import);
323  aws->create_autosize_button("CREATE_AND_IMPORT", "CREATE AND IMPORT", "I");
324 
325  aws->at("merge");
326  aws->callback(nt_intro_start_merge);
327  aws->create_autosize_button("MERGE_TWO_DATABASES", "MERGE TWO ARB DATABASES", "O");
328 
329  aws->at("expert");
330  aws->create_toggle(AWAR_EXPERT);
331 
332  return aws;
333 }
334 
336  static bool avoid_recursion = false;
337 
338  if (!avoid_recursion) {
339  LocallyModify<bool> flag(avoid_recursion, true);
340 
341  char *value = awr->awar(AWAR_DB_PATH)->read_string();
342  char *lslash = strrchr(value, '/');
343 
344  char *name = lslash ? lslash+1 : value;
345 #if defined(DEBUG)
346  printf("writing '%s' to AWAR_DB_NAME\n", name);
347 #endif // DEBUG
348  awr->awar(AWAR_DB_NAME)->write_string(name);
349 
350  if (lslash) { // update value of directory
351  lslash[0] = 0;
352  awr->awar(AWAR_DB_DIRECTORY)->write_string(value);
353  lslash[0] = '/';
354  }
355 
356  free(value);
357  }
358 }
359 
360 class NtreeCommandLine : virtual Noncopyable {
361  int arg_count;
362  char const*const* args;
363 
364  bool help_requested;
365  bool do_import;
366 
367  const char *macro_name;
368 
369 public:
370  NtreeCommandLine(int argc_, char const*const* argv_)
371  : arg_count(argc_-1),
372  args(argv_+1),
373  help_requested(false),
374  do_import(false),
375  macro_name(NULp)
376  {}
377 
378  void shift() { ++args; --arg_count; }
379 
380  int free_args() const { return arg_count; }
381  const char *get_arg(int num) const { return num<arg_count ? args[num] : NULp; }
382 
383  bool wants_help() const { return help_requested; }
384  bool wants_import() const { return do_import; }
385  bool wants_merge() const { return arg_count == 2; }
386 
387  const char *autorun_macro() const { return macro_name; }
388 
389  void print_help(FILE *out) const {
390  fprintf(out,
391  "\n"
392  "arb_ntree version " ARB_VERSION_DETAILED "\n"
393  "(C) 1993-" ARB_BUILD_YEAR " The ARB-project\n"
394  "http://www.arb-home.de/\n"
395  "(version build by: " ARB_BUILD_USER "@" ARB_BUILD_HOST ")\n"
396  "\n"
397  "Possible usage:\n"
398  " arb_ntree => start ARB (intro)\n"
399  " arb_ntree DB => start ARB with DB\n"
400  " arb_ntree DB1 DB2 => merge from DB1 into DB2\n"
401  " arb_ntree --import FILE => import FILE into new database (FILE may be a filemask)\n"
402  "\n"
403  "Additional arguments possible with command lines above:\n"
404  " --execute macroname => execute macro 'macroname' after startup\n"
405  "\n"
406  "Each DB argument may be one of the following:\n"
407  " database.arb -> use existing or new database\n"
408  " \":\" -> connect to database of a running instance of ARB\n"
409  " directory -> prompt for databases inside directory\n"
410  " filemask -> also prompt for DB, but more specific (e.g. \"prot*.arb\")\n"
411  "\n"
412  );
413  }
414 
417 
418  while (!error && arg_count>0 && args[0][0] == '-') {
419  const char *opt = args[0]+1;
420  if (opt[0] == '-') ++opt; // accept '-' or '--'
421  if (strcmp(opt, "help") == 0 || strcmp(opt, "h") == 0) { help_requested = true; }
422  else if (strcmp(opt, "execute") == 0) { shift(); macro_name = *args; }
423  else if (strcmp(opt, "import") == 0) { do_import = true; }
424 
425  // bunch of test switches to provoke various ways to terminate (see also http://bugs.arb-home.de/ticket/538)
426  else if (strcmp(opt, "crash") == 0) { GBK_terminate("crash requested"); }
427  else if (strcmp(opt, "trap") == 0) { arb_assert(0); }
428  else if (strcmp(opt, "sighup") == 0) { raise(SIGHUP); }
429  else if (strcmp(opt, "sigsegv") == 0) { raise(SIGSEGV); }
430  else if (strcmp(opt, "sigterm") == 0) { raise(SIGTERM); }
431  else if (strcmp(opt, "fail") == 0) { exit(EXIT_FAILURE); }
432  else if (strcmp(opt, "exit") == 0) { exit(EXIT_SUCCESS); }
433  // end of test switches ----------------------------------------
434 
435  else error = GBS_global_string("Unknown switch '%s'", args[0]);
436  shift();
437  }
438  // non-switch arguments remain in arg_count/args
439  if (!error) {
440  if (do_import && arg_count != 1) error = "expected exactly one file-name or file-mask behind --import";
441  else if (arg_count>2) error = "too many stray arguments given (max. 2 accepted)";
442  }
443  return error;
444  }
445 };
446 
447 enum ArgType { // args that might be specified on command line (for DB or FILE; see above)
455 };
456 
457 inline bool has_arb_suffix(const char *arg) {
458  const char *suffix = strstr(arg, ".arb");
459  if (suffix) {
460  return strcmp(suffix, ".arb") == 0;
461  }
462  return false;
463 }
464 
465 static ArgType detectArgType(const char *arg) {
466  if (strcmp(arg, ":") == 0) return RUNNING_DB;
467  if (GB_is_directory(arg)) return DIRECTORY;
468  if (strpbrk(arg, "*?")) return FILEMASK;
469  if (has_arb_suffix(arg)) {
470  return GB_is_regularfile(arg) ? EXISTING_DB : NEW_DB;
471  }
472 
473  GB_ERROR load_file_err = GBT_check_arb_file(arg);
474  if (!load_file_err) return EXISTING_DB;
475 
477 }
478 
480 
481 #define ABORTED_BY_USER "aborted by user"
482 
483 static ARB_ERROR check_argument_for_mode(const char *database, char *&browser_startdir, RunMode& mode) {
484  // Check whether 'database' is a
485  // - ARB database
486  // - directory name
487  // - file to import
488  //
489  // Modify 'mode' occordingly.
490  // Set 'browser_startdir'
491 
493  if (mode != IMPORT) {
494  if (!database) mode = BROWSE;
495  else {
496  GB_ERROR load_file_err = GBT_check_arb_file(database);
497  if (load_file_err) {
498  char *full_path = AW_unfold_path("PWD", database);
499 
500  enum Action { LOAD_DB, CONVERT_DB, BROWSE_DB, EXIT, NOIDEA };
501  Action action = NOIDEA;
502  if (GB_is_directory(full_path)) {
503  action = BROWSE_DB;
504  }
505  else {
506  if (!GB_is_regularfile(full_path)) {
507  const char *msg = GBS_global_string("'%s' is neither a known option nor a legal file- or directory-name.\n(Error: %s)",
508  full_path, load_file_err);
509 
510  int ans = aw_question(NULp, msg, "Browser,Exit");
511  action = ans ? EXIT : BROWSE_DB;
512  }
513  else {
514  const char *msg = GBS_global_string("Your file is not an original arb file\n(%s)", load_file_err);
515  action = (Action)aw_question(NULp, msg, "Continue (dangerous),Start Converter,Browser,Exit");
516  }
517  }
518 
519  switch (action) {
520  case CONVERT_DB: mode = IMPORT; break;
521  case LOAD_DB: break;
522  case NOIDEA: nt_assert(0); FALLTHROUGH; // in NDEBUG
523  case EXIT: error = ABORTED_BY_USER; break;
524  case BROWSE_DB: {
525  char *dir = nulldup(full_path);
526  while (dir && !GB_is_directory(dir)) freeset(dir, AW_extract_directory(dir));
527 
528  if (dir) {
530  reassign(browser_startdir, dir);
531  mode = BROWSE;
532  }
533  free(dir);
534  break;
535  }
536 
537  }
538  free(full_path);
539  }
540  }
541  }
542 
543  return error;
544 }
545 
546 class SelectedDatabase : virtual Noncopyable {
547  GBDATA*& gb_main;
548  char *name;
549  ArgType type;
550  char *role;
551 
552  void fix_name() {
553  if (type != RUNNING_DB && name[0]) {
554  const char *changed;
555 
556  if (type == NEW_DB) {
557  changed = GB_unfold_in_directory(GB_getcwd(), name);
558  }
559  else {
560  changed = GB_canonical_path(name);
561  }
562 
563  if (strcmp(name, changed) != 0) {
564  reselect_file(changed);
565  }
566  }
567  }
568 
569 public:
570  SelectedDatabase(GBDATA*& gb_main_, const char *name_, const char *role_)
571  : gb_main(gb_main_),
572  name(ARB_strdup(name_)),
573  type(detectArgType(name)),
574  role(ARB_strdup(role_))
575  {
576  fix_name();
577  }
579  free(role);
580  free(name);
581  }
582 
583  ArgType arg_type() const { return type; }
584 
585  bool needs_to_prompt() const {
586  return type == DIRECTORY || type == FILEMASK || type == UNKNOWN_ARG;
587  }
588 
589  const char *get_fullname() const { return name; }
590  const char *get_nameonly() const {
591  const char *slash = strrchr(name, '/');
592  return slash ? slash+1 : name;
593  }
594  const char *get_role() const { return role; }
595  const char *get_description() const { return GBS_global_string("%s (%s)", get_role(), get_nameonly()); }
596 
597  ArgType get_type() const { return type; }
598 
599  const char *get_dir() const {
600  const char *dir = NULp;
601  switch (type) {
602  case DIRECTORY:
603  dir = get_fullname();
604  break;
605 
606  case NEW_DB:
607  case FILEMASK:
608  case EXISTING_FILE:
609  case EXISTING_DB: {
610  char *dir_copy;
611  GB_split_full_path(name, &dir_copy, NULp, NULp, NULp);
612 
613  static SmartCharPtr dir_store;
614  dir_store = dir_copy;
615 
616  dir = dir_copy;
617  break;
618  }
619  case UNKNOWN_ARG:
620  case RUNNING_DB:
621  dir = ".";
622  break;
623  }
624  return dir;
625  }
626 
627  const char *get_mask() const {
628  const char *mask;
629  switch (type) {
630  case FILEMASK: {
631  char *mask_copy;
632  GB_split_full_path(name, NULp, &mask_copy, NULp, NULp);
633 
634  static SmartCharPtr mask_store;
635  mask_store = mask_copy;
636 
637  mask = mask_copy;
638  break;
639  }
640  default:
641  mask = ".arb";
642  break;
643  }
644  return mask;
645  }
646 
647  void reselect_file(const char *file) {
648  freedup(name, file);
649  type = detectArgType(name);
650  fix_name();
651  }
652  void reselect_from_awar(AW_root *aw_root, const char *awar_name) {
653  if (awar_name) {
654  const char *file = aw_root->awar(awar_name)->read_char_pntr();
655  if (file) reselect_file(file);
656  }
657  }
658 
659  GB_ERROR open_db_for_merge(bool is_source_db);
660  void close_db() { if (gb_main) GB_close(gb_main); }
661 };
662 
664  GB_ERROR error = NULp;
665  const char *openMode = "rw";
666 
667  switch (get_type()) {
668  case DIRECTORY:
669  case FILEMASK:
670  GBK_terminate("Program logic error (should have been prompted for explicit DB name)");
671  break;
672 
673  case UNKNOWN_ARG:
674  case EXISTING_FILE:
675  error = GBS_global_string("'%s' is no arb-database", get_fullname());
676  break;
677 
678  case NEW_DB:
679  if (is_source_db) {
680  error = GBS_global_string("'%s' has to exist", get_fullname());
681  break;
682  }
683  openMode = "crw"; // allow to create DB
684  break;
685 
686  case EXISTING_DB:
687  case RUNNING_DB:
688  break;
689  }
690 
691  if (!error) {
692  gb_main = GBT_open(get_fullname(), openMode);
693  if (!gb_main) error = GB_await_error();
694  else {
695  IF_DEBUG(AWT_announce_db_to_browser(gb_main, get_description()));
696  }
697  }
698 
699  return error;
700 }
701 
702 struct merge_scheme : virtual Noncopyable {
705 
706  char *awar_src;
707  char *awar_dst;
708 
710 
712  : src(src_),
713  dst(dst_),
714  awar_src(NULp),
715  awar_dst(NULp),
716  error(NULp)
717  {}
719  if (error) {
720  src->close_db();
721  dst->close_db();
722  }
723  delete src;
724  delete dst;
725  free(awar_src);
726  free(awar_dst);
727  }
728 
729 
730  void open_dbs() {
731  if (!error) error = src->open_db_for_merge(true);
732  if (!error) error = dst->open_db_for_merge(false);
733  }
734 
735  void fix_dst(AW_root *aw_root) { dst->reselect_from_awar(aw_root, awar_dst); }
736  void fix_src(AW_root *aw_root) { src->reselect_from_awar(aw_root, awar_src); }
737 
738  bool knows_dbs() const { return !src->needs_to_prompt() && !dst->needs_to_prompt(); }
739 };
740 
741 static bool merge_tool_running_as_client = true; // default to safe state (true avoids call of 'arb_clean' at exit)
742 static void exit_from_merge(const char *restart_args) {
743  if (merge_tool_running_as_client) { // there is a main ARB running
744  if (restart_args) NT_start(restart_args, true);
745  exit(EXIT_SUCCESS); // exit w/o killing clients (in contrast to NT_exit())
746  }
747  else {
748  NT_restart(AW_root::SINGLETON, null2empty(restart_args));
749  nt_assert(0);
750  }
751 }
752 
754  fputs("Error: merge aborted by user\n", stderr);
756 }
757 
759  AW_window_simple *aw_msg = new AW_window_simple;
760 
761  aw_msg->init(aw_root, "arb_merge_error", "ARB merge error");
762  aw_msg->recalc_size_atShow(AW_RESIZE_DEFAULT); // force size recalc (ignores user size)
763 
764  aw_msg->at(10, 10);
765  aw_msg->auto_space(10, 10);
766 
767  aw_msg->create_autosize_button(NULp, error, "", 2);
768  aw_msg->at_newline();
769 
770  aw_msg->callback(merge_startup_abort_cb);
771  aw_msg->create_autosize_button("OK", "Ok", "O", 2);
772 
773  aw_msg->window_fit();
774 
775  return aw_msg;
776 }
778  ms->fix_src(aw_root);
779  ms->fix_dst(aw_root);
780 
781  if (ms->knows_dbs()) {
782  ms->open_dbs();
783  }
784  else {
785  ms->error = "Need two databases to merge";
786  }
787 
788  AW_window *aw_result;
789  if (!ms->error) {
791  bool dst_is_new = ms->dst->arg_type() == NEW_DB;
792  aw_result = MERGE_create_main_window(aw_root, dst_is_new, exit_from_merge);
793 
794  nt_assert(got_macro_ability(aw_root));
795  }
796  else {
797  aw_result = merge_startup_error_window(aw_root, ms->error);
798  }
799  delete ms; // was allocated in startup_gui()
800  return aw_result;
801 }
802 
804  AW_window *aw_result;
805  if (ms->dst->needs_to_prompt()) {
806  aw_result = awt_create_load_box(aw_root, "Select", ms->dst->get_role(),
807  ms->dst->get_dir(), ms->dst->get_mask(),
808  &(ms->awar_dst),
809  AW_window::makeWindowReplacer(makeCreateWindowCallback(startup_merge_main_window, ms)),
810  makeWindowCallback(merge_startup_abort_cb), "Cancel");
811  }
812  else {
813  aw_result = startup_merge_main_window(aw_root, ms);
814  }
815  return aw_result;
816 }
817 
819  // if src_spec or dst_spec needs to be prompted for -> startup prompters with callbacks bound to continue
820  // otherwise just startup merge
821 
822  AW_window *aw_result;
823  if (ms->src->needs_to_prompt()) {
824  aw_result = awt_create_load_box(aw_root, "Select", ms->src->get_role(),
825  ms->src->get_dir(), ms->src->get_mask(),
826  &(ms->awar_src),
828  makeWindowCallback(merge_startup_abort_cb), "Cancel");
829  }
830  else {
831  aw_result = startup_merge_prompting_for_nonexplicit_dst_db(aw_root, ms);
832  }
833  return aw_result;
834 }
835 
837  {
838  char *message = ARB_strdup(GB_path_in_ARBLIB("message"));
839  char *stamp = ARB_strdup(GB_path_in_arbprop("msgtime"));
840  if (GB_time_of_file(message)>GB_time_of_file(stamp)) {
841  AW_edit(message);
842  AWT_system_cb(GBS_global_string("touch %s", stamp));
843  }
844  free(stamp);
845  free(message);
846  }
847 
848  // create some early awars
849  // Note: normally you don't like to add your awar-init-function here, but into nt_create_all_awars()
850 
851  AW_root* aw_root = GLOBAL.aw_root;
852 
853  AW_create_fileselection_awars(aw_root, AWAR_DBBASE, "", ".arb", "noname.arb");
854  aw_root->awar_string(AWAR_DB_NAME, "noname.arb");
856 
857  aw_root->awar_int(AWAR_EXPERT, 0);
858 
860 
862 
863  aw_root->setUserActionTracker(new NullTracker); // no macro recording inside prompters that may popup
864  if (!error) {
865  nt_assert(!cl.wants_help());
866 
867  RunMode mode = NORMAL;
868 
869  if (cl.wants_merge()) mode = MERGE;
870  else if (cl.wants_import()) mode = IMPORT;
871 
872  if (mode == MERGE) {
874 
875  merge_scheme *ms = new merge_scheme( // freed in startup_merge_main_window()
876  new SelectedDatabase(GLOBAL_gb_src, cl.get_arg(0), "Source DB for merge"),
877  new SelectedDatabase(GLOBAL_gb_dst, cl.get_arg(1), "Destination DB for merge"));
878 
880 
881  if (ms->src->arg_type() == RUNNING_DB && ms->dst->arg_type() == RUNNING_DB) {
882  error = "You cannot merge from running to running DB";
883  }
884  else {
885  aw_root->setUserActionTracker(new NullTracker); // no macro recording during startup of merge tool (file prompts)
887 
888  nt_assert(contradicted(aww, error));
889 
890  if (!error) {
891  aww->show();
892  aw_root->main_loop();
893  nt_assert(0);
894  }
895  }
896  }
897  else {
898  const char *database = NULp;
899  char *browser_startdir = ARB_strdup(".");
900 
901  if (cl.free_args() > 0) database = cl.get_arg(0);
902 
903  error = check_argument_for_mode(database, browser_startdir, mode);
904  if (!error) {
905  if (mode == IMPORT) {
906  AWTI_open_import_window(aw_root, database, true, NULp, makeRootCallback(start_main_window_after_import));
908 
909  nt_assert(got_macro_ability(aw_root));
910  aw_root->main_loop();
911  }
912  else if (mode == NORMAL) {
913  aw_root->awar(AWAR_DB_PATH)->write_string(database);
914  error = load_and_startup_main_window(aw_root, cl.autorun_macro());
915  if (!error) {
916  nt_assert(got_macro_ability(aw_root));
917  aw_root->main_loop();
918  }
919  }
920  else if (mode == BROWSE) {
921  aw_root->awar(AWAR_DB_DIRECTORY)->write_string(browser_startdir);
922  char *latest = GB_find_latest_file(browser_startdir, "/\\.(arb|a[0-9]{2})$/");
923  if (latest) {
924  int l = strlen(latest);
925  strcpy(latest+l-3, "arb");
926  aw_root->awar(AWAR_DB_PATH)->write_string(latest);
927  free(latest);
928  }
929  nt_create_intro_window(aw_root)->show();
930  aw_root->setUserActionTracker(new NullTracker); // no macro recording inside intro window
931  aw_root->main_loop();
932  }
933  }
934  free(browser_startdir);
935  }
936  }
937 
938  if (error) {
939  const char *msg = error.preserve();
940  if (strcmp(msg, ABORTED_BY_USER) != 0) aw_popup_ok(msg);
941  }
942 }
943 
944 int ARB_main(int argc, char *argv[]) {
945  {
946  // i really dont want 'arb_ntree --help' to startup the GUI
947  // hack: parse CL twice
948  NtreeCommandLine cl(argc, argv);
949  bool cl_ok = !cl.parse().deliver();
950  if (cl_ok) {
951  if (cl.wants_help()) {
952  cl.print_help(stderr);
953  return EXIT_SUCCESS;
954  }
955  }
956  }
957 
958  aw_initstatus();
959  GB_set_verbose();
960 
961  GB_shell shell;
962  AW_root *aw_root = AWT_create_root("ntree.arb", "ARB_NT", need_macro_ability());
963 
964  GLOBAL.aw_root = aw_root;
965 
966  NtreeCommandLine cl(argc, argv);
967  ARB_ERROR error = cl.parse();
968 
969  if (!error) {
970  if (cl.wants_help()) {
971  cl.print_help(stderr);
972  }
973  else {
974  ModRLimit increase_stacksize(RLIMIT_STACK, TREEDISP_STACKSIZE);
975  startup_gui(cl, error);
976  }
977  }
978 
979  int exitcode = EXIT_SUCCESS;
980  if (error) {
981  exitcode = EXIT_FAILURE;
982  fprintf(stderr, "arb_ntree: Error: %s\n", error.deliver());
983  }
984  else {
985  error.expect_no_error();
986  }
987 
988  delete aw_root;
989 
990  return exitcode;
991 }
992 
void reselect_file(const char *file)
Definition: NT_main.cxx:647
static __ATTR__USERESULT GB_ERROR startup_mainwindow_and_dbserver(AW_root *aw_root, const char *autorun_macro, TREE_canvas *&result_ntw)
Definition: NT_main.cxx:157
GB_ERROR GBK_system(const char *system_command)
Definition: arb_msg.cxx:505
#define arb_assert(cond)
Definition: arb_assert.h:245
const char * GB_ERROR
Definition: arb_core.h:25
#define AWAR_DB_NAME
Definition: aw_awar_defs.hxx:6
GB_TYPES type
bool wants_merge() const
Definition: NT_main.cxx:385
const char * get_dir() const
Definition: NT_main.cxx:599
void MERGE_create_db_file_awars(AW_root *awr, AW_default aw_def, const char *src_name, const char *dst_name)
Definition: MG_main.cxx:395
static GB_ERROR nt_check_database_consistency()
Definition: NT_main.cxx:147
#define AWAR_DB_DIRECTORY
Definition: NT_main.cxx:214
GB_ERROR preserve() const
Definition: arb_error.h:143
GB_CSTR GB_path_in_arbprop(const char *relative_path)
Definition: adsocket.cxx:1166
const char * get_mask() const
Definition: NT_main.cxx:627
void NT_create_config_after_import(TREE_canvas *ntw, bool imported_from_scratch)
Definition: NT_edconf.cxx:1316
const char * get_role() const
Definition: NT_main.cxx:594
long GB_read_int(GBDATA *gbd)
Definition: arbdb.cxx:723
ArgType arg_type() const
Definition: NT_main.cxx:583
bool wants_import() const
Definition: NT_main.cxx:384
bool GB_is_server(GBDATA *gbd)
Definition: adcomm.cxx:1697
bool knows_dbs() const
Definition: NT_main.cxx:738
void load_xfig(const char *file, bool resize=true)
Definition: AW_window.cxx:717
const char * get_arg(int num) const
Definition: NT_main.cxx:381
SelectedDatabase(GBDATA *&gb_main_, const char *name_, const char *role_)
Definition: NT_main.cxx:570
int GBT_count_alignments(GBDATA *gb_main)
Definition: adali.cxx:33
bool needs_to_prompt() const
Definition: NT_main.cxx:585
void AW_edit(const char *path)
Definition: AW_edit.cxx:16
static AW_window * startup_merge_main_window(AW_root *aw_root, merge_scheme *ms)
Definition: NT_main.cxx:777
AW_window * awt_create_load_box(AW_root *aw_root, const char *action, const char *what, const char *default_directory, const char *file_extension, char **set_file_name_awar, const WindowCallback &ok_cb, const WindowCallback &close_cb, const char *close_button_text)
void print_help(FILE *out) const
Definition: NT_main.cxx:389
void open_dbs()
Definition: NT_main.cxx:730
AW_window * MERGE_create_main_window(AW_root *aw_root, bool dst_is_new, void(*exit_cb)(const char *))
Definition: MG_main.cxx:153
#define ARB_BUILD_USER
Definition: arb_build.h:6
GBDATA * GB_nextEntry(GBDATA *entry)
Definition: adquery.cxx:339
void AWTI_set_importDB_pointer(GBDATA *&dbPtr)
void aw_initstatus()
Definition: AW_status.cxx:766
static AW_window * merge_startup_error_window(AW_root *aw_root, GB_ERROR error)
Definition: NT_main.cxx:758
bool wants_help() const
Definition: NT_main.cxx:383
void AW_create_standard_fileselection(AW_window *aws, const char *awar_prefix)
Definition: aw_file.hxx:30
#define ARB_VERSION_DETAILED
Definition: arb_build.h:2
GB_ERROR GB_delete_database(GB_CSTR filename)
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
static void nt_intro_start_import(AW_window *aw_intro)
Definition: NT_main.cxx:275
long read_int() const
Definition: AW_awar.cxx:187
Action
Definition: NT_taxonomy.cxx:36
static WindowCallback makeWindowReplacer(const CreateWindowCallback &cwcb)
Definition: aw_window.hxx:563
#define MAXNAMELEN
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:202
AW_root * awr
Definition: awt_canvas.hxx:338
AW_root * aw_root
Definition: NT_local.h:36
static void nt_intro_start_merge(AW_window *aw_intro)
Definition: NT_main.cxx:267
static void nt_intro_start_existing(AW_window *aw_intro)
Definition: NT_main.cxx:254
STL namespace.
#define ARB_VERSION
Definition: arb_build.h:1
NtreeCommandLine(int argc_, char const *const *argv_)
Definition: NT_main.cxx:370
#define ARB_BUILD_HOST
Definition: arb_build.h:5
#define EXIT_SUCCESS
Definition: arb_a2ps.c:154
static ARB_ERROR check_argument_for_mode(const char *database, char *&browser_startdir, RunMode &mode)
Definition: NT_main.cxx:483
__ATTR__USERESULT GB_ERROR configure_macro_recording(AW_root *aw_root, const char *client_id, GBDATA *gb_main)
Definition: trackers.cxx:454
const char * get_fullname() const
Definition: NT_main.cxx:589
bool has_arb_suffix(const char *arg)
Definition: NT_main.cxx:457
static void start_main_window_after_import(AW_root *aw_root)
Definition: NT_main.cxx:237
GB_CSTR GB_canonical_path(const char *anypath)
Definition: adsocket.cxx:1000
GBDATA * GBT_open(const char *path, const char *opent)
Definition: adtools.cxx:524
GBDATA * GLOBAL_gb_dst
Definition: MG_main.cxx:32
static void exit_from_merge(const char *restart_args)
Definition: NT_main.cxx:742
AW_awar * add_callback(const RootCallback &cb)
Definition: AW_awar.cxx:234
void setUserActionTracker(UserActionTracker *user_tracker)
Definition: AW_root.cxx:210
#define AWAR_DB_FILTER
Definition: NT_main.cxx:213
GB_ERROR open_db_for_merge(bool is_source_db)
Definition: NT_main.cxx:663
ARB_ERROR parse()
Definition: NT_main.cxx:415
const char * read_char_pntr() const
Definition: AW_awar.cxx:171
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:341
GBDATA * AWTI_acquire_imported_DB_and_cleanup_importer()
static AW_root * SINGLETON
Definition: aw_root.hxx:102
void show()
Definition: AW_window.cxx:1667
WindowCallback makeHelpCallback(const char *helpfile)
Definition: aw_window.hxx:106
GB_ERROR ARB_format_alignment(GBDATA *Main, const char *alignment_name)
Definition: insdel.cxx:1439
static void merge_startup_abort_cb(AW_window *)
Definition: NT_main.cxx:753
#define ARB_BUILD_YEAR
Definition: arb_build.h:4
GB_ERROR deliver() const
Definition: arb_error.h:116
void MERGE_create_all_awars(AW_root *awr, AW_default aw_def)
Definition: MG_main.cxx:344
void aw_popup_ok(const char *msg)
void recalc_size_atShow(enum AW_SizeRecalc sr)
Definition: AW_window.cxx:1436
int ARB_main(int argc, char *argv[])
Definition: NT_main.cxx:944
#define AWAR_DB_PATH
Definition: aw_awar_defs.hxx:5
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:450
unsigned long GB_time_of_file(const char *path)
Definition: arb_file.cxx:44
char * GB_find_latest_file(const char *dir, const char *mask)
Definition: adfile.cxx:152
#define false
Definition: ureadseq.h:13
void NT_restart(AW_root *aw_root, const char *arb_ntree_args)
Definition: NT_extern.cxx:352
static ARB_ERROR load_and_startup_main_window(AW_root *aw_root, const char *autorun_macro)
Definition: NT_main.cxx:176
static bool merge_tool_running_as_client
Definition: NT_main.cxx:741
merge_scheme(SelectedDatabase *src_, SelectedDatabase *dst_)
Definition: NT_main.cxx:711
void message(char *errortext)
static char const * macro_name
Definition: mkptypes.cxx:81
void touch()
Definition: AW_awar.cxx:210
SelectedDatabase * dst
Definition: NT_main.cxx:704
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define AWAR_TREE_REFRESH
void AW_create_fileselection_awars(AW_root *awr, const char *awar_base, const char *directories, const char *filter, const char *file_name)
Definition: AW_file.cxx:72
#define ABORTED_BY_USER
Definition: NT_main.cxx:481
AW_HEADER_MAIN NT_global GLOBAL
Definition: NT_main.cxx:45
void fix_dst(AW_root *aw_root)
Definition: NT_main.cxx:735
void expect_no_error() const
Definition: arb_error.h:138
static ArgType detectArgType(const char *arg)
Definition: NT_main.cxx:465
#define AWAR_DBBASE
Definition: aw_awar_defs.hxx:4
SelectedDatabase * src
Definition: NT_main.cxx:703
#define AWAR_IMPORT_AUTOCONF
Definition: awti_import.hxx:26
void execute_macro(AW_root *root, const char *macroname)
Definition: macro_gui.cxx:180
ArgType
Definition: NT_main.cxx:447
static AW_window * nt_create_intro_window(AW_root *awr)
Definition: NT_main.cxx:287
char * AW_unfold_path(const char *pwd_envar, const char *path)
Definition: AW_file.cxx:51
UserActionTracker * need_macro_ability()
Definition: trackers.cxx:450
char * read_string() const
Definition: AW_awar.cxx:201
GB_CSTR GB_path_in_ARBLIB(const char *relative_path)
Definition: adsocket.cxx:1156
AW_awar * awar(const char *awar)
Definition: AW_root.cxx:554
GB_CSTR GB_getcwd(void)
Definition: adfile.cxx:24
#define GENOM_ALIGNMENT
Definition: adGene.h:19
#define EXIT_FAILURE
Definition: arb_a2ps.c:157
GB_ERROR GB_write_int(GBDATA *gbd, long i)
Definition: arbdb.cxx:1244
GBDATA * GLOBAL_gb_src
Definition: MG_main.cxx:31
#define nt_assert(cond)
Definition: NT_local.h:27
TYPE get_type() const
Definition: probe_tree.h:64
bool got_macro_ability(AW_root *aw_root)
Definition: trackers.cxx:475
long int flag
Definition: f2c.h:39
#define AW_HEADER_MAIN
Definition: aw_window.hxx:36
void ARB_declare_global_awars(AW_root *aw_root, AW_default aw_def)
bool aw_ask_sure(const char *unique_id, const char *msg)
void main_loop()
Definition: AW_root.cxx:625
AW_root * AWT_create_root(const char *properties, const char *program, UserActionTracker *user_tracker)
int aw_question(const char *unique_id, const char *question, const char *buttons, bool sameSizeButtons, const char *helpfile)
Definition: AW_question.cxx:26
fputs(TRACE_PREFIX, stderr)
#define ARB_BUILD_DATE
Definition: arb_build.h:3
int free_args() const
Definition: NT_main.cxx:380
TREE_canvas * NT_create_main_window(AW_root *aw_root)
Definition: NT_extern.cxx:1829
ArgType get_type() const
Definition: NT_main.cxx:597
const char * get_nameonly() const
Definition: NT_main.cxx:590
static AW_window * startup_merge_prompting_for_nonexplicit_dbs(AW_root *aw_root, merge_scheme *ms)
Definition: NT_main.cxx:818
AW_awar * awar_int(const char *var_name, long default_value=0, AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:580
GB_CSTR GB_unfold_in_directory(const char *relative_directory, const char *path)
Definition: adsocket.cxx:1123
GB_ERROR close(GB_ERROR error)
Definition: arbdbpp.cxx:32
static void nt_delete_database(AW_window *aww)
Definition: NT_main.cxx:216
bool GB_is_directory(const char *path)
Definition: arb_file.cxx:176
#define __ATTR__USERESULT
Definition: attributes.h:58
GB_ERROR NT_format_all_alignments(GBDATA *gb_main)
Definition: NT_main.cxx:53
#define TREEDISP_STACKSIZE
Definition: TreeDisplay.hxx:32
void aw_message(const char *msg)
Definition: AW_status.cxx:932
GB_ERROR error
Definition: NT_main.cxx:709
void hide()
Definition: AW_window.cxx:1819
GB_ERROR NT_repair_DB(GBDATA *gb_main)
void NT_start(const char *arb_ntree_args, bool restart_with_new_ARB_PID)
Definition: NT_extern.cxx:330
AW_root * get_root()
Definition: aw_window.hxx:349
void GB_set_verbose()
Definition: ad_load.cxx:31
void GB_split_full_path(const char *fullpath, char **res_dir, char **res_fullname, char **res_name_only, char **res_suffix)
Definition: adsocket.cxx:1268
#define NULp
Definition: cxxforward.h:97
GBDATA * gb_main
Definition: NT_local.h:37
bool GB_is_regularfile(const char *path)
Definition: arb_file.cxx:76
FormatAction
Definition: AWTI_edit.cxx:35
void reselect_from_awar(AW_root *aw_root, const char *awar_name)
Definition: NT_main.cxx:652
void fix_src(AW_root *aw_root)
Definition: NT_main.cxx:736
static AW_window * startup_merge_prompting_for_nonexplicit_dst_db(AW_root *aw_root, merge_scheme *ms)
Definition: NT_main.cxx:803
char * awar_src
Definition: NT_main.cxx:706
GB_ERROR write_string(const char *aw_string)
static void startup_gui(NtreeCommandLine &cl, ARB_ERROR &error)
Definition: NT_main.cxx:836
void AWT_install_cb_guards()
void AWTI_open_import_window(AW_root *awr, const char *def_importname, bool do_exit, GBDATA *gb_main, const RootCallback &after_import_cb)
#define FALLTHROUGH
Definition: cxxforward.h:110
char * AW_extract_directory(const char *path)
Definition: AW_file.cxx:59
const char * autorun_macro() const
Definition: NT_main.cxx:387
GB_transaction ta(gb_var)
GB_ERROR GBT_write_int(GBDATA *gb_container, const char *fieldpath, long content)
Definition: adtools.cxx:471
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
Definition: arbdb.cxx:898
#define AWAR_EXPERT
GBDATA * gb_main
Definition: adname.cxx:33
AW_awar * awar_string(const char *var_name, const char *default_value="", AW_default default_file=AW_ROOT_DEFAULT)
Definition: AW_root.cxx:570
GB_ERROR GBT_check_data(GBDATA *Main, const char *alignment_name)
Definition: adali.cxx:217
AW_window * aww
Definition: awt_canvas.hxx:337
GBDATA * GBT_get_presets(GBDATA *gb_main)
Definition: adali.cxx:29
#define IF_DEBUG(x)
Definition: arb_assert.h:303
GB_ERROR GBT_check_arb_file(const char *name)
Definition: ad_load.cxx:1369
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
void NT_exit(AW_window *aws, int exitcode)
Definition: NT_extern.cxx:343
RunMode
Definition: NT_main.cxx:479
const char * get_description() const
Definition: NT_main.cxx:595
void NT_repair_userland_problems(void)
static void AWAR_DB_PATH_changed_cb(AW_root *awr)
Definition: NT_main.cxx:335
#define AW_ROOT_DEFAULT
Definition: aw_base.hxx:106
char * awar_dst
Definition: NT_main.cxx:707
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
void inc_and_check_user_abort(GB_ERROR &error)
Definition: arb_progress.h:274
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
void AWT_initTreeAwarRegistry(GBDATA *gbmain)
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:193
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:649
Definition: arbdb.h:66
void AWT_system_cb(AW_window *, const char *command)
Definition: AWT_misc.cxx:84