1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string.h>
6
7#include <fbl/alloc_checker.h>
8#include <fbl/unique_ptr.h>
9#include <fuzz-utils/string-list.h>
10
11namespace fuzzing {
12
13StringList::StringList() {
14    iterator_ = elements_.end();
15}
16
17StringList::StringList(const char* const* elements, size_t num_elements) {
18    for (size_t i = 0; i < num_elements; ++i) {
19        push_back(elements[i]);
20    }
21}
22
23StringList::~StringList() {}
24
25bool StringList::is_empty() const {
26    return elements_.is_empty();
27}
28
29size_t StringList::length() const {
30    return elements_.size_slow();
31}
32
33const char* StringList::first() {
34    iterator_ = elements_.begin();
35    return next();
36}
37
38const char* StringList::next() {
39    return iterator_ != elements_.end() ? (iterator_++)->str_.c_str() : nullptr;
40}
41
42void StringList::push_front(const char* str) {
43    push(str, true /* front */);
44}
45
46void StringList::push_back(const char* str) {
47    push(str, false /* !front */);
48}
49
50void StringList::push(const char* str, bool front) {
51    if (!str) {
52        return;
53    }
54    fbl::AllocChecker ac;
55    fbl::unique_ptr<StringElement> element(new (&ac) StringElement());
56    ZX_ASSERT(ac.check());
57    element->str_.Set(str, &ac);
58    ZX_ASSERT(ac.check());
59    if (front) {
60        elements_.push_front(fbl::move(element));
61    } else {
62        elements_.push_back(fbl::move(element));
63    }
64    iterator_ = elements_.end();
65}
66
67void StringList::keep_if(const char* substr) {
68    if (!substr) {
69        return;
70    }
71    while (elements_.erase_if([substr](const StringElement& element) -> bool {
72        return strstr(element.str_.c_str(), substr) == nullptr;
73    })) {
74    }
75    iterator_ = elements_.end();
76}
77
78void StringList::keep_if_any(StringList* substrs) {
79    ZX_DEBUG_ASSERT(substrs);
80    while (elements_.erase_if([substrs](const StringElement& element) -> bool {
81        for (const char* substr = substrs->first(); substr; substr = substrs->next()) {
82            if (strstr(element.str_.c_str(), substr)) {
83                return false;
84            }
85        }
86        return true;
87    })) {
88    }
89    iterator_ = elements_.end();
90}
91
92void StringList::keep_if_all(StringList* substrs) {
93    ZX_DEBUG_ASSERT(substrs);
94    while (elements_.erase_if([substrs](const StringElement& element) -> bool {
95        for (const char* substr = substrs->first(); substr; substr = substrs->next()) {
96            if (!strstr(element.str_.c_str(), substr)) {
97                return true;
98            }
99        }
100        return false;
101    })) {
102    }
103    iterator_ = elements_.end();
104}
105
106void StringList::erase_if(const char* match) {
107    if (!match) {
108        return;
109    }
110    while (elements_.erase_if([match](const StringElement& element) -> bool {
111        return strcmp(element.str_.c_str(), match) == 0;
112    })) {
113    }
114    iterator_ = elements_.end();
115}
116
117void StringList::clear() {
118    elements_.clear();
119    iterator_ = elements_.begin();
120}
121
122} // namespace fuzzing
123