- initial import of revision 374 from cnc
[apt.git] / apt-pkg / contrib / error.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: error.cc,v 1.2 2002/07/25 18:07:18 niemeyer Exp $
4 /* ######################################################################
5    
6    Global Erorr Class - Global error mechanism
7
8    We use a simple STL vector to store each error record. A PendingFlag
9    is kept which indicates when the vector contains a Sever error.
10    
11    This source is placed in the Public Domain, do with it what you will
12    It was originally written by Jason Gunthorpe.
13    
14    ##################################################################### */
15                                                                         /*}}}*/
16 // Include Files                                                        /*{{{*/
17 #ifdef __GNUG__
18 #pragma implementation "apt-pkg/error.h"
19 #endif 
20
21 #include <apt-pkg/error.h>
22
23 #include <iostream>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <string>
27 #include <stdarg.h>
28 #include <unistd.h>
29
30 #include "config.h"
31                                                                         /*}}}*/
32
33 using namespace std;
34
35 // Global Error Object                                                  /*{{{*/
36 /* If the implementation supports posix threads then the accessor function
37    is compiled to be thread safe otherwise a non-safe version is used. A
38    Per-Thread error object is maintained in much the same manner as libc
39    manages errno */
40 #if defined(_POSIX_THREADS) && defined(HAVE_PTHREAD)
41  #include <pthread.h>
42
43  static pthread_key_t ErrorKey;
44  static void ErrorDestroy(void *Obj) {delete (GlobalError *)Obj;};
45  static void KeyAlloc() {pthread_key_create(&ErrorKey,ErrorDestroy);};
46
47  GlobalError *_GetErrorObj()
48  {
49     static pthread_once_t Once = PTHREAD_ONCE_INIT;
50     pthread_once(&Once,KeyAlloc);
51     
52     void *Res = pthread_getspecific(ErrorKey);
53     if (Res == 0)
54        pthread_setspecific(ErrorKey,Res = new GlobalError);
55     return (GlobalError *)Res;
56  }
57 #else
58  GlobalError *_GetErrorObj()
59  {
60     static GlobalError *Obj = new GlobalError;
61     return Obj;
62  }
63 #endif
64                                                                         /*}}}*/
65
66 // GlobalError::GlobalError - Constructor                               /*{{{*/
67 // ---------------------------------------------------------------------
68 /* */
69 // CNC:2003-02-26
70 GlobalError::GlobalError() : List(0), PendingFlag(false), Stack(0)
71 {
72 }
73                                                                         /*}}}*/
74 // GlobalError::Errno - Get part of the error string from errno         /*{{{*/
75 // ---------------------------------------------------------------------
76 /* Function indicates the stdlib function that failed and Description is
77    a user string that leads the text. Form is:
78      Description - Function (errno: strerror)
79    Carefull of the buffer overrun, sprintf.
80  */
81 bool GlobalError::Errno(const char *Function,const char *Description,...)
82 {
83    va_list args;
84    va_start(args,Description);
85
86    // sprintf the description
87    char S[400];
88    vsnprintf(S,sizeof(S),Description,args);
89    snprintf(S + strlen(S),sizeof(S) - strlen(S),
90             " - %s (%i %s)",Function,errno,strerror(errno));
91
92    // Put it on the list
93    Item *Itm = new Item;
94    Itm->Text = S;
95    Itm->Error = true;
96    Insert(Itm);
97    
98    PendingFlag = true;
99
100    return false;   
101 }
102                                                                         /*}}}*/
103 // GlobalError::WarningE - Get part of the warn string from errno       /*{{{*/
104 // ---------------------------------------------------------------------
105 /* Function indicates the stdlib function that failed and Description is
106    a user string that leads the text. Form is:
107      Description - Function (errno: strerror)
108    Carefull of the buffer overrun, sprintf.
109  */
110 bool GlobalError::WarningE(const char *Function,const char *Description,...)
111 {
112    va_list args;
113    va_start(args,Description);
114
115    // sprintf the description
116    char S[400];
117    vsnprintf(S,sizeof(S),Description,args);
118    snprintf(S + strlen(S),sizeof(S) - strlen(S)," - %s (%i %s)",Function,errno,strerror(errno));
119
120    // Put it on the list
121    Item *Itm = new Item;
122    Itm->Text = S;
123    Itm->Error = false;
124    Insert(Itm);
125    
126    return false;   
127 }
128                                                                         /*}}}*/
129 // GlobalError::Error - Add an error to the list                        /*{{{*/
130 // ---------------------------------------------------------------------
131 /* Just vsprintfs and pushes */
132 bool GlobalError::Error(const char *Description,...)
133 {
134    va_list args;
135    va_start(args,Description);
136
137    // sprintf the description
138    char S[400];
139    vsnprintf(S,sizeof(S),Description,args);
140
141    // Put it on the list
142    Item *Itm = new Item;
143    Itm->Text = S;
144    Itm->Error = true;
145    Insert(Itm);
146    
147    PendingFlag = true;
148    
149    return false;
150 }
151                                                                         /*}}}*/
152 // GlobalError::Warning - Add a warning to the list                     /*{{{*/
153 // ---------------------------------------------------------------------
154 /* This doesn't set the pending error flag */
155 bool GlobalError::Warning(const char *Description,...)
156 {
157    va_list args;
158    va_start(args,Description);
159
160    // sprintf the description
161    char S[400];
162    vsnprintf(S,sizeof(S),Description,args);
163
164    // Put it on the list
165    Item *Itm = new Item;
166    Itm->Text = S;
167    Itm->Error = false;
168    Insert(Itm);
169    
170    return false;
171 }
172                                                                         /*}}}*/
173 // GlobalError::PopMessage - Pulls a single message out                 /*{{{*/
174 // ---------------------------------------------------------------------
175 /* This should be used in a loop checking empty() each cycle. It returns
176    true if the message is an error. */
177 bool GlobalError::PopMessage(string &Text)
178 {
179    if (List == 0)
180       return false;
181       
182    bool Ret = List->Error;
183    Text = List->Text;
184    Item *Old = List;
185    List = List->Next;
186    delete Old;
187    
188    // This really should check the list to see if only warnings are left..
189    if (List == 0)
190       PendingFlag = false;
191    
192    return Ret;
193 }
194                                                                         /*}}}*/
195 // GlobalError::DumpErrors - Dump all of the errors/warns to cerr       /*{{{*/
196 // ---------------------------------------------------------------------
197 /* */
198 void GlobalError::DumpErrors()
199 {
200    // Print any errors or warnings found
201    string Err;
202    while (empty() == false)
203    {
204       bool Type = PopMessage(Err);
205       if (Type == true)
206          cerr << "E: " << Err << endl;
207       else
208          cerr << "W: " << Err << endl;
209    }
210 }
211                                                                         /*}}}*/
212 // GlobalError::Discard - Discard                                                                       /*{{{*/
213 // ---------------------------------------------------------------------
214 /* */
215 void GlobalError::Discard()
216 {
217    while (List != 0)
218    {
219       Item *Old = List;
220       List = List->Next;
221       delete Old;
222    }
223    
224    PendingFlag = false;
225 };
226                                                                         /*}}}*/
227 // GlobalError::Insert - Insert a new item at the end                   /*{{{*/
228 // ---------------------------------------------------------------------
229 /* */
230 void GlobalError::Insert(Item *Itm)
231 {
232    Item **End = &List;
233    for (Item *I = List; I != 0; I = I->Next)
234       End = &I->Next;
235    Itm->Next = *End;
236    *End = Itm;
237 }
238                                                                         /*}}}*/
239
240 // CNC:2003-02-24
241 // GlobalError::*State() - Functions allowing a given error state to be /*}}}*/
242 //                         saved and restored later on.
243 // ---------------------------------------------------------------------
244 /* */
245 void GlobalError::PushState()
246 {
247    State *New = new State;
248    New->List = List;
249    New->Next = Stack;
250    New->PendingFlag = PendingFlag;
251    Stack = New;
252    List = 0;
253    PendingFlag = false;
254 }
255
256 bool GlobalError::PopState()
257 {
258    if (Stack == 0)
259       return false;
260    State *Top = Stack;
261    Item **End = &Top->List;
262    for (Item *I = Top->List; I != 0; I = I->Next)
263       End = &I->Next;
264    *End = List;
265    List = Top->List;
266    PendingFlag |= Top->PendingFlag;
267    Stack = Top->Next;
268    delete Top;
269    return true;
270 }
271
272 bool GlobalError::PopBackState()
273 {
274    if (Stack == 0)
275       return false;
276    State *Bottom = Stack;
277    State *PreBottom = 0;
278    while (Bottom->Next != 0) {
279       PreBottom = Bottom;
280       Bottom = Bottom->Next;
281    }
282    Item **End = &Bottom->List;
283    for (Item *I = Bottom->List; I != 0; I = I->Next)
284       End = &I->Next;
285    *End = List;
286    List = Bottom->List;
287    PendingFlag |= Bottom->PendingFlag;
288    delete Bottom;
289    if (PreBottom != 0)
290       PreBottom->Next = 0;
291    else
292       Stack = 0;
293    return true;
294 }
295                                                                         /*}}}*/
296
297 // vim:sts=3:sw=3