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 "qemu-common.h"
14#include "android/utils/misc.h"
15#include "android/utils/stralloc.h"
16#include "android/utils/debug.h"
17#include <string.h>
18#include <stdio.h>
19#include <stdlib.h>
20
21#define  E(...)    derror(__VA_ARGS__)
22
23extern void
24print_tabular( const char** strings, int  count,
25               const char*  prefix,  int  width )
26{
27    int  nrows, ncols, r, c, n, maxw = 0;
28
29    for (n = 0; n < count; n++) {
30        int  len = strlen(strings[n]);
31        if (len > maxw)
32            maxw = len;
33    }
34    maxw += 2;
35    ncols = width/maxw;
36    nrows = (count + ncols-1)/ncols;
37
38    for (r = 0; r < nrows; r++) {
39        printf( "%s", prefix );
40        for (c = 0; c < ncols; c++) {
41            int  index = c*nrows + r;
42            if (index >= count) {
43                break;
44            }
45            printf( "%-*s", maxw, strings[index] );
46        }
47        printf( "\n" );
48    }
49}
50
51extern void
52string_translate_char( char*  str, char from, char to )
53{
54    char*  p = str;
55    while (p != NULL && (p = strchr(p, from)) != NULL)
56        *p++ = to;
57}
58
59extern void
60buffer_translate_char( char*        buff,
61                       unsigned     buffLen,
62                       const char*  src,
63                       char         fromChar,
64                       char         toChar )
65{
66    int    len = strlen(src);
67
68    if (len >= buffLen)
69        len = buffLen-1;
70
71    memcpy(buff, src, len);
72    buff[len] = 0;
73
74    string_translate_char( buff, fromChar, toChar );
75}
76
77
78/** TEMP CHAR STRINGS
79 **
80 ** implement a circular ring of temporary string buffers
81 **/
82
83typedef struct Temptring {
84    struct TempString*  next;
85    char*               buffer;
86    int                 size;
87} TempString;
88
89#define  MAX_TEMP_STRINGS   16
90
91static TempString  _temp_strings[ MAX_TEMP_STRINGS ];
92static int         _temp_string_n;
93
94extern char*
95tempstr_get( int  size )
96{
97    TempString*  t = &_temp_strings[_temp_string_n];
98
99    if ( ++_temp_string_n >= MAX_TEMP_STRINGS )
100        _temp_string_n = 0;
101
102    size += 1;  /* reserve 1 char for terminating zero */
103
104    if (t->size < size) {
105        t->buffer = realloc( t->buffer, size );
106        if (t->buffer == NULL) {
107            derror( "%s: could not allocate %d bytes",
108                    __FUNCTION__, size );
109            exit(1);
110        }
111        t->size   = size;
112    }
113    return  t->buffer;
114}
115
116extern char*
117tempstr_format( const char*  fmt, ... )
118{
119    va_list  args;
120    char*    result;
121    STRALLOC_DEFINE(s);
122    va_start(args, fmt);
123    stralloc_formatv(s, fmt, args);
124    va_end(args);
125    result = stralloc_to_tempstr(s);
126    stralloc_reset(s);
127    return result;
128}
129
130/** QUOTING
131 **
132 ** dumps a human-readable version of a string. this replaces
133 ** newlines with \n, etc...
134 **/
135
136extern const char*
137quote_bytes( const char*  str, int  len )
138{
139    STRALLOC_DEFINE(s);
140    char*  q;
141
142    stralloc_add_quote_bytes( s, str, len );
143    q = stralloc_to_tempstr( s );
144    stralloc_reset(s);
145    return q;
146}
147
148extern const char*
149quote_str( const char*  str )
150{
151    int  len = strlen(str);
152    return quote_bytes( str, len );
153}
154
155/** HEXADECIMAL CHARACTER SEQUENCES
156 **/
157
158static int
159hexdigit( int  c )
160{
161    unsigned  d;
162
163    d = (unsigned)(c - '0');
164    if (d < 10) return d;
165
166    d = (unsigned)(c - 'a');
167    if (d < 6) return d+10;
168
169    d = (unsigned)(c - 'A');
170    if (d < 6) return d+10;
171
172    return -1;
173}
174
175int
176hex2int( const uint8_t*  hex, int  len )
177{
178    int  result = 0;
179    while (len > 0) {
180        int  c = hexdigit(*hex++);
181        if (c < 0)
182            return -1;
183
184        result = (result << 4) | c;
185        len --;
186    }
187    return result;
188}
189
190void
191int2hex( uint8_t*  hex, int  len, int  val )
192{
193    static const uint8_t  hexchars[16] = "0123456789abcdef";
194    while ( --len >= 0 )
195        *hex++ = hexchars[(val >> (len*4)) & 15];
196}
197
198/** STRING PARAMETER PARSING
199 **/
200
201int
202strtoi(const char *nptr, char **endptr, int base)
203{
204    long val;
205
206    errno = 0;
207    val = strtol(nptr, endptr, base);
208    if (errno) {
209        return (val == LONG_MAX) ? INT_MAX : INT_MIN;
210    } else {
211        if (val == (int)val) {
212            return (int)val;
213        } else {
214            errno = ERANGE;
215            return val > 0 ? INT_MAX : INT_MIN;
216        }
217    }
218}
219
220int
221get_token_value(const char* params, const char* name, char* value, int val_size)
222{
223    const char* val_end;
224    int len = strlen(name);
225    const char* par_end = params + strlen(params);
226    const char* par_start = strstr(params, name);
227
228    /* Search for 'name=' */
229    while (par_start != NULL) {
230        /* Make sure that we're within the parameters buffer. */
231        if ((par_end - par_start) < len) {
232            par_start = NULL;
233            break;
234        }
235        /* Make sure that par_start starts at the beginning of <name>, and only
236         * then check for '=' value separator. */
237        if ((par_start == params || (*(par_start - 1) == ' ')) &&
238                par_start[len] == '=') {
239            break;
240        }
241        /* False positive. Move on... */
242        par_start = strstr(par_start + 1, name);
243    }
244    if (par_start == NULL) {
245        return -1;
246    }
247
248    /* Advance past 'name=', and calculate value's string length. */
249    par_start += len + 1;
250    val_end = strchr(par_start, ' ');
251    if (val_end == NULL) {
252        val_end = par_start + strlen(par_start);
253    }
254    len = val_end - par_start;
255
256    /* Check if fits... */
257    if ((len + 1) <= val_size) {
258        memcpy(value, par_start, len);
259        value[len] = '\0';
260        return 0;
261    } else {
262        return len + 1;
263    }
264}
265
266int
267get_token_value_alloc(const char* params, const char* name, char** value)
268{
269    char tmp;
270    int res;
271
272    /* Calculate size of string buffer required for the value. */
273    const int val_size = get_token_value(params, name, &tmp, 0);
274    if (val_size < 0) {
275        *value = NULL;
276        return val_size;
277    }
278
279    /* Allocate string buffer, and retrieve the value. */
280    *value = (char*)malloc(val_size);
281    if (*value == NULL) {
282        E("%s: Unable to allocated %d bytes for string buffer.",
283          __FUNCTION__, val_size);
284        return -2;
285    }
286    res = get_token_value(params, name, *value, val_size);
287    if (res) {
288        E("%s: Unable to retrieve value into allocated buffer.", __FUNCTION__);
289        free(*value);
290        *value = NULL;
291    }
292
293    return res;
294}
295
296int
297get_token_value_int(const char* params, const char* name, int* value)
298{
299    char val_str[64];   // Should be enough for all numeric values.
300    if (!get_token_value(params, name, val_str, sizeof(val_str))) {
301        errno = 0;
302        *value = strtoi(val_str, (char**)NULL, 10);
303        if (errno) {
304            E("%s: Value '%s' of the parameter '%s' in '%s' is not a decimal number.",
305              __FUNCTION__, val_str, name, params);
306            return -2;
307        } else {
308            return 0;
309        }
310    } else {
311        return -1;
312    }
313}
314