/* 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 /* 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 # 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 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 */