Add parse_options helper for parsing cmd line args

This commit is contained in:
Andrew Ayer
2014-06-29 13:49:10 -07:00
parent f3390ff7ff
commit bec9e7f318
5 changed files with 198 additions and 45 deletions

View File

@@ -3,7 +3,7 @@ CXXFLAGS := -Wall -pedantic -Wno-long-long -O2
LDFLAGS := -lcrypto
PREFIX := /usr/local
OBJFILES = git-crypt.o commands.o crypto.o gpg.o key.o util.o
OBJFILES = git-crypt.o commands.o crypto.o gpg.o key.o util.o parse_options.o
all: git-crypt

View File

@@ -33,6 +33,7 @@
#include "util.hpp"
#include "key.hpp"
#include "gpg.hpp"
#include "parse_options.hpp"
#include <unistd.h>
#include <stdint.h>
#include <algorithm>
@@ -890,58 +891,28 @@ int refresh (int argc, char** argv) // TODO: do a force checkout, much like in u
int status (int argc, char** argv)
{
int argi = 0;
// Usage:
// git-crypt status -r [-z] Show repo status
// git-crypt status [-e | -u] [-z] [FILE ...] Show encrypted status of files
// git-crypt status -f Fix unencrypted blobs
// Flags:
// -e show encrypted files only
// -u show unencrypted files only
// -f fix problems
// -z machine-parseable output
// -r show repo status only
// TODO: help option / usage output
bool repo_status_only = false;
bool show_encrypted_only = false;
bool show_unencrypted_only = false;
bool fix_problems = false;
bool machine_output = false;
bool repo_status_only = false; // -r show repo status only
bool show_encrypted_only = false; // -e show encrypted files only
bool show_unencrypted_only = false; // -u show unencrypted files only
bool fix_problems = false; // -f fix problems
bool machine_output = false; // -z machine-parseable output
while (argi < argc && argv[argi][0] == '-') {
if (std::strcmp(argv[argi], "--") == 0) {
++argi;
break;
}
const char* flags = argv[argi] + 1;
while (char flag = *flags++) {
switch (flag) {
case 'r':
repo_status_only = true;
break;
case 'e':
show_encrypted_only = true;
break;
case 'u':
show_unencrypted_only = true;
break;
case 'f':
fix_problems = true;
break;
case 'z':
machine_output = true;
break;
default:
std::clog << "Error: unknown option `" << flag << "'" << std::endl;
return 2;
}
}
++argi;
}
Options_list options;
options.push_back(Option_def("-r", &repo_status_only));
options.push_back(Option_def("-e", &show_encrypted_only));
options.push_back(Option_def("-u", &show_unencrypted_only));
options.push_back(Option_def("-f", &fix_problems));
options.push_back(Option_def("--fix", &fix_problems));
options.push_back(Option_def("-z", &machine_output));
int argi = parse_options(options, argc, argv);
if (repo_status_only) {
if (show_encrypted_only || show_unencrypted_only) {

View File

@@ -34,6 +34,7 @@
#include "crypto.hpp"
#include "key.hpp"
#include "gpg.hpp"
#include "parse_options.hpp"
#include <cstring>
#include <unistd.h>
#include <iostream>
@@ -188,6 +189,9 @@ try {
} catch (const Crypto_error& e) {
std::cerr << "git-crypt: Crypto error: " << e.where << ": " << e.message << std::endl;
return 1;
} catch (const Option_error& e) {
std::cerr << "git-crypt: Error: " << e.option_name << ": " << e.message << std::endl;
return 1;
} catch (Key_file::Incompatible) {
std::cerr << "git-crypt: This repository contains a incompatible key file. Please upgrade git-crypt." << std::endl;
return 1;

118
parse_options.cpp Normal file
View File

@@ -0,0 +1,118 @@
/*
* Copyright 2014 Andrew Ayer
*
* This file is part of git-crypt.
*
* git-crypt 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 3 of the License, or
* (at your option) any later version.
*
* git-crypt 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 git-crypt. If not, see <http://www.gnu.org/licenses/>.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify the Program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, the licensors of the Program
* grant you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#include "parse_options.hpp"
#include <cstring>
static const Option_def* find_option (const Options_list& options, const std::string& name)
{
for (Options_list::const_iterator opt(options.begin()); opt != options.end(); ++opt) {
if (opt->name == name) {
return &*opt;
}
}
return 0;
}
int parse_options (const Options_list& options, int argc, char** argv)
{
int argi = 0;
while (argi < argc && argv[argi][0] == '-') {
if (std::strcmp(argv[argi], "--") == 0) {
++argi;
break;
} else if (std::strncmp(argv[argi], "--", 2) == 0) {
std::string option_name;
const char* option_value = 0;
if (char* eq = std::strchr(argv[argi], '=')) {
option_name.assign(argv[argi], eq);
option_value = eq + 1;
} else {
option_name = argv[argi];
}
++argi;
const Option_def* opt(find_option(options, option_name));
if (!opt) {
throw Option_error(option_name, "Invalid option");
}
if (opt->is_set) {
*opt->is_set = true;
}
if (opt->value) {
if (option_value) {
*opt->value = option_value;
} else {
if (argi >= argc) {
throw Option_error(option_name, "Option requires a value");
}
*opt->value = argv[argi];
++argi;
}
} else {
if (option_value) {
throw Option_error(option_name, "Option takes no value");
}
}
} else {
const char* arg = argv[argi] + 1;
++argi;
while (*arg) {
std::string option_name("-");
option_name.push_back(*arg);
++arg;
const Option_def* opt(find_option(options, option_name));
if (!opt) {
throw Option_error(option_name, "Invalid option");
}
if (opt->is_set) {
*opt->is_set = true;
}
if (opt->value) {
if (*arg) {
*opt->value = arg;
} else {
if (argi >= argc) {
throw Option_error(option_name, "Option requires a value");
}
*opt->value = argv[argi];
++argi;
}
break;
}
}
}
}
return argi;
}

60
parse_options.hpp Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright 2014 Andrew Ayer
*
* This file is part of git-crypt.
*
* git-crypt 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 3 of the License, or
* (at your option) any later version.
*
* git-crypt 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 git-crypt. If not, see <http://www.gnu.org/licenses/>.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify the Program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, the licensors of the Program
* grant you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#ifndef PARSE_OPTIONS_HPP
#define PARSE_OPTIONS_HPP
#include <string>
#include <vector>
struct Option_def {
std::string name;
bool* is_set;
const char** value;
Option_def () : is_set(0), value(0) { }
Option_def (const std::string& arg_name, bool* arg_is_set)
: name(arg_name), is_set(arg_is_set), value(0) { }
Option_def (const std::string& arg_name, const char** arg_value)
: name(arg_name), is_set(0), value(arg_value) { }
};
typedef std::vector<Option_def> Options_list;
int parse_options (const Options_list& options, int argc, char** argv);
struct Option_error {
std::string option_name;
std::string message;
Option_error (const std::string& n, const std::string& m) : option_name(n), message(m) { }
};
#endif