/* Copyright (C) 2007-2008 The Android Open Source Project ** ** This software is licensed under the terms of the GNU General Public ** License version 2, as published by the Free Software Foundation, and ** may be copied, distributed, and modified under those terms. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. */ #include "android/utils/stralloc.h" #include "android/utils/debug.h" #include "android/utils/misc.h" #include #include #include #include extern void stralloc_tabular( stralloc_t* out, const char** strings, int count, const char* prefix, int width ) { int nrows, ncols, r, c, n, maxw = 0; for (n = 0; n < count; n++) { int len = strlen(strings[n]); if (len > maxw) maxw = len; } maxw += 2; ncols = width/maxw; nrows = (count + ncols-1)/ncols; for (r = 0; r < nrows; r++) { stralloc_add_str( out, prefix ); for (c = 0; c < ncols; c++) { int index = c*nrows + r; if (index >= count) { break; } stralloc_add_format( out, "%-*s", maxw, strings[index] ); } stralloc_add_str( out, "\n" ); } } /** DYNAMIC STRINGS **/ extern void stralloc_reset( stralloc_t* s ) { free(s->s); s->s = NULL; s->n = 0; s->a = 0; } extern void stralloc_ready( stralloc_t* s, unsigned int len ) { unsigned old_max = s->a; unsigned new_max = old_max; while (new_max < len) { unsigned new_max2 = new_max + (new_max >> 1) + 16; if (new_max2 < new_max) new_max2 = UINT_MAX; new_max = new_max2; } s->s = realloc( s->s, new_max ); if (s->s == NULL) { derror( "%s: not enough memory to reallocate %ld bytes", __FUNCTION__, new_max ); exit(1); } s->a = new_max; } extern void stralloc_readyplus( stralloc_t* s, unsigned int len ) { unsigned len2 = s->n + len; if (len2 < s->n) { /* overflow ? */ derror("%s: trying to grow by too many bytes: %ld", __FUNCTION__, len); exit(1); } stralloc_ready( s, len2 ); } extern void stralloc_copy( stralloc_t* s, stralloc_t* from ) { stralloc_ready(s, from->n); memcpy( s->s, from->s, from->n ); s->n = from->n; } extern void stralloc_append( stralloc_t* s, stralloc_t* from ) { stralloc_readyplus( s, from->n ); memcpy( s->s + s->n, from->s, from->n ); s->n += from->n; } extern void stralloc_add_c( stralloc_t* s, int c ) { stralloc_add_bytes( s, (char*)&c, 1 ); } extern void stralloc_add_str( stralloc_t* s, const char* str ) { stralloc_add_bytes( s, str, strlen(str) ); } extern void stralloc_add_bytes( stralloc_t* s, const void* from, unsigned len ) { stralloc_readyplus( s, len ); memcpy( s->s + s->n, from, len ); s->n += len; } extern char* stralloc_cstr( stralloc_t* s ) { stralloc_readyplus( s, 1 ); s->s[s->n] = 0; return s->s; } void stralloc_lstrip( stralloc_t* s ) { int count; for (count = 0; count < s->n; count++) { if (s->s[count] != ' ' && s->s[count] != '\t') break; } if (count > 0) { memmove(s->s, s->s + count, s->n - count); s->n -= count; } } void stralloc_rstrip( stralloc_t* s ) { int count = s->n; while (count > 0 && (s->s[count-1] == ' ' || s->s[count-1] == '\t')) count--; s->n = count; } void stralloc_strip( stralloc_t* s ) { stralloc_rstrip(s); stralloc_lstrip(s); } extern char* stralloc_to_tempstr( stralloc_t* s ) { char* q = tempstr_get( s->n ); memcpy( q, s->s, s->n ); q[s->n] = 0; return q; } extern void stralloc_formatv( stralloc_t* s, const char* fmt, va_list args ) { stralloc_reset(s); stralloc_ready(s,10); while (1) { int n; va_list args2; va_copy(args2, args); n = vsnprintf( s->s, s->a, fmt, args2 ); va_end(args2); /* funky old C libraries returns -1 when truncation occurs */ if (n > -1 && n < s->a) { s->n = n; break; } if (n > -1) { /* we now precisely what we need */ stralloc_ready( s, n+1 ); } else { stralloc_ready( s, s->a*2 ); } } } extern void stralloc_format( stralloc_t* s, const char* fmt, ... ) { va_list args; va_start(args, fmt); stralloc_formatv(s, fmt, args); va_end(args); } extern void stralloc_add_formatv( stralloc_t* s, const char* fmt, va_list args ) { STRALLOC_DEFINE(s2); stralloc_formatv(s2, fmt, args); stralloc_append( s, s2 ); stralloc_reset( s2 ); } extern void stralloc_add_format( stralloc_t* s, const char* fmt, ... ) { va_list args; va_start(args, fmt); stralloc_add_formatv( s, fmt, args ); va_end(args); } extern void stralloc_add_quote_c( stralloc_t* s, int c ) { stralloc_add_quote_bytes( s, (char*)&c, 1 ); } extern void stralloc_add_quote_str( stralloc_t* s, const char* str ) { stralloc_add_quote_bytes( s, str, strlen(str) ); } extern void stralloc_add_quote_bytes( stralloc_t* s, const void* from, unsigned len ) { uint8_t* p = (uint8_t*) from; uint8_t* end = p + len; for ( ; p < end; p++ ) { int c = p[0]; if (c == '\\') { stralloc_add_str( s, "\\\\" ); } else if (c >= ' ' && c < 128) { stralloc_add_c( s, c ); } else if (c == '\n') { stralloc_add_str( s, "\\n" ); } else if (c == '\t') { stralloc_add_str( s, "\\t" ); } else if (c == '\r') { stralloc_add_str( s, "\\r" ); } else { stralloc_add_format( s, "\\x%02x", c ); } } } extern void stralloc_add_hex( stralloc_t* s, unsigned value, int num_digits ) { const char hexdigits[16] = "0123456789abcdef"; int nn; if (num_digits <= 0) return; stralloc_readyplus(s, num_digits); for (nn = num_digits-1; nn >= 0; nn--) { s->s[s->n+nn] = hexdigits[value & 15]; value >>= 4; } s->n += num_digits; } extern void stralloc_add_hexdump( stralloc_t* s, void* base, int size, const char* prefix ) { uint8_t* p = (uint8_t*)base; const int max_count = 16; int prefix_len = strlen(prefix); while (size > 0) { int count = size > max_count ? max_count : size; int count2; int n; stralloc_add_bytes( s, prefix, prefix_len ); stralloc_add_hex( s, p[0], 2 ); for (n = 1; n < count; n++) { stralloc_add_c( s, ' ' ); stralloc_add_hex( s, p[n], 2 ); } count2 = 4 + 3*(max_count - count); stralloc_readyplus( s, count2 ); memset( s->s + s->n, ' ', count2 ); s->n += count2; stralloc_readyplus(s, count+1); for (n = 0; n < count; n++) { int c = p[n]; if (c < 32 || c > 127) c = '.'; s->s[s->n++] = c; } s->s[s->n++] = '\n'; size -= count; p += count; } }