From f68ac974d84737d1d37d2a68b4de903015309d98 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Sat, 2 Nov 2024 11:17:36 +0000 Subject: [PATCH] initial commit --- .gitignore | 145 +++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 20 ++++++ cmake/FindBluelib.cmake | 153 ++++++++++++++++++++++++++++++++++++++++ src/capture.c | 115 ++++++++++++++++++++++++++++++ src/check-sig.c | 33 +++++++++ src/commands.h | 17 +++++ src/create.c | 40 +++++++++++ src/explore.c | 34 +++++++++ src/extract.c | 33 +++++++++ src/get-manifest.c | 33 +++++++++ src/main.c | 19 +++++ src/query.c | 39 ++++++++++ src/shell.c | 54 ++++++++++++++ src/wrap.c | 96 +++++++++++++++++++++++++ 14 files changed, 831 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 cmake/FindBluelib.cmake create mode 100644 src/capture.c create mode 100644 src/check-sig.c create mode 100644 src/commands.h create mode 100644 src/create.c create mode 100644 src/explore.c create mode 100644 src/extract.c create mode 100644 src/get-manifest.c create mode 100644 src/main.c create mode 100644 src/query.c create mode 100644 src/shell.c create mode 100644 src/wrap.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f342b6b --- /dev/null +++ b/.gitignore @@ -0,0 +1,145 @@ +# Created by https://www.toptal.com/developers/gitignore/api/linux,vim,c,cmake,macos +# Edit at https://www.toptal.com/developers/gitignore?templates=linux,vim,c,cmake,macos + +### C ### +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +### CMake ### +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +### CMake Patch ### +# External projects +*-prefix/ + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +# End of https://www.toptal.com/developers/gitignore/api/linux,vim,c,cmake,macos + +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9f5cd61 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.18) +project(ec3) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +find_package(Bluelib REQUIRED) +find_package(LibLZMA REQUIRED) + +file(GLOB ec3_sources + src/*.c + src/*.h) + +add_executable(ec3 ${ec3_sources}) +target_link_libraries(ec3 + Bluelib::Core + Bluelib::Object + Bluelib::Term + Bluelib::Cmd + LibLZMA::LibLZMA) + diff --git a/cmake/FindBluelib.cmake b/cmake/FindBluelib.cmake new file mode 100644 index 0000000..95fe532 --- /dev/null +++ b/cmake/FindBluelib.cmake @@ -0,0 +1,153 @@ +#[=======================================================================[.rst: +FindBluelib +------------ + +Find the Bluelib library and header directories + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module defines the following :prop_tgt:`IMPORTED` target: + +``Bluelib::Bluelib`` +The Bluelib library, if found + +Result Variables +^^^^^^^^^^^^^^^^ + +This module will set the following variables in your project: + +``Bluelib_FOUND`` +true if the Bluelib C headers and libraries were found +``Bluelib_INCLUDE_DIR`` +directories containing the Bluelib C headers. + +``Bluelib_LIBRARY`` +the C library to link against + +Hints +^^^^^ + +The user may set the environment variable ``Bluelib_PREFIX`` to the root +directory of a Bluelib library installation. +#]=======================================================================] + +set (Bluelib_SEARCH_PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr/local/share + /usr + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt + ${Bluelib_PREFIX} + $ENV{Bluelib_PREFIX}) + +if (Bluelib_STATIC) + set(_lib_suffix "-s") +endif () + +set(supported_components Core Object Term Cmd) +set(components ${Bluelib_FIND_COMPONENTS}) +string(REPLACE ";" ", " supported_components_string_list "${supported_components}") + +if (NOT components) + set(components ${supported_components}) +endif () + +set(required_vars) + +foreach (component ${components}) + if (NOT "${component}" IN_LIST supported_components) + message(FATAL_ERROR "'${component}' is not a valid Bluelib module.\nSupported modules: ${supported_components_string_list}") + endif () + + string(TOLOWER ${component} header_name) + set(lib_name ${header_name}${_lib_suffix}) + + if (NOT Bluelib_${component}_INCLUDE_DIR) + find_path(Bluelib_${component}_INCLUDE_DIR + NAMES blue/${header_name}.h ${Bluelib_FIND_ARGS} + PATH_SUFFIXES include + PATHS ${Bluelib_SEARCH_PATHS}) + endif () + + if (NOT Bluelib_${component}_LIBRARY) + find_library(Bluelib_${component}_LIBRARY + NAMES blue-${lib_name} ${Bluelib_FIND_ARGS} + PATH_SUFFIXES lib + PATHS ${Bluelib_SEARCH_PATHS}) + else () + # on Windows, ensure paths are in canonical format (forward slahes): + file(TO_CMAKE_PATH "${Bluelib_${component}_LIBRARY}" Bluelib_${component}_LIBRARY) + endif() + + list(APPEND required_vars Bluelib_${component}_INCLUDE_DIR Bluelib_${component}_LIBRARY) +endforeach (component) + +unset(Bluelib_FIND_ARGS) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(Bluelib + REQUIRED_VARS ${required_vars}) + +if (Bluelib_FOUND) + set(created_targets) + foreach (component ${components}) + string(TOLOWER ${component} header_name) + set(lib_name ${header_name}${_lib_suffix}) + + if(NOT TARGET Bluelib::${component}) + add_library(Bluelib::${component} UNKNOWN IMPORTED) + set_target_properties(Bluelib::${component} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Bluelib_${component}_INCLUDE_DIR}") + target_compile_definitions(Bluelib::${component} INTERFACE _CRT_SECURE_NO_WARNINGS=1) + + set_target_properties(Bluelib::${component} PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${Bluelib_${component}_LIBRARY}") + set(created_targets ${created_targets} ${component}) + endif () + endforeach (component) + + foreach (component ${created_targets}) + if ("${component}" STREQUAL "Object") + if (NOT TARGET Bluelib::Core) + message(FATAL_ERROR "Bluelib: Module 'Object' depends on 'Core', which was not specified in find_package()") + endif () + + target_link_libraries(Bluelib::Object INTERFACE Bluelib::Core) + endif () + + if ("${component}" STREQUAL "Term") + if (NOT TARGET Bluelib::Core) + message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Core', which was not specified in find_package()") + endif () + + if (NOT TARGET Bluelib::Object) + message(FATAL_ERROR "Bluelib: Module 'Term' depends on 'Object', which was not specified in find_package()") + endif () + + target_link_libraries(Bluelib::Term INTERFACE Bluelib::Core Bluelib::Object) + endif () + + if ("${component}" STREQUAL "Cmd") + if (NOT TARGET Bluelib::Core) + message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Core', which was not specified in find_package()") + endif () + + if (NOT TARGET Bluelib::Object) + message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Object', which was not specified in find_package()") + endif () + + if (NOT TARGET Bluelib::Term) + message(FATAL_ERROR "Bluelib: Module 'Cmd' depends on 'Term', which was not specified in find_package()") + endif () + + target_link_libraries(Bluelib::Cmd INTERFACE Bluelib::Core Bluelib::Object Bluelib::Term) + endif () + endforeach (component) +endif() diff --git a/src/capture.c b/src/capture.c new file mode 100644 index 0000000..fb6a41a --- /dev/null +++ b/src/capture.c @@ -0,0 +1,115 @@ +#include "commands.h" + +#include + +#define BUFFER_SIZE 65536 + +enum { + OPT_OUTPATH, + OPT_OUTPATH_PATH, + + ARG_DIRECTORY, + + OPT_TAGGED_DIRECTORY, + OPT_TAGGED_DIRECTORY_TAG, + OPT_TAGGED_DIRECTORY_PATH, + + OPT_VERBOSE, +}; + +static int capture( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + return 0; +} + +B_COMMAND(CMD_CAPTURE, CMD_ROOT) +{ + B_COMMAND_NAME("capture"); + B_COMMAND_SHORT_NAME('Z'); + B_COMMAND_DESC( + "capture one or more directories into an ec3 container. each " + "directory specified will be stored in a separate volume " + "within " + "the created container."); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(capture); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_OPTION(OPT_OUTPATH) + { + B_OPTION_SHORT_NAME('o'); + B_OPTION_LONG_NAME("out"); + B_OPTION_DESC("the path to save the new file to."); + + B_OPTION_ARG(OPT_OUTPATH_PATH) + { + B_ARG_NAME("path"); + B_ARG_NR_VALUES(1); + } + } + + B_COMMAND_ARG(ARG_DIRECTORY) + { + B_ARG_NAME("directory"); + B_ARG_DESC( + "a directory to add to the container. a volume " + "will be created " + "within the container to store the specified " + "directory."); + + B_ARG_NR_VALUES(B_ARG_1_OR_MORE_VALUES); + } + + B_COMMAND_OPTION(OPT_TAGGED_DIRECTORY) + { + B_OPTION_SHORT_NAME('D'); + B_OPTION_LONG_NAME("tagged-directory"); + B_OPTION_DESC( + "a file to add to the container, with an associated " + "tag. a disk " + "image will be created within the container to store " + "the specified " + "directory. the tag must be either: (a) a 64-bit " + "hexadecimal " + "number; or (b) a string of no more than 8 " + "characters."); + + B_OPTION_ARG(OPT_TAGGED_DIRECTORY_TAG) + { + B_ARG_NAME("tag"); + B_ARG_NR_VALUES(1); + } + + B_OPTION_ARG(OPT_TAGGED_DIRECTORY_PATH) + { + B_ARG_NAME("path"); + B_ARG_NR_VALUES(1); + } + } + + B_COMMAND_OPTION(OPT_VERBOSE) + { + B_OPTION_SHORT_NAME('v'); + B_OPTION_LONG_NAME("verbose"); + B_OPTION_DESC( + "show detailed output logs. this option can be " + "specified multiple " + "times to increase the level of output."); + } + + B_COMMAND_USAGE() + { + B_COMMAND_USAGE_OPT(OPT_OUTPATH); + B_COMMAND_USAGE_ARG(ARG_DIRECTORY); + } + + B_COMMAND_USAGE() + { + B_COMMAND_USAGE_OPT(OPT_OUTPATH); + B_COMMAND_USAGE_OPT(OPT_TAGGED_DIRECTORY); + } +} diff --git a/src/check-sig.c b/src/check-sig.c new file mode 100644 index 0000000..be378d2 --- /dev/null +++ b/src/check-sig.c @@ -0,0 +1,33 @@ +#include "commands.h" + +#include + +enum { + ARG_FILE, +}; + +static int check_sig( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + return 0; +} + +B_COMMAND(CMD_CHECK_SIG, CMD_ROOT) +{ + B_COMMAND_NAME("check-sig"); + B_COMMAND_SHORT_NAME('Y'); + B_COMMAND_DESC("validate the digital signature of an ec3 file"); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(check_sig); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_ARG(ARG_FILE) + { + B_ARG_NAME("file"); + B_ARG_NR_VALUES(B_ARG_1_OR_MORE_VALUES); + B_ARG_DESC("the file(s) to validate"); + } +} diff --git a/src/commands.h b/src/commands.h new file mode 100644 index 0000000..b7d05a2 --- /dev/null +++ b/src/commands.h @@ -0,0 +1,17 @@ +#ifndef COMMANDS_H_ +#define COMMANDS_H_ + +enum command_id { + CMD_ROOT = 0, + CMD_CREATE, + CMD_WRAP, + CMD_CAPTURE, + CMD_SHELL, + CMD_EXTRACT, + CMD_GET_MANIFEST, + CMD_CHECK_SIG, + CMD_EXPLORE, + CMD_QUERY, +}; + +#endif diff --git a/src/create.c b/src/create.c new file mode 100644 index 0000000..a8e6b73 --- /dev/null +++ b/src/create.c @@ -0,0 +1,40 @@ +#include "commands.h" + +#include + +enum { + OPT_OUTPATH, + OPT_OUTPATH_PATH, +}; + +static int create( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + return 0; +} + +B_COMMAND(CMD_CREATE, CMD_ROOT) +{ + B_COMMAND_NAME("create"); + B_COMMAND_SHORT_NAME('C'); + B_COMMAND_DESC("create an ec3 file"); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(create); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_OPTION(OPT_OUTPATH) + { + B_OPTION_SHORT_NAME('o'); + B_OPTION_LONG_NAME("out"); + B_OPTION_DESC("the path to save the new file to"); + + B_OPTION_ARG(OPT_OUTPATH_PATH) + { + B_ARG_NAME("path"); + B_ARG_NR_VALUES(1); + } + } +} diff --git a/src/explore.c b/src/explore.c new file mode 100644 index 0000000..0f124e0 --- /dev/null +++ b/src/explore.c @@ -0,0 +1,34 @@ +#include "commands.h" + +#include + +enum { + ARG_FILE, +}; + +static int explore( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + return 0; +} + +B_COMMAND(CMD_EXPLORE, CMD_ROOT) +{ + B_COMMAND_NAME("explore"); + B_COMMAND_SHORT_NAME('E'); + B_COMMAND_DESC( + "start a basic shell to browse the contents of an ec3 file"); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(explore); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_ARG(ARG_FILE) + { + B_ARG_NAME("file"); + B_ARG_NR_VALUES(1); + B_ARG_DESC("the file to explore"); + } +} diff --git a/src/extract.c b/src/extract.c new file mode 100644 index 0000000..4f313d7 --- /dev/null +++ b/src/extract.c @@ -0,0 +1,33 @@ +#include "commands.h" + +#include + +enum { + ARG_FILE, +}; + +static int extract( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + return 0; +} + +B_COMMAND(CMD_EXTRACT, CMD_ROOT) +{ + B_COMMAND_NAME("extract"); + B_COMMAND_SHORT_NAME('X'); + B_COMMAND_DESC("extract the contents of an ec3 file"); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(extract); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_ARG(ARG_FILE) + { + B_ARG_NAME("file"); + B_ARG_NR_VALUES(B_ARG_1_OR_MORE_VALUES); + B_ARG_DESC("the file to extract"); + } +} diff --git a/src/get-manifest.c b/src/get-manifest.c new file mode 100644 index 0000000..7b29077 --- /dev/null +++ b/src/get-manifest.c @@ -0,0 +1,33 @@ +#include "commands.h" + +#include + +enum { + ARG_FILE, +}; + +static int get_manifest( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + return 0; +} + +B_COMMAND(CMD_GET_MANIFEST, CMD_ROOT) +{ + B_COMMAND_NAME("get-manifest"); + B_COMMAND_SHORT_NAME('M'); + B_COMMAND_DESC("retrieve and print the manifest of an ec3 file"); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(get_manifest); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_ARG(ARG_FILE) + { + B_ARG_NAME("file"); + B_ARG_NR_VALUES(1); + B_ARG_DESC("the file to query"); + } +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..77e7423 --- /dev/null +++ b/src/main.c @@ -0,0 +1,19 @@ +#include "commands.h" + +#include +#include + +B_COMMAND(CMD_ROOT, B_COMMAND_INVALID_ID) +{ + B_COMMAND_NAME("ec3"); + B_COMMAND_DESC( + "Elastic, Compressed, Content-Addressed Container image " + "manipulation tool"); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_HELP_OPTION(); +} + +int main(int argc, const char **argv) +{ + return b_command_dispatch(CMD_ROOT, argc, argv); +} diff --git a/src/query.c b/src/query.c new file mode 100644 index 0000000..0e3f329 --- /dev/null +++ b/src/query.c @@ -0,0 +1,39 @@ +#include "commands.h" + +#include + +enum { + ARG_CONTAINER, + OPT_VERBOSE, +}; + +static int query( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + return 0; +} + +B_COMMAND(CMD_QUERY, CMD_ROOT) +{ + B_COMMAND_NAME("query"); + B_COMMAND_SHORT_NAME('Q'); + B_COMMAND_DESC("query information about a container."); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(query); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_ARG(ARG_CONTAINER) + { + B_ARG_NAME("container"); + B_ARG_DESC("the container to query."); + B_ARG_NR_VALUES(1); + } + + B_COMMAND_USAGE() + { + B_COMMAND_USAGE_ARG(ARG_CONTAINER); + } +} diff --git a/src/shell.c b/src/shell.c new file mode 100644 index 0000000..2727a04 --- /dev/null +++ b/src/shell.c @@ -0,0 +1,54 @@ +#include "commands.h" + +#include + +enum { + ARG_CONTAINER, + OPT_VERBOSE, +}; + +static int shell( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + return 0; +} + +B_COMMAND(CMD_SHELL, CMD_ROOT) +{ + B_COMMAND_NAME("shell"); + B_COMMAND_SHORT_NAME('S'); + B_COMMAND_DESC( + "start a basic shell to explore the volumes within a " + "container."); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(shell); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_OPTION(OPT_VERBOSE) + { + B_OPTION_SHORT_NAME('v'); + B_OPTION_LONG_NAME("verbose"); + B_OPTION_DESC( + "show detailed output logs. this option can be " + "specified multiple " + "times to increase the level of output."); + } + + B_COMMAND_ARG(ARG_CONTAINER) + { + B_ARG_NAME("container"); + B_ARG_DESC( + "the container to explore. the container must contain " + "at least one " + "volume."); + B_ARG_NR_VALUES(1); + } + + B_COMMAND_USAGE() + { + B_COMMAND_USAGE_ARG(ARG_CONTAINER); + } +} diff --git a/src/wrap.c b/src/wrap.c new file mode 100644 index 0000000..cda0809 --- /dev/null +++ b/src/wrap.c @@ -0,0 +1,96 @@ +#include "commands.h" + +#include +#include + +enum { + OPT_OUTPATH, + OPT_OUTPATH_PATH, + + ARG_FILE, + ARG_FILE_PATH, + + OPT_TAGGED_FILE, + OPT_TAGGED_FILE_TAG, + OPT_TAGGED_FILE_PATH, +}; + +static int wrap( + const b_command *self, + const b_arglist *opt, + const b_array *args) +{ + return 0; +} + +B_COMMAND(CMD_WRAP, CMD_ROOT) +{ + B_COMMAND_NAME("wrap"); + B_COMMAND_SHORT_NAME('W'); + B_COMMAND_DESC( + "wrap one or more files into an ec3 container. each file will " + "be " + "stored in a separate blob tag within the created container."); + B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT); + B_COMMAND_FUNCTION(wrap); + + B_COMMAND_HELP_OPTION(); + + B_COMMAND_OPTION(OPT_OUTPATH) + { + B_OPTION_SHORT_NAME('o'); + B_OPTION_LONG_NAME("out"); + B_OPTION_DESC("the path to save the new file to"); + + B_OPTION_ARG(OPT_OUTPATH_PATH) + { + B_ARG_NAME("path"); + B_ARG_NR_VALUES(1); + } + } + + B_COMMAND_ARG(ARG_FILE) + { + B_ARG_NAME("file"); + B_ARG_DESC("a file to add to the container"); + + B_ARG_NR_VALUES(B_ARG_1_OR_MORE_VALUES); + } + + B_COMMAND_OPTION(OPT_TAGGED_FILE) + { + B_OPTION_SHORT_NAME('I'); + B_OPTION_LONG_NAME("tagged-file"); + B_OPTION_DESC( + "a file to add to the container, with an associated " + "tag. " + "the tag must be either: (a) a 64-bit hexadecimal " + "number; " + "or (b) a string of no more than 8 characters."); + + B_OPTION_ARG(OPT_TAGGED_FILE_TAG) + { + B_ARG_NAME("tag"); + B_ARG_DESC("the tag!"); + B_ARG_NR_VALUES(1); + } + + B_OPTION_ARG(OPT_TAGGED_FILE_PATH) + { + B_ARG_NAME("path"); + B_ARG_NR_VALUES(1); + } + } + + B_COMMAND_USAGE() + { + B_COMMAND_USAGE_OPT(OPT_OUTPATH); + B_COMMAND_USAGE_ARG(ARG_FILE); + } + + B_COMMAND_USAGE() + { + B_COMMAND_USAGE_OPT(OPT_OUTPATH); + B_COMMAND_USAGE_OPT(OPT_TAGGED_FILE); + } +}