source: branches/alilink/CORE/arb_handlers.cxx

Last change on this file was 18126, checked in by westram, 5 years ago
File size: 8.0 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : arb_handlers.cxx                                   //
4//   Purpose   :                                                    //
5//                                                                  //
6//   Coded by Ralf Westram (coder@reallysoft.de) in November 2010   //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11
12#include <arb_handlers.h>
13#include <arb_msg.h>
14#include "arb_misc.h"
15#include <smartptr.h>
16#include <unistd.h>
17#include <time.h>
18#include <arb_algo.h>
19
20// AISC_MKPT_PROMOTE:#ifndef ARB_CORE_H
21// AISC_MKPT_PROMOTE:#include <arb_core.h>
22// AISC_MKPT_PROMOTE:#endif
23
24static FILE *arberr = stderr;
25static FILE *arbout = stdout;
26
27static void to_arberr(const char *msg) {
28    fflush(arbout);
29    fprintf(arberr, "%s\n", msg);
30    fflush(arberr);
31}
32static void to_arbout(const char *msg) {
33    fprintf(arbout, "%s\n", msg);
34}
35
36// -------------------------
37//      ARB_arbout_status
38
39const int  WIDTH = 70;
40const char CHAR  = '.';
41
42const int MIN_SECONDS_PER_ROW = 10;   // otherwise decrease number of rows
43const int MAX_SECONDS_PER_ROW = 3*60; // otherwise increase number of rows
44
45const int DEFAULT_HEIGHT = 12; // 12 can be devided by 2, 3, 4, 6 (so subtitles tend to be at start of line)
46const int MAXHEIGHT      = 3*DEFAULT_HEIGHT;
47
48#if defined(DEBUG)
49// # define TRACE_BASIC_COUNTER
50#endif
51
52class BasicStatus : virtual Noncopyable {
53    int         openCount;
54    char       *subtitle;
55    const char *cursor;
56
57    int printed;
58    int height; // number of rows to print (gets decided while printing 1st row)
59
60    bool mayReconsiderHeight;   // true -> 'height' may change
61    int  printedAtHeightChange; // value of 'printed' at time when 'height' was reconsidered and changed
62
63    time_t start;
64
65    void reset() {
66        printed  = 0;
67        cursor   = NULp;
68        subtitle = NULp;
69
70        time(&start);
71
72        mayReconsiderHeight       = true;
73        printedAtHeightChange = 0;
74
75        height = DEFAULT_HEIGHT;
76    }
77
78public:
79    BasicStatus() : openCount(0) { reset(); }
80    ~BasicStatus() { if (openCount) close(); }
81
82    void open(const char *title) {
83        arb_assert(++openCount <= 1);
84        fprintf(arbout, "Progress: %s\n", title);
85        reset();
86    }
87    void close() {
88        freenull(subtitle);
89        fprintf(arbout, "[done]\n");
90        arb_assert(--openCount >= 0);
91        fflush(arbout);
92    }
93
94    int next_LF() const { return printed-printed%WIDTH+WIDTH; }
95
96    void set_subtitle(const char *stitle) {
97        arb_assert(openCount == 1);
98        if (!cursor) {
99            freeset(subtitle, GBS_global_string_copy("{%s}", stitle));
100            cursor = subtitle;
101        }
102    }
103
104    static double estimate_overall_seconds(double seconds_passed, double gauge) {
105        return seconds_passed / gauge;
106    }
107
108    void set_gauge(double gauge) {
109        arb_assert(openCount == 1);
110
111        int wanted = int(gauge*WIDTH*height);
112        if (printed<wanted) {
113#if defined(TRACE_BASIC_COUNTER)
114            fprintf(arbout, "\nBasicStatus::set_gauge(gauge=%f) -> wanted=%i printed=%i; ", gauge, wanted, printed);
115#endif
116            while (printed<wanted) {
117                if (cursor && cursor[0]) {
118                    fputc(*cursor++, arbout);
119                }
120                else {
121                    cursor = NULp;
122                    fputc(CHAR, arbout);
123                }
124                int nextLF = next_LF();
125                printed++;
126                if (printed == nextLF) {
127                    mayReconsiderHeight = false;
128
129                    time_t now;
130                    time(&now);
131
132                    fprintf(arbout, " [%5.1f%%]", printed*100.0/(WIDTH*height));
133                    bool   done    = (printed == (WIDTH*height));
134                    double seconds = difftime(now, start);
135
136                    const char *whatshown = done ? "used" : "left";
137                    fprintf(arbout, " %s: ", whatshown);
138
139                    long show_sec = done ? seconds : long((estimate_overall_seconds(seconds, gauge)-seconds)+0.5);
140                    fputs(GBS_readable_timediff(show_sec), arbout);
141                    fputc('\n', arbout);
142
143                    nextLF = next_LF();
144                }
145                else if (mayReconsiderHeight) {
146                    if ((2*printed) > nextLF) {
147                        mayReconsiderHeight = false; // stop redeciding
148                    }
149                    else {
150                        time_t now;
151                        time(&now);
152
153                        double seconds         = difftime(now, start)+0.5;
154                        double overall_seconds = estimate_overall_seconds(seconds, gauge);
155
156                        int max_wanted_height = int(overall_seconds/MIN_SECONDS_PER_ROW+0.5);
157                        int min_wanted_height = int(overall_seconds/MAX_SECONDS_PER_ROW+0.5);
158
159                        arb_assert(min_wanted_height <= max_wanted_height);
160
161                        int old_height = height;
162
163                        height = force_in_range(min_wanted_height, DEFAULT_HEIGHT, max_wanted_height);
164                        height = force_in_range(1, height, MAXHEIGHT);
165
166                        if (old_height != height) {
167#if defined(TRACE_BASIC_COUNTER)
168                            fprintf(arbout, "redeciding height=%i printedAtHeightChange=%i printed=%i wanted=%i\n", height, printedAtHeightChange, printed, wanted);
169#endif
170                            printedAtHeightChange = std::max(printedAtHeightChange, printed);
171                            // now 'wanted' got wrong -> rerun this loop by recursion
172                            set_gauge(gauge);
173                            return;
174                        }
175                    }
176                }
177            }
178            fflush(arbout);
179#if defined(DEBUG)
180            // ARB_sleep(25, MS); // uncomment to see slow status
181#endif
182        }
183        else if (!mayReconsiderHeight && printed>printedAtHeightChange && wanted<printed) {
184            arb_assert(wanted>0);
185            int print_limit = (printed * 9) / 10;
186            if (wanted<print_limit) {
187                int print_again_from = (wanted * 8) / 10;
188                fprintf(arbout, "\n *** progress counter ran backwards *** (wanted=%i printed=%i print_limit=%i print_again_from=%i)\n", wanted, printed, print_limit, print_again_from);
189                printed              = print_again_from;
190
191                // rerun this loop by recursion:
192                set_gauge(gauge);
193                arb_assert(0); // progress went backwards. to find reason, uncomment TRACE_BASIC_COUNTER and run in debugger!
194                return;
195            }
196        }
197    }
198};
199
200static BasicStatus status;
201
202static void basic_openstatus(const char *title) { status.open(title); }
203static void basic_closestatus() { status.close(); }
204static void basic_set_title(const char */*title*/) { }
205static void basic_set_subtitle(const char *stitle) { status.set_subtitle(stitle); }
206static void basic_set_gauge(double gauge) {
207    arb_assert(gauge>=0);
208    status.set_gauge(gauge);
209}
210static bool basic_user_abort() { return false; }
211
212static arb_status_implementation ARB_arbout_status = {
213    AST_FORWARD,
214    basic_openstatus,   // openstatus
215    basic_closestatus,  // closestatus
216    basic_set_title,    // set_title
217    basic_set_subtitle, // set_subtitle
218    basic_set_gauge,    // set_gauge
219    basic_user_abort    // user_abort
220};
221
222static arb_handlers arbout_handlers = {
223    to_arberr,
224    to_arbout,
225    to_arbout,
226    ARB_arbout_status,
227};
228
229arb_handlers *active_arb_handlers = &arbout_handlers; // default-handlers
230
231void ARB_install_handlers(arb_handlers& handlers) { active_arb_handlers = &handlers; }
232
233void ARB_redirect_handlers_to(FILE *errStream, FILE *outStream) {
234    arberr = errStream;
235    arbout = outStream;
236}
Note: See TracBrowser for help on using the repository browser.