Objectively
Ultra-lightweight object oriented framework for GNU C.
Loading...
Searching...
No Matches
String.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include "Config.h"
25
26#include <assert.h>
27#include <iconv.h>
28#include <stdarg.h>
29#include <stdlib.h>
30#include <stdio.h>
31#include <string.h>
32#include <wchar.h>
33
34#include "Hash.h"
35#include "String.h"
36
37#if defined(__MINGW32__)
38#define towlower_l _towlower_l
39#define towupper_l _towupper_l
40#endif
41
42#define _Class _String
43
44#pragma mark - Object
45
49static Object *copy(const Object *self) {
50
51 const String *this = (const String *) self;
52 String *that = $(alloc(String), initWithString, this);
53
54 return (Object *) that;
55}
56
60static void dealloc(Object *self) {
61
62 String *this = (String *) self;
63
64 free(this->chars);
65
66 super(Object, self, dealloc);
67}
68
72static String *description(const Object *self) {
73
74 return (String *) $((Object *) self, copy);
75}
76
80static int hash(const Object *self) {
81
82 String *this = (String *) self;
83
84 return HashForCString(HASH_SEED, this->chars);
85}
86
90static bool isEqual(const Object *self, const Object *other) {
91
92 if (super(Object, self, isEqual, other)) {
93 return true;
94 }
95
96 if (other && $(other, isKindOfClass, _String())) {
97
98 const String *this = (String *) self;
99 const String *that = (String *) other;
100
101 if (this->length == that->length) {
102
103 const Range range = { 0, this->length };
104 return $(this, compareTo, that, range) == OrderSame;
105 }
106 }
107
108 return false;
109}
110
111#pragma mark - String
112
117typedef struct {
120 char *in;
121 size_t length;
122 char *out;
123 size_t size;
124} Transcode;
125
131static size_t transcode(Transcode *trans) {
132
133 assert(trans);
134 assert(trans->to);
135 assert(trans->from);
136 assert(trans->out);
137 assert(trans->size);
138
139 iconv_t cd = iconv_open(NameForStringEncoding(trans->to), NameForStringEncoding(trans->from));
140 assert(cd != (iconv_t) -1);
141
142 char *in = trans->in;
143 char *out = trans->out;
144
145 size_t inBytesRemaining = trans->length;
146 size_t outBytesRemaining = trans->size;
147
148 const size_t ret = iconv(cd, &in, &inBytesRemaining, &out, &outBytesRemaining);
149 assert(ret != (size_t) -1);
150
151 int err = iconv_close(cd);
152 assert(err == 0);
153
154 return trans->size - outBytesRemaining;
155}
156
161static Order compareTo(const String *self, const String *other, const Range range) {
162
163 assert(range.location + range.length <= self->length);
164
165 if (other) {
166 const int i = strncmp(self->chars + range.location, other->chars, range.length);
167 if (i == 0) {
168 return OrderSame;
169 }
170 if (i > 0) {
171 return OrderDescending;
172 }
173 }
174
175 return OrderAscending;
176}
177
182static Array *componentsSeparatedByCharacters(const String *self, const char *chars) {
183
184 assert(chars);
185
186 Array *components = $(alloc(Array), init);
187
188 Range search = { 0, self->length };
189 Range result = $(self, rangeOfCharacters, chars, search);
190
191 while (result.length) {
192 search.length = result.location - search.location;
193
194 String *component = $(self, substring, search);
195 $(components, addObject, component);
196 release(component);
197
198 search.location = result.location + result.length;
199 search.length = self->length - search.location;
200
201 result = $(self, rangeOfCharacters, chars, search);
202 }
203
204 String *component = $(self, substring, search);
205 $(components, addObject, component);
206 release(component);
207
208 return components;
209}
210
215static Array *componentsSeparatedByString(const String *self, const String *string) {
216
217 assert(string);
218
220}
221
226static Data *getData(const String *self, StringEncoding encoding) {
227
228 Transcode trans = {
229 .to = encoding,
230 .from = STRING_ENCODING_UTF8,
231 .in = self->chars,
232 .length = self->length,
233 .out = calloc(self->length, sizeof(Unicode) / sizeof(char)),
234 .size = self->length * sizeof(Unicode)
235 };
236
237 assert(trans.out);
238
239 const size_t size = transcode(&trans);
240 assert(size <= trans.size);
241
242 return $$(Data, dataWithMemory, trans.out, size);
243}
244
249static bool hasPrefix(const String *self, const String *prefix) {
250
251 if (prefix->length > self->length) {
252 return false;
253 }
254
255 Range range = { 0, prefix->length };
256 return $(self, compareTo, prefix, range) == OrderSame;
257}
258
263static bool hasSuffix(const String *self, const String *suffix) {
264
265 if (suffix->length > self->length) {
266 return false;
267 }
268
269 Range range = { self->length - suffix->length, suffix->length };
270 return $(self, compareTo, suffix, range) == OrderSame;
271}
272
281static String *lowercaseString(const String *self) {
282
284 assert(data);
285
286 const size_t codepoints = data->length / sizeof(Unicode);
287 Unicode *unicode = (Unicode *) data->bytes;
288
289 for (size_t i = 0; i < codepoints; i++, unicode++) {
290 *unicode = towlower(*unicode);
291 }
292
294
295 release(data);
296 return lowercase;
297}
298
303static Range rangeOfCharacters(const String *self, const char *chars, const Range range) {
304
305 assert(chars);
306 assert(range.location > -1);
307 assert(range.length > 0);
308 assert(range.location + range.length <= self->length);
309
310 Range match = { -1, 0 };
311 const size_t len = strlen(chars);
312
313 const char *str = self->chars + range.location;
314 for (size_t i = 0; i < range.length; i++, str++) {
315 if (strncmp(str, chars, len) == 0) {
316 match.location = range.location + i;
317 match.length = len;
318 break;
319 }
320 }
321
322 return match;
323}
324
329static Range rangeOfString(const String *self, const String *string, const Range range) {
330
331 assert(string);
332
333 return $(self, rangeOfCharacters, string->chars, range);
334}
335
340static String *stringWithBytes(const uint8_t *bytes, size_t length, StringEncoding encoding) {
341
342 return $(alloc(String), initWithBytes, bytes, length, encoding);
343}
344
349static String *stringWithCharacters(const char *chars) {
350
351 return $(alloc(String), initWithCharacters, chars);
352}
353
358static String *stringWithContentsOfFile(const char *path, StringEncoding encoding) {
359
360 return $(alloc(String), initWithContentsOfFile, path, encoding);
361}
362
367static String *stringWithData(const Data *data, StringEncoding encoding) {
368
369 return $(alloc(String), initWithData, data, encoding);
370}
371
376static String *stringWithFormat(const char *fmt, ...) {
377
378 va_list args;
379 va_start(args, fmt);
380
381 String *string = $(alloc(String), initWithVaList, fmt, args);
382
383 va_end(args);
384
385 return string;
386}
387
392static String *stringWithMemory(const ident mem, size_t length) {
393
394 return $(alloc(String), initWithMemory, mem, length);
395}
396
401static String *substring(const String *self, const Range range) {
402
403 assert(range.location + range.length <= self->length);
404
405 ident mem = calloc(range.length + 1, sizeof(char));
406 assert(mem);
407
408 strncpy(mem, self->chars + range.location, range.length);
409
410 return $(alloc(String), initWithMemory, mem, range.length);
411}
412
417static String *trimmedString(const String *self) {
418
419 Range range = { .location = 0, .length = self->length };
420
421 while (isspace(self->chars[range.location])) {
422 range.location++;
423 range.length--;
424 }
425
426 while (range.length > 0 && isspace(self->chars[range.location + range.length - 1])) {
427 range.length--;
428 }
429
430 return $(self, substring, range);
431}
432
437static String *uppercaseString(const String *self) {
438
440 assert(data);
441
442 const size_t codepoints = data->length / sizeof(Unicode);
443 Unicode *unicode = (Unicode *) data->bytes;
444
445 for (size_t i = 0; i < codepoints; i++, unicode++) {
446 *unicode = towupper(*unicode);
447 }
448
450
451 release(data);
452 return uppercase;
453}
454
459static bool writeToFile(const String *self, const char *path, StringEncoding encoding) {
460
461 Data *data = $(self, getData, encoding);
462 assert(data);
463
464 const bool success = $(data, writeToFile, path);
465
466 release(data);
467 return success;
468}
469
470#pragma mark - String mutation
471
476static void appendBytes(String *self, const uint8_t *bytes, size_t length, StringEncoding encoding) {
477
478 if (bytes) {
479
480 Transcode trans = {
482 .from = encoding,
483 .in = (char *) bytes,
484 .length = length,
485 .out = calloc(length * sizeof(Unicode) + 1, sizeof(char)),
486 .size = length * sizeof(Unicode) + 1
487 };
488
489 assert(trans.out);
490
491 const size_t size = transcode(&trans);
492 assert(size < trans.size);
493
494 trans.out[size] = '\0';
495
496 $(self, appendCharacters, trans.out);
497
498 free(trans.out);
499 }
500}
501
506static void appendCharacters(String *self, const char *chars) {
507
508 if (chars) {
509
510 const size_t len = strlen(chars);
511 if (len) {
512
513 const size_t newSize = self->length + strlen(chars) + 1;
514 const size_t newCapacity = (newSize / _pageSize + 1) * _pageSize;
515
516 if (newCapacity > self->capacity) {
517
518 if (self->length) {
519 self->chars = realloc(self->chars, newCapacity);
520 } else {
521 self->chars = malloc(newCapacity);
522 }
523
524 assert(self->chars);
525 self->capacity = newCapacity;
526 }
527
528 ident ptr = self->chars + self->length;
529 memmove(ptr, chars, len);
530
531 self->chars[newSize - 1] = '\0';
532 self->length += len;
533 }
534 }
535}
536
541static void appendFormat(String *self, const char *fmt, ...) {
542
543 va_list args;
544 va_start(args, fmt);
545
546 $(self, appendVaList, fmt, args);
547
548 va_end(args);
549}
550
555static void appendString(String *self, const String *string) {
556
557 if (string) {
558 $(self, appendCharacters, string->chars);
559 }
560}
561
566static void appendVaList(String *self, const char *fmt, va_list args) {
567 char *chars;
568
569 const int len = vasprintf(&chars, fmt, args);
570 if (len > 0) {
571 $(self, appendCharacters, chars);
572 }
573
574 free(chars);
575}
576
581static void deleteCharactersInRange(String *self, const Range range) {
582
583 assert(range.location >= 0);
584 assert(range.length <= self->length);
585
586 ident ptr = self->chars + range.location;
587 const size_t length = self->length - range.location - range.length + 1;
588
589 memmove(ptr, ptr + range.length, length);
590
591 self->length -= range.length;
592}
593
598static String *init(String *self) {
599 return $(self, initWithCapacity, 0);
600}
601
606static String *initWithBytes(String *self, const uint8_t *bytes, size_t length, StringEncoding encoding) {
607
608 self = $(self, init);
609 if (self) {
610 $(self, appendBytes, bytes, length, encoding);
611 }
612
613 return self;
614}
615
620static String *initWithCapacity(String *self, size_t capacity) {
621
622 self = $(self, initWithMemory, NULL, 0);
623 if (self) {
624 self->capacity = capacity;
625 if (self->capacity) {
626 self->chars = calloc(self->capacity, sizeof(char));
627 assert(self->chars);
628 }
629 }
630
631 return self;
632}
633
638static String *initWithCharacters(String *self, const char *chars) {
639
640 self = $(self, init);
641 if (self) {
642 $(self, appendCharacters, chars);
643 }
644
645 return self;
646}
647
652static String *initWithContentsOfFile(String *self, const char *path, StringEncoding encoding) {
653
654 Data *data = $$(Data, dataWithContentsOfFile, path);
655 if (data) {
656 self = $(self, initWithData, data, encoding);
657 } else {
658 self = $(self, init);
659 }
660
661 release(data);
662 return self;
663}
664
669static String *initWithData(String *self, const Data *data, StringEncoding encoding) {
670
671 assert(data);
672
673 return $(self, initWithBytes, data->bytes, data->length, encoding);
674}
675
680static String *initWithFormat(String *self, const char *fmt, ...) {
681
682 self = $(self, init);
683 if (self) {
684
685 va_list args;
686 va_start(args, fmt);
687
688 $(self, appendVaList, fmt, args);
689
690 va_end(args);
691 }
692
693 return self;
694}
695
700static String *initWithMemory(String *self, const ident mem, size_t length) {
701
702 self = (String *) super(Object, self, init);
703 if (self) {
704 self->chars = (char *) mem;
705 self->length = length;
706 self->capacity = self->chars ? length + 1 : 0;
707 }
708
709 return self;
710}
711
716static String *initWithString(String *self, const String *string) {
717
718 self = $(self, init);
719 if (self) {
720 $(self, appendString, string);
721 }
722
723 return self;
724}
725
730static String *initWithVaList(String *self, const char *fmt, va_list args) {
731
732 self = $(self, init);
733 if (self) {
734 $(self, appendVaList, fmt, args);
735 }
736
737 return self;
738}
739
744static void insertCharactersAtIndex(String *self, const char *chars, size_t index) {
745
746 const Range range = { .location = index };
747
748 $(self, replaceCharactersInRange, range, chars);
749}
750
755static void insertStringAtIndex(String *self, const String *string, size_t index) {
756
757 $(self, insertCharactersAtIndex, string->chars, index);
758}
759
764static void replaceCharactersInRange(String *self, const Range range, const char *chars) {
765
766 assert(range.location >= 0);
767 assert(range.location + range.length <= self->length);
768
769 if (self->capacity == 0) {
770 $(self, appendCharacters, chars);
771 } else {
772 char *remainder = strdup(self->chars + range.location + range.length);
773
774 self->length = range.location;
775 self->chars[range.location + 1] = '\0';
776
777 $(self, appendCharacters, chars);
778 $(self, appendCharacters, remainder);
779
780 free(remainder);
781 }
782}
783
788static void replaceOccurrencesOfCharacters(String *self, const char *chars, const char *replacement) {
789 $(self, replaceOccurrencesOfCharactersInRange, chars, (Range) { .length = self->length }, replacement);
790}
791
796static void replaceOccurrencesOfCharactersInRange(String *self, const char *chars, const Range range, const char *replacement) {
797
798 assert(chars);
799 assert(replacement);
800
801 assert(range.location >= 0);
802 assert(range.location + range.length <= self->length);
803
804 Range search = range;
805 while (true) {
806
807 const Range result = $((String *) self, rangeOfCharacters, chars, search);
808 if (result.location == -1) {
809 break;
810 }
811
812 $(self, replaceCharactersInRange, result, replacement);
813
814 search.length -= (result.location - search.location);
815 search.length -= strlen(replacement);
816 search.length += ((int) strlen(replacement) - (int) strlen(chars));
817
818 search.location = result.location + strlen(replacement);
819 }
820}
821
826static void replaceOccurrencesOfString(String *self, const String *string, const String *replacement) {
827 $(self, replaceOccurrencesOfStringInRange, string, (Range) { .length = self->length }, replacement);
828}
829
834static void replaceOccurrencesOfStringInRange(String *self, const String *string, const Range range, const String *replacement) {
835
836 assert(string);
837 assert(replacement);
838
839 $(self, replaceOccurrencesOfCharactersInRange, string->chars, range, replacement->chars);
840}
841
846static void replaceStringInRange(String *self, const Range range, const String *string) {
847
848 $(self, replaceCharactersInRange, range, string->chars);
849}
850
855static void setCharacters(String *self, const char *chars) {
856
857 $(self, setLength, 0);
858
859 $(self, appendCharacters, chars);
860}
861
866static void setFormat(String *self, const char *fmt, ...) {
867
868 $(self, setLength, 0);
869
870 va_list args;
871 va_start(args, fmt);
872
873 $(self, appendVaList, fmt, args);
874
875 va_end(args);
876}
877
882static void setLength(String *self, size_t length) {
883
884 if (length < self->length) {
885 self->length = length;
886 self->chars[length] = '\0';
887 }
888}
889
894static void setString(String *self, const String *string) {
895
896 $(self, setLength, 0);
897
898 $(self, appendString, string);
899}
900
905static String *string(void) {
906 return $(alloc(String), init);
907}
908
913static String *stringWithCapacity(size_t capacity) {
914 return $(alloc(String), initWithCapacity, capacity);
915}
916
921static void trim(String *self) {
922
923 String *trimmed = $((String *) self, trimmedString);
924
925 $(self, replaceStringInRange, (const Range) { .length = self->length }, trimmed);
926
927 release(trimmed);
928}
929
930#pragma mark - Class lifecycle
931
935static void initialize(Class *clazz) {
936
937 ((ObjectInterface *) clazz->interface)->copy = copy;
938 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
939 ((ObjectInterface *) clazz->interface)->description = description;
940 ((ObjectInterface *) clazz->interface)->hash = hash;
941 ((ObjectInterface *) clazz->interface)->isEqual = isEqual;
942
943 ((StringInterface *) clazz->interface)->compareTo = compareTo;
944 ((StringInterface *) clazz->interface)->componentsSeparatedByCharacters = componentsSeparatedByCharacters;
945 ((StringInterface *) clazz->interface)->componentsSeparatedByString = componentsSeparatedByString;
946 ((StringInterface *) clazz->interface)->getData = getData;
947 ((StringInterface *) clazz->interface)->hasPrefix = hasPrefix;
948 ((StringInterface *) clazz->interface)->hasSuffix = hasSuffix;
949 ((StringInterface *) clazz->interface)->initWithBytes = initWithBytes;
950 ((StringInterface *) clazz->interface)->initWithCharacters = initWithCharacters;
951 ((StringInterface *) clazz->interface)->initWithContentsOfFile = initWithContentsOfFile;
952 ((StringInterface *) clazz->interface)->initWithData = initWithData;
953 ((StringInterface *) clazz->interface)->initWithFormat = initWithFormat;
954 ((StringInterface *) clazz->interface)->initWithMemory = initWithMemory;
955 ((StringInterface *) clazz->interface)->initWithVaList = initWithVaList;
956 ((StringInterface *) clazz->interface)->lowercaseString = lowercaseString;
957 ((StringInterface *) clazz->interface)->appendBytes = appendBytes;
958 ((StringInterface *) clazz->interface)->appendCharacters = appendCharacters;
959 ((StringInterface *) clazz->interface)->appendFormat = appendFormat;
960 ((StringInterface *) clazz->interface)->appendString = appendString;
961 ((StringInterface *) clazz->interface)->appendVaList = appendVaList;
962 ((StringInterface *) clazz->interface)->deleteCharactersInRange = deleteCharactersInRange;
963 ((StringInterface *) clazz->interface)->init = init;
964 ((StringInterface *) clazz->interface)->initWithCapacity = initWithCapacity;
965 ((StringInterface *) clazz->interface)->initWithString = initWithString;
966 ((StringInterface *) clazz->interface)->insertCharactersAtIndex = insertCharactersAtIndex;
967 ((StringInterface *) clazz->interface)->insertStringAtIndex = insertStringAtIndex;
968 ((StringInterface *) clazz->interface)->replaceCharactersInRange = replaceCharactersInRange;
969 ((StringInterface *) clazz->interface)->replaceOccurrencesOfCharacters = replaceOccurrencesOfCharacters;
970 ((StringInterface *) clazz->interface)->replaceOccurrencesOfCharactersInRange = replaceOccurrencesOfCharactersInRange;
971 ((StringInterface *) clazz->interface)->replaceOccurrencesOfString = replaceOccurrencesOfString;
972 ((StringInterface *) clazz->interface)->replaceOccurrencesOfStringInRange = replaceOccurrencesOfStringInRange;
973 ((StringInterface *) clazz->interface)->replaceStringInRange = replaceStringInRange;
974 ((StringInterface *) clazz->interface)->setCharacters = setCharacters;
975 ((StringInterface *) clazz->interface)->setFormat = setFormat;
976 ((StringInterface *) clazz->interface)->setLength = setLength;
977 ((StringInterface *) clazz->interface)->setString = setString;
978 ((StringInterface *) clazz->interface)->string = string;
979 ((StringInterface *) clazz->interface)->stringWithCapacity = stringWithCapacity;
980 ((StringInterface *) clazz->interface)->trim = trim;
981 ((StringInterface *) clazz->interface)->rangeOfCharacters = rangeOfCharacters;
982 ((StringInterface *) clazz->interface)->rangeOfString = rangeOfString;
983 ((StringInterface *) clazz->interface)->stringWithBytes = stringWithBytes;
984 ((StringInterface *) clazz->interface)->stringWithCharacters = stringWithCharacters;
985 ((StringInterface *) clazz->interface)->stringWithContentsOfFile = stringWithContentsOfFile;
986 ((StringInterface *) clazz->interface)->stringWithData = stringWithData;
987 ((StringInterface *) clazz->interface)->stringWithFormat = stringWithFormat;
988 ((StringInterface *) clazz->interface)->stringWithMemory = stringWithMemory;
989 ((StringInterface *) clazz->interface)->substring = substring;
990 ((StringInterface *) clazz->interface)->trimmedString = trimmedString;
991 ((StringInterface *) clazz->interface)->uppercaseString = uppercaseString;
992 ((StringInterface *) clazz->interface)->writeToFile = writeToFile;
993}
994
1000 static Class *clazz;
1001 static Once once;
1002
1003 do_once(&once, {
1004 clazz = _initialize(&(const ClassDef) {
1005 .name = "String",
1006 .superclass = _Object(),
1007 .instanceSize = sizeof(String),
1008 .interfaceOffset = offsetof(String, interface),
1009 .interfaceSize = sizeof(StringInterface),
1011 });
1012 });
1013
1014 return clazz;
1015}
1016
1017#undef _Class
1018
1020
1021 switch (encoding) {
1023 return "ASCII";
1025 return "ISO-8859-1";
1027 return "ISO-8859-2";
1029 return "MacRoman";
1031 return "UTF-16";
1033 return "UTF-32";
1035 return "UTF-8";
1037 return "WCHAR_T";
1038 }
1039
1040 return "ASCII";
1041}
1042
1044
1045 if (strcasecmp("ASCII", name) == 0) {
1046 return STRING_ENCODING_ASCII;
1047 } else if (strcasecmp("ISO-8859-1", name) == 0) {
1049 } else if (strcasecmp("ISO-8859-2", name) == 0) {
1051 } else if (strcasecmp("MacRoman", name) == 0) {
1053 } else if (strcasecmp("UTF-16", name) == 0) {
1054 return STRING_ENCODING_UTF16;
1055 } else if (strcasecmp("UTF-32", name) == 0) {
1056 return STRING_ENCODING_UTF32;
1057 } else if (strcasecmp("UTF-8", name) == 0) {
1058 return STRING_ENCODING_UTF8;
1059 } else if (strcasecmp("WCHAR", name) == 0) {
1060 return STRING_ENCODING_WCHAR;
1061 }
1062
1063 return STRING_ENCODING_ASCII;
1064}
1065
1066Order StringCompare(const ident a, const ident b) {
1067
1068 if (a) {
1069 if (b) {
1070 const int i = strcmp(((String *) a)->chars, ((String *) b)->chars);
1071 if (i == 0) {
1072 return OrderSame;
1073 }
1074 if (i > 0) {
1075 return OrderDescending;
1076 }
1077 } else {
1078 return OrderDescending;
1079 }
1080 }
1081 return OrderAscending;
1082}
1083
1084String *str(const char *fmt, ...) {
1085
1086 va_list args;
1087 va_start(args, fmt);
1088
1089 String *string = $(alloc(String), initWithVaList, fmt, args);
1090 assert(string);
1091
1092 va_end(args);
1093
1094 return string;
1095}
1096
1097char *strtrim(const char *s) {
1098
1099 assert(s);
1100 while (isspace(*s)) {
1101 s++;
1102 }
1103
1104 char *trimmed = strdup(s);
1105 assert(trimmed);
1106
1107 char *end = trimmed + strlen(trimmed);
1108 if (end > trimmed) {
1109 while (isspace(*(--end))) {
1110 *end = '\0';
1111 }
1112 }
1113
1114 return trimmed;
1115}
static void addObject(Array *self, const ident obj)
Definition Array.c:181
size_t _pageSize
Definition Class.c:39
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
Definition Class.c:195
Class * _initialize(const ClassDef *def)
Initializes the given Class.
Definition Class.c:86
#define alloc(type)
Allocate and initialize and instance of type.
Definition Class.h:176
#define super(type, obj, method,...)
static Data * data(void)
Definition Data.c:286
static Data * dataWithContentsOfFile(const char *path)
Definition Data.c:133
static Data * dataWithMemory(ident mem, size_t length)
Definition Data.c:142
int HashForCString(int hash, const char *string)
Accumulates the hash value of the null-terminated string into hash.
Definition Hash.c:51
Utilities for calculating hash values.
#define HASH_SEED
The hash seed value.
Definition Hash.h:37
static bool isKindOfClass(const Object *self, const Class *clazz)
Definition Object.c:101
Class * _Object(void)
Definition Object.c:136
Pointer * ptr(ident pointer, Consumer destroy)
Definition Pointer.c:157
static Range rangeOfString(const String *self, const String *string, const Range range)
Definition String.c:329
static String * initWithData(String *self, const Data *data, StringEncoding encoding)
Definition String.c:669
static void insertCharactersAtIndex(String *self, const char *chars, size_t index)
Definition String.c:744
static String * stringWithData(const Data *data, StringEncoding encoding)
Definition String.c:367
static void replaceOccurrencesOfCharactersInRange(String *self, const char *chars, const Range range, const char *replacement)
Definition String.c:796
static size_t transcode(Transcode *trans)
Transcodes input from one character encoding to another via iconv.
Definition String.c:131
static String * init(String *self)
Definition String.c:598
static String * initWithContentsOfFile(String *self, const char *path, StringEncoding encoding)
Definition String.c:652
static String * stringWithCapacity(size_t capacity)
Definition String.c:913
static bool writeToFile(const String *self, const char *path, StringEncoding encoding)
Definition String.c:459
static String * initWithCapacity(String *self, size_t capacity)
Definition String.c:620
static String * stringWithFormat(const char *fmt,...)
Definition String.c:376
static bool isEqual(const Object *self, const Object *other)
Definition String.c:90
static bool hasSuffix(const String *self, const String *suffix)
Definition String.c:263
static void deleteCharactersInRange(String *self, const Range range)
Definition String.c:581
static Range rangeOfCharacters(const String *self, const char *chars, const Range range)
Definition String.c:303
const char * NameForStringEncoding(StringEncoding encoding)
Definition String.c:1019
static void setString(String *self, const String *string)
Definition String.c:894
static String * description(const Object *self)
Definition String.c:72
static String * initWithString(String *self, const String *string)
Definition String.c:716
static String * initWithMemory(String *self, const ident mem, size_t length)
Definition String.c:700
static String * initWithFormat(String *self, const char *fmt,...)
Definition String.c:680
static bool hasPrefix(const String *self, const String *prefix)
Definition String.c:249
static String * uppercaseString(const String *self)
Definition String.c:437
static String * string(void)
Definition String.c:905
static void appendVaList(String *self, const char *fmt, va_list args)
Definition String.c:566
static void replaceCharactersInRange(String *self, const Range range, const char *chars)
Definition String.c:764
char * strtrim(const char *s)
Copies the given null-terminated C string, trimming leading and trailing whitespace.
Definition String.c:1097
String * str(const char *fmt,...)
Definition String.c:1084
static String * stringWithContentsOfFile(const char *path, StringEncoding encoding)
Definition String.c:358
static Array * componentsSeparatedByString(const String *self, const String *string)
Definition String.c:215
static void setLength(String *self, size_t length)
Definition String.c:882
static void setFormat(String *self, const char *fmt,...)
Definition String.c:866
static void trim(String *self)
Definition String.c:921
static String * lowercaseString(const String *self)
Definition String.c:281
static String * substring(const String *self, const Range range)
Definition String.c:401
static void dealloc(Object *self)
Definition String.c:60
static void replaceOccurrencesOfCharacters(String *self, const char *chars, const char *replacement)
Definition String.c:788
static String * initWithBytes(String *self, const uint8_t *bytes, size_t length, StringEncoding encoding)
Definition String.c:606
static void appendCharacters(String *self, const char *chars)
Definition String.c:506
static String * trimmedString(const String *self)
Definition String.c:417
static void appendFormat(String *self, const char *fmt,...)
Definition String.c:541
static String * stringWithCharacters(const char *chars)
Definition String.c:349
static Object * copy(const Object *self)
Definition String.c:49
static Array * componentsSeparatedByCharacters(const String *self, const char *chars)
Definition String.c:182
StringEncoding StringEncodingForName(const char *name)
Definition String.c:1043
static void initialize(Class *clazz)
Definition String.c:935
static void replaceOccurrencesOfString(String *self, const String *string, const String *replacement)
Definition String.c:826
static void appendBytes(String *self, const uint8_t *bytes, size_t length, StringEncoding encoding)
Definition String.c:476
static String * initWithVaList(String *self, const char *fmt, va_list args)
Definition String.c:730
static void appendString(String *self, const String *string)
Definition String.c:555
static Data * getData(const String *self, StringEncoding encoding)
Definition String.c:226
static String * stringWithMemory(const ident mem, size_t length)
Definition String.c:392
static void setCharacters(String *self, const char *chars)
Definition String.c:855
Class * _String(void)
Definition String.c:999
static void insertStringAtIndex(String *self, const String *string, size_t index)
Definition String.c:755
Order StringCompare(const ident a, const ident b)
Definition String.c:1066
static void replaceOccurrencesOfStringInRange(String *self, const String *string, const Range range, const String *replacement)
Definition String.c:834
static String * initWithCharacters(String *self, const char *chars)
Definition String.c:638
static void replaceStringInRange(String *self, const Range range, const String *string)
Definition String.c:846
static int hash(const Object *self)
Definition String.c:80
static Order compareTo(const String *self, const String *other, const Range range)
Definition String.c:161
static String * stringWithBytes(const uint8_t *bytes, size_t length, StringEncoding encoding)
Definition String.c:340
UTF-8 strings.
StringEncoding
Character encodings for Strings.
Definition String.h:46
@ STRING_ENCODING_LATIN1
Definition String.h:48
@ STRING_ENCODING_WCHAR
Definition String.h:54
@ STRING_ENCODING_UTF32
Definition String.h:52
@ STRING_ENCODING_MACROMAN
Definition String.h:50
@ STRING_ENCODING_UTF16
Definition String.h:51
@ STRING_ENCODING_ASCII
Definition String.h:47
@ STRING_ENCODING_LATIN2
Definition String.h:49
@ STRING_ENCODING_UTF8
Definition String.h:53
wchar_t Unicode
The Unicode type.
Definition String.h:41
void * ident
The identity type, similar to Objective-C id.
Definition Types.h:49
Order
Comparison constants.
Definition Types.h:70
@ OrderSame
Definition Types.h:72
@ OrderDescending
Definition Types.h:73
@ OrderAscending
Definition Types.h:71
long Once
The Once type.
Definition Once.h:37
#define do_once(once, block)
Executes the given block at most one time.
Definition Once.h:43
Arrays.
Definition Array.h:56
ClassDefs are passed to _initialize via an archetype to initialize a Class.
Definition Class.h:41
The runtime representation of a Class.
Definition Class.h:95
ident interface
The interface of the Class.
Definition Class.h:105
Data buffers.
Definition Data.h:50
size_t length
The length of bytes.
Definition Data.h:76
uint8_t * bytes
The bytes.
Definition Data.h:66
Data * initWithBytes(Data *self, const uint8_t *bytes, size_t length)
Initializes this Data by copying length of bytes.
Definition Data.c:151
Object is the root Class of The Objectively Class hierarchy.
Definition Object.h:46
int hash(const Object *self)
Definition Array.c:129
void dealloc(Object *self)
Frees all resources held by this Object.
Definition Array.c:99
A location and length into contiguous collections.
Definition Types.h:54
ssize_t location
The location.
Definition Types.h:59
size_t length
The length.
Definition Types.h:64
UTF-8 strings.
Definition String.h:69
String * uppercaseString(const String *self)
Definition String.c:437
char * chars
The backing null-terminated UTF-8 encoded character array.
Definition String.h:85
void appendBytes(String *self, const uint8_t *bytes, size_t length, StringEncoding encoding)
Appends the decoded contents of bytes.
Definition String.c:476
bool writeToFile(const String *self, const char *path, StringEncoding encoding)
Writes this String to path.
Definition String.c:459
String * initWithVaList(String *self, const char *fmt, va_list args)
Initializes this String with the specified arguments list.
Definition String.c:730
String * stringWithMemory(const ident mem, size_t length)
Returns a new String with the given buffer.
Definition String.c:392
size_t length
The length of the String in bytes.
Definition String.h:90
String * lowercaseString(const String *self)
Definition String.c:281
String * initWithCharacters(String *self, const char *chars)
Initializes this String by copying chars.
Definition String.c:638
String * trimmedString(const String *self)
Creates a copy of this String with leading and trailing whitespace removed.
Definition String.c:417
String * stringWithData(const Data *data, StringEncoding encoding)
Returns a new String with the the given Data.
Definition String.c:367
String * stringWithFormat(const char *fmt)
Returns a new String with the given format string.
String * initWithMemory(String *self, const ident mem, size_t length)
Initializes this String with the specified buffer.
Definition String.c:700
void insertCharactersAtIndex(String *self, const char *chars, size_t index)
Inserts the specified String at the given index.
Definition String.c:744
String * stringWithCapacity(size_t capacity)
Returns a new String with the given capacity.
Definition String.c:913
String * substring(const String *string, const Range range)
Creates a new String from a subset of this one.
Definition String.c:401
String * initWithData(String *self, const Data *data, StringEncoding encoding)
Initializes this String with the given Data.
Definition String.c:669
String * initWithContentsOfFile(String *self, const char *path, StringEncoding encoding)
Initializes this String with the contents of the FILE at path.
Definition String.c:652
void trim(String *self)
Trims leading and trailing whitespace from this String.
Definition String.c:921
String * initWithString(String *self, const String *string)
Initializes this String with the contents of string.
Definition String.c:716
String * initWithCapacity(String *self, size_t capacity)
Initializes this String with the given capacity.
Definition String.c:620
String * initWithFormat(String *self, const char *fmt,...)
Initializes this String with the specified format string.
Definition String.c:680
String * stringWithContentsOfFile(const char *path, StringEncoding encoding)
Returns a new String with the contents of the FILE at path.
Definition String.c:358
String * stringWithCharacters(const char *chars)
Returns a new String by copying chars.
Definition String.c:349
Character transcoding context for iconv.
Definition String.c:117
char * out
Definition String.c:122
char * in
Definition String.c:120
size_t length
Definition String.c:121
StringEncoding from
Definition String.c:119
size_t size
Definition String.c:123
StringEncoding to
Definition String.c:118