1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "android-base/stringprintf.h"
18 
19 #include <stdio.h>
20 
21 #include <string>
22 
23 namespace android {
24 namespace base {
25 
StringAppendV(std::string * dst,const char * format,va_list ap)26 void StringAppendV(std::string* dst, const char* format, va_list ap) {
27   // First try with a small fixed size buffer
28   char space[1024];
29 
30   // It's possible for methods that use a va_list to invalidate
31   // the data in it upon use.  The fix is to make a copy
32   // of the structure before using it and use that copy instead.
33   va_list backup_ap;
34   va_copy(backup_ap, ap);
35   int result = vsnprintf(space, sizeof(space), format, backup_ap);
36   va_end(backup_ap);
37 
38   if (result < static_cast<int>(sizeof(space))) {
39     if (result >= 0) {
40       // Normal case -- everything fit.
41       dst->append(space, result);
42       return;
43     }
44 
45     if (result < 0) {
46       // Just an error.
47       return;
48     }
49   }
50 
51   // Increase the buffer size to the size requested by vsnprintf,
52   // plus one for the closing \0.
53   int length = result + 1;
54   char* buf = new char[length];
55 
56   // Restore the va_list before we use it again
57   va_copy(backup_ap, ap);
58   result = vsnprintf(buf, length, format, backup_ap);
59   va_end(backup_ap);
60 
61   if (result >= 0 && result < length) {
62     // It fit
63     dst->append(buf, result);
64   }
65   delete[] buf;
66 }
67 
StringPrintf(const char * fmt,...)68 std::string StringPrintf(const char* fmt, ...) {
69   va_list ap;
70   va_start(ap, fmt);
71   std::string result;
72   StringAppendV(&result, fmt, ap);
73   va_end(ap);
74   return result;
75 }
76 
StringAppendF(std::string * dst,const char * format,...)77 void StringAppendF(std::string* dst, const char* format, ...) {
78   va_list ap;
79   va_start(ap, format);
80   StringAppendV(dst, format, ap);
81   va_end(ap);
82 }
83 
84 }  // namespace base
85 }  // namespace android
86