#include <stdlib.h>
#include <string.h>
+#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
+ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
+ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
+#include <fcntl.h>
+#include <spawn.h>
+#include <unistd.h>
+#endif
+
#include "helpers.h"
typedef struct SDArchiverInternalToWrite {
return 0;
}
+
+int simple_archiver_de_compress(int pipe_fd_in, int pipe_fd_out,
+ const char *cmd) {
+ posix_spawn_file_actions_t file_actions;
+ memset(&file_actions, 0, sizeof(file_actions));
+ if (posix_spawn_file_actions_init(&file_actions) != 0) {
+ close(pipe_fd_in);
+ close(pipe_fd_out);
+ return 1;
+ } else if (posix_spawn_file_actions_adddup2(&file_actions, pipe_fd_in, 0) !=
+ 0) {
+ posix_spawn_file_actions_destroy(&file_actions);
+ close(pipe_fd_in);
+ close(pipe_fd_out);
+ return 2;
+ } else if (posix_spawn_file_actions_adddup2(&file_actions, pipe_fd_out, 1) !=
+ 0) {
+ posix_spawn_file_actions_destroy(&file_actions);
+ close(pipe_fd_in);
+ close(pipe_fd_out);
+ return 3;
+ }
+
+ __attribute__((cleanup(
+ simple_archiver_helper_cmd_string_argv_free_ptr))) char **cmd_argv =
+ simple_archiver_helper_cmd_string_to_argv(cmd);
+
+ pid_t spawned_pid;
+ if (posix_spawnp(&spawned_pid, cmd_argv[0], &file_actions, NULL, cmd_argv,
+ NULL) != 0) {
+ posix_spawn_file_actions_destroy(&file_actions);
+ return 4;
+ }
+
+ posix_spawn_file_actions_destroy(&file_actions);
+
+ return 0;
+}
/// Returns zero on success.
int simple_archiver_print_archive_info(FILE *in_f);
+/// Returns zero on success.
+int simple_archiver_de_compress(int pipe_fd_in, int pipe_fd_out,
+ const char *cmd);
+
#endif
#include "helpers.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
int simple_archiver_helper_is_big_endian(void) {
union {
uint32_t i;
}
}
}
+
+char **simple_archiver_helper_cmd_string_to_argv(const char *cmd) {
+ unsigned int capacity = 16;
+ unsigned int idx = 0;
+ // Size of every pointer is the same, so using size of (void*) should be ok.
+ char **args = malloc(sizeof(void *) * capacity);
+ memset(args, 0, sizeof(void *) * capacity);
+
+ unsigned int word_capacity = 16;
+ unsigned int word_idx = 0;
+ char *word = malloc(word_capacity);
+ memset(word, 0, word_capacity);
+ for (const char *c = cmd; *c != 0; ++c) {
+ if (isspace(*c)) {
+ if (word_idx > 0) {
+ if (idx >= capacity) {
+ capacity *= 2;
+ args = realloc(args, sizeof(void *) * capacity);
+ }
+ args[idx] = malloc(word_idx + 1);
+ memcpy(args[idx], word, word_idx);
+ args[idx][word_idx] = 0;
+ ++idx;
+ word_idx = 0;
+ }
+ } else {
+ if (word_idx >= word_capacity) {
+ word_capacity *= 2;
+ word = realloc(word, word_capacity);
+ }
+ word[word_idx++] = *c;
+ }
+ }
+ if (word_idx > 0) {
+ if (idx >= capacity) {
+ capacity *= 2;
+ args = realloc(args, sizeof(void *) * capacity);
+ }
+ args[idx] = malloc(word_idx + 1);
+ memcpy(args[idx], word, word_idx);
+ args[idx][word_idx] = 0;
+ ++idx;
+ word_idx = 0;
+ }
+
+ free(word);
+
+ if (idx >= capacity) {
+ args = realloc(args, sizeof(void *) * (capacity + 1));
+ args[capacity] = NULL;
+ }
+
+ return args;
+}
+
+void simple_archiver_helper_cmd_string_argv_free(char **argv_strs) {
+ if (argv_strs) {
+ for (char **iter = argv_strs; *iter != 0; ++iter) {
+ free(*iter);
+ }
+ free(argv_strs);
+ }
+}
+
+void simple_archiver_helper_cmd_string_argv_free_ptr(char ***argv_strs) {
+ if (argv_strs) {
+ simple_archiver_helper_cmd_string_argv_free(*argv_strs);
+ *argv_strs = NULL;
+ }
+}
/// Swaps value from/to big-endian. Nop on big-endian systems.
void simple_archiver_helper_64_bit_be(uint64_t *value);
+/// Returns a array of c-strings on success, NULL on error.
+/// The returned array must be free'd with
+/// simple_archiver_helper_cmd_string_argv_free(...).
+char **simple_archiver_helper_cmd_string_to_argv(const char *cmd);
+
+void simple_archiver_helper_cmd_string_argv_free(char **argv_strs);
+void simple_archiver_helper_cmd_string_argv_free_ptr(char ***argv_strs);
+
#endif
++checks_passed; \
} \
} while (0);
+#define CHECK_STREQ(a, b) \
+ do { \
+ ++checks_checked; \
+ if (strcmp((a), (b)) == 0) { \
+ ++checks_passed; \
+ } else { \
+ printf("CHECK_STREQ at line %u failed: %s != %s\n", __LINE__, #a, #b); \
+ } \
+ } while (0);
int main(void) {
// Test parser.
}
}
+ // Test helpers cmd string to argv.
+ do {
+ const char *cmd = "zstd --compress --ultra\n -20 derp_file";
+ char **result_argv = simple_archiver_helper_cmd_string_to_argv(cmd);
+ CHECK_TRUE(result_argv);
+ if (!result_argv) {
+ break;
+ }
+ CHECK_STREQ("zstd", result_argv[0]);
+ CHECK_STREQ("--compress", result_argv[1]);
+ CHECK_STREQ("--ultra", result_argv[2]);
+ CHECK_STREQ("-20", result_argv[3]);
+ CHECK_STREQ("derp_file", result_argv[4]);
+ CHECK_TRUE(result_argv[5] == NULL);
+
+ simple_archiver_helper_cmd_string_argv_free(result_argv);
+ } while (0);
+
printf("Checks checked: %u\n", checks_checked);
printf("Checks passed: %u\n", checks_passed);
return checks_passed == checks_checked ? 0 : 1;