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