/** * Extracts the directory component of a path. * * Example: * @code * path_dirname("/usr/local/foobar"); --> "/usr/local" * @endcode * @param path * A path. * @return * A directory name. This string should be freed when no longer * needed. * @author Hongli Lai (public domain) */ char *path_dirname(const char *path) { const char *end; char *result; TOOLKIT_PROTECT(); if (!path) { return NULL; } end = strrchr(path, '/'); if (!end) { return estrdup("."); } while (end > path && *end == '/') { end--; } result = estrndup(path, end - path + 1); if (result[0] == '\0') { efree(result); return estrdup("/"); } return result; }
TOOLKIT_DEINIT_FUNC_FINISH /** * Joins two path components, eg, '/usr' and 'bin' -> '/usr/bin'. * @param path * First path component. * @param path2 * Second path component. * @return * The joined path; should be freed when no longer needed. */ char *path_join(const char *path, const char *path2) { StringBuffer *sb; size_t len; char *cp; TOOLKIT_PROTECT(); sb = stringbuffer_new(); stringbuffer_append_string(sb, path); len = strlen(path); if (len && path[len - 1] != '/') { stringbuffer_append_string(sb, "/"); } stringbuffer_append_string(sb, path2); cp = stringbuffer_finish(sb); return cp; }
/** * Copy the contents of file 'src' into 'dst'. * @param src * Path of the file to copy contents from. * @param dst * Where to put the contents of 'src'. * @param mode * Mode to open 'src' in. * @return * 1 on success, 0 on failure. */ int path_copy_file(const char *src, FILE *dst, const char *mode) { FILE *fp; char buf[HUGE_BUF]; TOOLKIT_PROTECT(); if (!src || !dst || !mode) { return 0; } fp = fopen(src, mode); if (!fp) { return 0; } while (fgets(buf, sizeof(buf), fp)) { fputs(buf, dst); } fclose(fp); return 1; }
/** * Normalize a path, eg, foo//bar, foo/foo2/../bar, foo/./bar all become * foo/bar. * * If the path begins with either a forward slash or a dot *and* a forward * slash, they will be preserved. * @param path * Path to normalize. * @return * The normalized path; never NULL. Must be freed. */ char *path_normalize(const char *path) { StringBuffer *sb; size_t pos, startsbpos; char component[MAX_BUF]; ssize_t last_slash; TOOLKIT_PROTECT(); if (string_isempty(path)) { return estrdup("."); } sb = stringbuffer_new(); pos = 0; if (string_startswith(path, "/")) { stringbuffer_append_string(sb, "/"); } else if (string_startswith(path, "./")) { stringbuffer_append_string(sb, "./"); } startsbpos = stringbuffer_length(sb); while (string_get_word(path, &pos, '/', component, sizeof(component), 0)) { if (strcmp(component, ".") == 0) { continue; } if (strcmp(component, "..") == 0) { if (stringbuffer_length(sb) > startsbpos) { last_slash = stringbuffer_rindex(sb, '/'); if (last_slash == -1) { LOG(BUG, "Should have found a forward slash, but didn't: %s", path); continue; } stringbuffer_seek(sb, last_slash); } } else { size_t len = stringbuffer_length(sb); if (len == 0 || stringbuffer_data(sb)[len - 1] != '/') { stringbuffer_append_string(sb, "/"); } stringbuffer_append_string(sb, component); } } if (stringbuffer_length(sb) == 0) { stringbuffer_append_string(sb, "."); } return stringbuffer_finish(sb); }
/** * Default logger printing function, uses fputs to write to stdout. * @param str * String to print. */ void logger_do_print(const char *str) { TOOLKIT_PROTECT(); fputs(str, stdout); #ifdef WIN32 fflush(stdout); #endif }
/** * Get size of the specified file, in bytes. * @param path * Path to the file. * @return * Size of the file. */ size_t path_size(const char *path) { struct stat statbuf; TOOLKIT_PROTECT(); if (stat(path, &statbuf) != 0) { return 0; } return statbuf.st_size; }
/** * Print a message to the console/stdout/log file/etc. * @param level * Log level to use. * @param function * Name of the function that is calling this. * @param line * Line in the code that is calling this. * @param format * Format string. * @param ... * Format arguments. */ void logger_print(logger_level level, const char *function, uint64_t line, const char *format, ...) { char formatted[HUGE_BUF], timebuf[HUGE_BUF], buf[sizeof(formatted) * 2]; va_list ap; struct timeval tv; struct tm *tm; TOOLKIT_PROTECT(); /* Safety... */ if (level >= LOG_MAX) { return; } /* If the log level is unwanted, bail out. */ if (!((1U << level) & logger_filter_stdout) && !((1U << level) & logger_filter_logfile)) { return; } va_start(ap, format); vsnprintf(formatted, sizeof(formatted), format, ap); va_end(ap); gettimeofday(&tv, NULL); tm = localtime(&tv.tv_sec); if (tm != NULL) { char timebuf2[MAX_BUF]; strftime(VS(timebuf2), "%H:%M:%S", tm); snprintf(VS(timebuf), "[%s.%06"PRIu64 "] ", timebuf2, (uint64_t) tv.tv_usec); } else { timebuf[0] = '\0'; } if ((1U << level) & logger_filter_stdout) { snprintf(VS(buf), "%s%s%s""%s%-6s%s ""%s[%s:%" PRIu64 "]%s ""%s%s%s\n", LOGGER_ESC_SEQ(BOLD), timebuf, LOGGER_ESC_SEQ(END), LOGGER_ESC_SEQ(RED), logger_names[level], LOGGER_ESC_SEQ(END), LOGGER_ESC_SEQ(CYAN), function, line, LOGGER_ESC_SEQ(END), LOGGER_ESC_SEQ(YELLOW), formatted, LOGGER_ESC_SEQ(END)); print_func(buf); } if (log_fp != NULL && (1U << level) & logger_filter_logfile) { fprintf(log_fp, "%s%-6s [%s:%"PRIu64 "] %s\n", timebuf, logger_names[level], function, line, formatted); fflush(log_fp); } }
/** * Check if the specified path exists. * @param path * Path to check. * @return * 1 if 'path' exists, 0 otherwise. */ int path_exists(const char *path) { struct stat statbuf; TOOLKIT_PROTECT(); if (stat(path, &statbuf) != 0) { return 0; } return 1; }
TOOLKIT_DEINIT_FUNC_FINISH /** * Open the specified path as a log file. * @param path * File to open. */ void logger_open_log(const char *path) { TOOLKIT_PROTECT(); if (log_fp != NULL) { fclose(log_fp); } log_fp = fopen(path, "w"); }
/** * Extracts the basename from path. * * Example: * @code * path_basename("/usr/bin/kate"); --> "kate" * @endcode * @param path * A path. * @return * The basename of the path. Should be freed when no longer * needed. */ char *path_basename(const char *path) { const char *slash; TOOLKIT_PROTECT(); if (!path) { return NULL; } while ((slash = strrchr(path, '/'))) { if (*(slash + 1) != '\0') { return estrdup(slash + 1); } } return estrdup(path); }
TOOLKIT_DEINIT_FUNC_FINISH /** * Get the current UTC time as UNIX timestamp. * @return * UTC time as UNIX timestamp. */ time_t datetime_getutc(void) { time_t t; struct tm *tm; TOOLKIT_PROTECT(); time(&t); tm = gmtime(&t); return mktime(tm); }
/** * Create a new blank file. * @param path * Path to the file. * @return * 1 on success, 0 on failure. */ int path_touch(const char *path) { FILE *fp; TOOLKIT_PROTECT(); path_ensure_directories(path); fp = fopen(path, "w"); if (!fp) { return 0; } if (fclose(fp) == EOF) { return 0; } return 1; }
mempool_struct * mempool_create (const char *description, size_t expand, size_t size, uint32_t flags, chunk_initialisator initialisator, chunk_deinitialisator deinitialisator, chunk_constructor constructor, chunk_destructor destructor) { size_t i; mempool_struct *pool; TOOLKIT_PROTECT(); pool = ecalloc(1, sizeof(*pool)); pool->chunk_description = description; pool->expand_size = expand; pool->chunksize = size; pool->flags = flags; pool->initialisator = initialisator; pool->deinitialisator = deinitialisator; pool->constructor = constructor; pool->destructor = destructor; for (i = 0; i < MEMPOOL_NROF_FREELISTS; i++) { pool->freelist[i] = &end_marker; pool->nrof_free[i] = 0; pool->nrof_allocated[i] = 0; } pools = erealloc(pools, sizeof(*pools) * (pools_num + 1)); pools[pools_num] = pool; pools_num++; return pool; }
/** * Checks whether any directories in the given path don't exist, and * creates them if necessary. * @param path * The path to check. */ void path_ensure_directories(const char *path) { char buf[MAXPATHLEN], *cp; struct stat statbuf; TOOLKIT_PROTECT(); if (path == NULL || *path == '\0') { return; } snprintf(VS(buf), "%s", path); cp = buf; while ((cp = strchr(cp + 1, '/')) != NULL) { *cp = '\0'; if (mkdir(buf, 0777) != 0 && errno != EEXIST) { LOG(BUG, "Cannot mkdir %s (path: %s): %s", buf, path, strerror(errno)); return; } if (stat(buf, &statbuf) != 0) { LOG(BUG, "Cannot stat %s (path: %s): %s", buf, path, strerror(errno)); return; } if (!S_ISDIR(statbuf.st_mode)) { LOG(BUG, "Not a directory: %s (path: %s)", buf, path); return; } *cp = '/'; } }
/** * Load the entire contents of file 'path' into a StringBuffer instance, * then return the created string. * @param path * File to load contents of. * @return * The loaded contents. Must be freed. */ char *path_file_contents(const char *path) { FILE *fp; StringBuffer *sb; char buf[MAX_BUF]; TOOLKIT_PROTECT(); fp = fopen(path, "rb"); if (!fp) { return NULL; } sb = stringbuffer_new(); while (fgets(buf, sizeof(buf), fp)) { stringbuffer_append_string(sb, buf); } fclose(fp); return stringbuffer_finish(sb); }
/** * Converts UTC time to local time. * @param t * UTC time. * @return * Converted local time. */ time_t datetime_utctolocal(time_t t) { TOOLKIT_PROTECT(); return t - (datetime_getutc() - time(NULL)); }
/** * Set the logger's printing function. * @param func * Function to use. */ void logger_set_print_func(logger_print_func func) { TOOLKIT_PROTECT(); print_func = func; }
/** * Acquire the log file pointer. * @return * Log file pointer. In the case that no log file is currently open, * stdout is returned. */ FILE *logger_get_logfile(void) { TOOLKIT_PROTECT(); return log_fp != NULL ? log_fp : stdout; }