#include "cli.h"
#include <unistd.h>
static int cmd_extract(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "usage: dtob extract <input.dtob> <key> > output\n");
return 1;
}
size_t len;
uint8_t *buf = read_file(argv[0], &len);
if (!buf) return 1;
DtobValue *root = dtob_decode(buf, len);
free(buf);
if (!root) {
fprintf(stderr, "error: failed to decode DTOB\n");
return 1;
}
if (root->type != DTOB_KV_SET) {
fprintf(stderr, "error: root is not a kv_set\n");
dtob_free(root);
return 1;
}
const char *target = argv[1];
DtobValue *found = NULL;
for (size_t i = 0; i < root->num_pairs; i++) {
if (root->pairs[i].key_len == strlen(target) &&
memcmp(root->pairs[i].key, target, root->pairs[i].key_len) == 0) {
found = root->pairs[i].value;
break;
}
}
if (!found) {
fprintf(stderr, "error: key '%s' not found\n", target);
dtob_free(root);
return 1;
}
if (found->data && found->data_len > 0) {
fwrite(found->data, 1, found->data_len, stdout);
}
dtob_free(root);
return 0;
}
static int cmd_info(int argc, char **argv)
{
if (argc < 1) {
fprintf(stderr, "usage: dtob info <input.dtob>\n");
return 1;
}
size_t len;
uint8_t *buf = read_file(argv[0], &len);
if (!buf) return 1;
DtobValue *root = dtob_decode(buf, len);
free(buf);
if (!root) {
fprintf(stderr, "error: failed to decode DTOB\n");
return 1;
}
fprintf(stderr, "file size: %zu bytes\n", len);
dtob_print(root, 0);
dtob_free(root);
return 0;
}
static void exec_subcommand(const char *argv0, const char *cmd,
int argc, char **argv)
{
char subcmd[256];
snprintf(subcmd, sizeof(subcmd), "dtob-%s", cmd);
char **new_argv = malloc(((size_t)argc + 2) * sizeof(char *));
if (!new_argv) { perror("malloc"); exit(1); }
new_argv[0] = subcmd;
for (int i = 0; i < argc; i++)
new_argv[i + 1] = argv[i];
new_argv[argc + 1] = NULL;
const char *slash = strrchr(argv0, '/');
if (slash) {
size_t dir_len = (size_t)(slash - argv0 + 1);
char path[512];
if (dir_len + strlen(subcmd) < sizeof(path)) {
memcpy(path, argv0, dir_len);
strcpy(path + dir_len, subcmd);
new_argv[0] = path;
execv(path, new_argv);
}
}
execvp(subcmd, new_argv);
fprintf(stderr, "dtob: '%s' is not a dtob command\n", cmd);
free(new_argv);
exit(1);
}
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "usage: dtob <command> [args...]\n");
fprintf(stderr, "commands: encode, represent, extract, info, memcache\n");
return 1;
}
const char *cmd = argv[1];
int sub_argc = argc - 2;
char **sub_argv = argv + 2;
if (strcmp(cmd, "extract") == 0) return cmd_extract(sub_argc, sub_argv);
if (strcmp(cmd, "info") == 0) return cmd_info(sub_argc, sub_argv);
if (strcmp(cmd, "memcache") == 0) return cmd_memcache(sub_argc, sub_argv);
exec_subcommand(argv[0], cmd, sub_argc, sub_argv);
return 1;
}