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
<uint32_t> &values
) const {
334 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
335 values
.push_back(hdf
.configGetUInt32(0));
339 void Hdf::configGet(std::vector
<std::string
> &values
) const {
341 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
342 values
.push_back(hdf
.configGetString(""));
346 void Hdf::configGet(std::set
<std::string
> &values
) const {
348 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
349 values
.insert(hdf
.configGetString(""));
353 void Hdf::configGet(boost::container::flat_set
<std::string
> &values
) const {
355 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
356 values
.insert(hdf
.configGetString(""));
360 void Hdf::configGet(std::unordered_map
<std::string
, int> &values
) const {
362 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
363 values
[hdf
.getName()] = hdf
.configGetInt32();
367 void Hdf::configGet(std::set
<std::string
, stdltistr
> &values
) const {
369 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
370 values
.insert(hdf
.configGetString(""));
374 void Hdf::configGet(std::map
<std::string
, std::string
> &values
) const {
376 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
377 values
[hdf
.getName()] = hdf
.configGetString("");
381 void Hdf::configGet(std::map
<std::string
, std::string
,
382 stdltistr
> &values
) const {
384 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
385 values
[hdf
.getName()] = hdf
.configGetString("");
389 void Hdf::configGet(hphp_string_imap
<std::string
> &values
) const {
391 for (Hdf hdf
= firstChild(); hdf
.exists(); hdf
= hdf
.next()) {
392 values
[hdf
.getName()] = hdf
.configGetString("");
396 bool Hdf::convertRawConfigToBool(const char *v
) {
397 return *v
&& strcmp(v
, "0") &&
398 strcasecmp(v
, "false") && strcasecmp(v
, "no") && strcasecmp(v
, "off");
401 int Hdf::compare(const char *v2
) const {
402 const char *v1
= configGet();
403 if (v1
== nullptr && v2
== nullptr) return 0;
404 if (v1
== nullptr) return -1;
405 if (v2
== nullptr) return 1;
406 return strcmp(v1
, v2
);
409 int Hdf::compare(const std::string
&v2
) const {
410 std::string v1
= configGetString();
411 return strcmp(v1
.c_str(), v2
.c_str());
414 int Hdf::compare(char v2
) const {
415 char v1
= configGetByte();
416 if (v1
== v2
) return 0;
417 return v1
> v2
? 1 : -1;
420 int Hdf::compare(unsigned char v2
) const {
421 unsigned char v1
= configGetUByte();
422 if (v1
== v2
) return 0;
423 return v1
> v2
? 1 : -1;
426 int Hdf::compare(int16_t v2
) const {
427 int16_t v1
= configGetInt16();
428 if (v1
== v2
) return 0;
429 return v1
> v2
? 1 : -1;
432 int Hdf::compare(uint16_t v2
) const {
433 uint16_t v1
= configGetUInt16();
434 if (v1
== v2
) return 0;
435 return v1
> v2
? 1 : -1;
438 int Hdf::compare(int32_t v2
) const {
439 int32_t v1
= configGetInt32();
440 if (v1
== v2
) return 0;
441 return v1
> v2
? 1 : -1;
444 int Hdf::compare(uint32_t v2
) const {
445 uint32_t v1
= configGetUInt32();
446 if (v1
== v2
) return 0;
447 return v1
> v2
? 1 : -1;
450 int Hdf::compare(int64_t v2
) const {
451 int64_t v1
= configGetInt64();
452 if (v1
== v2
) return 0;
453 return v1
> v2
? 1 : -1;
456 int Hdf::compare(uint64_t v2
) const {
457 uint64_t v1
= configGetUInt64();
458 if (v1
== v2
) return 0;
459 return v1
> v2
? 1 : -1;
462 int Hdf::compare(double v2
) const {
463 double v1
= configGetDouble();
464 if (v1
== v2
) return 0;
465 return v1
> v2
? 1 : -1;
468 ///////////////////////////////////////////////////////////////////////////////
471 Hdf
&Hdf::operator=(const Hdf
&hdf
) {
473 if (m_rawp
!= hdf
.m_rawp
) {
495 void Hdf::set(const char *value
) {
496 CheckNeoError(hdf_set_value(getRaw(), nullptr, (char*)value
));
499 void Hdf::set(int64_t value
) {
501 snprintf(buf
, sizeof(buf
), "%lld", (long long)value
);
505 void Hdf::set(uint64_t value
) {
507 snprintf(buf
, sizeof(buf
), "%llu", (unsigned long long)value
);
511 void Hdf::set(double value
) {
513 snprintf(buf
, sizeof(buf
), "%g", value
);
517 ///////////////////////////////////////////////////////////////////////////////
520 std::string
Hdf::getName(bool markVisited
/* = true */) const {
522 char *name
= hdf_obj_name(hdf
);
523 if (markVisited
) hdf_set_visited(hdf
, 1);
524 return name
? name
: "";
527 std::string
Hdf::getFullPath() const {
528 std::string fullpath
;
529 if (m_path
.empty()) {
533 if (!m_name
.empty()) {
541 Hdf
Hdf::parentImpl() const {
543 if (m_name
.empty()) {
544 if (m_path
.empty()) {
545 throw HdfInvalidOperation("calling parent() on topmost node");
547 size_t pos
= m_path
.rfind('.');
548 if (pos
== std::string::npos
) {
552 hdf
.m_name
= m_path
.substr(pos
+ 1);
553 hdf
.m_path
= m_path
.substr(0, pos
);
561 const Hdf
Hdf::parent() const {
569 const Hdf
Hdf::operator[](int name
) const {
571 sprintf(buf
, "%d", name
);
572 return operator[](buf
);
575 const Hdf
Hdf::operator[](const char *name
) const {
576 return Hdf(this, name
);
579 const Hdf
Hdf::operator[](const std::string
&name
) const {
580 return operator[](name
.c_str());
583 Hdf
Hdf::operator[](int name
) {
585 sprintf(buf
, "%d", name
);
586 return operator[](buf
);
589 Hdf
Hdf::operator[](const char *name
) {
590 return Hdf(this, name
);
593 Hdf
Hdf::operator[](const std::string
&name
) {
594 return operator[](name
.c_str());
597 bool Hdf::exists() const {
598 if (m_rawp
== nullptr) {
599 return m_hdf
!= nullptr;
602 std::string fullpath
= getFullPath();
603 if (fullpath
.empty()) {
606 return hdf_get_obj(m_rawp
->m_hdf
, fullpath
.c_str());
609 bool Hdf::exists(int name
) const {
611 sprintf(buf
, "%d", name
);
615 bool Hdf::exists(const char *name
) const {
618 std::string fullpath
= getFullPath();
620 if (!fullpath
.empty()) {
621 hdf
= hdf_get_obj(hdf
, fullpath
.c_str());
624 return hdf
&& hdf_get_obj(hdf
, name
);
627 bool Hdf::exists(const std::string
&name
) const {
628 return exists(name
.c_str());
631 void Hdf::remove(int name
) const {
633 sprintf(buf
, "%d", name
);
637 void Hdf::remove(const char *name
) const {
638 assert(name
&& *name
);
639 CheckNeoError(hdf_remove_tree(getRaw(), name
));
642 void Hdf::remove(const std::string
&name
) const {
643 remove(name
.c_str());
646 ///////////////////////////////////////////////////////////////////////////////
649 Hdf
Hdf::firstChild(bool markVisited
/* = true */) const {
651 if (markVisited
) hdf_set_visited(hdf
, 1);
652 Hdf
ret(hdf_obj_child(hdf
));
653 ret
.m_path
= getFullPath();
654 ret
.m_name
= ret
.getName(markVisited
);
658 Hdf
Hdf::next(bool markVisited
/* = true */) const {
660 if (markVisited
) hdf_set_visited(hdf
, 1);
661 Hdf
ret(hdf_obj_next(hdf
));
663 ret
.m_name
= ret
.getName(markVisited
);
667 ///////////////////////////////////////////////////////////////////////////////
670 void Hdf::fromString(const char *input
) {
671 CheckNeoError(hdf_read_string(getRaw(), (char*)input
));
674 const char *Hdf::toString() const {
679 CheckNeoError(hdf_write_string(getRaw(), &m_dump
));
683 void Hdf::write(const char *filename
) const {
684 CheckNeoError(hdf_write_file(getRaw(), filename
));
687 ///////////////////////////////////////////////////////////////////////////////
690 HDF
*Hdf::getRaw() const {
691 if (m_hdf
) return m_hdf
;
693 if (m_rawp
== nullptr) {
698 std::string fullpath
= getFullPath();
699 if (fullpath
.empty()) {
702 hdf_get_node(m_rawp
->m_hdf
, (char*)fullpath
.c_str(), &ret
);
708 void Hdf::CheckNeoError(NEOERR
*err
) {
709 if (err
!= STATUS_OK
) {
712 nerr_error_string(err
, &str
);
713 throw HdfException("%s", str
.buf
);
717 ///////////////////////////////////////////////////////////////////////////////
720 HdfException::HdfException(const char *fmt
, ...) {
721 va_list ap
; va_start(ap
, fmt
); format(fmt
, ap
); va_end(ap
);
724 ///////////////////////////////////////////////////////////////////////////////