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