From 56ebb9f6af88312a21358a1a10a8346c39b0370f Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 1 Aug 2025 16:07:33 +0100 Subject: [PATCH] [feature] Add command handling and usage functions for aaruformattool using argtable3 --- tool/CMakeLists.txt | 8 +- tool/commands.c | 123 +++++++++++++++++++ tool/commands.h | 42 +++++++ tool/main.c | 237 ++----------------------------------- tool/usage.c | 101 ++++++++++++++++ tool/usage.h | 32 +++++ tool/{main.h => version.h} | 0 7 files changed, 318 insertions(+), 225 deletions(-) create mode 100644 tool/commands.c create mode 100644 tool/commands.h create mode 100644 tool/usage.c create mode 100644 tool/usage.h rename tool/{main.h => version.h} (100%) diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt index 3471333..c623266 100644 --- a/tool/CMakeLists.txt +++ b/tool/CMakeLists.txt @@ -1,8 +1,14 @@ project(aaruformattool) find_package(ICU COMPONENTS uc REQUIRED) +find_package(Argtable3 CONFIG REQUIRED) include_directories(${ICU_INCLUDE_DIRS}) -add_executable(aaruformattool main.c main.h aaruformattool.h identify.c info.c helpers.c read.c printhex.c verify.c ecc_cd.c) +add_executable(aaruformattool main.c version.h aaruformattool.h identify.c info.c helpers.c read.c printhex.c verify.c ecc_cd.c + commands.h + commands.c + usage.h + usage.c) +target_link_libraries(aaruformattool "aaruformat" argtable3::argtable3) target_link_libraries(aaruformattool "aaruformat" ICU::uc) diff --git a/tool/commands.c b/tool/commands.c new file mode 100644 index 0000000..27200e8 --- /dev/null +++ b/tool/commands.c @@ -0,0 +1,123 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 Natalia Portillo. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "commands.h" +#include +#include +#include +#include "aaruformattool.h" +#include "usage.h" + +int cmd_identify(int argc, char *argv[]) +{ + struct arg_str *filename = arg_str1(NULL, NULL, "", "Image to identify"); + struct arg_end *end = arg_end(10); + void *argtable[] = {filename, end}; + + if(arg_parse(argc, argv, argtable) > 0) + { + arg_print_errors(stderr, end, "identify"); + usage_identify(); + arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); + return -1; + } + + int result = identify(filename->sval[0]); + arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); + return result; +} + +int cmd_info(int argc, char *argv[]) +{ + struct arg_str *filename = arg_str1(NULL, NULL, "", "Image to inspect"); + struct arg_end *end = arg_end(10); + void *argtable[] = {filename, end}; + + if(arg_parse(argc, argv, argtable) > 0) + { + arg_print_errors(stderr, end, "info"); + usage_info(); + arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); + return -1; + } + + int result = info(filename->sval[0]); + arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); + return result; +} + +int cmd_read_common(int argc, char *argv[], bool long_mode) +{ + struct arg_int *sector = arg_int1(NULL, NULL, "", "Sector number"); + struct arg_str *filename = arg_str1(NULL, NULL, "", "Image file"); + struct arg_end *end = arg_end(10); + void *argtable[] = {sector, filename, end}; + + if(arg_parse(argc, argv, argtable) > 0 || sector->ival[0] < 0) + { + arg_print_errors(stderr, end, long_mode ? "read_long" : "read"); + long_mode ? usage_read_long() : usage_read(); + arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); + return -1; + } + + int result = long_mode ? read_long(sector->ival[0], filename->sval[0]) : read(sector->ival[0], filename->sval[0]); + + arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); + return result; +} + +int cmd_read(int argc, char *argv[]) { return cmd_read_common(argc, argv, false); } + +int cmd_read_long(int argc, char *argv[]) { return cmd_read_common(argc, argv, true); } + +int cmd_verify_common(int argc, char *argv[], bool sectors_mode) +{ + struct arg_str *filename = arg_str1(NULL, NULL, "", "Image file"); + struct arg_end *end = arg_end(10); + void *argtable[] = {filename, end}; + + if(arg_parse(argc, argv, argtable) > 0) + { + arg_print_errors(stderr, end, sectors_mode ? "verify_sectors" : "verify"); + sectors_mode ? usage_verify_sectors() : usage_verify(); + arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); + return -1; + } + + int result = sectors_mode ? verify_sectors(filename->sval[0]) : verify(filename->sval[0]); + + arg_freetable(argtable, sizeof(argtable) / sizeof(argtable[0])); + return result; +} + +int cmd_verify(int argc, char *argv[]) { return cmd_verify_common(argc, argv, false); } + +int cmd_verify_sectors(int argc, char *argv[]) { return cmd_verify_common(argc, argv, true); } + +Command commands[] = { + { "identify", cmd_identify}, + { "info", cmd_info}, + { "read", cmd_read}, + { "read_long", cmd_read_long}, + { "verify", cmd_verify}, + {"verify_sectors", cmd_verify_sectors}, +}; + +const size_t num_commands = sizeof(commands) / sizeof(commands[0]); diff --git a/tool/commands.h b/tool/commands.h new file mode 100644 index 0000000..b0507f4 --- /dev/null +++ b/tool/commands.h @@ -0,0 +1,42 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 Natalia Portillo. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef LIBAARUFORMAT_COMMANDS_H +#define LIBAARUFORMAT_COMMANDS_H + +typedef int (*command_func)(int argc, char *argv[]); + +typedef struct +{ + const char *verb; + command_func handler; +} Command; + +extern Command commands[]; +extern const size_t num_commands; + +// Command wrappers +int cmd_identify(int argc, char *argv[]); +int cmd_info(int argc, char *argv[]); +int cmd_read(int argc, char *argv[]); +int cmd_read_long(int argc, char *argv[]); +int cmd_verify(int argc, char *argv[]); +int cmd_verify_sectors(int argc, char *argv[]); + +#endif // LIBAARUFORMAT_COMMANDS_H diff --git a/tool/main.c b/tool/main.c index 9be0d8d..d7313b5 100644 --- a/tool/main.c +++ b/tool/main.c @@ -17,108 +17,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include #include -#include - -#include - -#include "aaruformattool.h" -#include "main.h" - -void usage() -{ - printf("\n"); - printf("Usage:\n"); - printf("aaruformattool [arguments]\n"); - printf("\n"); - printf("Available verbs:\n"); - printf("\tidentify\tIdentifies if the indicated file is a supported AaruFormat image.\n"); - printf("\tinfo\tPrints information about a given AaruFormat image.\n"); - printf("\tread\tReads a sector and prints it out on screen.\n"); - printf("\tread_long\tReads a sector with all its prefixes and suffixes and prints it out on screen.\n"); - printf("\tverify\tVerifies the integrity of all blocks in a AaruFormat image.\n"); - printf("\tverify_sectors\tVerifies the integrity of all sectors in a AaruFormat image.\n"); - printf("\n"); - printf("For help on the verb invoke the tool with the verb and no arguments.\n"); -} - -void usage_identify() -{ - printf("\n"); - printf("Usage:\n"); - printf("aaruformattool identify \n"); - printf("Identifies if the indicated file is a support AaruFormat image.\n"); - printf("\n"); - printf("Arguments:\n"); - printf("\t\tPath to file to identify if it is a supported AaruFormat image.\n"); -} - -void usage_info() -{ - printf("\n"); - printf("Usage:\n"); - printf("aaruformattool info \n"); - printf("Prints information about a given AaruFormat image.\n"); - printf("\n"); - printf("Arguments:\n"); - printf("\t\tPath to AaruFormat image to print information from.\n"); -} - -void usage_read() -{ - printf("\n"); - printf("Usage:\n"); - printf("aaruformattool read \n"); - printf("Reads a sector and prints it out on screen.\n"); - printf("\n"); - printf("Arguments:\n"); - printf("\t\tSector number to read and print out.\n"); - printf("\t\tPath to AaruFormat image to print information from.\n"); -} - -void usage_read_long() -{ - printf("\n"); - printf("Usage:\n"); - printf("aaruformattool read_long \n"); - printf("Reads a sector with all its prefixes and suffixes and prints it out on screen.\n"); - printf("\n"); - printf("Arguments:\n"); - printf("\t\tSector number to read and print out.\n"); - printf("\t\tPath to AaruFormat image to print information from.\n"); -} - -void usage_verify() -{ - printf("\n"); - printf("Usage:\n"); - printf("aaruformattool verify \n"); - printf("Verifies the integrity of all blocks in a AaruFormat image.\n"); - printf("\n"); - printf("Arguments:\n"); - printf("\t\tPath to AaruFormat image to verify.\n"); -} - -void usage_verify_sectors() -{ - printf("\n"); - printf("Usage:\n"); - printf("aaruformattool verify_sectors \n"); - printf("Verifies the integrity of all sectors in a AaruFormat image.\n"); - printf("\n"); - printf("Arguments:\n"); - printf("\t\tPath to AaruFormat image to verify.\n"); -} +#include +#include "commands.h" +#include "usage.h" int main(int argc, char *argv[]) { - uint64_t sector_no = 0; - - printf("AaruFormat Tool version %d.%d\n", AARUFORMAT_TOOL_MAJOR_VERSION, AARUFORMAT_TOOL_MINOR_VERSION); - printf("Copyright (C) 2019-2022 Natalia Portillo\n"); - printf("libaaruformat version %d.%d\n", LIBAARUFORMAT_MAJOR_VERSION, LIBAARUFORMAT_MINOR_VERSION); - printf("\n"); + print_banner(); if(argc < 2) { @@ -126,133 +32,16 @@ int main(int argc, char *argv[]) return -1; } - if(strncmp(argv[1], "identify", strlen("identify")) == 0) + const char *verb = argv[1]; + argc--; + argv++; // Shift to pass only args to verb handlers + + for(size_t i = 0; i < num_commands; ++i) { - if(argc == 2) - { - usage_identify(); - return -1; - } - - if(argc > 3) - { - fprintf(stderr, "Invalid number of arguments\n"); - usage_identify(); - return -1; - } - - return identify(argv[2]); + if(strcmp(commands[i].verb, verb) == 0) { return commands[i].handler(argc, argv); } } - if(strncmp(argv[1], "info", strlen("info")) == 0) - { - if(argc == 2) - { - usage_info(); - return -1; - } - - if(argc > 3) - { - fprintf(stderr, "Invalid number of arguments\n"); - usage_info(); - return -1; - } - - return info(argv[2]); - } - - if(strncmp(argv[1], "read_long", strlen("read_long")) == 0) - { - if(argc < 4) - { - usage_read_long(); - return -1; - } - - if(argc > 5) - { - fprintf(stderr, "Invalid number of arguments\n"); - usage_read_long(); - return -1; - } - - errno = 0; - - sector_no = strtoll(argv[2], NULL, 10); - - if(errno != 0) - { - fprintf(stderr, "Invalid sector number\n"); - usage_read_long(); - return -1; - } - - return read_long(sector_no, argv[3]); - } - else if(strncmp(argv[1], "read", strlen("read")) == 0) - { - if(argc < 4) - { - usage_read(); - return -1; - } - - if(argc > 5) - { - fprintf(stderr, "Invalid number of arguments\n"); - usage_read(); - return -1; - } - - errno = 0; - - sector_no = strtoll(argv[2], NULL, 10); - - if(errno != 0) - { - fprintf(stderr, "Invalid sector number\n"); - usage_read(); - return -1; - } - - return read(sector_no, argv[3]); - } - - if(strncmp(argv[1], "verify_sectors", strlen("verify_sectors")) == 0) - { - if(argc == 2) - { - usage_verify_sectors(); - return -1; - } - - if(argc > 3) - { - fprintf(stderr, "Invalid number of arguments\n"); - usage_verify_sectors(); - return -1; - } - - return verify_sectors(argv[2]); - } - else if(strncmp(argv[1], "verify", strlen("verify")) == 0) - { - if(argc == 2) - { - usage_verify(); - return -1; - } - - if(argc > 3) - { - fprintf(stderr, "Invalid number of arguments\n"); - usage_verify(); - return -1; - } - - return verify(argv[2]); - } - - return 0; + fprintf(stderr, "Unknown verb: %s\n", verb); + usage(); + return -1; } diff --git a/tool/usage.c b/tool/usage.c new file mode 100644 index 0000000..e331ea4 --- /dev/null +++ b/tool/usage.c @@ -0,0 +1,101 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 Natalia Portillo. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "usage.h" +#include +#include "aaruformat.h" +#include "version.h" // Optional if you want a central place for version macros + +void print_banner() +{ + printf("AaruFormat Tool version %d.%d\n", AARUFORMAT_TOOL_MAJOR_VERSION, AARUFORMAT_TOOL_MINOR_VERSION); + printf("Copyright (C) 2019-2022 Natalia Portillo\n"); + printf("libaaruformat version %d.%d\n\n", LIBAARUFORMAT_MAJOR_VERSION, LIBAARUFORMAT_MINOR_VERSION); +} + +void usage() +{ + printf("\nUsage:\n"); + printf(" aaruformattool [arguments]\n\n"); + printf("Available verbs:\n"); + printf(" identify Identifies if the indicated file is a supported AaruFormat image.\n"); + printf(" info Prints information about a given AaruFormat image.\n"); + printf(" read Reads a sector and prints it out on screen.\n"); + printf(" read_long Reads a sector with all its prefixes and suffixes.\n"); + printf(" verify Verifies the integrity of blocks in an image.\n"); + printf(" verify_sectors Verifies the integrity of all sectors in an image.\n\n"); + printf("For help with any verb, run:\n"); + printf(" aaruformattool --help\n"); +} + +void usage_identify() +{ + printf("\nUsage:\n"); + printf(" aaruformattool identify \n\n"); + printf("Identifies if the file is a supported AaruFormat image.\n"); + printf("Arguments:\n"); + printf(" Path to the image file.\n"); +} + +void usage_info() +{ + printf("\nUsage:\n"); + printf(" aaruformattool info \n\n"); + printf("Prints metadata about the image.\n"); + printf("Arguments:\n"); + printf(" Path to AaruFormat image.\n"); +} + +void usage_read() +{ + printf("\nUsage:\n"); + printf(" aaruformattool read \n\n"); + printf("Reads a sector and prints it out.\n"); + printf("Arguments:\n"); + printf(" Sector number to read.\n"); + printf(" Path to image file.\n"); +} + +void usage_read_long() +{ + printf("\nUsage:\n"); + printf(" aaruformattool read_long \n\n"); + printf("Reads sector with all metadata and prints it out.\n"); + printf("Arguments:\n"); + printf(" Sector number to read.\n"); + printf(" Path to image file.\n"); +} + +void usage_verify() +{ + printf("\nUsage:\n"); + printf(" aaruformattool verify \n\n"); + printf("Checks block-level integrity.\n"); + printf("Arguments:\n"); + printf(" Path to image file.\n"); +} + +void usage_verify_sectors() +{ + printf("\nUsage:\n"); + printf(" aaruformattool verify_sectors \n\n"); + printf("Checks sector-level integrity.\n"); + printf("Arguments:\n"); + printf(" Path to image file.\n"); +} diff --git a/tool/usage.h b/tool/usage.h new file mode 100644 index 0000000..ab5fd64 --- /dev/null +++ b/tool/usage.h @@ -0,0 +1,32 @@ +/* + * This file is part of the Aaru Data Preservation Suite. + * Copyright (c) 2019-2022 Natalia Portillo. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef LIBAARUFORMAT_USAGE_H +#define LIBAARUFORMAT_USAGE_H + +void print_banner(); +void usage(); +void usage_identify(); +void usage_info(); +void usage_read(); +void usage_read_long(); +void usage_verify(); +void usage_verify_sectors(); + +#endif // LIBAARUFORMAT_USAGE_H diff --git a/tool/main.h b/tool/version.h similarity index 100% rename from tool/main.h rename to tool/version.h