/tests/libpakfire/progressbar
/tests/libpakfire/repo
/tests/libpakfire/snapshot
+/tests/libpakfire/string
/tests/libpakfire/util
/tmp
*.py[co]
src/libpakfire/scriptlet.c \
src/libpakfire/snapshot.c \
src/libpakfire/solution.c \
+ src/libpakfire/string.c \
src/libpakfire/transaction.c \
src/libpakfire/ui.c \
src/libpakfire/util.c
src/libpakfire/include/pakfire/scriptlet.h \
src/libpakfire/include/pakfire/snapshot.h \
src/libpakfire/include/pakfire/solution.h \
+ src/libpakfire/include/pakfire/string.h \
src/libpakfire/include/pakfire/transaction.h \
src/libpakfire/include/pakfire/ui.h \
src/libpakfire/include/pakfire/util.h
tests/libpakfire/progressbar \
tests/libpakfire/repo \
tests/libpakfire/snapshot \
+ tests/libpakfire/string \
tests/libpakfire/util
dist_tests_libpakfire_main_SOURCES = \
tests_libpakfire_snapshot_LDADD = \
$(TESTSUITE_LDADD)
+dist_tests_libpakfire_string_SOURCES = \
+ tests/libpakfire/string.c
+
+tests_libpakfire_string_CPPFLAGS = \
+ $(TESTSUITE_CPPFLAGS)
+
+tests_libpakfire_string_CFLAGS = \
+ $(TESTSUITE_CFLAGS)
+
+tests_libpakfire_string_LDADD = \
+ $(TESTSUITE_LDADD)
+
dist_tests_libpakfire_util_SOURCES = \
tests/libpakfire/util.c
#include <pakfire/arch.h>
#include <pakfire/constants.h>
#include <pakfire/private.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
struct pakfire_arch {
#include <pakfire/pwd.h>
#include <pakfire/repo.h>
#include <pakfire/scriptlet.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
enum pakfire_archive_verify_flags {
#include <pakfire/request.h>
#include <pakfire/scriptlet.h>
#include <pakfire/snapshot.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define CCACHE_DIR "/var/cache/ccache"
}
// Split requirements into packages
- packages = pakfire_split_string(requires, ',');
+ packages = pakfire_string_split(requires, ',');
if (!packages)
goto ERROR;
#include <pakfire/cgroup.h>
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define ROOT "/sys/fs/cgroup"
#include <sys/queue.h>
#include <pakfire/config.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define KEY_MAX_LENGTH 32
#include <pakfire/package.h>
#include <pakfire/pakfire.h>
#include <pakfire/repo.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define DATABASE_PATH PAKFIRE_PRIVATE_DIR "/packages.db"
#include <pakfire/logging.h>
#include <pakfire/package.h>
#include <pakfire/pakfire.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
static const struct pakfire_rich_operation {
#include <pakfire/parser.h>
#include <pakfire/private.h>
#include <pakfire/repo.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
// XXX for now
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
#include <pakfire/progressbar.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
// Retry a mirror up to N times before marking it as broken
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
#include <pakfire/private.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define MAX_DIGESTS 4
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
#include <pakfire/private.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
struct pakfire_filelist {
--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2022 Pakfire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# 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. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#ifndef PAKFIRE_STRING_H
+#define PAKFIRE_STRING_H
+
+#ifdef PAKFIRE_PRIVATE
+
+#define pakfire_string_format(s, fmt, ...) snprintf(s, sizeof(s) - 1, fmt, __VA_ARGS__)
+#define pakfire_string_set(s, value) pakfire_string_format(s, "%s", value)
+
+int pakfire_string_startswith(const char* s, const char* prefix);
+int pakfire_string_endswith(const char* s, const char* suffix);
+int pakfire_string_matches(const char* s, const char* pattern);
+
+int pakfire_string_partition(const char* s, const char* delim, char** s1, char** s2);
+char* pakfire_string_replace(const char* s, const char* pattern, const char* repl);
+char** pakfire_string_split(const char* s, char delim);
+char* pakfire_string_join(char** list, const char* delim);
+
+#define pakfire_format_size(dst, value) \
+ __pakfire_format_size(dst, sizeof(dst) - 1, value)
+int __pakfire_format_size(char* dst, size_t length, double value);
+int pakfire_format_speed(char* dst, size_t length, double value);
+char* pakfire_format_date(time_t t);
+
+#define pakfire_strftime_now(dest, format) \
+ __pakfire_strftime_now(dest, sizeof(dest) - 1, format)
+int __pakfire_strftime_now(char* dest, size_t length, const char* format)
+ __attribute__((format(strftime, 3, 0)));;
+
+#endif
+
+#endif /* PAKFIRE_STRING_H */
#include <pakfire/pakfire.h>
-#define pakfire_string_format(s, fmt, ...) snprintf(s, sizeof(s) - 1, fmt, __VA_ARGS__)
-#define pakfire_string_set(s, value) pakfire_string_format(s, "%s", value)
-
-int pakfire_string_startswith(const char* s, const char* prefix);
-int pakfire_string_endswith(const char* s, const char* suffix);
-int pakfire_string_matches(const char* s, const char* pattern);
char* pakfire_unquote_in_place(char* s);
-int pakfire_string_partition(const char* s, const char* delim, char** s1, char** s2);
-char* pakfire_string_replace(const char* s, const char* pattern, const char* repl);
-char** pakfire_split_string(const char* s, char delim);
-char* pakfire_string_join(char** list, const char* delim);
-
-#define pakfire_format_size(dst, value) \
- __pakfire_format_size(dst, sizeof(dst) - 1, value)
-int __pakfire_format_size(char* dst, size_t length, double value);
-int pakfire_format_speed(char* dst, size_t length, double value);
-char* pakfire_format_date(time_t t);
-
-#define pakfire_strftime_now(dest, format) \
- __pakfire_strftime_now(dest, sizeof(dest) - 1, format)
-int __pakfire_strftime_now(char* dest, size_t length, const char* format)
- __attribute__((format(strftime, 3, 0)));;
int pakfire_path_exists(const char* path);
time_t pakfire_path_age(const char* path);
#include <pakfire/pakfire.h>
#include <pakfire/private.h>
#include <pakfire/pwd.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define BUFFER_SIZE 1024 * 64
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
#include <pakfire/private.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
struct pakfire_key {
#include <pakfire/keystore.h>
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
static int pakfire_init_gpgme(struct pakfire* pakfire) {
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
#include <pakfire/mount.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
static const struct pakfire_mountpoint {
#include <pakfire/pakfire.h>
#include <pakfire/private.h>
#include <pakfire/repo.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
struct pakfire_package {
}
PAKFIRE_EXPORT void pakfire_package_set_groups(struct pakfire_package* pkg, const char* groups) {
- char** list = pakfire_split_string(groups, ' ');
+ char** list = pakfire_string_split(groups, ' ');
if (!list)
return;
}
static void pakfire_package_dump_add_lines(char** str, const char* key, const char* val) {
- char** lines = pakfire_split_string(val, '\n');
+ char** lines = pakfire_string_split(val, '\n');
if (!lines)
return;
#include <pakfire/packager.h>
#include <pakfire/pakfire.h>
#include <pakfire/pwd.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
struct pakfire_packager {
#include <pakfire/pwd.h>
#include <pakfire/repo.h>
#include <pakfire/request.h>
+#include <pakfire/string.h>
#include <pakfire/transaction.h>
#include <pakfire/ui.h>
#include <pakfire/util.h>
#include <pakfire/package.h>
#include <pakfire/parser.h>
#include <pakfire/pakfire.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
struct pakfire_parser {
return NULL;
// Split the string
- char** list = pakfire_split_string(value, delim);
+ char** list = pakfire_string_split(value, delim);
free(value);
return list;
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
#include <pakfire/parser.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define YYERROR_VERBOSE 1
#include <stdlib.h>
#include <pakfire/parser.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#include "grammar.h"
#include <pakfire/i18n.h>
#include <pakfire/private.h>
#include <pakfire/progressbar.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define DRAWS_PER_SECOND 20
#include <pakfire/logging.h>
#include <pakfire/pakfire.h>
#include <pakfire/pwd.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define ETC_SUBUID "/etc/subuid"
#include <pakfire/private.h>
#include <pakfire/progressbar.h>
#include <pakfire/repo.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
// Refresh mirrorlists once a day
#include <pakfire/private.h>
#include <pakfire/problem.h>
#include <pakfire/request.h>
+#include <pakfire/string.h>
#include <pakfire/transaction.h>
#include <pakfire/util.h>
#include <pakfire/jail.h>
#include <pakfire/logging.h>
#include <pakfire/scriptlet.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
const char* pakfire_scriptlet_types[] = {
#include <pakfire/problem.h>
#include <pakfire/request.h>
#include <pakfire/solution.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
struct pakfire_solution {
--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2022 Pakfire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# 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. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <pakfire/string.h>
+
+int pakfire_string_startswith(const char* s, const char* prefix) {
+ // Validate input
+ if (!s || !prefix) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ return !strncmp(s, prefix, strlen(prefix));
+}
+
+int pakfire_string_endswith(const char* s, const char* suffix) {
+ // Validate input
+ if (!s || !suffix) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ return !strcmp(s + strlen(s) - strlen(suffix), suffix);
+}
+
+int pakfire_string_matches(const char* s, const char* pattern) {
+ // Validate input
+ if (!s || !pattern) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ return !!strstr(s, pattern);
+}
+
+int pakfire_string_partition(const char* s, const char* delim, char** s1, char** s2) {
+ char* p = strstr(s, delim);
+
+ // Delim was not found
+ if (!p) {
+ *s1 = NULL;
+ *s2 = NULL;
+ return 1;
+ }
+
+ // Length of string before delim
+ size_t l = p - s;
+
+ char* buffer = malloc(l + 1);
+ if (!buffer)
+ return 1;
+
+ // Copy first part
+ *s1 = memcpy(buffer, s, l);
+ buffer[l] = '\0';
+
+ // Copy second part
+ *s2 = strdup(p + strlen(delim));
+
+ return 0;
+}
+
+char* pakfire_string_replace(const char* s, const char* pattern, const char* repl) {
+ // Return NULL on no input or no pattern
+ if (!s || !pattern) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ // Replace with nothing when repl is NULL
+ if (!repl)
+ repl = "";
+
+ char* result = NULL;
+ const char** cache = NULL;
+ unsigned int count = 0;
+
+ const size_t pattern_length = strlen(pattern);
+
+ // Working pointer
+ const char* p = s;
+
+ // Find all occurrences of pattern and store their location
+ while (1) {
+ const char* needle = strstr(p, pattern);
+ if (!needle)
+ break;
+
+ // Make space in the cache
+ cache = reallocarray(cache, sizeof(*cache), count + 1);
+ cache[count++] = needle;
+
+ // Move p forward
+ p = needle + pattern_length;
+ }
+
+ // Copy the string if no occurence was found
+ if (count == 0) {
+ result = strdup(s);
+ goto ERROR;
+ }
+
+ // Store the end pointer
+ cache = reallocarray(cache, sizeof(*cache), count + 1);
+ cache[count] = s + strlen(s);
+
+ const size_t repl_length = strlen(repl);
+
+ // Determine the length of the final string
+ const size_t length = strlen(s) + ((repl_length - pattern_length) * count);
+
+ // Allocate enough memory for the result
+ result = malloc(length + 1);
+ if (!result)
+ goto ERROR;
+
+ // Reset p
+ p = s;
+
+ // Working pointer for the result
+ char* r = result;
+
+ // Copy everything up to the first match
+ ssize_t l = cache[0] - s;
+ memcpy(r, p, l);
+ r += l;
+ p += l;
+
+ for (unsigned int i = 0; i < count; i++) {
+ // Put replacement here
+ memcpy(r, repl, repl_length);
+ r += repl_length;
+ p += pattern_length;
+
+ // Determine the length between two matches
+ l = cache[i+1] - (cache[i] + pattern_length);
+
+ memcpy(r, p, l);
+ r += l;
+ p += l;
+ }
+
+ // Terminate the string
+ result[length] = '\0';
+
+ERROR:
+ if (cache)
+ free(cache);
+
+ return result;
+}
+
+static unsigned int pakfire_chrcnt(const char* s, char delim) {
+ size_t length = strlen(s);
+
+ unsigned int count = 0;
+
+ for (unsigned int i = 0; i < length; i++)
+ if (s[i] == delim)
+ count++;
+
+ return count;
+}
+
+char** pakfire_string_split(const char* s, char delim) {
+ char** array = NULL;
+
+ if (!s) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ // Count how often we need to split
+ unsigned int count = pakfire_chrcnt(s, delim) + 1;
+
+ // Allocate array
+ array = calloc(count + 1, sizeof(*array));
+ if (!array)
+ return NULL;
+
+ // Copy string to stack
+ char* p = strdupa(s);
+ if (!p)
+ return NULL;
+
+ unsigned int i = 0;
+ while (*p) {
+ char* e = strchr(p, delim);
+
+ // Terminate the string
+ if (e)
+ *e = '\0';
+
+ // Add string to the array
+ array[i++] = strdup(p);
+
+ // End loop when we reached the end
+ if (!e)
+ break;
+
+ // Or continue at the next line
+ p = e + 1;
+ }
+
+ return array;
+}
+
+char* pakfire_string_join(char** list, const char* delim) {
+ // Validate input
+ if (!list || !delim) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ size_t length = 0;
+ unsigned int elements = 0;
+
+ // Count the number of elements and the total length
+ for (char** item = list; *item; item++) {
+ length += strlen(*item);
+ elements++;
+ }
+
+ // Empty list?
+ if (!elements)
+ return NULL;
+
+ // Add the delimiters
+ length += strlen(delim) * (elements - 1);
+
+ // Allocate the result string
+ char* string = malloc(length + 1);
+ if (!string)
+ return NULL;
+
+ // Pointer to where we are writing
+ char* p = string;
+
+ size_t bytes_left = length + 1;
+ size_t bytes_written;
+
+ for (char** item = list; *item; item++) {
+ bytes_written = snprintf(p, bytes_left, "%s", *item);
+
+ bytes_left -= bytes_written;
+ p += bytes_written;
+
+ // Write the delimiter
+ if (bytes_left) {
+ bytes_written = snprintf(p, bytes_left, "%s", delim);
+
+ bytes_left -= bytes_written;
+ p += bytes_written;
+ }
+ }
+
+ return string;
+}
+
+int __pakfire_format_size(char* dst, size_t length, double value) {
+ const char* units[] = {
+ "%.0f ",
+ "%.0fk",
+ "%.1fM",
+ "%.1fG",
+ "%.1fT",
+ NULL
+ };
+ const char** unit = units;
+
+ while (*(unit + 1) && value >= 1024.0) {
+ value /= 1024.0;
+ unit++;
+ }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ return snprintf(dst, length, *unit, value);
+#pragma GCC diagnostic pop
+}
+
+int pakfire_format_speed(char* dst, size_t length, double value) {
+ const char* units[] = {
+ "%4.0fB/s",
+ "%4.0fkB/s",
+ "%4.1fMB/s",
+ "%4.1fGB/s",
+ "%4.1fTB/s",
+ NULL
+ };
+ const char** unit = units;
+
+ while (*(unit + 1) && value >= 1024.0) {
+ value /= 1024.0;
+ unit++;
+ }
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ return snprintf(dst, length, *unit, value);
+#pragma GCC diagnostic pop
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+static char* pakfire_strftime(const char* format, time_t t) {
+ char string[128];
+ struct tm* tm = gmtime(&t);
+
+ strftime(string, sizeof(string) - 1, format, tm);
+
+ return strdup(string);
+}
+#pragma GCC diagnostic pop
+
+char* pakfire_format_date(time_t t) {
+ return pakfire_strftime("%Y-%m-%d", t);
+}
+
+int __pakfire_strftime_now(char* dest, size_t length, const char* format) {
+ struct tm tm;
+
+ // Fetch the current time
+ const time_t t = time(NULL);
+ if (t < 0)
+ return 1;
+
+ // Convert to struct tm
+ struct tm* now = gmtime_r(&t, &tm);
+ if (!now)
+ return 1;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+ strftime(dest, length, format, now);
+#pragma GCC diagnostic pop
+
+ return 0;
+}
#include <pakfire/pakfire.h>
#include <pakfire/private.h>
#include <pakfire/repo.h>
+#include <pakfire/string.h>
#include <pakfire/transaction.h>
#include <pakfire/ui.h>
#include <pakfire/util.h>
#include <pakfire/constants.h>
#include <pakfire/logging.h>
#include <pakfire/package.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#define BUFFER_SIZE 64 * 1024
#define NSEC_PER_SEC 1000000000
-int pakfire_string_startswith(const char* s, const char* prefix) {
- // Validate input
- if (!s || !prefix) {
- errno = EINVAL;
- return 1;
- }
-
- return !strncmp(s, prefix, strlen(prefix));
-}
-
-int pakfire_string_endswith(const char* s, const char* suffix) {
- // Validate input
- if (!s || !suffix) {
- errno = EINVAL;
- return 1;
- }
-
- return !strcmp(s + strlen(s) - strlen(suffix), suffix);
-}
-
-int pakfire_string_matches(const char* s, const char* pattern) {
- // Validate input
- if (!s || !pattern) {
- errno = EINVAL;
- return 1;
- }
-
- return !!strstr(s, pattern);
-}
-
char* pakfire_unquote_in_place(char* s) {
if (!s || !*s)
return s;
return s;
}
-int pakfire_string_partition(const char* s, const char* delim, char** s1, char** s2) {
- char* p = strstr(s, delim);
-
- // Delim was not found
- if (!p) {
- *s1 = NULL;
- *s2 = NULL;
- return 1;
- }
-
- // Length of string before delim
- size_t l = p - s;
-
- char* buffer = malloc(l + 1);
- if (!buffer)
- return -ENOMEM;
-
- // Copy first part
- *s1 = memcpy(buffer, s, l);
- buffer[l] = '\0';
-
- // Copy second part
- *s2 = strdup(p + strlen(delim));
-
- return 0;
-}
-
-char* pakfire_string_replace(const char* s, const char* pattern, const char* repl) {
- // Return NULL on no input or no pattern
- if (!s || !pattern) {
- errno = EINVAL;
- return NULL;
- }
-
- // Replace with nothing when repl is NULL
- if (!repl)
- repl = "";
-
- char* result = NULL;
- const char** cache = NULL;
- unsigned int count = 0;
-
- const size_t pattern_length = strlen(pattern);
-
- // Working pointer
- const char* p = s;
-
- // Find all occurrences of pattern and store their location
- while (1) {
- const char* needle = strstr(p, pattern);
- if (!needle)
- break;
-
- // Make space in the cache
- cache = reallocarray(cache, sizeof(*cache), count + 1);
- cache[count++] = needle;
-
- // Move p forward
- p = needle + pattern_length;
- }
-
- // Copy the string if no occurence was found
- if (count == 0) {
- result = strdup(s);
- goto ERROR;
- }
-
- // Store the end pointer
- cache = reallocarray(cache, sizeof(*cache), count + 1);
- cache[count] = s + strlen(s);
-
- const size_t repl_length = strlen(repl);
-
- // Determine the length of the final string
- const size_t length = strlen(s) + ((repl_length - pattern_length) * count);
-
- // Allocate enough memory for the result
- result = malloc(length + 1);
- if (!result)
- goto ERROR;
-
- // Reset p
- p = s;
-
- // Working pointer for the result
- char* r = result;
-
- // Copy everything up to the first match
- ssize_t l = cache[0] - s;
- memcpy(r, p, l);
- r += l;
- p += l;
-
- for (unsigned int i = 0; i < count; i++) {
- // Put replacement here
- memcpy(r, repl, repl_length);
- r += repl_length;
- p += pattern_length;
-
- // Determine the length between two matches
- l = cache[i+1] - (cache[i] + pattern_length);
-
- memcpy(r, p, l);
- r += l;
- p += l;
- }
-
- // Terminate the string
- result[length] = '\0';
-
-ERROR:
- if (cache)
- free(cache);
-
- return result;
-}
-
-static unsigned int pakfire_chrcnt(const char* s, char delim) {
- size_t length = strlen(s);
-
- unsigned int count = 0;
-
- for (unsigned int i = 0; i < length; i++)
- if (s[i] == delim)
- count++;
-
- return count;
-}
-
-char** pakfire_split_string(const char* s, char delim) {
- char** array = NULL;
-
- if (!s) {
- errno = EINVAL;
- return NULL;
- }
-
- // Count how often we need to split
- unsigned int count = pakfire_chrcnt(s, delim) + 1;
-
- // Allocate array
- array = calloc(count + 1, sizeof(*array));
- if (!array)
- return NULL;
-
- // Copy string to stack
- char* p = strdupa(s);
- if (!p)
- return NULL;
-
- unsigned int i = 0;
- while (*p) {
- char* e = strchr(p, delim);
-
- // Terminate the string
- if (e)
- *e = '\0';
-
- // Add string to the array
- array[i++] = strdup(p);
-
- // End loop when we reached the end
- if (!e)
- break;
-
- // Or continue at the next line
- p = e + 1;
- }
-
- return array;
-}
-
-char* pakfire_string_join(char** list, const char* delim) {
- // Validate input
- if (!list || !delim) {
- errno = EINVAL;
- return NULL;
- }
-
- size_t length = 0;
- unsigned int elements = 0;
-
- // Count the number of elements and the total length
- for (char** item = list; *item; item++) {
- length += strlen(*item);
- elements++;
- }
-
- // Empty list?
- if (!elements)
- return NULL;
-
- // Add the delimiters
- length += strlen(delim) * (elements - 1);
-
- // Allocate the result string
- char* string = malloc(length + 1);
- if (!string)
- return NULL;
-
- // Pointer to where we are writing
- char* p = string;
-
- size_t bytes_left = length + 1;
- size_t bytes_written;
-
- for (char** item = list; *item; item++) {
- bytes_written = snprintf(p, bytes_left, "%s", *item);
-
- bytes_left -= bytes_written;
- p += bytes_written;
-
- // Write the delimiter
- if (bytes_left) {
- bytes_written = snprintf(p, bytes_left, "%s", delim);
-
- bytes_left -= bytes_written;
- p += bytes_written;
- }
- }
-
- return string;
-}
-
-int __pakfire_format_size(char* dst, size_t length, double value) {
- const char* units[] = {
- "%.0f ",
- "%.0fk",
- "%.1fM",
- "%.1fG",
- "%.1fT",
- NULL
- };
- const char** unit = units;
-
- while (*(unit + 1) && value >= 1024.0) {
- value /= 1024.0;
- unit++;
- }
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
- return snprintf(dst, length, *unit, value);
-#pragma GCC diagnostic pop
-}
-
-int pakfire_format_speed(char* dst, size_t length, double value) {
- const char* units[] = {
- "%4.0fB/s",
- "%4.0fkB/s",
- "%4.1fMB/s",
- "%4.1fGB/s",
- "%4.1fTB/s",
- NULL
- };
- const char** unit = units;
-
- while (*(unit + 1) && value >= 1024.0) {
- value /= 1024.0;
- unit++;
- }
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
- return snprintf(dst, length, *unit, value);
-#pragma GCC diagnostic pop
-}
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-static char* pakfire_strftime(const char* format, time_t t) {
- char string[128];
- struct tm* tm = gmtime(&t);
-
- strftime(string, sizeof(string) - 1, format, tm);
-
- return strdup(string);
-}
-#pragma GCC diagnostic pop
-
-char* pakfire_format_date(time_t t) {
- return pakfire_strftime("%Y-%m-%d", t);
-}
-
-int __pakfire_strftime_now(char* dest, size_t length, const char* format) {
- struct tm tm;
-
- // Fetch the current time
- const time_t t = time(NULL);
- if (t < 0)
- return 1;
-
- // Convert to struct tm
- struct tm* now = gmtime_r(&t, &tm);
- if (!now)
- return 1;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
- strftime(dest, length, format, now);
-#pragma GCC diagnostic pop
-
- return 0;
-}
-
int __pakfire_path_join(char* dest, size_t length,
const char* first, const char* second) {
if (!first)
#include <string.h>
#include <pakfire/compress.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#include "../testsuite.h"
#############################################################################*/
#include <pakfire/repo.h>
+#include <pakfire/string.h>
#include <pakfire/util.h>
#include "../testsuite.h"
--- /dev/null
+/*#############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2022 Pakfire development team #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# 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. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pakfire/string.h>
+
+#include "../testsuite.h"
+
+static int test_string_startswith(const struct test* t) {
+ ASSERT_TRUE(pakfire_string_startswith("ABC", "A"));
+ ASSERT_FALSE(pakfire_string_startswith("ABC", "B"));
+
+ // Check for invalid inputs
+ ASSERT_ERRNO(pakfire_string_startswith("ABC", NULL), EINVAL);
+ ASSERT_ERRNO(pakfire_string_startswith(NULL, "ABC"), EINVAL);
+ ASSERT_ERRNO(pakfire_string_startswith(NULL, NULL), EINVAL);
+
+ return EXIT_SUCCESS;
+
+FAIL:
+ return EXIT_FAILURE;
+}
+
+static int test_string_endswith(const struct test* t) {
+ ASSERT_TRUE(pakfire_string_endswith("ABC", "C"));
+ ASSERT_FALSE(pakfire_string_endswith("ABC", "B"));
+
+ // Check for invalid inputs
+ ASSERT_ERRNO(pakfire_string_endswith("ABC", NULL), EINVAL);
+ ASSERT_ERRNO(pakfire_string_endswith(NULL, "ABC"), EINVAL);
+ ASSERT_ERRNO(pakfire_string_endswith(NULL, NULL), EINVAL);
+
+ return EXIT_SUCCESS;
+
+FAIL:
+ return EXIT_FAILURE;
+}
+
+static int test_string_matches(const struct test* t) {
+ ASSERT_TRUE(pakfire_string_matches("ABC", "A"));
+ ASSERT_TRUE(pakfire_string_matches("ABC", "B"));
+ ASSERT_TRUE(pakfire_string_matches("ABC", "C"));
+ ASSERT_TRUE(pakfire_string_matches("ABC", "AB"));
+ ASSERT_TRUE(pakfire_string_matches("ABC", "BC"));
+ ASSERT_TRUE(pakfire_string_matches("ABC", "ABC"));
+ ASSERT_FALSE(pakfire_string_matches("ABC", "D"));
+ ASSERT_FALSE(pakfire_string_matches("ABC", "ABCD"));
+
+ // Check for invalid inputs
+ ASSERT_ERRNO(pakfire_string_matches("ABC", NULL), EINVAL);
+ ASSERT_ERRNO(pakfire_string_matches(NULL, "ABC"), EINVAL);
+ ASSERT_ERRNO(pakfire_string_matches(NULL, NULL), EINVAL);
+
+ return EXIT_SUCCESS;
+
+FAIL:
+ return EXIT_FAILURE;
+}
+
+static int test_string_partition(const struct test* t) {
+ char* part1;
+ char* part2;
+
+ // Regular case
+ int r = pakfire_string_partition("ABC:DEF", ":", &part1, &part2);
+ ASSERT(r == 0);
+ ASSERT_STRING_EQUALS(part1, "ABC");
+ ASSERT_STRING_EQUALS(part2, "DEF");
+
+ free(part1);
+ free(part2);
+
+ // No delimiter
+ r = pakfire_string_partition("ABCDEF", ":", &part1, &part2);
+ ASSERT(r == 1);
+ ASSERT(part1 == NULL);
+ ASSERT(part2 == NULL);
+
+ // Nothing after the delimiter
+ r = pakfire_string_partition("ABC:", ":", &part1, &part2);
+ ASSERT(r == 0);
+ ASSERT_STRING_EQUALS(part1, "ABC");
+ ASSERT_STRING_EQUALS(part2, "");
+
+ free(part1);
+ free(part2);
+
+ // Nothing before the delimiter
+ r = pakfire_string_partition(":ABC", ":", &part1, &part2);
+ ASSERT(r == 0);
+ ASSERT_STRING_EQUALS(part1, "");
+ ASSERT_STRING_EQUALS(part2, "ABC");
+
+ free(part1);
+ free(part2);
+
+ // Multi-character delimiter
+ r = pakfire_string_partition("ABC:-:DEF", ":-:", &part1, &part2);
+ ASSERT(r == 0);
+ ASSERT_STRING_EQUALS(part1, "ABC");
+ ASSERT_STRING_EQUALS(part2, "DEF");
+
+ free(part1);
+ free(part2);
+
+ return EXIT_SUCCESS;
+
+FAIL:
+ return EXIT_FAILURE;
+}
+
+static int test_string_replace(const struct test* t) {
+ const char* result = pakfire_string_replace(
+ "ABCABCABCABC", "AB", "CC"
+ );
+ ASSERT_STRING_EQUALS(result, "CCCCCCCCCCCC");
+
+ return EXIT_SUCCESS;
+
+FAIL:
+ return EXIT_FAILURE;
+}
+
+static int test_string_split(const struct test* t) {
+ char** result = pakfire_string_split(NULL, 'X');
+
+ // Must return on invalid input
+ ASSERT_ERRNO(!result, EINVAL);
+
+ // Split a string
+ result = pakfire_string_split("ABCXABCXABC", 'X');
+ ASSERT(result);
+
+ ASSERT_STRING_EQUALS(result[0], "ABC");
+ ASSERT_STRING_EQUALS(result[1], "ABC");
+ ASSERT_STRING_EQUALS(result[2], "ABC");
+ ASSERT_NULL(result[3]);
+
+ // Split a string withtout the delimiter
+ result = pakfire_string_split("ABCABC", 'X');
+ ASSERT(result);
+
+ ASSERT_STRING_EQUALS(result[0], "ABCABC");
+ ASSERT_NULL(result[1]);
+
+ // String with only delimiters
+ result = pakfire_string_split("XXXX", 'X');
+ ASSERT(result);
+
+ ASSERT_STRING_EQUALS(result[0], "");
+ ASSERT_STRING_EQUALS(result[1], "");
+ ASSERT_STRING_EQUALS(result[2], "");
+ ASSERT_STRING_EQUALS(result[3], "");
+ ASSERT_NULL(result[4]);
+
+ return EXIT_SUCCESS;
+
+FAIL:
+ return EXIT_FAILURE;
+}
+
+static int test_string_join(const struct test* t) {
+ char* s = NULL;
+
+ // Some test elements
+ char* elements1[] = {
+ "A",
+ "B",
+ "C",
+ NULL,
+ };
+
+ // Join with newline
+ s = pakfire_string_join(elements1, "\n");
+ ASSERT_STRING_EQUALS(s, "A\nB\nC");
+
+ if (s) {
+ free(s);
+ s = NULL;
+ }
+
+ // Join with empty delimiter
+ s = pakfire_string_join(elements1, "");
+ ASSERT_STRING_EQUALS(s, "ABC");
+
+ if (s) {
+ free(s);
+ s = NULL;
+ }
+
+ char* elements2[] = {
+ "",
+ "",
+ "",
+ NULL,
+ };
+
+ // Join list with empty elements
+ s = pakfire_string_join(elements2, "X");
+ ASSERT_STRING_EQUALS(s, "XX");
+
+ if (s) {
+ free(s);
+ s = NULL;
+ }
+
+ // Invalid inputs
+ s = pakfire_string_join(NULL, NULL);
+ ASSERT_ERRNO(!s, EINVAL);
+
+ s = pakfire_string_join(elements1, NULL);
+ ASSERT_ERRNO(!s, EINVAL);
+
+ s = pakfire_string_join(NULL, "\n");
+ ASSERT_ERRNO(!s, EINVAL);
+
+ char* elements3[] = {
+ NULL,
+ };
+
+ // Join empty elements
+ ASSERT_NULL(pakfire_string_join(elements3, "\n"));
+
+ return EXIT_SUCCESS;
+
+FAIL:
+ if (s)
+ free(s);
+
+ return EXIT_FAILURE;
+}
+
+static int test_format_size(const struct test* t) {
+ char buffer[128];
+ char small_buffer[2];
+ int r;
+
+ ASSERT(pakfire_format_size(buffer, 0) == 2);
+ ASSERT_STRING_EQUALS(buffer, "0 ");
+
+ ASSERT(pakfire_format_size(buffer, 1024) == 2);
+ ASSERT_STRING_EQUALS(buffer, "1k");
+
+ ASSERT(pakfire_format_size(buffer, 1024 * 1024) == 4);
+ ASSERT_STRING_EQUALS(buffer, "1.0M");
+
+ ASSERT(pakfire_format_size(small_buffer, 0) == 2);
+ ASSERT_STRING_EQUALS(small_buffer, "");
+
+ return EXIT_SUCCESS;
+
+FAIL:
+ return EXIT_FAILURE;
+}
+
+int main(int argc, const char* argv[]) {
+ testsuite_add_test(test_string_startswith);
+ testsuite_add_test(test_string_endswith);
+ testsuite_add_test(test_string_matches);
+ testsuite_add_test(test_string_partition);
+ testsuite_add_test(test_string_replace);
+ testsuite_add_test(test_string_split);
+ testsuite_add_test(test_string_join);
+ testsuite_add_test(test_format_size);
+
+ return testsuite_run(argc, argv);
+}
# #
#############################################################################*/
-#include <errno.h>
#include <stdlib.h>
-#include <string.h>
-#include <pakfire/parser.h>
#include <pakfire/util.h>
#include "../testsuite.h"
return EXIT_FAILURE;
}
-static int test_string_startswith(const struct test* t) {
- ASSERT_TRUE(pakfire_string_startswith("ABC", "A"));
- ASSERT_FALSE(pakfire_string_startswith("ABC", "B"));
-
- // Check for invalid inputs
- ASSERT_ERRNO(pakfire_string_startswith("ABC", NULL), EINVAL);
- ASSERT_ERRNO(pakfire_string_startswith(NULL, "ABC"), EINVAL);
- ASSERT_ERRNO(pakfire_string_startswith(NULL, NULL), EINVAL);
-
- return EXIT_SUCCESS;
-
-FAIL:
- return EXIT_FAILURE;
-}
-
-static int test_string_endswith(const struct test* t) {
- ASSERT_TRUE(pakfire_string_endswith("ABC", "C"));
- ASSERT_FALSE(pakfire_string_endswith("ABC", "B"));
-
- // Check for invalid inputs
- ASSERT_ERRNO(pakfire_string_endswith("ABC", NULL), EINVAL);
- ASSERT_ERRNO(pakfire_string_endswith(NULL, "ABC"), EINVAL);
- ASSERT_ERRNO(pakfire_string_endswith(NULL, NULL), EINVAL);
-
- return EXIT_SUCCESS;
-
-FAIL:
- return EXIT_FAILURE;
-}
-
-static int test_string_matches(const struct test* t) {
- ASSERT_TRUE(pakfire_string_matches("ABC", "A"));
- ASSERT_TRUE(pakfire_string_matches("ABC", "B"));
- ASSERT_TRUE(pakfire_string_matches("ABC", "C"));
- ASSERT_TRUE(pakfire_string_matches("ABC", "AB"));
- ASSERT_TRUE(pakfire_string_matches("ABC", "BC"));
- ASSERT_TRUE(pakfire_string_matches("ABC", "ABC"));
- ASSERT_FALSE(pakfire_string_matches("ABC", "D"));
- ASSERT_FALSE(pakfire_string_matches("ABC", "ABCD"));
-
- // Check for invalid inputs
- ASSERT_ERRNO(pakfire_string_matches("ABC", NULL), EINVAL);
- ASSERT_ERRNO(pakfire_string_matches(NULL, "ABC"), EINVAL);
- ASSERT_ERRNO(pakfire_string_matches(NULL, NULL), EINVAL);
-
- return EXIT_SUCCESS;
-
-FAIL:
- return EXIT_FAILURE;
-}
-
-static int test_string_partition(const struct test* t) {
- char* part1;
- char* part2;
-
- // Regular case
- int r = pakfire_string_partition("ABC:DEF", ":", &part1, &part2);
- ASSERT(r == 0);
- ASSERT_STRING_EQUALS(part1, "ABC");
- ASSERT_STRING_EQUALS(part2, "DEF");
-
- free(part1);
- free(part2);
-
- // No delimiter
- r = pakfire_string_partition("ABCDEF", ":", &part1, &part2);
- ASSERT(r == 1);
- ASSERT(part1 == NULL);
- ASSERT(part2 == NULL);
-
- // Nothing after the delimiter
- r = pakfire_string_partition("ABC:", ":", &part1, &part2);
- ASSERT(r == 0);
- ASSERT_STRING_EQUALS(part1, "ABC");
- ASSERT_STRING_EQUALS(part2, "");
-
- free(part1);
- free(part2);
-
- // Nothing before the delimiter
- r = pakfire_string_partition(":ABC", ":", &part1, &part2);
- ASSERT(r == 0);
- ASSERT_STRING_EQUALS(part1, "");
- ASSERT_STRING_EQUALS(part2, "ABC");
-
- free(part1);
- free(part2);
-
- // Multi-character delimiter
- r = pakfire_string_partition("ABC:-:DEF", ":-:", &part1, &part2);
- ASSERT(r == 0);
- ASSERT_STRING_EQUALS(part1, "ABC");
- ASSERT_STRING_EQUALS(part2, "DEF");
-
- free(part1);
- free(part2);
-
- return EXIT_SUCCESS;
-
-FAIL:
- return EXIT_FAILURE;
-}
-
-static int test_string_replace(const struct test* t) {
- const char* result = pakfire_string_replace(
- "ABCABCABCABC", "AB", "CC"
- );
- ASSERT_STRING_EQUALS(result, "CCCCCCCCCCCC");
-
- return EXIT_SUCCESS;
-
-FAIL:
- return EXIT_FAILURE;
-}
-
-static int test_string_split(const struct test* t) {
- char** result = pakfire_split_string(NULL, 'X');
-
- // Must return on invalid input
- ASSERT_ERRNO(!result, EINVAL);
-
- // Split a string
- result = pakfire_split_string("ABCXABCXABC", 'X');
- ASSERT(result);
-
- ASSERT_STRING_EQUALS(result[0], "ABC");
- ASSERT_STRING_EQUALS(result[1], "ABC");
- ASSERT_STRING_EQUALS(result[2], "ABC");
- ASSERT_NULL(result[3]);
-
- // Split a string withtout the delimiter
- result = pakfire_split_string("ABCABC", 'X');
- ASSERT(result);
-
- ASSERT_STRING_EQUALS(result[0], "ABCABC");
- ASSERT_NULL(result[1]);
-
- // String with only delimiters
- result = pakfire_split_string("XXXX", 'X');
- ASSERT(result);
-
- ASSERT_STRING_EQUALS(result[0], "");
- ASSERT_STRING_EQUALS(result[1], "");
- ASSERT_STRING_EQUALS(result[2], "");
- ASSERT_STRING_EQUALS(result[3], "");
- ASSERT_NULL(result[4]);
-
- return EXIT_SUCCESS;
-
-FAIL:
- return EXIT_FAILURE;
-}
-
-static int test_string_join(const struct test* t) {
- char* s = NULL;
-
- // Some test elements
- char* elements1[] = {
- "A",
- "B",
- "C",
- NULL,
- };
-
- // Join with newline
- s = pakfire_string_join(elements1, "\n");
- ASSERT_STRING_EQUALS(s, "A\nB\nC");
-
- if (s) {
- free(s);
- s = NULL;
- }
-
- // Join with empty delimiter
- s = pakfire_string_join(elements1, "");
- ASSERT_STRING_EQUALS(s, "ABC");
-
- if (s) {
- free(s);
- s = NULL;
- }
-
- char* elements2[] = {
- "",
- "",
- "",
- NULL,
- };
-
- // Join list with empty elements
- s = pakfire_string_join(elements2, "X");
- ASSERT_STRING_EQUALS(s, "XX");
-
- if (s) {
- free(s);
- s = NULL;
- }
-
- // Invalid inputs
- s = pakfire_string_join(NULL, NULL);
- ASSERT_ERRNO(!s, EINVAL);
-
- s = pakfire_string_join(elements1, NULL);
- ASSERT_ERRNO(!s, EINVAL);
-
- s = pakfire_string_join(NULL, "\n");
- ASSERT_ERRNO(!s, EINVAL);
-
- char* elements3[] = {
- NULL,
- };
-
- // Join empty elements
- ASSERT_NULL(pakfire_string_join(elements3, "\n"));
-
- return EXIT_SUCCESS;
-
-FAIL:
- if (s)
- free(s);
-
- return EXIT_FAILURE;
-}
-
-static int test_format_size(const struct test* t) {
- char buffer[128];
- char small_buffer[2];
- int r;
-
- ASSERT(pakfire_format_size(buffer, 0) == 2);
- ASSERT_STRING_EQUALS(buffer, "0 ");
-
- ASSERT(pakfire_format_size(buffer, 1024) == 2);
- ASSERT_STRING_EQUALS(buffer, "1k");
-
- ASSERT(pakfire_format_size(buffer, 1024 * 1024) == 4);
- ASSERT_STRING_EQUALS(buffer, "1.0M");
-
- ASSERT(pakfire_format_size(small_buffer, 0) == 2);
- ASSERT_STRING_EQUALS(small_buffer, "");
-
- return EXIT_SUCCESS;
-
-FAIL:
- return EXIT_FAILURE;
-}
-
int main(int argc, const char* argv[]) {
testsuite_add_test(test_basename);
testsuite_add_test(test_dirname);
- testsuite_add_test(test_string_startswith);
- testsuite_add_test(test_string_endswith);
- testsuite_add_test(test_string_matches);
- testsuite_add_test(test_string_partition);
- testsuite_add_test(test_string_replace);
- testsuite_add_test(test_string_split);
- testsuite_add_test(test_string_join);
- testsuite_add_test(test_format_size);
return testsuite_run(argc, argv);
}