2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/util/hdf.h"
21 #include <folly/portability/String.h>
23 #include <boost/algorithm/string/predicate.hpp>
26 ///////////////////////////////////////////////////////////////////////////////
29 * Helper class storing HDF raw pointer and reference counts on it.
32 static std::mutex HdfMutex
;
34 HdfRaw() : m_hdf(nullptr), m_count(1) {
35 // ClearSilver is not thread-safe when calling hdf_init(), so guarding it.
36 std::lock_guard
<std::mutex
> lock(HdfMutex
);
37 Hdf::CheckNeoError(hdf_init(&m_hdf
));
49 void inc() { m_count
++;}
50 void dec() { assert(m_count
> 0); if (--m_count
== 0) { delete this;}}
53 std::mutex
HdfRaw::HdfMutex
;
55 ///////////////////////////////////////////////////////////////////////////////
58 Hdf::Hdf() : m_hdf(nullptr), m_dump(nullptr) {
59 m_rawp
= new HdfRaw();
62 Hdf::Hdf(const char *filename
) : m_hdf(nullptr), m_dump(nullptr) {
63 m_rawp
= new HdfRaw();
67 Hdf::Hdf(const std::string
&filename
) : m_hdf(nullptr), m_dump(nullptr) {
68 m_rawp
= new HdfRaw();
69 append(filename
.c_str());
72 Hdf::Hdf(const Hdf
*hdf
, const char *name
) : m_hdf(nullptr), m_dump(nullptr) {
74 assert(name
&& *name
);
78 m_path
= hdf
->getFullPath();
82 hdf_get_node(hdf
->m_hdf
, (char*)name
, &m_hdf
);
86 Hdf::Hdf(const Hdf
&hdf
)
87 : m_hdf(hdf
.m_hdf
), m_rawp(hdf
.m_rawp
), m_path(hdf
.m_path
),
88 m_name(hdf
.m_name
), m_dump(nullptr) {
95 : m_hdf(hdf
), m_rawp(nullptr), m_dump(nullptr) {
107 bool Hdf::isEmpty() const {
108 return this->getFullPath() == "" &&
109 this->getName() == "";
112 void Hdf::assign(const Hdf
&hdf
) {
129 void Hdf::copy(const Hdf
&hdf
) {
130 CheckNeoError(hdf_copy(getRaw(), nullptr, hdf
.getRaw()));
133 void Hdf::open(const char *filename
) {
138 void Hdf::append(const char *filename
) {
139 assert(filename
&& *filename
);
140 if (!(boost::contains(filename
, ".hdf")
141 || boost::ends_with(filename
, ".hphp"))) {
144 CheckNeoError(hdf_read_file(getRaw(), (char*)filename
));
151 m_rawp
= new HdfRaw();
161 static bool match(const std::string
&name
, const std::string
&pattern
) {
162 assert(!name
.empty() && !pattern
.empty());
164 unsigned int len
= pattern
.size();
165 char first
= pattern
[0];
166 char last
= pattern
[len
- 1];
169 return name
.find(pattern
.substr(1, len
- 2)) != std::string::npos
;
171 return name
.size() >= len
- 1 &&
172 name
.substr(name
.size() - len
+ 1) == pattern
.substr(1);
175 return strncmp(name
.c_str(), pattern
.c_str(), len
- 1) == 0;
177 return name
== pattern
;
180 bool Hdf::lintImpl(std::vector
<std::string
> &names
,
181 const std::vector
<std::string
> &excludes
, bool visited
) {
182 unsigned int size
= names
.size();
184 bool childVisited
= false;
185 for (Hdf hdf
= firstChild(false); hdf
.exists(); hdf
= hdf
.next(false)) {
186 if (hdf
.lintImpl(names
, excludes
, visited
)) {
190 bool meVisited
= childVisited
|| hdf_is_visited(getRaw());
192 std::string fullname
= getFullPath();
193 if (!fullname
.empty()) {
194 if (meVisited
== visited
) {
195 bool excluded
= false;
196 for (unsigned int i
= 0; i
< excludes
.size(); i
++) {
197 if (match(fullname
, excludes
[i
])) {
204 names
.resize(size
); // so reports about my children are gone
206 names
.push_back(fullname
);
214 void Hdf::lint(std::vector
<std::string
> &names
,
215 const char *excludePatternNode
/* = "LintExcludePatterns" */,
216 bool visited
/* = false */) {
217 std::vector
<std::string
> patterns
;
218 if (excludePatternNode
&& *excludePatternNode
) {
219 for (Hdf hdf
= operator[](excludePatternNode
).firstChild();
220 hdf
.exists(); hdf
= hdf
.next()) {
221 std::string value
= hdf
.configGetString();
222 if (!value
.empty()) {
223 patterns
.push_back(value
);
228 lintImpl(names
, patterns
, visited
);
231 void Hdf::setVisited(bool visited
/* = true */) {
232 hdf_set_visited(getRaw(), visited
? 1 : 0);
233 for (Hdf hdf
= firstChild(false); hdf
.exists(); hdf
= hdf
.next(false)) {
234 hdf
.setVisited(visited
);
238 ///////////////////////////////////////////////////////////////////////////////
241 const char *Hdf::configGet(const char *defValue
/* = NULL */) const {
243 const char *v
= hdf_obj_value(hdf
);
244 hdf_set_visited(hdf
, 1);
245 return v
? v
: defValue
;
248 std::string
Hdf::configGetString(const std::string
&defValue
/* = "" */) const {
249 const char *v
= configGet();
250 if (v
== nullptr) return defValue
;
254 bool Hdf::configGetBool(bool defValue
/* = false */) const {
255 const char *v
= configGet();
256 if (v
== nullptr) return defValue
;
257 return convertRawConfigToBool(v
);
260 int64_t Hdf::getInt(int64_t defValue
, const char *type
, int64_t maxValue
) const {
261 const char *v
= configGet();
262 if (v
== nullptr) return defValue
;
264 char *endptr
= nullptr;
265 int64_t n
= strtoll(v
, &endptr
, 0);
266 if ((!endptr
&& !*endptr
) ||
267 (maxValue
&& (n
> maxValue
|| n
< (- maxValue
- 1)))) {
268 throw HdfDataTypeException(this, type
, v
);
274 char Hdf::configGetByte(char defValue
/* = 0 */) const {
275 return getInt(defValue
, "byte", 0x7FL
);
278 int16_t Hdf::configGetInt16(int16_t defValue
/* = 0 */) const {
279 return getInt(defValue
, "int16", 0x7FFFL
);
282 int32_t Hdf::configGetInt32(int32_t defValue
/* = 0 */) const {
283 return getInt(defValue
, "int32", 0x7FFFFFFFL
);
286 int64_t Hdf::configGetInt64(int64_t defValue
/* = 0 */) const {
287 return getInt(defValue
, "int64", 0);
290 uint64_t Hdf::getUInt(uint64_t defValue
, const char *type
, uint64_t mask
) const {
291 const char *v
= configGet();
292 if (v
== nullptr) return defValue
;
294 char *endptr
= nullptr;
295 int64_t n
= strtoull(v
, &endptr
, 0);
296 if ((!endptr
&& !*endptr
) || (mask
&& ((uint64_t)n
& mask
))) {
297 throw HdfDataTypeException(this, type
, v
);
303 unsigned char Hdf::configGetUByte(unsigned char defValue
/* = 0 */) const {
304 return getUInt(defValue
, "unsigned byte", ~0xFFUL
);
307 uint16_t Hdf::configGetUInt16(uint16_t defValue
/* = 0 */) const {
308 return getUInt(defValue
, "unsigned int16", ~0xFFFFUL
);
311 uint32_t Hdf::configGetUInt32(uint32_t defValue
/* = 0 */) const {
312 return getUInt(defValue
, "unsigned int32", ~0xFFFFFFFFUL
);
315 uint64_t Hdf::configGetUInt64(uint64_t defValue
/* = 0 */) const {
316 return getUInt(defValue
, "unsigned int64", 0);
319 double Hdf::configGetDouble(double defValue
/* = 0 */) const {
320 const char *v
= configGet();
321 if (v
== nullptr) return defValue
;
323 char *endptr
= nullptr;
324 double n
= strtod(v
, &endptr
);
325 if (!endptr
&& !*endptr
) {
326 throw HdfDataTypeException(this, "double", v
);
332 void Hdf::configGet(std::vector
<std::string
> &values
) const {
334 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
335 values
.push_back(hdf
.configGetString(""));
339 void Hdf::configGet(std::set
<std::string
> &values
) const {
341 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
342 values
.insert(hdf
.configGetString(""));
346 void Hdf::configGet(boost::container::flat_set
<std::string
> &values
) const {
348 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
349 values
.insert(hdf
.configGetString(""));
353 void Hdf::configGet(std::set
<std::string
, stdltistr
> &values
) const {
355 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
356 values
.insert(hdf
.configGetString(""));
360 void Hdf::configGet(std::map
<std::string
, std::string
> &values
) const {
362 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
363 values
[hdf
.getName()] = hdf
.configGetString("");
367 void Hdf::configGet(std::map
<std::string
, std::string
,
368 stdltistr
> &values
) const {
370 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
371 values
[hdf
.getName()] = hdf
.configGetString("");
375 void Hdf::configGet(hphp_string_imap
<std::string
> &values
) const {
377 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
378 values
[hdf
.getName()] = hdf
.configGetString("");
382 bool Hdf::convertRawConfigToBool(const char *v
) {
383 return *v
&& strcmp(v
, "0") &&
384 strcasecmp(v
, "false") && strcasecmp(v
, "no") && strcasecmp(v
, "off");
387 int Hdf::compare(const char *v2
) const {
388 const char *v1
= configGet();
389 if (v1
== nullptr && v2
== nullptr) return 0;
390 if (v1
== nullptr) return -1;
391 if (v2
== nullptr) return 1;
392 return strcmp(v1
, v2
);
395 int Hdf::compare(const std::string
&v2
) const {
396 std::string v1
= configGetString();
397 return strcmp(v1
.c_str(), v2
.c_str());
400 int Hdf::compare(char v2
) const {
401 char v1
= configGetByte();
402 if (v1
== v2
) return 0;
403 return v1
> v2
? 1 : -1;
406 int Hdf::compare(unsigned char v2
) const {
407 unsigned char v1
= configGetUByte();
408 if (v1
== v2
) return 0;
409 return v1
> v2
? 1 : -1;
412 int Hdf::compare(int16_t v2
) const {
413 int16_t v1
= configGetInt16();
414 if (v1
== v2
) return 0;
415 return v1
> v2
? 1 : -1;
418 int Hdf::compare(uint16_t v2
) const {
419 uint16_t v1
= configGetUInt16();
420 if (v1
== v2
) return 0;
421 return v1
> v2
? 1 : -1;
424 int Hdf::compare(int32_t v2
) const {
425 int32_t v1
= configGetInt32();
426 if (v1
== v2
) return 0;
427 return v1
> v2
? 1 : -1;
430 int Hdf::compare(uint32_t v2
) const {
431 uint32_t v1
= configGetUInt32();
432 if (v1
== v2
) return 0;
433 return v1
> v2
? 1 : -1;
436 int Hdf::compare(int64_t v2
) const {
437 int64_t v1
= configGetInt64();
438 if (v1
== v2
) return 0;
439 return v1
> v2
? 1 : -1;
442 int Hdf::compare(uint64_t v2
) const {
443 uint64_t v1
= configGetUInt64();
444 if (v1
== v2
) return 0;
445 return v1
> v2
? 1 : -1;
448 int Hdf::compare(double v2
) const {
449 double v1
= configGetDouble();
450 if (v1
== v2
) return 0;
451 return v1
> v2
? 1 : -1;
454 ///////////////////////////////////////////////////////////////////////////////
457 Hdf
&Hdf::operator=(const Hdf
&hdf
) {
459 if (m_rawp
!= hdf
.m_rawp
) {
481 void Hdf::set(const char *value
) {
482 CheckNeoError(hdf_set_value(getRaw(), nullptr, (char*)value
));
485 void Hdf::set(int64_t value
) {
487 snprintf(buf
, sizeof(buf
), "%lld", (long long)value
);
491 void Hdf::set(uint64_t value
) {
493 snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)value
);
497 void Hdf::set(double value
) {
499 snprintf(buf
, sizeof(buf
), "%g", value
);
503 ///////////////////////////////////////////////////////////////////////////////
506 std::string
Hdf::getName(bool markVisited
/* = true */) const {
508 char *name
= hdf_obj_name(hdf
);
509 if (markVisited
) hdf_set_visited(hdf
, 1);
510 return name
? name
: "";
513 std::string
Hdf::getFullPath() const {
514 std::string fullpath
;
515 if (m_path
.empty()) {
519 if (!m_name
.empty()) {
527 Hdf
Hdf::parentImpl() const {
529 if (m_name
.empty()) {
530 if (m_path
.empty()) {
531 throw HdfInvalidOperation("calling parent() on topmost node");
533 size_t pos
= m_path
.rfind('.');
534 if (pos
== std::string::npos
) {
538 hdf
.m_name
= m_path
.substr(pos
+ 1);
539 hdf
.m_path
= m_path
.substr(0, pos
);
547 const Hdf
Hdf::parent() const {
555 const Hdf
Hdf::operator[](int name
) const {
557 sprintf(buf
, "%d", name
);
558 return operator[](buf
);
561 const Hdf
Hdf::operator[](const char *name
) const {
562 return Hdf(this, name
);
565 const Hdf
Hdf::operator[](const std::string
&name
) const {
566 return operator[](name
.c_str());
569 Hdf
Hdf::operator[](int name
) {
571 sprintf(buf
, "%d", name
);
572 return operator[](buf
);
575 Hdf
Hdf::operator[](const char *name
) {
576 return Hdf(this, name
);
579 Hdf
Hdf::operator[](const std::string
&name
) {
580 return operator[](name
.c_str());
583 bool Hdf::exists() const {
584 if (m_rawp
== nullptr) {
585 return m_hdf
!= nullptr;
588 std::string fullpath
= getFullPath();
589 if (fullpath
.empty()) {
592 return hdf_get_obj(m_rawp
->m_hdf
, fullpath
.c_str());
595 bool Hdf::exists(int name
) const {
597 sprintf(buf
, "%d", name
);
601 bool Hdf::exists(const char *name
) const {
604 std::string fullpath
= getFullPath();
606 if (!fullpath
.empty()) {
607 hdf
= hdf_get_obj(hdf
, fullpath
.c_str());
610 return hdf
&& hdf_get_obj(hdf
, name
);
613 bool Hdf::exists(const std::string
&name
) const {
614 return exists(name
.c_str());
617 void Hdf::remove(int name
) const {
619 sprintf(buf
, "%d", name
);
623 void Hdf::remove(const char *name
) const {
624 assert(name
&& *name
);
625 CheckNeoError(hdf_remove_tree(getRaw(), name
));
628 void Hdf::remove(const std::string
&name
) const {
629 remove(name
.c_str());
632 ///////////////////////////////////////////////////////////////////////////////
635 Hdf
Hdf::firstChild(bool markVisited
/* = true */) const {
637 if (markVisited
) hdf_set_visited(hdf
, 1);
638 Hdf
ret(hdf_obj_child(hdf
));
639 ret
.m_path
= getFullPath();
640 ret
.m_name
= ret
.getName(markVisited
);
644 Hdf
Hdf::next(bool markVisited
/* = true */) const {
646 if (markVisited
) hdf_set_visited(hdf
, 1);
647 Hdf
ret(hdf_obj_next(hdf
));
649 ret
.m_name
= ret
.getName(markVisited
);
653 ///////////////////////////////////////////////////////////////////////////////
656 void Hdf::fromString(const char *input
) {
657 CheckNeoError(hdf_read_string(getRaw(), (char*)input
));
660 const char *Hdf::toString() const {
665 CheckNeoError(hdf_write_string(getRaw(), &m_dump
));
669 void Hdf::write(const char *filename
) const {
670 CheckNeoError(hdf_write_file(getRaw(), filename
));
673 ///////////////////////////////////////////////////////////////////////////////
676 HDF
*Hdf::getRaw() const {
677 if (m_hdf
) return m_hdf
;
679 if (m_rawp
== nullptr) {
684 std::string fullpath
= getFullPath();
685 if (fullpath
.empty()) {
688 hdf_get_node(m_rawp
->m_hdf
, (char*)fullpath
.c_str(), &ret
);
694 void Hdf::CheckNeoError(NEOERR
*err
) {
695 if (err
!= STATUS_OK
) {
698 nerr_error_string(err
, &str
);
699 throw HdfException("%s", str
.buf
);
703 ///////////////////////////////////////////////////////////////////////////////
706 HdfException::HdfException(const char *fmt
, ...) {
707 va_list ap
; va_start(ap
, fmt
); format(fmt
, ap
); va_end(ap
);
710 ///////////////////////////////////////////////////////////////////////////////