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