Merge upstream.
[ntk/apt.git] / apt-pkg / contrib / progress.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: progress.cc,v 1.12 2003/01/11 07:17:04 jgg Exp $
4 /* ######################################################################
5
6 OpProgress - Operation Progress
7
8 ##################################################################### */
9 /*}}}*/
10 // Include Files /*{{{*/
11 #include <apt-pkg/progress.h>
12 #include <apt-pkg/error.h>
13 #include <apt-pkg/configuration.h>
14
15 #include <apti18n.h>
16
17 #include <iostream>
18 #include <stdio.h>
19 #include <cstring>
20 /*}}}*/
21
22 using namespace std;
23
24 // OpProgress::OpProgress - Constructor /*{{{*/
25 // ---------------------------------------------------------------------
26 /* */
27 OpProgress::OpProgress() : Current(0), Total(0), Size(0), SubTotal(1),
28 LastPercent(0), Percent(0)
29 {
30 memset(&LastTime,0,sizeof(LastTime));
31 }
32 /*}}}*/
33 // OpProgress::Progress - Sub progress with no state change /*{{{*/
34 // ---------------------------------------------------------------------
35 /* Current is the Base Overall progress in units of Total. Cur is the sub
36 progress in units of SubTotal. Size is a scaling factor that says what
37 percent of Total SubTotal is. */
38 void OpProgress::Progress(unsigned long Cur)
39 {
40 if (Total == 0 || Size == 0 || SubTotal == 0)
41 Percent = 0;
42 else
43 Percent = (Current + Cur/((float)SubTotal)*Size)*100.0/Total;
44 Update();
45 }
46 /*}}}*/
47 // OpProgress::OverallProgress - Set the overall progress /*{{{*/
48 // ---------------------------------------------------------------------
49 /* */
50 void OpProgress::OverallProgress(unsigned long Current, unsigned long Total,
51 unsigned long Size,const string &Op)
52 {
53 this->Current = Current;
54 this->Total = Total;
55 this->Size = Size;
56 this->Op = Op;
57 SubOp = string();
58 if (Total == 0)
59 Percent = 0;
60 else
61 Percent = Current*100.0/Total;
62 Update();
63 }
64 /*}}}*/
65 // OpProgress::SubProgress - Set the sub progress state /*{{{*/
66 // ---------------------------------------------------------------------
67 /* */
68 void OpProgress::SubProgress(unsigned long SubTotal,const string &Op)
69 {
70 this->SubTotal = SubTotal;
71 SubOp = Op;
72 if (Total == 0)
73 Percent = 0;
74 else
75 Percent = Current*100.0/Total;
76 Update();
77 }
78 /*}}}*/
79 // OpProgress::SubProgress - Set the sub progress state /*{{{*/
80 // ---------------------------------------------------------------------
81 /* */
82 void OpProgress::SubProgress(unsigned long SubTotal)
83 {
84 this->SubTotal = SubTotal;
85 if (Total == 0)
86 Percent = 0;
87 else
88 Percent = Current*100.0/Total;
89 Update();
90 }
91 /*}}}*/
92 // OpProgress::CheckChange - See if the display should be updated /*{{{*/
93 // ---------------------------------------------------------------------
94 /* Progress calls are made so frequently that if every one resulted in
95 an update the display would be swamped and the system much slower.
96 This provides an upper bound on the update rate. */
97 bool OpProgress::CheckChange(float Interval)
98 {
99 // New major progress indication
100 if (Op != LastOp)
101 {
102 MajorChange = true;
103 LastOp = Op;
104 return true;
105 }
106 MajorChange = false;
107
108 if (SubOp != LastSubOp)
109 {
110 LastSubOp = SubOp;
111 return true;
112 }
113
114 if ((int)LastPercent == (int)Percent)
115 return false;
116
117 LastPercent = Percent;
118
119 if (Interval == 0)
120 return false;
121
122 // Check time delta
123 struct timeval Now;
124 gettimeofday(&Now,0);
125 double Diff = Now.tv_sec - LastTime.tv_sec + (Now.tv_usec - LastTime.tv_usec)/1000000.0;
126 if (Diff < Interval)
127 return false;
128 LastTime = Now;
129 return true;
130 }
131 /*}}}*/
132 // OpTextProgress::OpTextProgress - Constructor /*{{{*/
133 // ---------------------------------------------------------------------
134 /* */
135 OpTextProgress::OpTextProgress(Configuration &Config) :
136 NoUpdate(false), NoDisplay(false), LastLen(0)
137 {
138 if (Config.FindI("quiet",0) >= 1)
139 NoUpdate = true;
140 if (Config.FindI("quiet",0) >= 2)
141 NoDisplay = true;
142 };
143 /*}}}*/
144 // OpTextProgress::Done - Clean up the display /*{{{*/
145 // ---------------------------------------------------------------------
146 /* */
147 void OpTextProgress::Done()
148 {
149 if (NoUpdate == false && OldOp.empty() == false)
150 {
151 char S[300];
152 if (_error->PendingError() == true)
153 snprintf(S,sizeof(S),_("%c%s... Error!"),'\r',OldOp.c_str());
154 else
155 snprintf(S,sizeof(S),_("%c%s... Done"),'\r',OldOp.c_str());
156 Write(S);
157 cout << endl;
158 OldOp = string();
159 }
160
161 if (NoUpdate == true && NoDisplay == false && OldOp.empty() == false)
162 {
163 OldOp = string();
164 cout << endl;
165 }
166 }
167 /*}}}*/
168 // OpTextProgress::Update - Simple text spinner /*{{{*/
169 // ---------------------------------------------------------------------
170 /* */
171 void OpTextProgress::Update()
172 {
173 if (CheckChange((NoUpdate == true?0:0.7)) == false)
174 return;
175
176 // No percent spinner
177 if (NoUpdate == true)
178 {
179 if (MajorChange == false)
180 return;
181 if (NoDisplay == false)
182 {
183 if (OldOp.empty() == false)
184 cout << endl;
185 OldOp = "a";
186 cout << Op << "..." << flush;
187 }
188
189 return;
190 }
191
192 // Erase the old text and 'log' the event
193 char S[300];
194 if (MajorChange == true && OldOp.empty() == false)
195 {
196 snprintf(S,sizeof(S),"\r%s",OldOp.c_str());
197 Write(S);
198 cout << endl;
199 }
200
201 // Print the spinner
202 snprintf(S,sizeof(S),"\r%s... %u%%",Op.c_str(),(unsigned int)Percent);
203 Write(S);
204
205 OldOp = Op;
206 }
207 /*}}}*/
208 // OpTextProgress::Write - Write the progress string /*{{{*/
209 // ---------------------------------------------------------------------
210 /* This space fills the end to overwrite the previous text */
211 void OpTextProgress::Write(const char *S)
212 {
213 cout << S;
214 for (unsigned int I = strlen(S); I < LastLen; I++)
215 cout << ' ';
216 cout << '\r' << flush;
217 LastLen = strlen(S);
218 }
219 /*}}}*/