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
22namespace strlib {
23
24//--String----------------------------------------------------------------------
25
26struct 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
66private:
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
75template<typename T>
76struct 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
198protected:
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
212template<> void List<String *>::add(const char *s);
213template<> bool List<String *>::contains(const char *s);
214
215//--Stack-----------------------------------------------------------------------
216
217template<typename T>
218struct 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
228template<typename T>
229struct 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
246template<typename T>
247struct 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
301template<> void Properties<String *>::get(const char *key, List<String *> *arrayValues);
302template<> void Properties<String *>::load(const char *);
303template<> void Properties<String *>::load(const char *s, int slen);
304template<> void Properties<String *>::put(const char *key, const char *value);
305
306}
307
308typedef strlib::List<strlib::String *> StringList;
309
310#endif
311
312