aboutsummaryrefslogtreecommitdiffstats
path: root/android_utils.h
blob: 42a0d6166198377a8e26a27285f51ea6e29be0e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
/* 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.
*/
#ifndef _ANDROID_UTILS_H
#define _ANDROID_UTILS_H

#include "android_debug.h"
#include <stdint.h>  /* for uint64_t */

#ifndef STRINGIFY
#define  _STRINGIFY(x)  #x
#define  STRINGIFY(x)  _STRINGIFY(x)
#endif

#ifndef GLUE
#define  _GLUE(x,y)  x##y
#define  GLUE(x,y)   _GLUE(x,y)

#define  _GLUE3(x,y,z)  x##y##z
#define  GLUE3(x,y,z)    _GLUE3(x,y,z)
#endif

/* O_BINARY is required in the MS C library to avoid opening file
 * in text mode (the default, ahhhhh)
 */
#if !defined(_WIN32) && !defined(O_BINARY)
#  define  O_BINARY  0
#endif

/* define  PATH_SEP as a string containing the directory separateor */
#ifdef _WIN32
#  define  PATH_SEP   "\\"
#else
#  define  PATH_SEP   "/"
#endif

/* get MAX_PATH, note that PATH_MAX is set to 260 on Windows for
 * stupid backwards-compatibility reason, though any 32-bit version
 * of the OS handles much much longer paths
 */
#ifdef _WIN32
#  undef   MAX_PATH
#  define  MAX_PATH    1024
#  undef   PATH_MAX
#  define  PATH_MAX    MAX_PATH
#else
#  include <limits.h>
#  define  MAX_PATH    PATH_MAX
#endif

#ifdef _WIN32
#  define  strcasecmp  stricmp
#endif


#ifdef _WIN32
#  undef   strsep
#  define  strsep    win32_strsep
extern char*  win32_strsep(char**  pline, const char*  delim);
#endif

/** NON-GRAPHIC USAGE
 **
 ** this variable is TRUE if the -no-window argument was used.
 ** the emulator will still simulate a framebuffer according to the selected skin
 ** but no window will be displayed on the host computer.
 **/
extern int    arg_no_window;

/** EINTR HANDLING
 **
 ** since QEMU uses SIGALRM pretty extensively, having a system call returning
 ** EINTR on Unix happens very frequently. provide a simple macro to guard against
 ** this.
 **/

#ifdef _WIN32
#  define   CHECKED(ret, call)    (ret) = (call)
#else
#  define   CHECKED(ret, call)    do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
#endif

/** MISC FILE AND DIRECTORY HANDLING
 **/

/* checks that a given file exists */
extern int   path_exists( const char*  path );

/* checks that a path points to a regular file */
extern int   path_is_regular( const char*  path );

/* checks that a path points to a directory */
extern int   path_is_dir( const char*  path );

/* checks that one can read/write a given (regular) file */
extern int   path_can_read( const char*  path );
extern int   path_can_write( const char*  path );

/* try to make a directory. returns 0 on success, -1 on error */
extern int   path_mkdir( const char*  path, int  mode );

/* ensure that a given directory exists, create it if not, 
   0 on success, -1 on error */
extern int   path_mkdir_if_needed( const char*  path, int  mode );

/* return the size of a given file in '*psize'. returns 0 on
 * success, -1 on failure (error code in errno) */
extern int   path_get_size( const char*  path, uint64_t  *psize );

/** PATH HANDLING ROUTINES
 **
 **  path_parent() can be used to return the n-level parent of a given directory
 **  this understands . and .. when encountered in the input path
 **/

extern char*  path_parent( const char*  path, int  levels );

/** FORMATTED BUFFER PRINTING
 **
 **  bufprint() allows your to easily and safely append formatted string
 **  content to a given bounded character buffer, in a way that is easier
 **  to use than raw snprintf()
 **
 **  'buffer'  is the start position in the buffer,
 **  'buffend' is the end of the buffer, the function assumes (buffer <= buffend)
 **  'format'  is a standard printf-style format string, followed by any number
 **            of formatting arguments
 **
 **  the function returns the next position in the buffer if everything fits
 **  in it. in case of overflow or formatting error, it will always return "buffend"
 **
 **  this allows you to chain several calls to bufprint() and only check for
 **  overflow at the end, for exemple:
 **
 **     char   buffer[1024];
 **     char*  p   = buffer;
 **     char*  end = p + sizeof(buffer);
 **
 **     p = bufprint(p, end, "%s/%s", first, second);
 **     p = bufprint(p, end, "/%s", third);
 **     if (p >= end) ---> overflow
 **
 **  as a convenience, the appended string is zero-terminated if there is no overflow.
 **  (this means that even if p >= end, the content of "buffer" is zero-terminated)
 **
 **  vbufprint() is a variant that accepts a va_list argument
 **/

extern char*   vbufprint(char*  buffer, char*  buffend, const char*  fmt, va_list  args );
extern char*   bufprint (char*  buffer, char*  buffend, const char*  fmt, ... );

