Bug 1884032 [wpt PR 44942] - [css-color] add missing colorscheme-aware tests, a=testonly
[gecko.git] / memory / build / FdPrintf.cpp
blob272f3d0db881c6246357cca8494e5fa09f7fc010
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include <cstdarg>
9 #ifdef _WIN32
10 # include <windows.h>
11 #else
12 # include <unistd.h>
13 #endif
14 #include <cmath>
15 #include <cstring>
16 #include "mozilla/Assertions.h"
17 #include "mozilla/Unused.h"
18 #include "FdPrintf.h"
20 /* Template class allowing a limited number of increments on a value */
21 template <typename T>
22 class CheckedIncrement {
23 public:
24 CheckedIncrement(T aValue, size_t aMaxIncrement)
25 : mValue(aValue), mMaxIncrement(aMaxIncrement) {}
27 T operator++(int) {
28 if (!mMaxIncrement) {
29 MOZ_CRASH("overflow detected");
31 mMaxIncrement--;
32 return mValue++;
35 T& operator++() {
36 (*this)++;
37 return mValue;
40 void advance(T end) {
41 // Only makes sense if T is a pointer type.
42 size_t diff = end - mValue;
43 if (diff > mMaxIncrement) {
44 MOZ_CRASH("overflow detected");
46 mMaxIncrement -= diff;
47 mValue = end;
50 void rewind(T pos) {
51 size_t diff = mValue - pos;
52 mMaxIncrement += diff;
53 mValue = pos;
56 operator T() { return mValue; }
57 T value() { return mValue; }
59 private:
60 T mValue;
61 size_t mMaxIncrement;
64 template <typename T>
65 static unsigned NumDigits(T n) {
66 if (n < 1) {
67 // We want one digit, it will be 0.
68 return 1;
71 double l = log10(static_cast<double>(n));
72 double cl = ceil(l);
73 return l == cl ? unsigned(cl) + 1 : unsigned(cl);
76 static void LeftPad(CheckedIncrement<char*>& b, size_t pad) {
77 while (pad-- > 0) {
78 *(b++) = ' ';
82 // Write the digits into the buffer.
83 static void WriteDigits(CheckedIncrement<char*>& b, size_t i,
84 size_t num_digits) {
85 size_t x = pow(10, double(num_digits - 1));
86 do {
87 *(b++) = "0123456789"[(i / x) % 10];
88 x /= 10;
89 } while (x > 0);
92 void FdPrintf(intptr_t aFd, const char* aFormat, ...) {
93 if (aFd == 0) {
94 return;
96 char buf[256];
97 CheckedIncrement<char*> b(buf, sizeof(buf));
98 CheckedIncrement<const char*> f(aFormat, strlen(aFormat) + 1);
99 va_list ap;
100 va_start(ap, aFormat);
101 while (true) {
102 switch (*f) {
103 case '\0':
104 goto out;
106 case '%': {
107 // The start of the format specifier is used if this specifier is
108 // invalid.
109 const char* start = f;
111 // Read the field width
112 f++;
113 char* end = nullptr;
114 size_t width = strtoul(f, &end, 10);
115 // If strtol can't find a number that's okay, that means 0 in our
116 // case, but we must advance f).
117 f.advance(end);
119 switch (*f) {
120 case 'z': {
121 if (*(++f) == 'u') {
122 size_t i = va_arg(ap, size_t);
124 size_t num_digits = NumDigits(i);
125 LeftPad(b, width > num_digits ? width - num_digits : 0);
126 WriteDigits(b, i, num_digits);
127 } else {
128 // If the format specifier is unknown then write out '%' and
129 // rewind to the beginning of the specifier causing it to be
130 // printed normally.
131 *(b++) = '%';
132 f.rewind(start);
134 break;
137 case 'p': {
138 intptr_t ptr = va_arg(ap, intptr_t);
139 *(b++) = '0';
140 *(b++) = 'x';
141 int x = sizeof(intptr_t) * 8;
142 bool wrote_msb = false;
143 do {
144 x -= 4;
145 size_t hex_digit = ptr >> x & 0xf;
146 if (hex_digit || wrote_msb) {
147 *(b++) = "0123456789abcdef"[hex_digit];
148 wrote_msb = true;
150 } while (x > 0);
151 if (!wrote_msb) {
152 *(b++) = '0';
154 break;
157 case 's': {
158 const char* str = va_arg(ap, const char*);
159 size_t len = strlen(str);
161 LeftPad(b, width > len ? width - len : 0);
163 while (*str) {
164 *(b++) = *(str++);
167 break;
170 case '%':
171 // Print a single raw '%'.
172 *(b++) = '%';
173 break;
175 default:
176 // If the format specifier is unknown then write out '%' and
177 // rewind to the beginning of the specifier causing it to be
178 // printed normally.
179 *(b++) = '%';
180 f.rewind(start);
181 break;
183 break;
185 default:
186 *(b++) = *f;
187 break;
189 f++;
191 out:
192 #ifdef _WIN32
193 // See comment in FdPrintf.h as to why WriteFile is used.
194 DWORD written;
195 WriteFile(reinterpret_cast<HANDLE>(aFd), buf, b - buf, &written, nullptr);
196 #else
197 MOZ_UNUSED(write(aFd, buf, b - buf));
198 #endif
199 va_end(ap);