1 | // =========================================================== // |
---|
2 | // // |
---|
3 | // File : AW_root_debug.cxx // |
---|
4 | // Purpose : // |
---|
5 | // // |
---|
6 | // Coded by Ralf Westram (coder@reallysoft.de) in May 2009 // |
---|
7 | // Institute of Microbiology (Technical University Munich) // |
---|
8 | // http://www.arb-home.de/ // |
---|
9 | // // |
---|
10 | // =========================================================== // |
---|
11 | |
---|
12 | #include "aw_window.hxx" |
---|
13 | #include "aw_Xm.hxx" |
---|
14 | #include "aw_window_Xm.hxx" |
---|
15 | #include "aw_root.hxx" |
---|
16 | #include "aw_msg.hxx" |
---|
17 | |
---|
18 | #include <arbdbt.h> |
---|
19 | #include <arb_strarray.h> |
---|
20 | |
---|
21 | #include <vector> |
---|
22 | #include <iterator> |
---|
23 | #include <string> |
---|
24 | #include <algorithm> |
---|
25 | |
---|
26 | // do includes above (otherwise depends depend on DEBUG) |
---|
27 | |
---|
28 | #if defined(DEBUG) |
---|
29 | // -------------------------------------------------------------------------------- |
---|
30 | |
---|
31 | using namespace std; |
---|
32 | |
---|
33 | typedef vector<string> CallbackArray; |
---|
34 | typedef CallbackArray::const_iterator CallbackIter; |
---|
35 | |
---|
36 | static GB_HASH *dontCallHash = NULp; |
---|
37 | static GB_HASH *alreadyCalledHash = NULp; |
---|
38 | |
---|
39 | static void forgetCalledCallbacks() { |
---|
40 | if (alreadyCalledHash) GBS_free_hash(alreadyCalledHash); |
---|
41 | alreadyCalledHash = GBS_create_hash(2500, GB_MIND_CASE); |
---|
42 | } |
---|
43 | |
---|
44 | static void auto_dontcall1(const char *key, long value, void *cl_hash) { |
---|
45 | if (strncmp(key, "ARB_NT/", 7) == 0) { |
---|
46 | GB_HASH *autodontCallHash = (GB_HASH*)cl_hash; |
---|
47 | GBS_write_hash(autodontCallHash, GBS_global_string("ARB_NT_1/%s", key+7), value); |
---|
48 | } |
---|
49 | } |
---|
50 | static void auto_dontcall2(const char *key, long value, void *) { |
---|
51 | GBS_write_hash(dontCallHash, key, value); |
---|
52 | } |
---|
53 | |
---|
54 | static void forget_dontCallHash() { |
---|
55 | if (dontCallHash) { |
---|
56 | GBS_free_hash(dontCallHash); |
---|
57 | GBS_free_hash(alreadyCalledHash); |
---|
58 | dontCallHash = NULp; |
---|
59 | } |
---|
60 | } |
---|
61 | |
---|
62 | static void build_dontCallHash() { |
---|
63 | aw_assert(!dontCallHash); |
---|
64 | dontCallHash = GBS_create_hash(100, GB_MIND_CASE); |
---|
65 | forgetCalledCallbacks(); |
---|
66 | |
---|
67 | atexit(forget_dontCallHash); |
---|
68 | |
---|
69 | // avoid program termination/restart/etc. |
---|
70 | GBS_write_hash(dontCallHash, "ARB_NT/QUIT", 1); |
---|
71 | GBS_write_hash(dontCallHash, "quit", 1); |
---|
72 | GBS_write_hash(dontCallHash, "new_arb", 1); |
---|
73 | GBS_write_hash(dontCallHash, "restart_arb", 1); |
---|
74 | GBS_write_hash(dontCallHash, "ARB_EDIT4/QUIT", 1); |
---|
75 | GBS_write_hash(dontCallHash, "ARB_INTRO/CANCEL", 1); |
---|
76 | GBS_write_hash(dontCallHash, "NEIGHBOUR_JOINING/CLOSE", 1); |
---|
77 | GBS_write_hash(dontCallHash, "MERGE_SELECT_DATABASES/QUIT", 1); |
---|
78 | GBS_write_hash(dontCallHash, "quitnstart", 1); |
---|
79 | GBS_write_hash(dontCallHash, "PARS_PROPS/ABORT", 1); |
---|
80 | GBS_write_hash(dontCallHash, "ARB_PHYLO/QUIT", 1); |
---|
81 | GBS_write_hash(dontCallHash, "SELECT_ALIGNMENT/ABORT", 1); |
---|
82 | |
---|
83 | // avoid start of some external programs: |
---|
84 | #if 1 |
---|
85 | GBS_write_hash(dontCallHash, "GDE__User__Start_a_slave_ARB_on_a_foreign_host_/GO", 2); |
---|
86 | GBS_write_hash(dontCallHash, "NAME_SERVER_ADMIN/REMOVE_SUPERFLUOUS_ENTRIES_IN_NAMES_FILE", 2); |
---|
87 | GBS_write_hash(dontCallHash, "GDE__Print__Pretty_print_sequences_slow_/GO", 2); |
---|
88 | |
---|
89 | GBS_write_hash(dontCallHash, "ARB_NT/EDIT_SEQUENCES", 2); |
---|
90 | GBS_write_hash(dontCallHash, "merge_from", 2); |
---|
91 | GBS_write_hash(dontCallHash, "CPR_MAIN/HELP", 2); |
---|
92 | GBS_write_hash(dontCallHash, "HELP/BROWSE", 2); |
---|
93 | GBS_write_hash(dontCallHash, "mailing_list", 2); |
---|
94 | GBS_write_hash(dontCallHash, "bug_report", 2); |
---|
95 | GBS_write_hash(dontCallHash, "HELP/EDIT", 2); |
---|
96 | GBS_write_hash(dontCallHash, "MACROS/EDIT", 2); |
---|
97 | GBS_write_hash(dontCallHash, "MACROS/EXECUTE", 2); |
---|
98 | GBS_write_hash(dontCallHash, "NAME_SERVER_ADMIN/EDIT_NAMES_FILE", 2); |
---|
99 | GBS_write_hash(dontCallHash, "arb_dist", 2); |
---|
100 | GBS_write_hash(dontCallHash, "arb_pars", 2); |
---|
101 | GBS_write_hash(dontCallHash, "arb_pars_quick", 2); |
---|
102 | GBS_write_hash(dontCallHash, "arb_phyl", 2); |
---|
103 | GBS_write_hash(dontCallHash, "count_different_chars", 2); |
---|
104 | GBS_write_hash(dontCallHash, "corr_mutat_analysis", 2); |
---|
105 | GBS_write_hash(dontCallHash, "export_to_ARB", 2); |
---|
106 | GBS_write_hash(dontCallHash, "new2_arb_edit4", 2); |
---|
107 | GBS_write_hash(dontCallHash, "new_arb_edit4", 2); |
---|
108 | GBS_write_hash(dontCallHash, "primer_design", 2); |
---|
109 | GBS_write_hash(dontCallHash, "xterm", 2); |
---|
110 | GBS_write_hash(dontCallHash, "SUBMIT_REG/SEND", 2); |
---|
111 | GBS_write_hash(dontCallHash, "SUBMIT_BUG/SEND", 2); |
---|
112 | GBS_write_hash(dontCallHash, "PRINT_CANVAS/PRINT", 2); |
---|
113 | GBS_write_hash(dontCallHash, "PT_SERVER_ADMIN/CREATE_TEMPLATE", 2); |
---|
114 | GBS_write_hash(dontCallHash, "PT_SERVER_ADMIN/EDIT_LOG", 2); |
---|
115 | GBS_write_hash(dontCallHash, "NAME_SERVER_ADMIN/CREATE_TEMPLATE", 2); |
---|
116 | GBS_write_hash(dontCallHash, "SELECT_CONFIGURATION/START", 2); |
---|
117 | GBS_write_hash(dontCallHash, "EXPORT_TREE_AS_XFIG/START_XFIG", 2); |
---|
118 | GBS_write_hash(dontCallHash, "EXPORT_NDS_OF_MARKED/PRINT", 2); |
---|
119 | GBS_write_hash(dontCallHash, "ALIGNER_V2/GO", 2); |
---|
120 | GBS_write_hash(dontCallHash, "SINA/Start", 2); |
---|
121 | #endif |
---|
122 | |
---|
123 | // avoid saving |
---|
124 | GBS_write_hash(dontCallHash, "save_changes", 3); |
---|
125 | GBS_write_hash(dontCallHash, "save_props", 3); |
---|
126 | GBS_write_hash(dontCallHash, "save_alitype_props", 3); |
---|
127 | GBS_write_hash(dontCallHash, "save_alispecific_props", 3); |
---|
128 | GBS_write_hash(dontCallHash, "save_DB1", 3); |
---|
129 | GBS_write_hash(dontCallHash, "SAVE_DB/SAVE", 3); |
---|
130 | GBS_write_hash(dontCallHash, "ARB_NT/SAVE", 3); |
---|
131 | GBS_write_hash(dontCallHash, "ARB_NT/SAVE_AS", 3); |
---|
132 | GBS_write_hash(dontCallHash, "ARB_NT/QUICK_SAVE_AS", 3); |
---|
133 | |
---|
134 | GBS_write_hash(dontCallHash, "User1_search_1/SAVE", 3); |
---|
135 | GBS_write_hash(dontCallHash, "User2_search_1/SAVE", 3); |
---|
136 | GBS_write_hash(dontCallHash, "Probe_search_1/SAVE", 3); |
---|
137 | GBS_write_hash(dontCallHash, "Primer_local_search_1/SAVE", 3); |
---|
138 | GBS_write_hash(dontCallHash, "Primer_region_search_1/SAVE", 3); |
---|
139 | GBS_write_hash(dontCallHash, "Primer_global_search_1/SAVE", 3); |
---|
140 | GBS_write_hash(dontCallHash, "Signature_local_search_1/SAVE", 3); |
---|
141 | GBS_write_hash(dontCallHash, "Signature_region_search_1/SAVE", 3); |
---|
142 | GBS_write_hash(dontCallHash, "Signature_global_search_1/SAVE", 3); |
---|
143 | |
---|
144 | // avoid confusion by recording, executing or deleting macros |
---|
145 | GBS_write_hash(dontCallHash, "MACROS/DELETE", 1); |
---|
146 | GBS_write_hash(dontCallHash, "MACROS/EDIT", 1); |
---|
147 | GBS_write_hash(dontCallHash, "MACROS/EXECUTE", 1); |
---|
148 | GBS_write_hash(dontCallHash, "MACROS/macro_record", 1); |
---|
149 | |
---|
150 | #if 1 |
---|
151 | // @@@ crashing - fix later |
---|
152 | GBS_write_hash(dontCallHash, "ARB_NT/view_probe_group_result", 4); |
---|
153 | GBS_write_hash(dontCallHash, "PT_SERVER_ADMIN/CHECK_SERVER", 4); |
---|
154 | GBS_write_hash(dontCallHash, "ARB_EDIT4/SECEDIT", 4); |
---|
155 | GBS_write_hash(dontCallHash, "sec_edit", 4); |
---|
156 | GBS_write_hash(dontCallHash, "ARB_EDIT4/RNA3D", 4); |
---|
157 | GBS_write_hash(dontCallHash, "rna3d", 4); |
---|
158 | GBS_write_hash(dontCallHash, "reload_config", 4); |
---|
159 | GBS_write_hash(dontCallHash, "LOAD_OLD_CONFIGURATION/LOAD", 4); |
---|
160 | GBS_write_hash(dontCallHash, "table_admin", 4); // disabled in userland atm |
---|
161 | GBS_write_hash(dontCallHash, "PARS_PROPS/GO", 4); // has already been executed (designed to run only once) |
---|
162 | GBS_write_hash(dontCallHash, "ARB_PARSIMONY/POP", 4); // pop does not work correctly in all cases (see #528) |
---|
163 | GBS_write_hash(dontCallHash, "new_win", 4); // 2nd editor window (blocked by #429) |
---|
164 | GBS_write_hash(dontCallHash, "ARB_NT/UNDO", 4); // doesn't crash, but caused following commands to crash |
---|
165 | #endif |
---|
166 | |
---|
167 | // do not open 2nd ARB_NT window (to buggy) |
---|
168 | GBS_write_hash(dontCallHash, "new_window", 4); |
---|
169 | |
---|
170 | #if 1 |
---|
171 | // @@@ test callbacks asking questions again later |
---|
172 | GBS_write_hash(dontCallHash, "ARB_NT/tree_scale_lengths", 5); |
---|
173 | GBS_write_hash(dontCallHash, "CREATE_USER_MASK/CREATE", 5); |
---|
174 | GBS_write_hash(dontCallHash, "GDE__Import__Import_sequences_using_Readseq_slow_/GO", 5); |
---|
175 | GBS_write_hash(dontCallHash, "INFO_OF_ALIGNMENT/DELETE", 5); |
---|
176 | GBS_write_hash(dontCallHash, "LOAD_SELECTION_BOX/LOAD", 5); |
---|
177 | GBS_write_hash(dontCallHash, "MULTI_PROBE/CREATE_NEW_SEQUENCE", 5); |
---|
178 | GBS_write_hash(dontCallHash, "PT_SERVER_ADMIN/KILL_ALL_SERVERS", 5); |
---|
179 | GBS_write_hash(dontCallHash, "PT_SERVER_ADMIN/KILL_SERVER", 5); |
---|
180 | GBS_write_hash(dontCallHash, "PT_SERVER_ADMIN/UPDATE_SERVER", 5); |
---|
181 | GBS_write_hash(dontCallHash, "REALIGN_DNA/REALIGN", 5); |
---|
182 | // GBS_write_hash(dontCallHash, "SPECIES_QUERY/DELETE_LISTED", 5); |
---|
183 | GBS_write_hash(dontCallHash, "SPECIES_QUERY/DELETE_LISTED_spec", 5); |
---|
184 | GBS_write_hash(dontCallHash, "SPECIES_QUERY/SAVELOAD_CONFIG_spec", 5); |
---|
185 | GBS_write_hash(dontCallHash, "SPECIES_SELECTIONS/RENAME", 5); |
---|
186 | GBS_write_hash(dontCallHash, "SPECIES_SELECTIONS/STORE_0", 5); |
---|
187 | GBS_write_hash(dontCallHash, "del_marked", 5); |
---|
188 | GBS_write_hash(dontCallHash, "create_group", 5); |
---|
189 | GBS_write_hash(dontCallHash, "dcs_threshold", 5); |
---|
190 | GBS_write_hash(dontCallHash, "NAME_SERVER_ADMIN/DELETE_OLD_NAMES_FILE", 5); |
---|
191 | GBS_write_hash(dontCallHash, "detail_col_stat", 5); |
---|
192 | #endif |
---|
193 | |
---|
194 | // don't call some close-callbacks |
---|
195 | // (needed when they perform cleanup that makes other callbacks from the same window fail) |
---|
196 | GBS_write_hash(dontCallHash, "ARB_IMPORT/CLOSE", 6); |
---|
197 | |
---|
198 | GB_HASH *autodontCallHash = GBS_create_hash(100, GB_MIND_CASE); |
---|
199 | GBS_hash_do_const_loop(dontCallHash, auto_dontcall1, autodontCallHash); |
---|
200 | GBS_hash_do_const_loop(autodontCallHash, auto_dontcall2, dontCallHash); |
---|
201 | GBS_free_hash(autodontCallHash); |
---|
202 | } |
---|
203 | |
---|
204 | class StringVectorArray : public ConstStrArray { |
---|
205 | CallbackArray array; |
---|
206 | public: |
---|
207 | StringVectorArray(const CallbackArray& a) |
---|
208 | : array(a) |
---|
209 | { |
---|
210 | reserve(a.size()); |
---|
211 | for (CallbackArray::iterator id = array.begin(); id != array.end(); ++id) { |
---|
212 | put(id->c_str()); |
---|
213 | } |
---|
214 | } |
---|
215 | }; |
---|
216 | |
---|
217 | inline bool exclude_key(const char *key) { |
---|
218 | if (strncmp(key, "FILTER_SELECT_", 14) == 0) { |
---|
219 | if (strstr(key, "/2filter/2filter/2filter/")) { |
---|
220 | return true; |
---|
221 | } |
---|
222 | } |
---|
223 | else { |
---|
224 | if (strstr(key, "SAVELOAD_CONFIG")) return true; |
---|
225 | } |
---|
226 | return false; |
---|
227 | } |
---|
228 | |
---|
229 | inline bool is_wanted_callback(const char *key) { |
---|
230 | return |
---|
231 | GBS_read_hash(alreadyCalledHash, key) == 0 && // dont call twice |
---|
232 | !exclude_key(key); // skip some problematic callbacks |
---|
233 | } |
---|
234 | |
---|
235 | static int sortedByCallbackLocation(const char *k0, long v0, const char *k1, long v1) { |
---|
236 | AW_cb *cbs0 = reinterpret_cast<AW_cb*>(v0); |
---|
237 | AW_cb *cbs1 = reinterpret_cast<AW_cb*>(v1); |
---|
238 | |
---|
239 | int cmp = cbs0->compare(*cbs1); |
---|
240 | if (!cmp) cmp = strcmp(k0, k1); |
---|
241 | |
---|
242 | return cmp; |
---|
243 | } |
---|
244 | |
---|
245 | // ------------------------ |
---|
246 | // get_action_ids |
---|
247 | |
---|
248 | static void add_wanted_callbacks(const char *key, long /*val*/, void *cl_callbacks) { |
---|
249 | if (is_wanted_callback(key)) { |
---|
250 | CallbackArray *callbacks = reinterpret_cast<CallbackArray*>(cl_callbacks); |
---|
251 | callbacks->push_back(string(key)); |
---|
252 | } |
---|
253 | } |
---|
254 | |
---|
255 | ConstStrArray *AW_root::get_action_ids() { |
---|
256 | if (!dontCallHash) build_dontCallHash(); |
---|
257 | CallbackArray callbacks; |
---|
258 | GBS_hash_do_const_sorted_loop(prvt->action_hash, add_wanted_callbacks, GBS_HCF_sortedByKey, &callbacks); |
---|
259 | return new StringVectorArray(callbacks); |
---|
260 | } |
---|
261 | |
---|
262 | // -------------------------- |
---|
263 | // callallcallbacks |
---|
264 | |
---|
265 | size_t AW_root::callallcallbacks(int mode) { |
---|
266 | // mode == -2 -> mark all as called |
---|
267 | // mode == -1 -> forget called |
---|
268 | // mode == 0 -> call all in alpha-order |
---|
269 | // mode == 1 -> call all in reverse alpha-order |
---|
270 | // mode == 2 -> call all in code-order |
---|
271 | // mode == 3 -> call all in reverse code-order |
---|
272 | // mode == 4 -> call all in random order |
---|
273 | // mode & 8 -> repeat until no uncalled callbacks left |
---|
274 | |
---|
275 | size_t count = GBS_hash_elements(prvt->action_hash); |
---|
276 | size_t callCount = 0; |
---|
277 | |
---|
278 | aw_message(GBS_global_string("Found %zi callbacks", count)); |
---|
279 | |
---|
280 | if (!dontCallHash) build_dontCallHash(); |
---|
281 | |
---|
282 | if (mode>0 && (mode&8)) { |
---|
283 | aw_message("Calling callbacks iterated"); |
---|
284 | for (int iter = 1; ; ++iter) { // forever |
---|
285 | size_t thisCount = callallcallbacks(mode&~8); // call all in wanted order |
---|
286 | aw_message(GBS_global_string("%zu callbacks were called (iteration %i)", thisCount, iter)); |
---|
287 | if (!thisCount) { |
---|
288 | aw_message("No uncalled callbacks left"); |
---|
289 | break; |
---|
290 | } |
---|
291 | |
---|
292 | callCount += thisCount; |
---|
293 | } |
---|
294 | } |
---|
295 | else if (mode == -1) { |
---|
296 | forgetCalledCallbacks(); |
---|
297 | } |
---|
298 | else { |
---|
299 | CallbackArray callbacks; |
---|
300 | switch (mode) { |
---|
301 | case 0: |
---|
302 | case 1: |
---|
303 | GBS_hash_do_const_sorted_loop(prvt->action_hash, add_wanted_callbacks, GBS_HCF_sortedByKey, &callbacks); |
---|
304 | break; |
---|
305 | case 2: |
---|
306 | case 3: |
---|
307 | GBS_hash_do_const_sorted_loop(prvt->action_hash, add_wanted_callbacks, sortedByCallbackLocation, &callbacks); |
---|
308 | break; |
---|
309 | case -2: |
---|
310 | aw_message("Marking all callbacks as \"called\""); |
---|
311 | FALLTHROUGH; |
---|
312 | case 4: |
---|
313 | GBS_hash_do_const_loop(prvt->action_hash, add_wanted_callbacks, &callbacks); |
---|
314 | break; |
---|
315 | default: |
---|
316 | aw_assert(0); |
---|
317 | break; |
---|
318 | } |
---|
319 | |
---|
320 | switch (mode) { |
---|
321 | case -2: |
---|
322 | case 0: |
---|
323 | case 2: break; // use this order |
---|
324 | case 1: |
---|
325 | case 3: reverse(callbacks.begin(), callbacks.end()); break; // use reverse order |
---|
326 | case 4: random_shuffle(callbacks.begin(), callbacks.end()); break; // use random order |
---|
327 | default: aw_assert(0); break; // unknown mode |
---|
328 | } |
---|
329 | |
---|
330 | count = callbacks.size(); |
---|
331 | aw_message(GBS_global_string("%zu callbacks were not called yet", count)); |
---|
332 | |
---|
333 | CallbackIter end = callbacks.end(); |
---|
334 | |
---|
335 | for (int pass = 1; pass <= 2; ++pass) { |
---|
336 | size_t curr = 1; |
---|
337 | CallbackIter cb = callbacks.begin(); |
---|
338 | |
---|
339 | for (; cb != end; ++cb) { |
---|
340 | const char *remote_command = cb->c_str(); |
---|
341 | const char *remote_command_name = remote_command; |
---|
342 | { |
---|
343 | const char *slash = strrchr(remote_command, '/'); |
---|
344 | if (slash) remote_command_name = slash+1; |
---|
345 | } |
---|
346 | |
---|
347 | char firstNameChar = remote_command_name[0]; |
---|
348 | bool this_pass = firstNameChar == '-' ? (pass == 2) : (pass == 1); |
---|
349 | |
---|
350 | if (this_pass) { |
---|
351 | GBS_write_hash(alreadyCalledHash, remote_command, 1); // don't call twice |
---|
352 | |
---|
353 | if (mode != -2) { // -2 means "only mark as called" |
---|
354 | AW_cb *cbs = (AW_cb *)GBS_read_hash(prvt->action_hash, remote_command); |
---|
355 | bool skipcb = firstNameChar == '!' || GBS_read_hash(dontCallHash, remote_command); |
---|
356 | |
---|
357 | if (!skipcb) { |
---|
358 | if (cbs->contains(AnyWinCB(AW_help_entry_pressed))) skipcb = true; |
---|
359 | } |
---|
360 | |
---|
361 | if (skipcb) { |
---|
362 | fprintf(stderr, "Skipped callback %zu/%zu (%s)\n", curr, count, remote_command); |
---|
363 | } |
---|
364 | else { |
---|
365 | fprintf(stderr, "Calling back %zu/%zu (%s)\n", curr, count, remote_command); |
---|
366 | |
---|
367 | GB_clear_error(); |
---|
368 | |
---|
369 | cbs->run_callbacks(); |
---|
370 | callCount++; |
---|
371 | process_pending_events(); |
---|
372 | |
---|
373 | if (GB_have_error()) { |
---|
374 | fprintf(stderr, "Unhandled error in '%s': %s\n", remote_command, GB_await_error()); |
---|
375 | } |
---|
376 | } |
---|
377 | } |
---|
378 | } |
---|
379 | else { |
---|
380 | if (pass == 1) { |
---|
381 | fprintf(stderr, "Delayed callback %zu/%zu (%s)\n", curr, count, remote_command); |
---|
382 | } |
---|
383 | } |
---|
384 | |
---|
385 | curr++; |
---|
386 | } |
---|
387 | |
---|
388 | if (pass == 1) fprintf(stderr, "Executing delayed callbacks:\n"); |
---|
389 | } |
---|
390 | |
---|
391 | aw_message(GBS_global_string("%zu callbacks are marked as called now", GBS_hash_elements(alreadyCalledHash))); |
---|
392 | } |
---|
393 | |
---|
394 | return callCount; |
---|
395 | } |
---|
396 | |
---|
397 | // -------------------------------------------------------------------------------- |
---|
398 | #endif // DEBUG |
---|
399 | |
---|