/** USEFUL DIRECTORY SUPPORT
 **
 **  bufprint_add_dir() appends the application's directory to a given bounded buffer
 **
 **  bufprint_config_path() appends the applications' user-specific configuration directory
 **  to a bounded buffer. on Unix this is usually ~/.android, and something a bit more
 **  complex on Windows
 **
 **  bufprint_config_file() appends the name of a file or directory relative to the
 **  user-specific configuration directory to a bounded buffer. this really is equivalent
 **  to concat-ing the config path + path separator + 'suffix'
 **
 **  bufprint_temp_dir() appends the temporary directory's path to a given bounded buffer
 **
 **  bufprint_temp_file() appens the name of a file or directory relative to the
 **  temporary directory. equivalent to concat-ing the temp path + path separator + 'suffix'
 **/

extern char*  bufprint_app_dir    (char*  buffer, char*  buffend);
extern char*  bufprint_config_path(char*  buffer, char*  buffend);
extern char*  bufprint_config_file(char*  buffer, char*  buffend, const char*  suffix);
extern char*  bufprint_temp_dir   (char*  buffer, char*  buffend);
extern char*  bufprint_temp_file  (char*  buffer, char*  buffend, const char*  suffix);

/** FILE LOCKS SUPPORT
 **
 ** a FileLock is useful to prevent several emulator instances from using the same
 ** writable file (e.g. the userdata.img disk images).
 **
 ** create a FileLock object with filelock_create(), the function will return
 ** NULL only if the corresponding path is already locked by another emulator
 ** of if the path is read-only.
 **
 ** note that 'path' can designate a non-existing path and that the lock creation
 ** function can detect stale file locks that can longer when the emulator
 ** crashes unexpectedly, and will happily clean them for you.
 **
 ** you can call filelock_release() to release a file lock explicitely. otherwise
 ** all file locks are automatically released when the program exits.
 **/

typedef struct FileLock  FileLock;

extern FileLock*  filelock_create ( const char*  path );
extern void       filelock_release( FileLock*  lock );

/** TEMP FILE SUPPORT
 **
 ** simple interface to create an empty temporary file on the system.
 **
 ** create the file with tempfile_create(), which returns a reference to a TempFile
 ** object, or NULL if your system is so weird it doesn't have a temporary directory.
 **
 ** you can then call tempfile_path() to retrieve the TempFile's real path to open
 ** it. the returned path is owned by the TempFile object and should not be freed.
 **
 ** all temporary files are destroyed when the program quits, unless you explicitely
 ** close them before that with tempfile_close()
 **/

typedef struct TempFile   TempFile;

extern  TempFile*    tempfile_create( void );
extern  const char*  tempfile_path( TempFile*  temp );
extern  void         tempfile_close( TempFile*  temp );

/** TEMP FILE CLEANUP
 **
 ** We delete all temporary files in atexit()-registered callbacks.
 ** however, the Win32 DeleteFile is unable to remove a file unless
 ** all HANDLEs to it are closed in the terminating process.
 **
 ** Call 'atexit_close_fd' on a newly open-ed file descriptor to indicate
 ** that you want it closed in atexit() time. You should always call
 ** this function unless you're certain that the corresponding file
 ** cannot be temporary.
 **
 ** Call 'atexit_close_fd_remove' before explicitely closing a 'fd'
 **/
extern void          atexit_close_fd(int  fd);
extern void          atexit_close_fd_remove(int  fd);

/** OTHER FILE UTILITIES
 **
 **  make_empty_file() creates an empty file at a given path location.
 **  if the file already exists, it is truncated without warning
 **
 **  copy_file() copies one file into another.
 **
 **  unlink_file() is equivalent to unlink() on Unix, on Windows,
 **  it will handle the case where _unlink() fails because the file is
 **  read-only by trying to change its access rights then calling _unlink()
 **  again.
 **
 **  these functions return 0 on success, and -1 on error
 **
 **  load_text_file() reads a file into a heap-allocated memory block,
 **  and appends a 0 to it. the caller must free it
 **/

extern int     make_empty_file( const char*  path );
extern int     copy_file( const char*  dest, const char*  source );
extern int     unlink_file( const char*  path );
extern void*   load_text_file( const char*  path );

/** HOST RESOLUTION SETTINGS
 **
 ** return the main monitor's DPI resolution according to the host device
 ** beware: this is not always reliable or even obtainable.
 **
 ** returns 0 on success, or -1 in case of error (e.g. the system returns funky values)
 **/
extern  int    get_monitor_resolution( int  *px_dpi, int  *py_dpi );

/** SIGNAL HANDLING
 **
 ** the following can be used to block SIGALRM for a given period of time.
 ** use with caution, the QEMU execution loop uses SIGALRM extensively
 **
 **/
#ifdef _WIN32
typedef struct { int  dumy; }      signal_state_t;
#else
#include <signal.h>
typedef struct { sigset_t  old; }  signal_state_t;
#endif

extern  void   disable_sigalrm( signal_state_t  *state );
extern  void   restore_sigalrm( signal_state_t  *state );

#ifdef _WIN32

#define   BEGIN_NOSIGALRM  \
    {

#define   END_NOSIGALRM  \
    }

