source: box/trunk/lib/common/Utils.cpp @ 3030

Revision 3030, 7.4 KB checked in by chris, 7 months ago (diff)

Avoid recompiling everything on MSVC when BoxVersion?.h changes.

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    Utils.cpp
5//              Purpose: Utility function
6//              Created: 2003/07/31
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <errno.h>
15
16#include <cstdlib>
17
18#ifdef SHOW_BACKTRACE_ON_EXCEPTION
19        #include <execinfo.h>
20        #include <stdlib.h>
21#endif
22
23#ifdef HAVE_CXXABI_H
24        #include <cxxabi.h>
25#endif
26
27#ifdef HAVE_DLFCN_H
28        #include <dlfcn.h>
29#endif
30
31#ifdef NEED_BOX_VERSION_H
32#       include "BoxVersion.h"
33#endif
34
35#include "CommonException.h"
36#include "Logging.h"
37#include "Utils.h"
38
39#include "MemLeakFindOn.h"
40
41std::string GetBoxBackupVersion()
42{
43        return BOX_VERSION;
44}
45
46// --------------------------------------------------------------------------
47//
48// Function
49//              Name:    SplitString(const std::string &, char, std::vector<std::string> &)
50//              Purpose: Splits a string at a given character
51//              Created: 2003/07/31
52//
53// --------------------------------------------------------------------------
54void SplitString(const std::string &String, char SplitOn, std::vector<std::string> &rOutput)
55{
56        // Split it up.
57        std::string::size_type b = 0;
58        std::string::size_type e = 0;
59        while(e = String.find_first_of(SplitOn, b), e != String.npos)
60        {
61                // Get this string
62                unsigned int len = e - b;
63                if(len >= 1)
64                {
65                        rOutput.push_back(String.substr(b, len));
66                }
67                b = e + 1;
68        }
69        // Last string
70        if(b < String.size())
71        {
72                rOutput.push_back(String.substr(b));
73        }
74/*#ifndef BOX_RELEASE_BUILD
75        BOX_TRACE("Splitting string '" << String << " on " << (char)SplitOn);
76        for(unsigned int l = 0; l < rOutput.size(); ++l)
77        {
78                BOX_TRACE(l << " = '" << rOutput[l] << "'");
79        }
80#endif*/
81}
82
83#ifdef SHOW_BACKTRACE_ON_EXCEPTION
84static std::string demangle(const std::string& mangled_name)
85{
86        #ifdef HAVE_CXXABI_H
87        int status;
88       
89#include "MemLeakFindOff.h"
90        char* result = abi::__cxa_demangle(mangled_name.c_str(),
91                NULL, NULL, &status);
92#include "MemLeakFindOn.h"
93
94        if (result == NULL)
95        {
96                if (status == 0)
97                {
98                        BOX_WARNING("Demangle failed but no error: " <<
99                                mangled_name);
100                }
101                else if (status == -1)
102                {
103                        BOX_WARNING("Demangle failed with "
104                                "memory allocation error: " <<
105                                mangled_name);
106                }
107                else if (status == -2)
108                {
109                        // Probably non-C++ name, don't demangle
110                        /*
111                        BOX_WARNING("Demangle failed with "
112                                "with invalid name: " <<
113                                mangled_name);
114                        */
115                }
116                else if (status == -3)
117                {
118                        BOX_WARNING("Demangle failed with "
119                                "with invalid argument: " <<
120                                mangled_name);
121                }
122                else
123                {
124                        BOX_WARNING("Demangle failed with "
125                                "with unknown error " << status <<
126                                ": " << mangled_name);
127                }
128
129                return std::string(mangled_name);
130        }
131        else
132        {
133                std::string output = result;
134#include "MemLeakFindOff.h"
135                std::free(result);
136#include "MemLeakFindOn.h"
137                return output;
138        }
139        #else // !HAVE_CXXABI_H
140        return mangled_name;
141        #endif // HAVE_CXXABI_H
142}
143
144void DumpStackBacktrace()
145{
146        void  *array[10];
147        size_t size = backtrace(array, 10);
148        BOX_TRACE("Obtained " << size << " stack frames.");
149
150        for(size_t i = 0; i < size; i++)
151        {
152                std::ostringstream output;
153                output << "Stack frame " << i << ": ";
154
155                #ifdef HAVE_DLADDR
156                        Dl_info info;
157                        int result = dladdr(array[i], &info);
158
159                        if(result == 0)
160                        {
161                                BOX_LOG_SYS_WARNING("Failed to resolve "
162                                        "backtrace address " << array[i]);
163                                output << "unresolved address " << array[i];
164                        }
165                        else if(info.dli_sname == NULL)
166                        {
167                                output << "unknown address " << array[i];
168                        }
169                        else
170                        {
171                                uint64_t diff = (uint64_t) array[i];
172                                diff -= (uint64_t) info.dli_saddr;
173                                output << demangle(info.dli_sname) << "+" <<
174                                        (void *)diff;
175                        }
176                #else
177                        output << "address " << array[i];
178                #endif // HAVE_DLADDR
179
180                BOX_TRACE(output.str());
181        }
182}
183#endif // SHOW_BACKTRACE_ON_EXCEPTION
184
185
186
187// --------------------------------------------------------------------------
188//
189// Function
190//              Name:    FileExists(const std::string& rFilename)
191//              Purpose: Does a file exist?
192//              Created: 20/11/03
193//
194// --------------------------------------------------------------------------
195bool FileExists(const std::string& rFilename, int64_t *pFileSize,
196        bool TreatLinksAsNotExisting)
197{
198        EMU_STRUCT_STAT st;
199        if(EMU_LSTAT(rFilename.c_str(), &st) != 0)
200        {
201                if(errno == ENOENT)
202                {
203                        return false;
204                }
205                else
206                {
207                        THROW_EXCEPTION(CommonException, OSFileError);
208                }
209        }
210
211        // is it a file?       
212        if((st.st_mode & S_IFDIR) == 0)
213        {
214                if(TreatLinksAsNotExisting && ((st.st_mode & S_IFLNK) != 0))
215                {
216                        return false;
217                }
218       
219                // Yes. Tell caller the size?
220                if(pFileSize != 0)
221                {
222                        *pFileSize = st.st_size;
223                }
224       
225                return true;
226        }
227        else
228        {
229                return false;
230        }
231}
232
233// --------------------------------------------------------------------------
234//
235// Function
236//              Name:    ObjectExists(const std::string& rFilename)
237//              Purpose: Does a object exist, and if so, is it a file or a directory?
238//              Created: 23/11/03
239//
240// --------------------------------------------------------------------------
241int ObjectExists(const std::string& rFilename)
242{
243        EMU_STRUCT_STAT st;
244        if(EMU_STAT(rFilename.c_str(), &st) != 0)
245        {
246                if(errno == ENOENT)
247                {
248                        return ObjectExists_NoObject;
249                }
250                else
251                {
252                        THROW_EXCEPTION(CommonException, OSFileError);
253                }
254        }
255
256        // is it a file or a dir?
257        return ((st.st_mode & S_IFDIR) == 0)?ObjectExists_File:ObjectExists_Dir;
258}
259
260std::string HumanReadableSize(int64_t Bytes)
261{
262        double readableValue = Bytes;
263        std::string units = " B";
264
265        if (readableValue > 1024)
266        {
267                readableValue /= 1024;
268                units = "kB";
269        }
270 
271        if (readableValue > 1024)
272        {
273                readableValue /= 1024;
274                units = "MB";
275        }
276 
277        if (readableValue > 1024)
278        {
279                readableValue /= 1024;
280                units = "GB";
281        }
282 
283        std::ostringstream result;
284        result << std::fixed << std::setprecision(2) << readableValue <<
285                " " << units;
286        return result.str();
287}
288
289std::string FormatUsageBar(int64_t Blocks, int64_t Bytes, int64_t Max,
290        bool MachineReadable)
291{
292        std::ostringstream result;
293       
294
295        if (MachineReadable)
296        {
297                result << (Bytes >> 10) << " kB, " <<
298                        std::setprecision(0) << ((Bytes*100)/Max) << "%";
299        }
300        else
301        {
302                // Bar graph
303                char bar[17];
304                unsigned int b = (int)((Bytes * (sizeof(bar)-1)) / Max);
305                if(b > sizeof(bar)-1) {b = sizeof(bar)-1;}
306                for(unsigned int l = 0; l < b; l++)
307                {
308                        bar[l] = '*';
309                }
310                for(unsigned int l = b; l < sizeof(bar) - 1; l++)
311                {
312                        bar[l] = ' ';
313                }
314                bar[sizeof(bar)-1] = '\0';
315               
316                result << std::fixed <<
317                        std::setw(10) << Blocks << " blocks, " <<
318                        std::setw(10) << HumanReadableSize(Bytes) << ", " << 
319                        std::setw(3) << std::setprecision(0) <<
320                        ((Bytes*100)/Max) << "% |" << bar << "|";
321        }
322       
323        return result.str();
324}
325
326std::string FormatUsageLineStart(const std::string& rName,
327        bool MachineReadable)
328{
329        std::ostringstream result;
330
331        if (MachineReadable)
332        {
333                result << rName << ": ";
334        }
335        else
336        {
337                result << std::setw(20) << std::right << rName << ": ";
338        }
339
340        return result.str();
341}
342
343std::string BoxGetTemporaryDirectoryName()
344{
345#ifdef WIN32
346        // http://msdn.microsoft.com/library/default.asp?
347        // url=/library/en-us/fileio/fs/creating_and_using_a_temporary_file.asp
348
349        DWORD dwRetVal;
350        char lpPathBuffer[1024];
351        DWORD dwBufSize = sizeof(lpPathBuffer);
352       
353        // Get the temp path.
354        dwRetVal = GetTempPath(dwBufSize,     // length of the buffer
355                                                   lpPathBuffer); // buffer for path
356        if (dwRetVal > dwBufSize)
357        {
358                THROW_EXCEPTION(CommonException, TempDirPathTooLong)
359        }
360       
361        return std::string(lpPathBuffer);
362#elif defined TEMP_DIRECTORY_NAME
363        return std::string(TEMP_DIRECTORY_NAME);
364#else   
365        #error non-static temporary directory names not supported yet
366#endif
367}
368
369
Note: See TracBrowser for help on using the repository browser.