Browse Source

Switch from getopt to cxxopts

master
Jake Wakeling 2 months ago
parent
commit
7040860c2b
8 changed files with 2252 additions and 123 deletions
  1. 2
    22
      CMakeLists.txt
  2. 2104
    0
      include/cxxopts.hpp
  3. 76
    0
      src/arg.cpp
  4. 25
    0
      src/arg.h
  5. 26
    87
      src/main.cpp
  6. 5
    2
      src/main.h
  7. 11
    12
      src/viewer.cpp
  8. 3
    0
      src/viewer.h

+ 2
- 22
CMakeLists.txt View File

@@ -5,36 +5,16 @@ project(HexView) # Project
set(CMAKE_CXX_STANDARD 17) # C++ Standard

# Output Directories
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)

IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux") # Linux Specific CMake Variables
set(LINK_DIR /lib/x64/) # Standard Linux Library Directory
set(INCLUDE_DIR /include/) # Standard Linux Include Directory
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
IF(${CMAKE_SYSTEM_NAME} MATCHES "Windows") # Windows Specific CMake Variables
set(LINK_DIR C:/Libraries/x64/) # Standard Windows Library Directory
set(INCLUDE_DIR C:/Include/) # Standard Windows Include Directory
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Windows")

file(GLOB SOURCES # Add Source Files
${CMAKE_SOURCE_DIR}/src/*
${CMAKE_SOURCE_DIR}/include/*
)

link_directories( # Library Directories
${LINK_DIR}
)

add_executable(xv ${SOURCES}) # Build Target

target_include_directories(xv PUBLIC # Target Include Directories
${INCLUDE_DIR}
)

target_link_libraries(xv # Target Libraries
getopt
target_include_directories(xv PRIVATE # Target Include Directories
${CMAKE_SOURCE_DIR}/include/
)

set_property( # Visual Studio Startup Project

+ 2104
- 0
include/cxxopts.hpp
File diff suppressed because it is too large
View File


+ 76
- 0
src/arg.cpp View File

@@ -0,0 +1,76 @@
// arg.cpp
// Argument parsing source file for HexView
// Copyright (C) 2019, Jakob Wakeling
// All rights reserved.

#include "arg.h"

// Parse program arguments and return result
cxxopts::ParseResult Arg::parse(int argc, char *argv[]) {
try {
cxxopts::Options options(PROGRAM_NAME, PROGRAM_DESC); // Create options object
options.add_options() // Add options
("help", "Show help", cxxopts::value<bool>())
("version", "Show version information", cxxopts::value<bool>())
("s, start", "View hex from", cxxopts::value<size_t>())
("e, end", "View hex to", cxxopts::value<size_t>())
("w, width", "Set view width", cxxopts::value<int>())
("file", "Input file", cxxopts::value<std::string>())
;

options.parse_positional({ "file" }); // Define positional arguments

cxxopts::ParseResult result = options.parse(argc, argv);

if (result.count("help")) { // Check for help argument
PrintHelp(); // Show help
exit(0x0000);
}
if (result.count("version")) { // Check for version argument
PrintVersion(); // Show version information
exit(0x0000);
}

return result;
}
catch (const cxxopts::OptionException &exception) { // Catch option exceptions
fprintf(stderr, "XVx0A00: Error parsing arguments: %s\n", exception.what());
exit(0x0A00);
}
}

// Print usage message
void Arg::PrintUsage(void) {
printf("Usage: %s [-sew] file\n", PROGRAM_NAME);
printf("Try '%s --help' for more information\n", PROGRAM_NAME);
printf("\n");
return;
}

// Print help message
void Arg::PrintHelp(void) {
printf("Usage: %s [-sew] file\n", PROGRAM_NAME);
printf("Examples:\n");
printf(" %s foo # View hex representation of foo\n", PROGRAM_NAME);
printf(" %s -s 20 -e 40 foo # View hex representation from byte 20 to 40 of foo\n", PROGRAM_NAME);
printf(" %s -w 16 foo # View hex representation of foo with a width of 16 bytes\n", PROGRAM_NAME);
printf("\n");
printf("Options:\n");
printf(" --help Show help\n");
printf(" --version Show version information\n");
printf(" -s, --start View hex from\n");
printf(" -e, --end View hex to\n");
printf(" -w, --width Set view width\n");
printf("\n");
return;
}

// Print version information
void Arg::PrintVersion(void) {
printf("%s\n", PROGRAM_DESC);
printf("Copyright (C) 2019, Jakob Wakeling\n");
printf("All rights reserved.\n");
printf("OMKOV Open Source Licence\n");
printf("\n");
return;
}

+ 25
- 0
src/arg.h View File

@@ -0,0 +1,25 @@
// arg.h
// Argument parsing header file for HexView
// Copyright (C) 2019, Jakob Wakeling
// All rights reserved.

#ifndef ARG_H
#define ARG_H

#define PROGRAM_NAME "xv"
#define PROGRAM_DESC "HexView, Version 0.0.1"

#include <cxxopts.hpp>

class Arg {
public:
static cxxopts::ParseResult Arg::parse(int argc, char *argv[]);

static void PrintUsage(void);

private:
static void PrintHelp(void);
static void PrintVersion(void);
};

#endif // ARG_H

+ 26
- 87
src/main.cpp View File

@@ -3,118 +3,57 @@
// Copyright (C) 2019, Jakob Wakeling
// All rights reserved.

#define _CRT_SECURE_NO_WARNINGS

#include <getopt.h>

#include <iostream>
#include <fstream>

#include "viewer.h"
#include "main.h"

int main(int argc, char *argv[]) {
if (argc > 1) {
static int flagVerbose;
int opt;

static struct option longOptions[] = {
{"verbose", ARG_NONE, &flagVerbose, 1},
{"help", ARG_NONE, 0, 'h'},
{"start", ARG_REQ, 0, 's'},
{"end", ARG_REQ, 0, 'e'},
{"width", ARG_REQ, 0, 'w'},
{ ARG_NULL , ARG_NULL , ARG_NULL , ARG_NULL }
};

cxxopts::ParseResult result = Arg::parse(argc, argv); // Parse arguments
size_t startByte = 0, endByte = 0;
int viewWidth = 16;

int optionIndex = 0;
while ((opt = getopt_long(argc, argv, "s:e:w:",
longOptions, &optionIndex)) != -1) {
switch (opt) {
case 0: { break; } // Flag is not NULL
case 'h': { PrintHelp(); break; } // Print help message
case 's': {
startByte = atoi(optarg);
break;
if (result.count("start")) { // Check for start argument
if (result["start"].as<size_t>() <= 0) { // Check validity of width
fprintf(stderr, "XVx0A01: Start byte must be greater than zero\n");
return 0x0A01;
}
case 'e': {
endByte = atoi(optarg);
break;
}
case 'w': {
if (atoi(optarg) <= 0) {
fprintf(stderr, "HexView: View width must \
be greater than zero\n");
return 0x0002;
}
else {
viewWidth = atoi(optarg);
}
break;
startByte = result["start"].as<size_t>(); // Set start byte
}
if (result.count("end")) { // Check for end argument
if (result["end"].as<size_t>() <= 0) { // Check validity of width
fprintf(stderr, "XVx0A02: End byte must be greater than zero\n");
return 0x0A02;
}
case '?': { break; } // Getopt error
default: { PrintHelp(); break; } // Print help message
endByte = result["end"].as<size_t>(); // Set end byte
}
if (result.count("width")) { // Check for width argument
if (result["width"].as<int>() <= 0) { // Check validity of width
fprintf(stderr, "XVx0A03: View width must be greater than zero\n");
return 0x0A03;
}
viewWidth = result["width"].as<int>(); // Set view width
}

if (optind < argc) {
std::string hexPath = argv[optind++];
if (result.count("file")) {
std::string hexPath = result["file"].as<std::string>();
std::ifstream hexFile;
hexFile.open(hexPath, std::ios::binary | std::ios::in);
if (!hexFile) {
fprintf(stderr, "HexView: Failed to open %s for reading\n", hexPath.c_str());
fprintf(stderr, "XVx0001: Failed to open %s for reading\n", hexPath.c_str());
return 0x0001;
}
if (endByte == 0) {
size_t retPos = hexFile.tellg();
hexFile.seekg(0, hexFile.end);
endByte = hexFile.tellg();
hexFile.seekg(retPos);
}
xv::Viewer::PrintHex(&hexFile, viewWidth, startByte, endByte);
}
else { PrintHelp(); } // Print help message

if (flagVerbose) { // Verbose for debugging
printf("Verbose flag is set\n");
if (optind < argc) {
printf("non-option ARGV elements: ");
while (optind < argc) {
printf("%s, ", argv[optind++]);
}
printf("\n");
}
}
else { Arg::PrintUsage(); }
}
else { PrintHelp(); } // Print help message
else { Arg::PrintUsage(); } // Print help message
return 0x0000;
}

// Print usage message
void PrintUsage(void) {
printf("Usage: %s [-sewhv] file(s)\n", PROGRAM_NAME);
printf("Try '%s --help' for more information", PROGRAM_NAME);
return;
}

// Print help message
void PrintHelp(void) {
printf("Usage: %s [-sewhv] file(s)\n", PROGRAM_NAME);
printf("Examples:\n");
printf(" %s foo # View hex representation of foo\n", PROGRAM_NAME);
printf(" %s -s 20 -e 40 foo # View hex representation from byte 20 to 40 of foo\n", PROGRAM_NAME);
printf(" %s -w 16 foo # View hex representation of foo with a width of 16 bytes\n", PROGRAM_NAME);
printf("\n");
printf("Options:\n");
printf(" --help Show help\n");
printf(" --verbose Verbose mode\n");
printf(" -s, --start View hex from\n");
printf(" -e, --end View hex to\n");
printf(" -w, --width Set view width");
return;
}

+ 5
- 2
src/main.h View File

@@ -8,7 +8,10 @@

#define PROGRAM_NAME "xv"

void PrintUsage(void);
void PrintHelp(void);
#include <fstream>
#include <iostream>

#include "arg.h"
#include "viewer.h"

#endif // MAIN_H

+ 11
- 12
src/viewer.cpp View File

@@ -3,24 +3,23 @@
// Copyright (C) 2019, Jakob Wakeling
// All rights reserved.

#include <iostream>
#include <fstream>

#include "viewer.h"

using namespace xv;

// Print bytes within given range from file in hex format
void xv::Viewer::PrintHex(std::ifstream *file, int viewWidth, size_t start, size_t end) {
file->seekg(start);
void Viewer::PrintHex(std::ifstream *file, int viewWidth, size_t start, size_t end) {
file->seekg(start); // Seek start byte in file

while ((size_t)file->tellg() < end) {
for (int offset = 0; offset < viewWidth; ++offset) {
PrintByte(file);
while ((size_t)file->tellg() < end) { // Loop until end byte is reached
for (int offset = 0; offset < viewWidth; ++offset) { // Loop through view columns
PrintByte(file); // Print current byte
if ((size_t)file->tellg() >= end) {
break;
if ((size_t)file->tellg() >= end) { // Check if end byte has been reached
break; // If so, break
}

putchar(' ');
putchar(' '); // Print space between bytes
}
printf("\n");
}
@@ -29,7 +28,7 @@ void xv::Viewer::PrintHex(std::ifstream *file, int viewWidth, size_t start, size
}

// Print next byte in file in hex format
void xv::Viewer::PrintByte(std::ifstream *file) {
void Viewer::PrintByte(std::ifstream *file) {
char byte;

file->read(&byte, 1); // Read character from file

+ 3
- 0
src/viewer.h View File

@@ -6,6 +6,9 @@
#ifndef VIEWER_H
#define VIEWER_H

#include <iostream>
#include <fstream>

namespace xv {
class Viewer {
public:

Loading…
Cancel
Save