1
0

initial commit

This commit is contained in:
2025-05-27 11:36:06 +03:00
commit 4ba42acfea
14 changed files with 1584 additions and 0 deletions

174
main.cc Normal file
View File

@@ -0,0 +1,174 @@
/* SPDX-License-Identifier: Apache-2.0
* (c) 2025, Konstantin Demin
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <cerrno>
#include <cstdio>
#include <cstdlib>
extern "C" {
#include <unistd.h>
}
#include "overlay.hh"
static
void usage(int retcode = 0)
{
static const char usage_msg[] =
"overlaydirs 0.0.1\n"
"Usage:\n"
" overlaydirs --help\n"
" show this message\n"
" overlaydirs --list [--no-sort|--zero] <source directory> [..<source directory>]\n"
// TODO: shell-escape mode
/* " overlaydirs --list [--no-sort|--zero|--escape] <source directory> [..<source directory>]\n" */
" list entries\n"
" overlaydirs --merge <target directory> <source directory> [..<source directory>]\n"
" symlinks entries into <target directory>\n"
"\n"
" --no-sort - don't sort entries\n"
" --zero - separate entries with NUL instead of LF\n"
// TODO: shell-escape mode
/*
" --escape - shell-escape strings\n"
"\n"
"Notes:\n"
" - flags \"--zero\" and \"--escape\" are mutually exclusive.\n"
*/
;
(void) write(STDERR_FILENO, usage_msg, sizeof(usage_msg));
exit(retcode);
}
static int main_list(int argc, char * argv[]);
static int main_merge(int argc, char * argv[]);
int main(int argc, char * argv[])
{
if (argc < 2) usage(0);
if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0))
usage(0);
else if (strcmp(argv[1], "--list") == 0)
return main_list(argc, argv);
else if (strcmp(argv[1], "--merge") == 0)
return main_merge(argc, argv);
else
usage(EINVAL);
return 0;
}
static int main_list(int argc, char * argv[])
{
if (argc < 3) usage(EINVAL);
print_mode print_m = print_mode::_default;
sort_mode sort_m = sort_mode::_default;
int arg_start = 2;
while (arg_start < argc) {
char * _arg = argv[arg_start];
if (strncmp(_arg, "--", 2) != 0) break;
if (strcmp(_arg, "--") == 0) {
arg_start++;
break;
}
else if (strcmp(_arg, "--no-sort") == 0) {
arg_start++;
if (sort_m != sort_mode::_default) {
(void) fprintf(stderr, "overlaydirs: no-sort mode already set\n");
}
sort_m = sort_mode::none;
}
else if (strcmp(_arg, "--zero") == 0) {
arg_start++;
if (print_m != print_mode::_default) {
(void) fprintf(stderr, "overlaydirs: output mode already set\n");
}
print_m = print_mode::zero;
}
// TODO
/*
else if (strcmp(_arg, "--escape") == 0) {
arg_start++;
if (print_m != print_mode::_default) {
(void) fprintf(stderr, "overlaydirs: output mode already set\n");
}
print_m = print_mode::shell_escape;
}
*/
else {
(void) fprintf(stderr, "overlaydirs: unknown option \"%s\"\n", _arg);
// nevertheless, continue and try argument as a directory
break;
}
}
auto roots = std::vector<ovl_dirspec_t>();
for (int i = arg_start; i < argc; i++) {
ovl_dirspec_t t;
if (!arg_to_rootspec(argv[i], &t, ovl_rootspec_flags::relative)) continue;
roots.push_back(t);
}
if (roots.empty()) {
(void) fprintf(stderr, "overlaydirs: no usable sources found\n");
return EINVAL;
}
auto ovl = process_overlay(roots, sort_m);
// not needed anymore
roots.clear();
roots.shrink_to_fit();
list_overlay(ovl, print_m);
return 0;
}
static int main_merge(int argc, char * argv[])
{
if (argc < 4) usage(EINVAL);
ovl_dirspec_t target;
if (!arg_to_rootspec(argv[2], &target, ovl_rootspec_flags::relative)) {
(void) fprintf(stderr, "overlaydirs: not a directory: \"%s\"\n", argv[2]);
return EINVAL;
}
if (!is_empty_dir(target.fd)) {
(void) fprintf(stderr, "overlaydirs: target directory is not empty\n");
return EEXIST;
}
auto roots = std::vector<ovl_dirspec_t>();
for (int i = 3; i < argc; i++) {
ovl_dirspec_t t;
if (!arg_to_rootspec(argv[i], &t)) continue;
roots.push_back(t);
}
if (roots.empty()) {
(void) fprintf(stderr, "overlaydirs: no usable sources found\n");
return EINVAL;
}
auto ovl = process_overlay(roots);
// not needed anymore
roots.clear();
roots.shrink_to_fit();
int rv = merge_overlay(ovl, target);
if (rv == -1) {
(void) fprintf(stderr, "overlaydirs: target directory is not empty\n");
return EEXIST;
}
return rv;
}