1/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12
13#include "android/utils/stralloc.h"
14#include "android/utils/debug.h"
15#include "android/utils/misc.h"
16#include <string.h>
17#include <stdlib.h>
18#include <stdio.h>
19#include <limits.h>
20
21extern void
22stralloc_tabular( stralloc_t*  out,
23                  const char** strings, int  count,
24                  const char*  prefix,  int  width )
25{
26    int  nrows, ncols, r, c, n, maxw = 0;
27
28    for (n = 0; n < count; n++) {
29        int  len = strlen(strings[n]);
30        if (len > maxw)
31            maxw = len;
32    }
33    maxw += 2;
34    ncols = width/maxw;
35    nrows = (count + ncols-1)/ncols;
36
37    for (r = 0; r < nrows; r++) {
38        stralloc_add_str( out, prefix );
39        for (c = 0; c < ncols; c++) {
40            int  index = c*nrows + r;
41            if (index >= count) {
42                break;
43            }
44            stralloc_add_format( out, "%-*s", maxw, strings[index] );
45        }
46        stralloc_add_str( out, "\n" );
47    }
48}
49
50/** DYNAMIC STRINGS
51 **/
52
53extern void
54stralloc_reset( stralloc_t*  s )
55{
56    free(s->s);
57    s->s = NULL;
58    s->n = 0;
59    s->a = 0;
60}
61
62extern void
63stralloc_ready( stralloc_t*  s, unsigned int  len )
64{
65    unsigned  old_max = s->a;
66    unsigned  new_max = old_max;
67
68    while (new_max < len) {
69        unsigned  new_max2 = new_max + (new_max >> 1) + 16;
70        if (new_max2 < new_max)
71            new_max2 = UINT_MAX;
72        new_max = new_max2;
73    }
74
75    s->s = realloc( s->s, new_max );
76    if (s->s == NULL) {
77        derror( "%s: not enough memory to reallocate %ld bytes",
78                __FUNCTION__, new_max );
79        exit(1);
80    }
81    s->a = new_max;
82}
83
84extern void
85stralloc_readyplus( stralloc_t*  s, unsigned int  len )
86{
87    unsigned  len2 = s->n + len;
88
89    if (len2 < s->n) { /* overflow ? */
90        derror("%s: trying to grow by too many bytes: %ld",
91               __FUNCTION__, len);
92        exit(1);
93    }
94    stralloc_ready( s, len2 );
95}
96
97extern void
98stralloc_copy( stralloc_t*  s, stralloc_t*  from )
99{
100    stralloc_ready(s, from->n);
101    memcpy( s->s, from->s, from->n );
102    s->n = from->n;
103}
104
105extern void
106stralloc_append( stralloc_t*  s, stralloc_t*  from )
107{
108    stralloc_readyplus( s, from->n );
109    memcpy( s->s + s->n, from->s, from->n );
110    s->n += from->n;
111}
112
113extern void
114stralloc_add_c( stralloc_t*  s, int  c )
115{
116    stralloc_add_bytes( s, (char*)&c, 1 );
117}
118
119extern void
120stralloc_add_str( stralloc_t*  s, const char*  str )
121{
122    stralloc_add_bytes( s, str, strlen(str) );
123}
124
125extern void
126stralloc_add_bytes( stralloc_t*  s, const void*  from, unsigned len )
127{
128    stralloc_readyplus( s, len );
129    memcpy( s->s + s->n, from, len );
130    s->n += len;
131}
132
133extern char*
134stralloc_cstr( stralloc_t*  s )
135{
136    stralloc_readyplus( s, 1 );
137    s->s[s->n] = 0;
138    return s->s;
139}
140
141void
142stralloc_lstrip( stralloc_t*  s )
143{
144    int  count;
145
146    for (count = 0; count < s->n; count++) {
147        if (s->s[count] != ' ' && s->s[count] != '\t')
148            break;
149    }
150
151    if (count > 0) {
152        memmove(s->s, s->s + count, s->n - count);
153        s->n -= count;
154    }
155}
156
157void
158stralloc_rstrip( stralloc_t*  s )
159{
160    int  count = s->n;
161
162    while (count > 0 && (s->s[count-1] == ' ' || s->s[count-1] == '\t'))
163        count--;
164
165    s->n = count;
166}
167
168void
169stralloc_strip( stralloc_t* s )
170{
171    stralloc_rstrip(s);
172    stralloc_lstrip(s);
173}
174
175extern char*
176stralloc_to_tempstr( stralloc_t*  s )
177{
178    char*  q = tempstr_get( s->n );
179
180    memcpy( q, s->s, s->n );
181    q[s->n] = 0;
182    return q;
183}
184
185extern void
186stralloc_formatv( stralloc_t*  s, const char*  fmt, va_list  args )
187{
188    stralloc_reset(s);
189    stralloc_ready(s,10);
190
191    while (1) {
192        int      n;
193        va_list  args2;
194
195        va_copy(args2, args);
196        n = vsnprintf( s->s, s->a, fmt, args2 );
197        va_end(args2);
198
199        /* funky old C libraries returns -1 when truncation occurs */
200        if (n > -1 && n < s->a) {
201            s->n = n;
202            break;
203        }
204        if (n > -1) {  /* we now precisely what we need */
205            stralloc_ready( s, n+1 );
206        } else {
207            stralloc_ready( s, s->a*2 );
208        }
209    }
210}
211
212
213extern void
214stralloc_format( stralloc_t*  s, const char*  fmt, ... )
215{
216    va_list  args;
217    va_start(args, fmt);
218    stralloc_formatv(s, fmt, args);
219    va_end(args);
220}
221
222extern void
223stralloc_add_formatv( stralloc_t*  s, const char*  fmt, va_list  args )
224{
225    STRALLOC_DEFINE(s2);
226    stralloc_formatv(s2, fmt, args);
227    stralloc_append( s, s2 );
228    stralloc_reset( s2 );
229}
230
231extern void
232stralloc_add_format( stralloc_t*  s, const char*  fmt, ... )
233{
234    va_list  args;
235    va_start(args, fmt);
236    stralloc_add_formatv( s, fmt, args );
237    va_end(args);
238}
239
240extern void
241stralloc_add_quote_c( stralloc_t*  s, int  c )
242{
243    stralloc_add_quote_bytes( s, (char*)&c, 1 );
244}
245
246extern void
247stralloc_add_quote_str( stralloc_t*  s, const char*  str )
248{
249    stralloc_add_quote_bytes( s, str, strlen(str) );
250}
251
252extern void
253stralloc_add_quote_bytes( stralloc_t*  s, const void*  from, unsigned  len )
254{
255    uint8_t*   p   = (uint8_t*) from;
256    uint8_t*   end = p + len;
257
258    for ( ; p < end; p++ ) {
259        int  c = p[0];
260
261        if (c == '\\') {
262            stralloc_add_str( s, "\\\\" );
263        } else if (c >= ' ' && c < 128) {
264            stralloc_add_c( s, c );
265        } else if (c == '\n') {
266            stralloc_add_str( s, "\\n" );
267        } else if (c == '\t') {
268            stralloc_add_str( s, "\\t" );
269        } else if (c == '\r') {
270            stralloc_add_str( s, "\\r" );
271        } else {
272            stralloc_add_format( s, "\\x%02x", c );
273        }
274    }
275}
276
277extern void
278stralloc_add_hex( stralloc_t*  s, unsigned  value, int  num_digits )
279{
280    const char   hexdigits[16] = "0123456789abcdef";
281    int          nn;
282
283    if (num_digits <= 0)
284        return;
285
286    stralloc_readyplus(s, num_digits);
287    for (nn = num_digits-1; nn >= 0; nn--) {
288        s->s[s->n+nn] = hexdigits[value & 15];
289        value >>= 4;
290    }
291    s->n += num_digits;
292}
293
294extern void
295stralloc_add_hexdump( stralloc_t*  s, void*  base, int  size, const char*  prefix )
296{
297    uint8_t*   p          = (uint8_t*)base;
298    const int  max_count  = 16;
299    int        prefix_len = strlen(prefix);
300
301    while (size > 0) {
302        int          count = size > max_count ? max_count : size;
303        int          count2;
304        int          n;
305
306        stralloc_add_bytes( s, prefix, prefix_len );
307        stralloc_add_hex( s, p[0], 2 );
308
309        for (n = 1; n < count; n++) {
310            stralloc_add_c( s, ' ' );
311            stralloc_add_hex( s, p[n], 2 );
312        }
313
314        count2 = 4 + 3*(max_count - count);
315        stralloc_readyplus( s, count2 );
316        memset( s->s + s->n, ' ', count2 );
317        s->n += count2;
318
319        stralloc_readyplus(s, count+1);
320        for (n = 0; n < count; n++) {
321            int  c = p[n];
322
323            if (c < 32 || c > 127)
324                c = '.';
325
326            s->s[s->n++] = c;
327        }
328        s->s[s->n++] = '\n';
329
330        size -= count;
331        p    += count;
332    }
333}
334
335