1 /* bzflag
2 * Copyright (c) 1993-2021 Tim Riker
3 *
4 * This package is free software; you can redistribute it and/or
5 * modify it under the terms of the license found in the file
6 * named COPYING that should have accompanied this file.
7 *
8 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 */
12
13 /*
14 * common definitions
15 */
16
17 #ifndef __TEXTUTILS_H__
18 #define __TEXTUTILS_H__
19
20 #include "common.h"
21
22 /* system interface headers */
23 #include <algorithm>
24 #include <ctype.h>
25 #ifdef HAVE_DEFINED_TOLOWER
26 #undef tolower
27 #undef toupper
28 #endif
29 #include <string>
30 #include <stdarg.h>
31 #include <vector>
32
33 /** This namespace provides basic functionality to parse and
34 * format strings
35 */
36 namespace TextUtils
37 {
38 std::string vformat(const char* fmt, va_list args);
39 std::string format(const char* fmt, ...);
40
41 /** returns a string converted to lowercase
42 */
tolower(const std::string & s)43 inline std::string tolower(const std::string& s)
44 {
45 std::string trans = s;
46
47 for (std::string::iterator i=trans.begin(), end=trans.end(); i!=end; ++i)
48 *i = ::tolower(*i);
49 return trans;
50 }
51
52 /** returns a string converted to uppercase
53 */
toupper(const std::string & s)54 inline std::string toupper(const std::string& s)
55 {
56 std::string trans = s;
57 for (std::string::iterator i=trans.begin(), end=trans.end(); i!=end; ++i)
58 *i = ::toupper(*i);
59 return trans;
60 }
61
62 inline std::string ltrim(const std::string& s, const char* trim = " ")
63 {
64 if (!trim)
65 return s;
66
67 size_t pos = s.find_first_not_of(trim);
68
69 if (pos == std::string::npos)
70 return s;
71
72 return s.substr(pos, s.length() + 1);
73 }
74
75 inline std::string rtrim(const std::string& s, const char* trim = " ")
76 {
77 if (!trim)
78 return s;
79
80 size_t pos = s.find_last_not_of(trim);
81
82 if (pos == std::string::npos)
83 return s;
84
85 return s.substr(0, pos + 1);
86 }
87
88 inline std::string trim(const std::string& s, const char* trim = " ")
89 {
90 return (rtrim(ltrim(s, trim), trim));
91 }
92
93 /** replace all of in in replaceMe with withMe
94 */
95 std::string replace_all(const std::string& in, const std::string& replaceMe, const std::string& withMe);
96
97 /** return copy of string with all whitespace stripped
98 */
99 std::string no_whitespace(const std::string &s);
100
101 /**
102 * Get a vector of strings from a string, using all of chars of thedelims
103 * string as separators. If maxTokens > 0, then the last 'token' maycontain delimiters
104 * as it just returns the rest of the line
105 * if you specify use quotes then tokens can be grouped in quotes and delimeters
106 * inside quotes are ignored.
107 * Hence /ban "Mr Blahblah" isajerk parses to "/ban", "Mr Blahlah" and "isajerk"
108 * but so does "Mr Blahblah" "isajerk", so if you want 3 tokens and a delimeter
109 * is in one of the tokens, by puting quotes around it you can get the correct
110 * parsing. When use quotes is enabled, \'s and "'s should\can be escaped with \
111 * escaping is not currently done for any other character.
112 * Should not have " as a delimeter if you want to use quotes
113 */
114 std::vector<std::string> tokenize(const std::string& in, const std::string &delims, const int maxTokens = 0,
115 const bool useQuotes = false);
116
117 /** convert a string representation of some duration into minutes
118 * example: "1d2h16m" -> 1500
119 * return true if the string can be parsed
120 */
121 bool parseDuration(const char *duration, int &durationInt);
122
123 // C h a r a c t e r c o m p a r i s o n
124
125 /** compare_nocase is strait from Stroustrup. This implementation uses
126 * strings instead of char arrays and includes a maxlength bounds check.
127 * It compares two strings and returns 0 if equal, <0 if s1 is less than
128 * s2, and >0 if s1 is greater than s2.
129 */
130 inline int compare_nocase(const std::string& s1, const std::string &s2, int maxlength=4096)
131 {
132 std::string::const_iterator p1 = s1.begin();
133 std::string::const_iterator p2 = s2.begin();
134 int i=0;
135 while (p1 != s1.end() && p2 != s2.end())
136 {
137 if (i >= maxlength)
138 return 0;
139 if (::tolower(*p1) != ::tolower(*p2))
140 return (::tolower(*p1) < ::tolower(*p2)) ? -1 : 1;
141 ++p1;
142 ++p2;
143 ++i;
144 }
145 return (s2.size() == s1.size()) ? 0 : (s1.size() < s2.size()) ? -1 : 1; // size is unsigned
146 }
147
148
149
150 /** utility function returns truthfully whether
151 * given character is a letter.
152 */
isAlphabetic(const char c)153 inline bool isAlphabetic(const char c)
154 {
155 if (( c > 64 && c < 91) ||
156 ( c > 96 && c < 123))
157 return true;
158 return false;
159 }
160
161
162 /** utility function returns truthfully whether
163 * given character is a number.
164 */
isNumeric(const char c)165 inline bool isNumeric(const char c)
166 {
167 if (( c > 47 && c < 58))
168 return true;
169 return false;
170 }
171
172
173 /** utility function returns truthfully whether
174 * a given character is printable whitespace.
175 * this includes newline, carriage returns, tabs
176 * and spaces.
177 */
isWhitespace(const char c)178 inline bool isWhitespace(const char c)
179 {
180 if ((( c >= 9 ) && ( c <= 13 )) ||
181 (c == 32))
182 return true;
183 return false;
184 }
185
186
187 /** utility function returns truthfully whether
188 * a given character is punctuation.
189 */
isPunctuation(const char c)190 inline bool isPunctuation(const char c)
191 {
192 if (( c > 32 && c < 48) ||
193 ( c > 57 && c < 65) ||
194 ( c > 90 && c < 97) ||
195 ( c > 122 && c < 127))
196 return true;
197 return false;
198 }
199
200
201 /** utility function returns truthfully whether
202 * given character is an alphanumeric. this is
203 * strictly letters and numbers.
204 */
isAlphanumeric(const char c)205 inline bool isAlphanumeric(const char c)
206 {
207 if (isAlphabetic(c) || isNumeric(c))
208 return true;
209 return false;
210 }
211
212
213 /** utility function returns truthfully whether
214 * given character is printable. this includes
215 * letters, numbers, and punctuation.
216 * (but NOT whitespace)
217 */
isVisible(const char c)218 inline bool isVisible(const char c)
219 {
220 if (isAlphanumeric(c) || isPunctuation(c))
221 return true;
222 return false;
223 }
224
225
226 /** utility function returns truthfully whether
227 * given character is printable. this includes
228 * letters, numbers, punctuation, and whitespace
229 */
isPrintable(const char c)230 inline bool isPrintable(const char c)
231 {
232 return (isVisible(c) || isWhitespace(c));
233 }
234
235
236
237 // S t r i n g i t e r a t i o n
238
239 /** utility method that returns the position of the
240 * first alphanumeric character from a string
241 */
242 inline int firstAlphanumeric(const std::string &input, unsigned short int max=4096)
243 {
244
245 if (max > input.length())
246 max = (unsigned short)input.length();
247
248 for (unsigned short i = 0; i < max; i++)
249 if (isAlphanumeric(input[i]))
250 return i;
251
252 return -1;
253 }
254
255
256 /** utility method that returns the position of the
257 * first non-alphanumeric character from a string
258 */
259 inline int firstNonalphanumeric(const std::string &input, unsigned short int max=4096)
260 {
261
262 if (max > input.length())
263 max = (unsigned short)input.length();
264
265 for (unsigned short i = 0; i < max; i++)
266 if (!isAlphanumeric(input[i]))
267 return i;
268
269 return -1;
270 }
271
272
273 /** utility method that returns the position of the
274 * first printable character from a string
275 */
276 inline int firstPrintable(const std::string &input, unsigned short int max=4096)
277 {
278
279 if (max > input.length())
280 max = (unsigned short)input.length();
281
282 for (unsigned short i = 0; i < max; i++)
283 if (isPrintable(input[i]))
284 return i;
285
286 return -1;
287 }
288
289
290 /** utility method that returns the position of the
291 * first non-printable character from a string
292 */
293 inline int firstNonprintable(const std::string &input, unsigned short int max=4096)
294 {
295 if (max > input.length())
296 max = (unsigned short)input.length();
297
298 for (unsigned short i = 0; i < max; i++)
299 if (!isPrintable(input[i]))
300 return i;
301
302 return -1;
303 }
304
305
306 /** utility method that returns the position of the
307 * first visible character from a string
308 */
309 inline int firstVisible(const std::string &input, unsigned short int max=4096)
310 {
311
312 if (max > input.length())
313 max = (unsigned short)input.length();
314
315 for (unsigned short i = 0; i < max; i++)
316 if (isVisible(input[i]))
317 return i;
318
319 return -1;
320 }
321
322
323 /** utility method that returns the position of the
324 * first non visible character from a string (control
325 * codes or whitespace
326 */
327 inline int firstNonvisible(const std::string &input, unsigned short int max=4096)
328 {
329 if (max > input.length())
330 max = (unsigned short)input.length();
331
332 for (unsigned short i = 0; i < max; i++)
333 if (!isVisible(input[i]))
334 return i;
335
336 return -1;
337 }
338
339
340 /** utility method that returns the position of the
341 * first alphabetic character from a string
342 */
343 inline int firstAlphabetic(const std::string &input, unsigned short int max=4096)
344 {
345 if (max > input.length())
346 max = (unsigned short)input.length();
347
348 for (unsigned short i = 0; i < max; i++)
349 if (isAlphabetic(input[i]))
350 return i;
351
352 return -1;
353 }
354
355
356 /** utility method that returns the position of the
357 * first printable character from a string
358 */
359 inline int firstNonalphabetic(const std::string &input, unsigned short int max=4096)
360 {
361 if (max > input.length())
362 max = (unsigned short)input.length();
363
364 for (unsigned short i = 0; i < max; i++)
365 if (!isAlphabetic(input[i]))
366 return i;
367
368 return -1;
369 }
370
371 /** integer to string
372 */
373 inline std::string itoa(int value, const char* fmt = "%i")
374 {
375 char buf[64];
376 snprintf(buf, sizeof(buf), fmt, value);
377 return std::string(buf);
378 }
379
380 /** url-encodes a string
381 */
382 std::string url_encode(const std::string &text);
383
384 /** url-decodes a string
385 */
386 std::string url_decode(const std::string &text);
387
388 /** octal-encode nonprintable characters in a string
389 * the quotechar parameter will always be encoded; '"' is a sensible value
390 */
391 std::string escape_nonprintable(const std::string &text, const char quotechar = '\\');
392
393 /** escape a string
394 */
395 std::string escape(const std::string &text, char escaper);
396
397 /** un-escape a string
398 */
399 std::string unescape(const std::string &text, char escaper);
400
401 /** lookup for an un-escaped separator
402 */
403 int unescape_lookup(const std::string &text, char escaper, char sep);
404
405 /** return a copy of a string, truncated to specified length,
406 * make last char a '~' if truncation took place
407 */
408 std::string str_trunc_continued (const std::string &text, int len);
409
410 /** find the first instance of a substring,
411 */
412 size_t find_first_substr(const std::string &findin, const std::string &findwhat, size_t offset = 0);
413 }
414
415
416 #endif // __TEXTUTILS_H__
417
418
419 // Local Variables: ***
420 // mode: C++ ***
421 // tab-width: 4 ***
422 // c-basic-offset: 4 ***
423 // indent-tabs-mode: nil ***
424 // End: ***
425 // ex: shiftwidth=4 tabstop=4
426