From 44080e85cc6cf07d799ae04b014eb1b51587811d Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Thu, 27 Jun 2024 11:57:29 +0900 Subject: [PATCH] Impl. parser (TODO Fix invalid free crash) During testing, having at least three positional args cause an invalid free crash. Should be investigated and fixed. --- .gitignore | 1 + CMakeLists.txt | 3 +- src/.lvimrc | 1 + src/main.c | 19 +++++- src/parser.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++ src/parser.h | 51 +++++++++++++++ 6 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 src/.lvimrc create mode 100644 src/parser.c create mode 100644 src/parser.h diff --git a/.gitignore b/.gitignore index 36cfdb9..deed12c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /build*/ compile_commands.json +/.cache/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ea54f8..8230cfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,12 +5,13 @@ set(SimpleArchiver_VERSION 1.0) set(SimpleArchiver_SOURCES src/main.c + src/parser.c ) add_compile_options( -Wall -Wextra -Wpedantic -Wno-missing-braces $<$:-Weffc++> - $<$:-O0> + $<$:-Og> ) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) diff --git a/src/.lvimrc b/src/.lvimrc new file mode 100644 index 0000000..77ce7d0 --- /dev/null +++ b/src/.lvimrc @@ -0,0 +1 @@ +set expandtab tabstop=2 softtabstop=2 shiftwidth=2 diff --git a/src/main.c b/src/main.c index c1d54f8..4a0f1da 100644 --- a/src/main.c +++ b/src/main.c @@ -15,6 +15,21 @@ * * `main.c` is the entry-point of this software/program. */ -int main(int argc, char **argv) { - return 0; + +#include + +#include "parser.h" + +int main(int argc, const char **argv) { + simple_archiver_print_usage(); + + //__attribute__((cleanup(simple_archiver_free_parsed))) + SDArchiverParsed parsed = simple_archiver_create_parsed(); + + simple_archiver_parse_args(argc, argv, &parsed); + + puts("freeing"); + simple_archiver_free_parsed(&parsed); + puts("end"); + return 0; } diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..28883d2 --- /dev/null +++ b/src/parser.c @@ -0,0 +1,166 @@ +/* + * Copyright 2024 Stephen Seo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * `parser.c` is the source file for parsing args. + */ + +#include "parser.h" + +#include +#include +#include + +void simple_archiver_print_usage(void) { + puts("Usage flags:"); + puts("-c : create archive file"); + puts("-x : extract archive file"); + puts("-f : filename to work on"); + puts("--compressor : requires --decompressor"); + puts("--decompressor : requires --compressor"); + puts("If creating archive file, remaining args specify files to archive."); + puts("If extracting archive file, remaining args specify files to extract."); +} + +SDArchiverParsed simple_archiver_create_parsed(void) { + SDArchiverParsed parsed; + + parsed.flags = 0; + parsed.filename = NULL; + parsed.compressor = NULL; + parsed.decompressor = NULL; + parsed.working_files = NULL; + + return parsed; +} + +int simple_archiver_parse_args(int argc, const char **argv, + SDArchiverParsed *out) { + if (out->filename) { + free(out->filename); + out->filename = NULL; + } + if (out->compressor) { + free(out->compressor); + out->compressor = NULL; + } + if (out->decompressor) { + free(out->decompressor); + out->decompressor = NULL; + } + + // Skip program name as it is the first arg usually. + --argc; + ++argv; + + int is_remaining_args = 0; + + while (argc > 0) { + if (!is_remaining_args) { + if (strcmp(argv[0], "-c") == 0) { + // unset first bit. + out->flags &= 0xFFFFFFFE; + } else if (strcmp(argv[0], "-x") == 0) { + // set first bit. + out->flags |= 0x1; + } else if (strcmp(argv[0], "-f") == 0 && argc > 1) { + int size = strlen(argv[1]) + 1; + out->filename = malloc(size); + strncpy(out->filename, argv[1], size); + --argc; + ++argv; + } else if (strcmp(argv[0], "--compressor") == 0 && argc > 1) { + int size = strlen(argv[1]) + 1; + out->compressor = malloc(size); + strncpy(out->compressor, argv[1], size); + --argc; + ++argv; + } else if (strcmp(argv[0], "--decompressor") == 0 && argc > 1) { + int size = strlen(argv[1]) + 1; + out->decompressor = malloc(size); + strncpy(out->decompressor, argv[1], size); + --argc; + ++argv; + } else if (argv[0][0] != '-') { + is_remaining_args = 1; + continue; + } + } else { + if (out->working_files == NULL) { + puts("first addition to working_files"); + out->working_files = malloc(sizeof(char *) * 2); + int arg_length = strlen(argv[0]) + 1; + out->working_files[0] = malloc(arg_length); + strncpy(out->working_files[0], argv[0], arg_length); + out->working_files[1] = NULL; + } else { + puts("later addition to working_files"); + int working_size = 1; + char **ptr = out->working_files; + while (ptr && *ptr) { + ++working_size; + ++ptr; + } + printf("working_size is %u\n", working_size); + + // TODO verify this is necessary, using different variables. + ptr = out->working_files; + out->working_files = realloc(ptr, working_size + 1); + + // Set new actual last element to NULL. + out->working_files[working_size] = NULL; + int size = strlen(argv[0]) + 1; + // Set last element to the arg. + out->working_files[working_size - 1] = malloc(size); + strncpy(out->working_files[working_size - 1], argv[0], size); + } + } + + --argc; + ++argv; + } + + return 0; +} + +void simple_archiver_free_parsed(SDArchiverParsed *parsed) { + parsed->flags = 0; + if (parsed->filename) { + free(parsed->filename); + parsed->filename = NULL; + } + if (parsed->compressor) { + free(parsed->compressor); + parsed->compressor = NULL; + } + if (parsed->decompressor) { + free(parsed->decompressor); + parsed->decompressor = NULL; + } + if (parsed->working_files) { + char **ptr = parsed->working_files; + unsigned int idx = 0; + puts("freeing working_files strings..."); + while (ptr[idx]) { + printf("Freeing at idx %u\n", idx); + free(ptr[idx]); + ++idx; + } + puts("freeing string array..."); + free(parsed->working_files); + parsed->working_files = NULL; + + puts("free_parsed is done."); + } +} diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..3f646a4 --- /dev/null +++ b/src/parser.h @@ -0,0 +1,51 @@ +/* + * Copyright 2024 Stephen Seo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * `parser.h` is the header for parsing args. + */ + +#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_ +#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_ + +typedef struct SDArchiverParsed { + /// Each bit is a flag. + /// 0b0 - is creating. + /// 0b1 - is extracting. + unsigned int flags; + /// Null-terminated string. + char *filename; + /// Null-terminated string. + char *compressor; + /// Null-terminated string. + char *decompressor; + /// Null-terminated strings in array of strings. + /// Last entry should be NULL. + /// Not used when extracting. + char **working_files; +} SDArchiverParsed; + +extern void simple_archiver_print_usage(void); + +extern SDArchiverParsed simple_archiver_create_parsed(void); + +/// Expects the user to pass a pointer to an SDArchiverParsed. +/// This means the user should have a SDArchiverParsed variable +/// and it should be passed with e.g. "&var". +extern int simple_archiver_parse_args(int argc, const char **argv, + SDArchiverParsed *out); + +extern void simple_archiver_free_parsed(SDArchiverParsed *parsed); + +#endif