| 1 | // ============================================================= // |
|---|
| 2 | // // |
|---|
| 3 | // File : arb_strbuf.h // |
|---|
| 4 | // Purpose : "unlimited" output buffer // |
|---|
| 5 | // // |
|---|
| 6 | // Institute of Microbiology (Technical University Munich) // |
|---|
| 7 | // http://www.arb-home.de/ // |
|---|
| 8 | // // |
|---|
| 9 | // ============================================================= // |
|---|
| 10 | |
|---|
| 11 | #ifndef ARB_STRBUF_H |
|---|
| 12 | #define ARB_STRBUF_H |
|---|
| 13 | |
|---|
| 14 | #ifndef ARBTOOLS_H |
|---|
| 15 | #include <arbtools.h> |
|---|
| 16 | #endif |
|---|
| 17 | #ifndef ARB_ASSERT_H |
|---|
| 18 | #include <arb_assert.h> |
|---|
| 19 | #endif |
|---|
| 20 | #ifndef ARB_MEM_H |
|---|
| 21 | #include "arb_mem.h" |
|---|
| 22 | #endif |
|---|
| 23 | #ifndef ATTRIBUTES_H |
|---|
| 24 | #include <attributes.h> |
|---|
| 25 | #endif |
|---|
| 26 | #ifndef ARB_STRING_H |
|---|
| 27 | #include "arb_string.h" |
|---|
| 28 | #endif |
|---|
| 29 | #ifndef _GLIBCXX_ALGORITHM |
|---|
| 30 | #include <algorithm> |
|---|
| 31 | #endif |
|---|
| 32 | |
|---|
| 33 | |
|---|
| 34 | // ----------------------- |
|---|
| 35 | // String streams |
|---|
| 36 | |
|---|
| 37 | class GBS_strstruct : virtual Noncopyable { |
|---|
| 38 | char *data; |
|---|
| 39 | size_t buffer_size; |
|---|
| 40 | size_t pos; |
|---|
| 41 | |
|---|
| 42 | void set_pos(size_t toPos) { |
|---|
| 43 | pos = toPos; |
|---|
| 44 | if (data) data[pos] = 0; |
|---|
| 45 | } |
|---|
| 46 | void inc_pos(size_t inc) { set_pos(pos+inc); } |
|---|
| 47 | |
|---|
| 48 | public: |
|---|
| 49 | |
|---|
| 50 | GBS_strstruct() : |
|---|
| 51 | data(NULp), |
|---|
| 52 | buffer_size(0), |
|---|
| 53 | pos(0) |
|---|
| 54 | {} |
|---|
| 55 | GBS_strstruct(size_t buffersize) : |
|---|
| 56 | data(NULp), |
|---|
| 57 | buffer_size(0), |
|---|
| 58 | pos(0) |
|---|
| 59 | { |
|---|
| 60 | alloc_mem(buffersize); |
|---|
| 61 | } |
|---|
| 62 | ~GBS_strstruct() { free(data); } |
|---|
| 63 | |
|---|
| 64 | size_t get_buffer_size() const { return buffer_size; } |
|---|
| 65 | size_t get_position() const { return pos; } // = length of string |
|---|
| 66 | |
|---|
| 67 | bool filled() const { return get_position()>0; } |
|---|
| 68 | bool empty() const { return !filled(); } |
|---|
| 69 | |
|---|
| 70 | const char *get_data() const { return null2empty(data); } |
|---|
| 71 | char *get_copy() const { return ARB_strndup(get_data(), get_position()); } |
|---|
| 72 | |
|---|
| 73 | char *release_mem(size_t& size) { |
|---|
| 74 | char *result = data; |
|---|
| 75 | size = buffer_size; |
|---|
| 76 | buffer_size = 0; |
|---|
| 77 | data = NULp; |
|---|
| 78 | return result; |
|---|
| 79 | } |
|---|
| 80 | char *release() { size_t s; return release_mem(s); } |
|---|
| 81 | |
|---|
| 82 | void erase() { set_pos(0); } |
|---|
| 83 | |
|---|
| 84 | void assign_mem(char *block, size_t blocksize) { |
|---|
| 85 | free(data); |
|---|
| 86 | |
|---|
| 87 | arb_assert(block && blocksize>0); |
|---|
| 88 | |
|---|
| 89 | data = block; |
|---|
| 90 | buffer_size = blocksize; |
|---|
| 91 | |
|---|
| 92 | erase(); |
|---|
| 93 | } |
|---|
| 94 | void reassign_mem(GBS_strstruct& from) { |
|---|
| 95 | size_t size; |
|---|
| 96 | char *block = from.release_mem(size); |
|---|
| 97 | |
|---|
| 98 | assign_mem(block, size); |
|---|
| 99 | } |
|---|
| 100 | void swap_content(GBS_strstruct& other) { |
|---|
| 101 | std::swap(data, other.data); |
|---|
| 102 | std::swap(buffer_size, other.buffer_size); |
|---|
| 103 | std::swap(pos, other.pos); |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | void alloc_mem(size_t blocksize) { |
|---|
| 107 | arb_assert(blocksize>0); |
|---|
| 108 | arb_assert(!data); |
|---|
| 109 | |
|---|
| 110 | assign_mem(ARB_alloc<char>(blocksize), blocksize); |
|---|
| 111 | } |
|---|
| 112 | void realloc_mem(size_t newsize) { |
|---|
| 113 | if (!data) alloc_mem(newsize); |
|---|
| 114 | else { |
|---|
| 115 | // cppcheck-suppress memleakOnRealloc |
|---|
| 116 | ARB_realloc(data, newsize); |
|---|
| 117 | buffer_size = newsize; |
|---|
| 118 | |
|---|
| 119 | arb_assert(pos<newsize); |
|---|
| 120 | } |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | void ensure_mem(size_t needed_size) { |
|---|
| 124 | // ensures insertion of 'needed_size' bytes is ok |
|---|
| 125 | size_t whole_needed_size = pos+needed_size+1; |
|---|
| 126 | if (buffer_size<whole_needed_size) { |
|---|
| 127 | size_t next_size = (whole_needed_size * 3) >> 1; |
|---|
| 128 | realloc_mem(next_size); |
|---|
| 129 | } |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | // -------------------- |
|---|
| 133 | |
|---|
| 134 | void cut_tail(size_t byte_count) { |
|---|
| 135 | set_pos(pos<byte_count ? 0 : pos-byte_count); |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | void put(char c) { |
|---|
| 139 | ensure_mem(1); |
|---|
| 140 | data[pos] = c; |
|---|
| 141 | inc_pos(1); |
|---|
| 142 | } |
|---|
| 143 | void nput(char c, size_t count) { |
|---|
| 144 | ensure_mem(count); |
|---|
| 145 | if (count) { |
|---|
| 146 | memset(data+pos, c, count); |
|---|
| 147 | inc_pos(count); |
|---|
| 148 | } |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | void ncat(const char *from, size_t count) { |
|---|
| 152 | if (count) { |
|---|
| 153 | ensure_mem(count); |
|---|
| 154 | memcpy(data+pos, from, count); |
|---|
| 155 | inc_pos(count); |
|---|
| 156 | } |
|---|
| 157 | } |
|---|
| 158 | void cat(const char *from) { ncat(from, strlen(from)); } |
|---|
| 159 | |
|---|
| 160 | int ncatTrimmed(const char *from, size_t count, size_t trimmedWidth) { |
|---|
| 161 | ensure_mem(std::max(count, trimmedWidth)); |
|---|
| 162 | ncat(from, count); |
|---|
| 163 | int toTrim = long(trimmedWidth)-long(count); |
|---|
| 164 | if (toTrim>0) nput(' ', toTrim); |
|---|
| 165 | return toTrim; |
|---|
| 166 | } |
|---|
| 167 | int catTrimmed(const char *from, size_t trimmedWidth) { |
|---|
| 168 | // cat 'from'. |
|---|
| 169 | // append spaces to trim to 'trimmedWidth'. |
|---|
| 170 | // return number of spaces appended or |
|---|
| 171 | // a negative number (strlen('from')-'trimmedWidth'. |
|---|
| 172 | |
|---|
| 173 | return ncatTrimmed(from, strlen(from), trimmedWidth); |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | void vnprintf(size_t maxlen, const char *templat, va_list& parg) __ATTR__VFORMAT_MEMBER(2); |
|---|
| 177 | void nprintf(size_t maxlen, const char *templat, ...) __ATTR__FORMAT_MEMBER(2); |
|---|
| 178 | |
|---|
| 179 | void putlong(long l) { nprintf(100, "%li", l); } |
|---|
| 180 | void putfloat(float f) { nprintf(100, "%f", f); } |
|---|
| 181 | }; |
|---|
| 182 | |
|---|
| 183 | // old interface |
|---|
| 184 | |
|---|
| 185 | GBS_strstruct *GBS_stropen(long init_size); |
|---|
| 186 | char *GBS_strclose(GBS_strstruct *strstr); |
|---|
| 187 | void GBS_strforget(GBS_strstruct *strstr); |
|---|
| 188 | char *GBS_mempntr(GBS_strstruct *strstr); |
|---|
| 189 | long GBS_memoffset(GBS_strstruct *strstr); |
|---|
| 190 | void GBS_str_cut_tail(GBS_strstruct *strstr, size_t byte_count); |
|---|
| 191 | void GBS_strncat(GBS_strstruct *strstr, const char *ptr, size_t len); |
|---|
| 192 | void GBS_strcat(GBS_strstruct *strstr, const char *ptr); |
|---|
| 193 | void GBS_strnprintf(GBS_strstruct *strstr, long maxlen, const char *templat, ...) __ATTR__FORMAT(3); |
|---|
| 194 | void GBS_chrcat(GBS_strstruct *strstr, char ch); |
|---|
| 195 | void GBS_chrncat(GBS_strstruct *strstr, char ch, size_t n); |
|---|
| 196 | void GBS_intcat(GBS_strstruct *strstr, long val); |
|---|
| 197 | void GBS_floatcat(GBS_strstruct *strstr, double val); |
|---|
| 198 | |
|---|
| 199 | #else |
|---|
| 200 | #error arb_strbuf.h included twice |
|---|
| 201 | #endif // ARB_STRBUF_H |
|---|