/** * \file paths.h * XDG Directory Specification implementation */ #ifndef PATHS_H #define PATHS_H /** * Opaque type for paths */ typedef struct paths_t paths_t; /** * Opaque type for a currently open file */ typedef struct paths_file_t paths_file_t; /** * The different sources or directories if you will that are in the * specification. */ typedef enum paths_source_t { /** directory for data files */ PATHS_DATA, /** directory for config files */ PATHS_CONFIG, /** directory for cache files */ PATHS_CACHE, /** directory for runtime files */ PATHS_RUNTIME, } paths_source_t; /** Do not block write calls */ #define PATHS_NONBLOCK (0x01) /** Append on each write */ #define PATHS_APPEND (0x02) /** Create file if needed */ #define PATHS_CREATE (0x04) /** Truncate file when opening */ #define PATHS_TRUNCATE (0x08) /** If PATHS_CREATE is set, give error if file already exists */ #define PATHS_EXCLUSIVE (0x10) /** * Create a new paths. * Initializes the list of directories from enviroment variables. * Returned object has a reference count of one. * Threadsafe. * Returns NULL in case of allocation errors. * @return a new paths */ MALLOC paths_t* paths_new(void); /** * Increase the reference count for paths. * Threadsafe. * @param paths paths object, may not be NULL */ NONULL void paths_ref(paths_t* paths); /** * Decrease the reference count for paths and free if it reached zero. * Threadsafe. * @param paths paths object, may be NULL */ void paths_unref(paths_t* paths); /** * Get single directory where user-specific files should be written. * May only return NULL for PATHS_RUNTIME all other sources are guaranteed to * return a non-NULL string. They may however return non-existant paths. * PATHS_RUNTIME will return NULL if no such path was found as it has no * default. * If you wish paths to be created if missing, please use paths_write(). * Threadsafe. * @param paths paths object, may not be NULL * @param source requested directory * @return absolute path to directory or NULL */ NONULL const char* paths_user_dir(paths_t* paths, paths_source_t source); /** * Get preference ordered list of directories to search for files. * All paths are absolute and NULL terminated. The list itself is NULL * terminated and may never be empty. Path returned by paths_user_dir() for * the same source is not included. * Will return NULL for PATHS_CACHE and PATHS_RUNTIME as they are only * user-specific writable directories. * Threadsafe. * @param paths paths object, may not be NULL * @param source requested directory * @return NULL terminated list of absolute paths to search or NULL */ NONULL const char** paths_search_dirs(paths_t* paths, paths_source_t source); /** * Callback called with the result(s) from paths_find(). May be called from * any thread. Return false to cancel the search, true to continue until all * has been found. filename will be NULL when no more matches was found. * The filename pointer is only valid until the callback has returned. * @param userdata userdata given to paths_find() * @param filenamme found file or NULL if no more results * @return true to continue the search, false to not */ typedef bool (* paths_find_callback_t)(void* userdata, const char* filename); /** * Asynchronous search for matching files in directories for source. * Returned in preference order, first paths_user_dir() and then * paths_search_dirs(). * The callback is always called at least once. * Match may use *, ?, [] and {} glob matches. It may also contain / characters * to search in subdirectories * Threadsafe. * @param paths paths object, may not be NULL * @param source requested directory * @param match glob pattern to search with. may not be NULL * @param find_callback callback to call when finding results, may not be NULL * @param userdata argument to callback, may be NULL */ NONULL_ARGS(1, 3, 4) void paths_find(paths_t* paths, paths_source_t source, const char* match, paths_find_callback_t find_callback, void* userdata); /** * Synchronous setup to create file in directory. * Returns NULL in case of error, see errno for details. * Depending on source and convention, the actual file may not be created with * the given name until paths_file_close(). * The file will eventually always end up in paths_user_dir() for directory. * If any part of the target path is missing it will be created if possible. * If flags contains PATHS_CREATE then the 5th argument mode_t mode must be * given, just as for open(). * Threadsafe but what happens if two threads at the same time opens the same * target file is up to the platforms locking mechanism. * The returned paths_file_t is not threadsafe. * @param paths paths object, may not be NULL * @param source target directoru * @param filename relative path of target file, may not be NULL * @param flags flags * @param ... mode if PATHS_CREATE is included in flags * @return a file reference or NULL */ NONULL paths_file_t* paths_write(paths_t* paths, paths_source_t source, const char* filename, unsigned int flags, ...); /** * Write data to file. * Works just as libc write(). * Not threadsafe, * the paths_file_t must only be accessed by one thread at a time. * @param file target file, may not be NULL * @param data data to write, may be NULL if size is zero * @param size the maximum number of bytes to read from data * @return number of bytes written to target */ NONULL_ARGS(1) ssize_t paths_file_write(paths_file_t* file, const void* data, size_t size); /** * Close and finish saving file. * If the file was saved successfully, the paths_file_t object is freed. * If the save failed in any way, the object is not freed so you must call * paths_file_abort() to finish up (or call paths_file_close() again and * hope for better luck this time). * Not threadsafe, * the paths_file_t must only be accessed by one thread at a time. * @param file target file, may not be NULL * @return zero on success, non-zero in case of error */ NONULL int paths_file_close(paths_file_t* file); /** * Abort saving the file. The target file is removed unless the original version * before paths_write() could be restored. * Not threadsafe, * the paths_file_t must only be accessed by one thread at a time. * @param file target file, may be NULL */ void paths_file_abort(paths_file_t* file); /** * Get absolute path to directory where user-specific data files should be * written. Returned directory may not exist. * Threadsafe. * @param paths paths object, may not be NULL * @return absolute path to data directory */ static inline NONULL const char* paths_user_data(paths_t* paths) { return paths_user_dir(paths, PATHS_DATA); } /** * Get absolute path to directory where user-specific config files should be * written. Returned directory may not exist. * Threadsafe. * @param paths paths object, may not be NULL * @return absolute path to config directory */ static inline NONULL const char* paths_user_config(paths_t* paths) { return paths_user_dir(paths, PATHS_CONFIG); } /** * Get absolute path to directory where user-specific cache files should be * written. Returned directory may not exist. * Threadsafe. * @param paths paths object, may not be NULL * @return absolute path to cache directory */ static inline NONULL const char* paths_user_cache(paths_t* paths) { return paths_user_dir(paths, PATHS_CACHE); } /** * Get absolute path to directory where user-specific runtime files should be * written. * If not defined in enviroment or not valid NULL is returned. * Threadsafe. * @param paths paths object, may not be NULL * @return absolute path to runtime directory or NULL */ static inline NONULL const char* paths_user_runtime(paths_t* paths) { return paths_user_dir(paths, PATHS_RUNTIME); } /** * Get preference ordered list of directories to search for data files. * All paths are absolute and NULL terminated. The list itself is NULL * terminated and may never be empty. Path returned by paths_user_data() * is not included. * Threadsafe. * @param paths paths object, may not be NULL * @return NULL terminated list of absolute paths to search */ static inline NONULL const char** paths_data(paths_t* paths) { return paths_search_dirs(paths, PATHS_DATA); } /** * Get preference ordered list of directories to search for config files. * All paths are absolute and NULL terminated. The list itself is NULL * terminated and may never be empty. Path returned by paths_user_config() * is not included. * Threadsafe. * @param paths paths object, may not be NULL * @return NULL terminated list of absolute paths to search */ static inline NONULL const char** paths_config(paths_t* paths) { return paths_search_dirs(paths, PATHS_CONFIG); } #endif /* PATHS_H */