move argument parsing to cli.cc

This commit is contained in:
Frédéric Mangano-Tarumi 2018-11-10 11:52:33 -05:00
parent 2a31c5491b
commit 132073b842
4 changed files with 114 additions and 80 deletions

View File

@ -18,6 +18,7 @@ include_directories(BEFORE src "${CMAKE_BINARY_DIR}")
add_library(
libopustags
OBJECT
src/cli.cc
src/ogg.cc
src/opus.cc
)

81
src/cli.cc Normal file
View File

@ -0,0 +1,81 @@
#include <opustags.h>
#include <getopt.h>
static struct option getopt_options[] = {
{"help", no_argument, 0, 'h'},
{"output", required_argument, 0, 'o'},
{"in-place", optional_argument, 0, 'i'},
{"overwrite", no_argument, 0, 'y'},
{"delete", required_argument, 0, 'd'},
{"add", required_argument, 0, 'a'},
{"set", required_argument, 0, 's'},
{"delete-all", no_argument, 0, 'D'},
{"set-all", no_argument, 0, 'S'},
{NULL, 0, 0, 0}
};
/**
* Parse the command-line arguments.
*
* Return EXIT_SUCCESS on success, meaning the parsing succeeded and the program execution may
* continue. On error, a relevant message is printed on stderr a non-zero exit code is returned.
*
* This function does not perform I/O related validations, but checks the consistency of its
* arguments.
*/
int ot::parse_options(int argc, char** argv, ot::options& opt)
{
int c;
while ((c = getopt_long(argc, argv, "ho:i::yd:a:s:DS", getopt_options, NULL)) != -1) {
switch (c) {
case 'h':
opt.print_help = true;
break;
case 'o':
opt.path_out = optarg;
if (opt.path_out.empty()) {
fputs("output's file path cannot be empty\n", stderr);
return EXIT_FAILURE;
}
break;
case 'i':
opt.inplace = optarg == nullptr ? ".otmp" : optarg;
if (strcmp(opt.inplace, "") == 0) {
fputs("the in-place suffix cannot be empty\n", stderr);
return EXIT_FAILURE;
}
break;
case 'y':
opt.overwrite = true;
break;
case 'd':
if (strchr(optarg, '=') != nullptr) {
fprintf(stderr, "invalid field name: '%s'\n", optarg);
return EXIT_FAILURE;
}
opt.to_delete.emplace_back(optarg);
break;
case 'a':
case 's':
if (strchr(optarg, '=') == NULL) {
fprintf(stderr, "invalid comment: '%s'\n", optarg);
return EXIT_FAILURE;
}
opt.to_add.emplace_back(optarg);
if (c == 's')
opt.to_delete.emplace_back(optarg);
break;
case 'S':
opt.set_all = true;
/* fall through */
case 'D':
opt.delete_all = true;
break;
default:
/* getopt printed a message */
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

View File

@ -3,7 +3,6 @@
#include "opustags.h"
#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@ -11,8 +10,6 @@
#include <unistd.h>
#include <ogg/ogg.h>
#include <vector>
const char *version = PROJECT_NAME " version " PROJECT_VERSION "\n";
const char *usage =
@ -32,35 +29,6 @@ const char *help =
" -D, --delete-all delete all the fields!\n"
" -S, --set-all read the fields from stdin\n";
struct option options[] = {
{"help", no_argument, 0, 'h'},
{"output", required_argument, 0, 'o'},
{"in-place", optional_argument, 0, 'i'},
{"overwrite", no_argument, 0, 'y'},
{"delete", required_argument, 0, 'd'},
{"add", required_argument, 0, 'a'},
{"set", required_argument, 0, 's'},
{"delete-all", no_argument, 0, 'D'},
{"set-all", no_argument, 0, 'S'},
{NULL, 0, 0, 0}
};
struct opustags_options {
std::string path_in;
std::string path_out;
/**
* If null, in-place editing is disabled.
* Otherwise, it contains the suffix to add to the file name.
*/
const char *inplace = nullptr;
std::vector<std::string> to_add;
std::vector<std::string> to_delete;
bool delete_all = false;
bool set_all = false;
bool overwrite = false;
bool print_help = false;
};
/**
* Display the tags on stdout.
*
@ -84,54 +52,10 @@ int main(int argc, char **argv){
fputs(usage, stdout);
return EXIT_SUCCESS;
}
opustags_options opt;
ot::ogg_reader reader;
ot::ogg_writer writer;
int c;
while((c = getopt_long(argc, argv, "ho:i::yd:a:s:DS", options, NULL)) != -1){
switch(c){
case 'h':
opt.print_help = true;
break;
case 'o':
opt.path_out = optarg;
if (opt.path_out.empty()) {
fputs("output's file path cannot be empty\n", stderr);
return EXIT_FAILURE;
}
break;
case 'i':
opt.inplace = optarg == nullptr ? ".otmp" : optarg;
break;
case 'y':
opt.overwrite = true;
break;
case 'd':
if(strchr(optarg, '=') != NULL){
fprintf(stderr, "invalid field: '%s'\n", optarg);
return EXIT_FAILURE;
}
opt.to_delete.emplace_back(optarg);
break;
case 'a':
case 's':
if(strchr(optarg, '=') == NULL){
fprintf(stderr, "invalid comment: '%s'\n", optarg);
return EXIT_FAILURE;
}
opt.to_add.emplace_back(optarg);
if(c == 's')
opt.to_delete.emplace_back(optarg);
break;
case 'S':
opt.set_all = true;
case 'D':
opt.delete_all = true;
break;
default:
return EXIT_FAILURE;
}
}
ot::options opt;
int exit_code = parse_options(argc, argv, opt);
if (exit_code != EXIT_SUCCESS)
return exit_code;
if (opt.print_help) {
puts(version);
puts(usage);
@ -161,6 +85,8 @@ int main(int argc, char **argv){
}
}
}
ot::ogg_reader reader;
ot::ogg_writer writer;
if (opt.path_in == "-") {
if (opt.set_all) {
fputs("can't open stdin for input when -S is specified\n", stderr);

View File

@ -10,6 +10,7 @@
#include <cstring>
#include <list>
#include <string>
#include <vector>
namespace ot {
@ -181,4 +182,29 @@ void delete_tags(opus_tags *tags, const char *field);
/** \} */
/**
* \defgroup cli Command-Line Interface
* \{
*/
struct options {
std::string path_in;
std::string path_out;
/**
* If null, in-place editing is disabled.
* Otherwise, it contains the suffix to add to the file name.
*/
const char *inplace = nullptr;
std::vector<std::string> to_add;
std::vector<std::string> to_delete;
bool delete_all = false;
bool set_all = false;
bool overwrite = false;
bool print_help = false;
};
int parse_options(int argc, char** argv, options& opt);
/** \} */
}