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 auto err
= STATUS_OK
;
244 const char *v
= hdf_obj_value(hdf
, &err
);
246 hdf_set_visited(hdf
, 1);
247 return v
? v
: defValue
;
250 std::string
Hdf::configGetString(const std::string
&defValue
/* = "" */) const {
251 const char *v
= configGet();
252 if (v
== nullptr) return defValue
;
256 bool Hdf::configGetBool(bool defValue
/* = false */) const {
257 const char *v
= configGet();
258 if (v
== nullptr) return defValue
;
259 return convertRawConfigToBool(v
);
262 int64_t Hdf::getInt(int64_t defValue
, const char *type
, int64_t maxValue
) const {
263 const char *v
= configGet();
264 if (v
== nullptr) return defValue
;
266 char *endptr
= nullptr;
267 int64_t n
= strtoll(v
, &endptr
, 0);
268 if ((!endptr
&& !*endptr
) ||
269 (maxValue
&& (n
> maxValue
|| n
< (- maxValue
- 1)))) {
270 throw HdfDataTypeException(this, type
, v
);
276 char Hdf::configGetByte(char defValue
/* = 0 */) const {
277 return getInt(defValue
, "byte", 0x7FL
);
280 int16_t Hdf::configGetInt16(int16_t defValue
/* = 0 */) const {
281 return getInt(defValue
, "int16", 0x7FFFL
);
284 int32_t Hdf::configGetInt32(int32_t defValue
/* = 0 */) const {
285 return getInt(defValue
, "int32", 0x7FFFFFFFL
);
288 int64_t Hdf::configGetInt64(int64_t defValue
/* = 0 */) const {
289 return getInt(defValue
, "int64", 0);
292 uint64_t Hdf::getUInt(uint64_t defValue
, const char *type
, uint64_t mask
) const {
293 const char *v
= configGet();
294 if (v
== nullptr) return defValue
;
296 char *endptr
= nullptr;
297 int64_t n
= strtoull(v
, &endptr
, 0);
298 if ((!endptr
&& !*endptr
) || (mask
&& ((uint64_t)n
& mask
))) {
299 throw HdfDataTypeException(this, type
, v
);
305 unsigned char Hdf::configGetUByte(unsigned char defValue
/* = 0 */) const {
306 return getUInt(defValue
, "unsigned byte", ~0xFFUL
);
309 uint16_t Hdf::configGetUInt16(uint16_t defValue
/* = 0 */) const {
310 return getUInt(defValue
, "unsigned int16", ~0xFFFFUL
);
313 uint32_t Hdf::configGetUInt32(uint32_t defValue
/* = 0 */) const {
314 return getUInt(defValue
, "unsigned int32", ~0xFFFFFFFFUL
);
317 uint64_t Hdf::configGetUInt64(uint64_t defValue
/* = 0 */) const {
318 return getUInt(defValue
, "unsigned int64", 0);
321 double Hdf::configGetDouble(double defValue
/* = 0 */) const {
322 const char *v
= configGet();
323 if (v
== nullptr) return defValue
;
325 char *endptr
= nullptr;
326 double n
= strtod(v
, &endptr
);
327 if (!endptr
&& !*endptr
) {
328 throw HdfDataTypeException(this, "double", v
);
334 void Hdf::configGet(std::vector
<uint32_t> &values
) const {
336 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
337 values
.push_back(hdf
.configGetUInt32(0));
341 void Hdf::configGet(std::vector
<std::string
> &values
) const {
343 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
344 values
.push_back(hdf
.configGetString(""));
348 void Hdf::configGet(std::set
<std::string
> &values
) const {
350 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
351 values
.insert(hdf
.configGetString(""));
355 void Hdf::configGet(boost::container::flat_set
<std::string
> &values
) const {
357 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
358 values
.insert(hdf
.configGetString(""));
362 void Hdf::configGet(std::unordered_map
<std::string
, int> &values
) const {
364 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
365 values
[hdf
.getName()] = hdf
.configGetInt32();
369 void Hdf::configGet(std::set
<std::string
, stdltistr
> &values
) const {
371 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
372 values
.insert(hdf
.configGetString(""));
376 void Hdf::configGet(std::map
<std::string
, std::string
> &values
) const {
378 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
379 values
[hdf
.getName()] = hdf
.configGetString("");
383 void Hdf::configGet(std::map
<std::string
, std::string
,
384 stdltistr
> &values
) const {
386 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
387 values
[hdf
.getName()] = hdf
.configGetString("");
391 void Hdf::configGet(hphp_string_imap
<std::string
> &values
) const {
393 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
394 values
[hdf
.getName()] = hdf
.configGetString("");
398 bool Hdf::convertRawConfigToBool(const char *v
) {
399 return *v
&& strcmp(v
, "0") &&
400 strcasecmp(v
, "false") && strcasecmp(v
, "no") && strcasecmp(v
, "off");
403 int Hdf::compare(const char *v2
) const {
404 const char *v1
= configGet();
405 if (v1
== nullptr && v2
== nullptr) return 0;
406 if (v1
== nullptr) return -1;
407 if (v2
== nullptr) return 1;
408 return strcmp(v1
, v2
);
411 int Hdf::compare(const std::string
&v2
) const {
412 std::string v1
= configGetString();
413 return strcmp(v1
.c_str(), v2
.c_str());
416 int Hdf::compare(char v2
) const {
417 char v1
= configGetByte();
418 if (v1
== v2
) return 0;
419 return v1
> v2
? 1 : -1;
422 int Hdf::compare(unsigned char v2
) const {
423 unsigned char v1
= configGetUByte();
424 if (v1
== v2
) return 0;
425 return v1
> v2
? 1 : -1;
428 int Hdf::compare(int16_t v2
) const {
429 int16_t v1
= configGetInt16();
430 if (v1
== v2
) return 0;
431 return v1
> v2
? 1 : -1;
434 int Hdf::compare(uint16_t v2
) const {
435 uint16_t v1
= configGetUInt16();
436 if (v1
== v2
) return 0;
437 return v1
> v2
? 1 : -1;
440 int Hdf::compare(int32_t v2
) const {
441 int32_t v1
= configGetInt32();
442 if (v1
== v2
) return 0;
443 return v1
> v2
? 1 : -1;
446 int Hdf::compare(uint32_t v2
) const {
447 uint32_t v1
= configGetUInt32();
448 if (v1
== v2
) return 0;
449 return v1
> v2
? 1 : -1;
452 int Hdf::compare(int64_t v2
) const {
453 int64_t v1
= configGetInt64();
454 if (v1
== v2
) return 0;
455 return v1
> v2
? 1 : -1;
458 int Hdf::compare(uint64_t v2
) const {
459 uint64_t v1
= configGetUInt64();
460 if (v1
== v2
) return 0;
461 return v1
> v2
? 1 : -1;
464 int Hdf::compare(double v2
) const {
465 double v1
= configGetDouble();
466 if (v1
== v2
) return 0;
467 return v1
> v2
? 1 : -1;
470 ///////////////////////////////////////////////////////////////////////////////
473 Hdf
&Hdf::operator=(const Hdf
&hdf
) {
475 if (m_rawp
!= hdf
.m_rawp
) {
497 void Hdf::set(const char *value
) {
498 CheckNeoError(hdf_set_value(getRaw(), nullptr, (char*)value
));
501 void Hdf::set(int64_t value
) {
503 snprintf(buf
, sizeof(buf
), "%lld", (long long)value
);
507 void Hdf::set(uint64_t value
) {
509 snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)value
);
513 void Hdf::set(double value
) {
515 snprintf(buf
, sizeof(buf
), "%g", value
);
519 ///////////////////////////////////////////////////////////////////////////////
522 std::string
Hdf::getName(bool markVisited
/* = true */) const {
524 char *name
= hdf_obj_name(hdf
);
525 if (markVisited
) hdf_set_visited(hdf
, 1);
526 return name
? name
: "";
529 std::string
Hdf::getFullPath() const {
530 std::string fullpath
;
531 if (m_path
.empty()) {
535 if (!m_name
.empty()) {
543 Hdf
Hdf::parentImpl() const {
545 if (m_name
.empty()) {
546 if (m_path
.empty()) {
547 throw HdfInvalidOperation("calling parent() on topmost node");
549 size_t pos
= m_path
.rfind('.');
550 if (pos
== std::string::npos
) {
554 hdf
.m_name
= m_path
.substr(pos
+ 1);
555 hdf
.m_path
= m_path
.substr(0, pos
);
563 const Hdf
Hdf::parent() const {
571 const Hdf
Hdf::operator[](int name
) const {
573 sprintf(buf
, "%d", name
);
574 return operator[](buf
);
577 const Hdf
Hdf::operator[](const char *name
) const {
578 return Hdf(this, name
);
581 const Hdf
Hdf::operator[](const std::string
&name
) const {
582 return operator[](name
.c_str());
585 Hdf
Hdf::operator[](int name
) {
587 sprintf(buf
, "%d", name
);
588 return operator[](buf
);
591 Hdf
Hdf::operator[](const char *name
) {
592 return Hdf(this, name
);
595 Hdf
Hdf::operator[](const std::string
&name
) {
596 return operator[](name
.c_str());
599 bool Hdf::exists() const {
600 if (m_rawp
== nullptr) {
601 return m_hdf
!= nullptr;
604 std::string fullpath
= getFullPath();
605 if (fullpath
.empty()) {
609 auto err
= STATUS_OK
;
610 auto const result
= hdf_get_obj(m_rawp
->m_hdf
, fullpath
.c_str(), &err
);
615 bool Hdf::exists(int name
) const {
617 sprintf(buf
, "%d", name
);
621 bool Hdf::exists(const char *name
) const {
624 std::string fullpath
= getFullPath();
626 if (!fullpath
.empty()) {
627 auto err
= STATUS_OK
;
628 hdf
= hdf_get_obj(hdf
, fullpath
.c_str(), &err
);
632 if (!hdf
) return false;
633 auto err
= STATUS_OK
;
634 if (hdf_get_obj(hdf
, name
, &err
)) return true;
639 bool Hdf::exists(const std::string
&name
) const {
640 return exists(name
.c_str());
643 void Hdf::remove(int name
) const {
645 sprintf(buf
, "%d", name
);
649 void Hdf::remove(const char *name
) const {
650 assert(name
&& *name
);
651 CheckNeoError(hdf_remove_tree(getRaw(), name
));
654 void Hdf::remove(const std::string
&name
) const {
655 remove(name
.c_str());
658 ///////////////////////////////////////////////////////////////////////////////
661 Hdf
Hdf::firstChild(bool markVisited
/* = true */) const {
663 if (markVisited
) hdf_set_visited(hdf
, 1);
664 auto err
= STATUS_OK
;
665 auto child
= hdf_obj_child(hdf
, &err
);
668 ret
.m_path
= getFullPath();
669 ret
.m_name
= ret
.getName(markVisited
);
673 Hdf
Hdf::next(bool markVisited
/* = true */) const {
675 if (markVisited
) hdf_set_visited(hdf
, 1);
676 Hdf
ret(hdf_obj_next(hdf
));
678 ret
.m_name
= ret
.getName(markVisited
);
682 ///////////////////////////////////////////////////////////////////////////////
685 void Hdf::fromString(const char *input
) {
686 CheckNeoError(hdf_read_string(getRaw(), (char*)input
));
689 const char *Hdf::toString() const {
694 CheckNeoError(hdf_write_string(getRaw(), &m_dump
));
698 void Hdf::write(const char *filename
) const {
699 CheckNeoError(hdf_write_file(getRaw(), filename
));
702 ///////////////////////////////////////////////////////////////////////////////
705 HDF
*Hdf::getRaw() const {
706 if (m_hdf
) return m_hdf
;
708 if (m_rawp
== nullptr) {
713 std::string fullpath
= getFullPath();
714 if (fullpath
.empty()) {
717 CheckNeoError(hdf_get_node(m_rawp
->m_hdf
, (char*)fullpath
.c_str(), &ret
));
723 void Hdf::CheckNeoError(NEOERR
*err
) {
724 if (err
!= STATUS_OK
) {
727 nerr_error_string(err
, &str
);
728 throw HdfException("%s", str
.buf
);
732 ///////////////////////////////////////////////////////////////////////////////
735 HdfException::HdfException(const char *fmt
, ...) {
736 va_list ap
; va_start(ap
, fmt
); format(fmt
, ap
); va_end(ap
);
739 ///////////////////////////////////////////////////////////////////////////////