1 | // This file is part of SmallBASIC |
2 | // |
3 | // Copyright(C) 2001-2017 Chris Warren-Smith. |
4 | // |
5 | // This program is distributed under the terms of the GPL v2.0 or later |
6 | // Download the GNU Public License (GPL) from www.gnu.org |
7 | // |
8 | |
9 | #ifndef STRINGLIB_H |
10 | #define STRINGLIB_H |
11 | |
12 | #include <string.h> |
13 | #include <stdio.h> |
14 | #include <stdlib.h> |
15 | #include <time.h> |
16 | #include <ctype.h> |
17 | |
18 | #ifndef IS_WHITE |
19 | #define IS_WHITE(c) (c == ' '|| c == '\n' || c == '\r' || c == '\t') |
20 | #endif |
21 | |
22 | namespace strlib { |
23 | |
24 | //--String---------------------------------------------------------------------- |
25 | |
26 | struct String { |
27 | String(); |
28 | String(const char *s); |
29 | String(const char *s, int len); |
30 | String(const String &s); |
31 | virtual ~String(); |
32 | |
33 | const String &operator=(const String &s); |
34 | const String &operator=(const char *s); |
35 | const String &operator=(const char c); |
36 | const void operator+=(const String &s); |
37 | const void operator+=(const char *s); |
38 | String &append(const String &s); |
39 | String &append(const String *s); |
40 | String &append(int i); |
41 | String &append(char c); |
42 | String &append(const char *s); |
43 | String &append(const char *s, int numCopy); |
44 | String &append(FILE *fp, long len); |
45 | operator const char *() const { return _buffer; } |
46 | const char *c_str() const { return _buffer; }; |
47 | void clear(); |
48 | bool equals(const String &s, bool ignoreCase = true) const; |
49 | bool equals(const char *s, bool ignoreCase = true) const; |
50 | bool endsWith(const String &s) const; |
51 | int indexOf(char chr, int fromIndex) const; |
52 | int indexOf(const char *s, int fromIndex) const; |
53 | bool empty() const { return _buffer == NULL || _buffer[0] == '\0'; }; |
54 | char lastChar() const { return (_buffer == NULL || !_buffer[0] ? '\0' : _buffer[strlen(_buffer) - 1]); } |
55 | int lastIndexOf(char chr, int untilIndex) const; |
56 | int length() const { return (_buffer == NULL ? 0 : strlen(_buffer)); } |
57 | String leftOf(char ch) const; |
58 | int toInteger() const { return (_buffer == NULL ? 0 : atoi(_buffer)); } |
59 | double toNumber() const { return (_buffer == NULL ? 0 : atof(_buffer)); } |
60 | void replaceAll(char a, char b); |
61 | String rightOf(char ch) const; |
62 | String substring(int beginIndex) const; |
63 | String substring(int beginIndex, int endIndex) const; |
64 | void trim(); |
65 | |
66 | private: |
67 | char *_buffer; |
68 | }; |
69 | |
70 | //--List------------------------------------------------------------------------ |
71 | |
72 | #define List_each(type, itr, v) \ |
73 | for (strlib::List<type>::TP itr = (v).begin(); itr < (v).end(); itr++) |
74 | |
75 | template<typename T> |
76 | struct List { |
77 | typedef T *TP; |
78 | |
79 | List(int growSize = 20) : |
80 | _head(0), |
81 | _growSize(growSize), |
82 | _count(0), |
83 | _size(0) { |
84 | init(); |
85 | } |
86 | |
87 | virtual ~List() { |
88 | for (int i = 0; i < _count; i++) { |
89 | delete _head[i]; |
90 | } |
91 | free(_head); |
92 | } |
93 | |
94 | /** |
95 | * Removes the list and the list contents |
96 | */ |
97 | void removeAll() { |
98 | for (int i = 0; i < _count; i++) { |
99 | delete _head[i]; |
100 | } |
101 | clear(); |
102 | } |
103 | |
104 | /** |
105 | * Empties the list without deleteing the list objects |
106 | */ |
107 | void clear() { |
108 | free(_head); |
109 | init(); |
110 | } |
111 | |
112 | /** |
113 | * Returns the number of items in the list |
114 | */ |
115 | int size() const { return _count; } |
116 | |
117 | /** |
118 | * Returns T at the given index |
119 | */ |
120 | T operator[] (const int index) const { return index < _count ? _head[index] : NULL; } |
121 | |
122 | /** |
123 | * Returns T at the given index |
124 | */ |
125 | T get(const int index) const { return index < _count ? _head[index] : NULL; } |
126 | |
127 | /** |
128 | * Adds T to the list |
129 | */ |
130 | void add(T object) { |
131 | if (++_count > _size) { |
132 | _size += _growSize; |
133 | _head = (TP) realloc(_head, sizeof(T) * _size); |
134 | } |
135 | _head[_count - 1] = object; |
136 | } |
137 | |
138 | /** |
139 | * Removes the element pointed to by TP i. |
140 | */ |
141 | void remove(TP i) { |
142 | TP e = end(); |
143 | while (i != (e-1)) { |
144 | *i = *(i+1); |
145 | i++; |
146 | } |
147 | _count--; |
148 | } |
149 | |
150 | /** |
151 | * Returns an TP pointing to the first element of the List. |
152 | */ |
153 | TP begin() const { return _head; } |
154 | |
155 | /** |
156 | * Returns an TP pointing beyond the last element of the List. |
157 | */ |
158 | TP end() const { return _head + _count; } |
159 | |
160 | /** |
161 | * String specialisation - Add a String to the list of strings |
162 | */ |
163 | void add(const char *s); |
164 | |
165 | /** |
166 | * returns whether the list is empty |
167 | */ |
168 | bool empty() const { |
169 | return !_count; |
170 | } |
171 | |
172 | /** |
173 | * Returns whether list of strings constains the string |
174 | */ |
175 | bool contains(const char *s); |
176 | |
177 | /** |
178 | * Returns whether the list contains t |
179 | */ |
180 | bool contains(T t) { |
181 | bool result = false; |
182 | for (T *it = begin(); it < end(); it++) { |
183 | T next = (*it); |
184 | if (next == t) { |
185 | result = true; |
186 | break; |
187 | } |
188 | } |
189 | return result; |
190 | } |
191 | |
192 | void sort(int (*compareFunc)(const void *p1, const void *p2)) { |
193 | if (_size > 1) { |
194 | qsort(_head, _count, sizeof(T), compareFunc); |
195 | } |
196 | } |
197 | |
198 | protected: |
199 | void init() { |
200 | _count = 0; |
201 | _size = _growSize; |
202 | _head = (TP) malloc(sizeof(T) * _size); |
203 | } |
204 | |
205 | TP _head; |
206 | int _growSize; |
207 | int _count; |
208 | int _size; |
209 | }; |
210 | |
211 | // specialisations for String List |
212 | template<> void List<String *>::add(const char *s); |
213 | template<> bool List<String *>::contains(const char *s); |
214 | |
215 | //--Stack----------------------------------------------------------------------- |
216 | |
217 | template<typename T> |
218 | struct Stack : public List<T> { |
219 | Stack() : List<T>() {} |
220 | Stack(int growSize) : List<T>(growSize) {} |
221 | T peek() { return !this->_count ? (T)NULL : this->_head[this->_count - 1]; } |
222 | T pop() { return !this->_count ? (T)NULL : this->_head[--this->_count]; } |
223 | void push(T o) { this->add(o); } |
224 | }; |
225 | |
226 | //--Queue----------------------------------------------------------------------- |
227 | |
228 | template<typename T> |
229 | struct Queue : public List<T> { |
230 | Queue() : List<T>() {} |
231 | Queue(int growSize) : List<T>(growSize) {} |
232 | T front() { return !this->_count ? (T)NULL : this->_head[0]; } |
233 | void pop(bool free=true) { |
234 | if (this->_count) { |
235 | if (free) { |
236 | delete this->_head[0]; |
237 | } |
238 | memmove(this->_head, this->_head + 1, (--this->_count) * sizeof(T)); |
239 | } |
240 | } |
241 | void push(T o) { this->add(o); } |
242 | }; |
243 | |
244 | //--Properties------------------------------------------------------------------ |
245 | |
246 | template<typename T> |
247 | struct Properties : public List<T> { |
248 | Properties() : List<T>() {} |
249 | Properties(int growSize) : List<T>(growSize) {} |
250 | virtual ~Properties() {} |
251 | |
252 | /** |
253 | * find the position of the key in the list |
254 | */ |
255 | int find(const char *key) { |
256 | int result = -1; |
257 | for (int i = 0; i < this->_count; i++) { |
258 | String *nextKey = (String *)this->_head[i++]; |
259 | if (nextKey == NULL || i == this->_count) { |
260 | break; |
261 | } |
262 | T nextValue = this->_head[i]; |
263 | if (nextValue == NULL) { |
264 | break; |
265 | } |
266 | if (nextKey->equals(key)) { |
267 | result = i; |
268 | break; |
269 | } |
270 | } |
271 | return result; |
272 | } |
273 | |
274 | T get(const char *key) { |
275 | int index = find(key); |
276 | return index == -1 ? NULL : this->_head[index]; |
277 | } |
278 | |
279 | int length() const { |
280 | return this->_count / 2; |
281 | } |
282 | |
283 | // for Properties<String *> |
284 | void get(const char *key, List<String *> *arrayValues); |
285 | void load(const char *s); |
286 | void load(const char *s, int len); |
287 | void put(const char *key, const char *value); |
288 | |
289 | void put(const char *key, T value) { |
290 | int index = find(key); |
291 | if (index != -1) { |
292 | this->_head[index] = value; |
293 | } else { |
294 | this->add((T)new String(key)); |
295 | this->add(value); |
296 | } |
297 | } |
298 | }; |
299 | |
300 | // specialisations for String properties |
301 | template<> void Properties<String *>::get(const char *key, List<String *> *arrayValues); |
302 | template<> void Properties<String *>::load(const char *); |
303 | template<> void Properties<String *>::load(const char *s, int slen); |
304 | template<> void Properties<String *>::put(const char *key, const char *value); |
305 | |
306 | } |
307 | |
308 | typedef strlib::List<strlib::String *> StringList; |
309 | |
310 | #endif |
311 | |
312 | |