#else /* !WIN32 */

#define   BEGIN_NOSIGALRM  \
    { signal_state_t  __sigalrm_state; \
      disable_sigalrm( &__sigalrm_state );

#define   END_NOSIGALRM  \
      restore_sigalrm( &__sigalrm_state );  \
    }

#endif /* !WIN32 */

/** TIME HANDLING
 **
 ** sleep for a given time in milliseconds. note: this uses
 ** disable_sigalrm()/restore_sigalrm()
 **/

extern  void   sleep_ms( int  timeout );

/** TABULAR OUTPUT
 **
 ** prints a list of strings in row/column format
 **
 **/

extern void   print_tabular( const char** strings, int  count,
                             const char*  prefix,  int  width );

/** CHARACTER TRANSLATION
 **
 ** converts one character into another in strings
 **/

extern void   buffer_translate_char( char*        buff,
                                     unsigned     buffLen,
                                     const char*  src,
                                     char         fromChar,
                                     char         toChar );

extern void   string_translate_char( char*  str, char from, char to );

/** DYNAMIC STRINGS
 **/

typedef struct {
    char*     s;
    unsigned  n;
    unsigned  a;
} stralloc_t;

#define  STRALLOC_INIT        { NULL, 0, 0 }
#define  STRALLOC_DEFINE(s)   stralloc_t   s[1] = { STRALLOC_INIT }

extern void   stralloc_reset( stralloc_t*  s );
extern void   stralloc_ready( stralloc_t*  s, unsigned  len );
extern void   stralloc_readyplus( stralloc_t*  s, unsigned  len );

extern void   stralloc_copy( stralloc_t*  s, stralloc_t*  from );
extern void   stralloc_append( stralloc_t*  s, stralloc_t*  from );

extern void   stralloc_add_c( stralloc_t*  s, int  c );
extern void   stralloc_add_str( stralloc_t*  s, const char*  str );
extern void   stralloc_add_bytes( stralloc_t*  s, const void*  from, unsigned  len );

extern char*  stralloc_cstr( stralloc_t*  s );

extern void   stralloc_format( stralloc_t*  s, const char*  fmt, ... );
extern void   stralloc_add_format( stralloc_t*  s, const char*  fmt, ... );

extern void   stralloc_add_quote_c( stralloc_t*  s, int  c );
extern void   stralloc_add_quote_str( stralloc_t*  s, const char*  str );
extern void   stralloc_add_quote_bytes( stralloc_t*  s, const void*  from, unsigned   len );

extern void   stralloc_add_hex( stralloc_t*  s, unsigned  value, int  num_digits );
extern void   stralloc_add_hexdump( stralloc_t*  s, void*  base, int  size, const char*  prefix );

extern void   stralloc_tabular( stralloc_t*  s, const char** strings, int  count,
                                                const char*  prefix,  int  width );


/** TEMP CHAR STRINGS
 **
 ** implement a circular ring of temporary string buffers
 **/

extern char*  tempstr_get( int   size );
extern char*  tempstr_format( const char*  fmt, ... );
extern char*  tempstr_from_stralloc( stralloc_t*  s );

/** QUOTING
 **
 ** dumps a human-readable version of a string. this replaces
 ** newlines with \n, etc...
 **/

extern const char*   quote_bytes( const char*  str, int  len );
extern const char*   quote_str( const char*  str );

/** DYNAMIC ARRAYS OF POINTERS
 **/

typedef struct {
    void**     i;
    unsigned   n;
    unsigned   a;
} qvector_t;

#define  QVECTOR_INIT                   { NULL, 0, 0 }
#define  QVECTOR_DEFINE(v)  qvector_t   v[1] = QVECTOR_INIT

extern void   qvector_init( qvector_t*  v );
extern void   qvector_reset( qvector_t*  v );
extern void   qvector_ready( qvector_t*  v, unsigned  len );
extern void   qvector_readyplus( qvector_t*  v, unsigned len );
extern void   qvector_add( qvector_t*  v, void*  item );
extern int    qvector_del( qvector_t*  v, void*  item );  /* returns 1 if deleted, 0 otherwise */
extern void*  qvector_get( qvector_t*  v, int  index );
extern int    qvector_len( qvector_t*  v );
extern int    qvector_index( qvector_t*  v, void*  item );  /* returns -1 is not found */
extern void   qvector_insert( qvector_t*  v, int  index, void*  item );
extern void   qvector_remove( qvector_t*  v, int  index );
extern void   qvector_remove_n( qvector_t*  v, int  index, int  count );

/** DECIMAL AND HEXADECIMAL CHARACTER SEQUENCES
 **/

/* decodes a sequence of 'len' hexadecimal chars from 'hex' into
 * an integer. returns -1 in case of error (i.e. badly formed chars)
 */
extern int    hex2int( const uint8_t*  hex, int  len );

/* encodes an integer 'val' into 'len' hexadecimal charaters into 'hex' */
extern void   int2hex( uint8_t*  hex, int  len, int  val );

#endif /* _ANDROID_UTILS_H */