polonius/edit/src/main.cpp

168 lines
5.5 KiB
C++

#include "includes.h"
#ifndef IOSTREAM
#define IOSTREAM
#include <iostream>
#endif
#ifndef GETOPT_H
#define GETOPT_H
#include <getopt.h>
#endif
using namespace std;
int main(int argc, char* argv[]) {
string program_name = "polonius-editor";
string helpstring = program_name + " " + program_version + "\nCopyright (C) 2023 " + program_author + "\n\nThis is free software (GNU GPL 3), and you are welcome to redistribute it under certain conditions.\n\nUsage: " + program_name + " -i filename -a \"{INSTRUCTION}\"\n\nOptions:\n -i\n --input\n Specify input file to edit\n\n -a\n --add-instruction\n Instruct the program on how to edit your file\n Example instructions:\n REPLACE 5 hello world\n (Replaces text, starting from byte #5, with \"hello world\")\n INSERT 7 salut a tous\n (Inserts \"salut a tous\" at byte #7, shifting the rest of the file without replacing it)\n REMOVE 9 15\n (Removes bytes #9 to #15 from the file)\n\n -s\n --add-instruction-set\n Provide a set of multiple instructions for editing the file\n Each instruction in the set should be on its own line, as in the following example:\n --add-instruction-set \"REPLACE 20 hello world\n INSERT 50 hello again\n REMOVE 70 75\"\n\n -c\n --special-chars\n Interpret escaped character sequences (\\n, \\t and \\\\)\n\n -b\n --block-size\n Specify the amount of data from the file we're willing to load into memory at any given time\n Example:\n -b 10M\n -b 200K\n (Default 10 kilobytes)\n\n -v\n --verbose\n Verbose mode\n\n -V\n --version\n Print version number\n\n -h\n --help\n Display this message\n\nExamples:\n " + program_name + " --input ./file.txt --add-instruction \"REPLACE 20 hello \\n world\" --add-instruction \"REMOVE 10 12\" --block-size 10K --special-chars\n\n " + program_name + " -a \"insert 0 hello world\" ./file.txt\n";
/*
Necessary information for the program to do its job
*/
string file_to_edit = "";
bool received_filename = false;
vector<editor::instruction> instructions_to_add;
int block_size = 10240;
bool interpret_special_chars = false;
bool verbose = false;
/*
temp_instruction_set vector
-s / --add-instruction-set option fills this vector, moves its elements to instructions_to_add, and then clears this vector
*/
vector<editor::instruction> temp_instruction_set;
/*
GETOPT
*/
int c;
opterr = 0;
int option_index = 0;
static struct option long_options[] =
{
{"input", required_argument, 0, 'i'},
{"add-instruction-set", required_argument, 0, 's'},
{"instruction-set", required_argument, 0, 's'},
{"add-instruction", required_argument, 0, 'a'},
{"instruction", required_argument, 0, 'a'},
{"block-size", required_argument, 0, 'b'},
{"special-chars", no_argument, 0, 'c'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'}
};
while ((c = getopt_long(argc, argv, "i:s:a:b:cvVh", long_options, &option_index)) != -1) {
switch(c) {
case 'i':
if (received_filename) {
cerr << "polonius-editor: Error: Multiple files specified" << endl;
return EXIT_BADFILE;
}
file_to_edit = optarg;
received_filename = true;
break;
case 'a':
instructions_to_add.push_back(parse_instruction_string(optarg));
break;
case 's':
temp_instruction_set = parse_instruction_set_string(optarg);
move(temp_instruction_set.begin(), temp_instruction_set.end(), inserter(instructions_to_add, instructions_to_add.end()));
break;
case 'b':
block_size = parse_block_units(optarg);
if (block_size == -1) {
cerr << program_name << ": Block size '" << optarg << "' is not understood" << endl << "Use -h for help" << endl;
return EXIT_BADARG;
}
break;
case 'c':
interpret_special_chars = true;
break;
case 'v':
verbose = true;
break;
case 'V':
cout << program_version << endl;
return EXIT_SUCCESS;
break;
case 'h':
cout << helpstring;
return EXIT_SUCCESS;
break;
case '?':
if (optopt == 'i' || optopt == 's' || optopt == 'a' || optopt == 'b') {
cerr << program_name << ": Option -" << (char)optopt << " requires an argument" << endl << "Use -h for help" << endl;
return EXIT_BADOPT;
}
break;
}
}
for (option_index = optind; option_index < argc; option_index++) {
if (received_filename) {
cerr << "polonius-editor: Error: Multiple files specified" << endl;
return EXIT_BADFILE;
}
file_to_edit = argv[option_index];
received_filename = true;
}
if (!received_filename) {
cerr << program_name << ": No input file given. Use -h for help" << endl;
return EXIT_BADFILE;
}
editor::file document(file_to_edit, block_size, verbose);
if (!document.is_initialized()) {
cerr << program_name << ": " << document.get_error_message() << endl;
return EXIT_OTHER;
}
for (int i = 0; i < instructions_to_add.size(); i++) {
if (interpret_special_chars) {
instructions_to_add[i].process_special_chars();
}
if (!document.add_instruction(instructions_to_add[i])) {
cerr << program_name << ": " << instructions_to_add[i].get_error_message() << endl;
return EXIT_BADARG;
}
}
vector<editor::instruction> instruction_set = document.get_instruction_set();
for (int i = 0; i < instruction_set.size(); i++) {
document.execute_single_instruction(instruction_set[i]);
}
/* Close file */
document.close();
return EXIT_SUCCESS;
}