Some work on arg parser
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 7s
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 7s
Also added unit tests for arg parser.
This commit is contained in:
parent
467c09a0e4
commit
3172920c9c
6 changed files with 213 additions and 4 deletions
|
@ -18,3 +18,5 @@ jobs:
|
||||||
name: Build
|
name: Build
|
||||||
- run: ./buildDebug/test_datastructures
|
- run: ./buildDebug/test_datastructures
|
||||||
name: Run test_datastructures
|
name: Run test_datastructures
|
||||||
|
- run: ./buildDebug/test_simplearchiver
|
||||||
|
name: Run test_simplearchiver
|
||||||
|
|
|
@ -33,3 +33,8 @@ add_executable(test_datastructures
|
||||||
src/data_structures/priority_heap.c
|
src/data_structures/priority_heap.c
|
||||||
src/algorithms/linear_congruential_gen.c
|
src/algorithms/linear_congruential_gen.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_executable(test_simplearchiver
|
||||||
|
src/test.c
|
||||||
|
src/parser.c
|
||||||
|
)
|
||||||
|
|
|
@ -13,6 +13,7 @@ SOURCES = \
|
||||||
|
|
||||||
HEADERS = \
|
HEADERS = \
|
||||||
../src/parser.h \
|
../src/parser.h \
|
||||||
|
../src/parser_internal.h \
|
||||||
../src/algorithms/linear_congruential_gen.h \
|
../src/algorithms/linear_congruential_gen.h \
|
||||||
../src/data_structures/linked_list.h \
|
../src/data_structures/linked_list.h \
|
||||||
../src/data_structures/hash_map.h \
|
../src/data_structures/hash_map.h \
|
||||||
|
|
68
src/parser.c
68
src/parser.c
|
@ -22,6 +22,59 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "parser_internal.h"
|
||||||
|
|
||||||
|
/// Gets the first non "./"-like character in the filename.
|
||||||
|
unsigned int simple_archiver_parser_internal_filename_idx(
|
||||||
|
const char *filename) {
|
||||||
|
unsigned int idx = 0;
|
||||||
|
unsigned int known_good_idx = 0;
|
||||||
|
const unsigned int length = strlen(filename);
|
||||||
|
|
||||||
|
// 0b0001 - checked that idx char is '.'
|
||||||
|
// 0b0010 - checked that idx char is '/'
|
||||||
|
unsigned int flags = 0;
|
||||||
|
|
||||||
|
for (; idx < length; ++idx) {
|
||||||
|
if ((flags & 3) == 0) {
|
||||||
|
if (filename[idx] == 0) {
|
||||||
|
return known_good_idx;
|
||||||
|
} else if (filename[idx] == '.') {
|
||||||
|
flags |= 1;
|
||||||
|
} else {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
} else if ((flags & 3) == 1) {
|
||||||
|
if (filename[idx] == 0) {
|
||||||
|
return known_good_idx;
|
||||||
|
} else if (filename[idx] == '/') {
|
||||||
|
flags |= 2;
|
||||||
|
} else {
|
||||||
|
return idx - 1;
|
||||||
|
}
|
||||||
|
} else if ((flags & 3) == 3) {
|
||||||
|
if (filename[idx] == 0) {
|
||||||
|
return known_good_idx;
|
||||||
|
} else if (filename[idx] == '/') {
|
||||||
|
continue;
|
||||||
|
} else if (filename[idx] == '.') {
|
||||||
|
flags &= 0xFFFFFFFC;
|
||||||
|
known_good_idx = idx;
|
||||||
|
--idx;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filename[idx] == 0) {
|
||||||
|
return known_good_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
void simple_archiver_print_usage(void) {
|
void simple_archiver_print_usage(void) {
|
||||||
puts("Usage flags:");
|
puts("Usage flags:");
|
||||||
puts("-c : create archive file");
|
puts("-c : create archive file");
|
||||||
|
@ -29,6 +82,7 @@ void simple_archiver_print_usage(void) {
|
||||||
puts("-f <filename> : filename to work on");
|
puts("-f <filename> : filename to work on");
|
||||||
puts("--compressor <full_compress_cmd> : requires --decompressor");
|
puts("--compressor <full_compress_cmd> : requires --decompressor");
|
||||||
puts("--decompressor <full_decompress_cmd> : requires --compressor");
|
puts("--decompressor <full_decompress_cmd> : requires --compressor");
|
||||||
|
puts("-- : specifies remaining arguments are files to archive/extract");
|
||||||
puts("If creating archive file, remaining args specify files to archive.");
|
puts("If creating archive file, remaining args specify files to archive.");
|
||||||
puts("If extracting archive file, remaining args specify files to extract.");
|
puts("If extracting archive file, remaining args specify files to extract.");
|
||||||
}
|
}
|
||||||
|
@ -92,6 +146,8 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
strncpy(out->decompressor, argv[1], size);
|
strncpy(out->decompressor, argv[1], size);
|
||||||
--argc;
|
--argc;
|
||||||
++argv;
|
++argv;
|
||||||
|
} else if (argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == 0) {
|
||||||
|
is_remaining_args = 1;
|
||||||
} else if (argv[0][0] != '-') {
|
} else if (argv[0][0] != '-') {
|
||||||
is_remaining_args = 1;
|
is_remaining_args = 1;
|
||||||
continue;
|
continue;
|
||||||
|
@ -99,9 +155,11 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
} else {
|
} else {
|
||||||
if (out->working_files == NULL) {
|
if (out->working_files == NULL) {
|
||||||
out->working_files = malloc(sizeof(char *) * 2);
|
out->working_files = malloc(sizeof(char *) * 2);
|
||||||
int arg_length = strlen(argv[0]) + 1;
|
unsigned int arg_idx =
|
||||||
|
simple_archiver_parser_internal_filename_idx(argv[0]);
|
||||||
|
int arg_length = strlen(argv[0] + arg_idx) + 1;
|
||||||
out->working_files[0] = malloc(arg_length);
|
out->working_files[0] = malloc(arg_length);
|
||||||
strncpy(out->working_files[0], argv[0], arg_length);
|
strncpy(out->working_files[0], argv[0] + arg_idx, arg_length);
|
||||||
out->working_files[1] = NULL;
|
out->working_files[1] = NULL;
|
||||||
} else {
|
} else {
|
||||||
int working_size = 1;
|
int working_size = 1;
|
||||||
|
@ -117,10 +175,12 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
|
|
||||||
// Set new actual last element to NULL.
|
// Set new actual last element to NULL.
|
||||||
out->working_files[working_size] = NULL;
|
out->working_files[working_size] = NULL;
|
||||||
int size = strlen(argv[0]) + 1;
|
unsigned int arg_idx =
|
||||||
|
simple_archiver_parser_internal_filename_idx(argv[0]);
|
||||||
|
int size = strlen(argv[0] + arg_idx) + 1;
|
||||||
// Set last element to the arg.
|
// Set last element to the arg.
|
||||||
out->working_files[working_size - 1] = malloc(size);
|
out->working_files[working_size - 1] = malloc(size);
|
||||||
strncpy(out->working_files[working_size - 1], argv[0], size);
|
strncpy(out->working_files[working_size - 1], argv[0] + arg_idx, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
src/parser_internal.h
Normal file
26
src/parser_internal.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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_internal.h` is the header for parsing args with internal functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_INTERNAL_H_
|
||||||
|
#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_INTERNAL_H_
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
unsigned int simple_archiver_parser_internal_filename_idx(const char *filename);
|
||||||
|
|
||||||
|
#endif
|
115
src/test.c
Normal file
115
src/test.c
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* `test.c` is the source for testing code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "parser_internal.h"
|
||||||
|
|
||||||
|
static int checks_checked = 0;
|
||||||
|
static int checks_passed = 0;
|
||||||
|
|
||||||
|
#define CHECK_TRUE(x) \
|
||||||
|
do { \
|
||||||
|
++checks_checked; \
|
||||||
|
if (!(x)) { \
|
||||||
|
printf("CHECK_TRUE at line %u failed: %s\n", __LINE__, #x); \
|
||||||
|
} else { \
|
||||||
|
++checks_passed; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
#define CHECK_FALSE(x) \
|
||||||
|
do { \
|
||||||
|
++checks_checked; \
|
||||||
|
if (x) { \
|
||||||
|
printf("CHECK_FALSE at line %u failed: %s\n", __LINE__, #x); \
|
||||||
|
} else { \
|
||||||
|
++checks_passed; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// Test parser.
|
||||||
|
{
|
||||||
|
unsigned int idx = simple_archiver_parser_internal_filename_idx("test");
|
||||||
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
|
idx = simple_archiver_parser_internal_filename_idx("./test");
|
||||||
|
CHECK_TRUE(idx == 2);
|
||||||
|
|
||||||
|
idx = simple_archiver_parser_internal_filename_idx("././test");
|
||||||
|
CHECK_TRUE(idx == 4);
|
||||||
|
|
||||||
|
idx = simple_archiver_parser_internal_filename_idx("././//././//./test");
|
||||||
|
CHECK_TRUE(idx == 14);
|
||||||
|
|
||||||
|
idx = simple_archiver_parser_internal_filename_idx("/././//././//./test");
|
||||||
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
|
idx = simple_archiver_parser_internal_filename_idx(".derp/.//././//./test");
|
||||||
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
|
idx = simple_archiver_parser_internal_filename_idx("././/.derp/.///./test");
|
||||||
|
CHECK_TRUE(idx == 5);
|
||||||
|
|
||||||
|
idx = simple_archiver_parser_internal_filename_idx("././/.//.//./");
|
||||||
|
CHECK_TRUE(idx == 11);
|
||||||
|
|
||||||
|
idx = simple_archiver_parser_internal_filename_idx("././/.//.//.");
|
||||||
|
CHECK_TRUE(idx == 11);
|
||||||
|
|
||||||
|
idx = simple_archiver_parser_internal_filename_idx("././/.//.//");
|
||||||
|
CHECK_TRUE(idx == 8);
|
||||||
|
|
||||||
|
SDArchiverParsed parsed = simple_archiver_create_parsed();
|
||||||
|
simple_archiver_parse_args(
|
||||||
|
4,
|
||||||
|
(const char *[]){"parser", "--", "././/././//./derp", "./doop", NULL},
|
||||||
|
&parsed);
|
||||||
|
|
||||||
|
CHECK_TRUE(strcmp("derp", parsed.working_files[0]) == 0);
|
||||||
|
CHECK_TRUE(strcmp("doop", parsed.working_files[1]) == 0);
|
||||||
|
CHECK_TRUE(parsed.working_files[2] == NULL);
|
||||||
|
CHECK_TRUE(parsed.filename == NULL);
|
||||||
|
CHECK_TRUE(parsed.flags == 0);
|
||||||
|
|
||||||
|
simple_archiver_free_parsed(&parsed);
|
||||||
|
|
||||||
|
parsed = simple_archiver_create_parsed();
|
||||||
|
simple_archiver_parse_args(
|
||||||
|
7,
|
||||||
|
(const char *[]){"parser", "-x", "-f", "the_filename",
|
||||||
|
"././/././//./.derp", "././//./_doop",
|
||||||
|
"./../../.prev_dir_file", NULL},
|
||||||
|
&parsed);
|
||||||
|
|
||||||
|
CHECK_TRUE(strcmp(".derp", parsed.working_files[0]) == 0);
|
||||||
|
CHECK_TRUE(strcmp("_doop", parsed.working_files[1]) == 0);
|
||||||
|
CHECK_TRUE(strcmp("../../.prev_dir_file", parsed.working_files[2]) == 0);
|
||||||
|
CHECK_TRUE(parsed.working_files[3] == NULL);
|
||||||
|
CHECK_TRUE(strcmp("the_filename", parsed.filename) == 0);
|
||||||
|
CHECK_TRUE(parsed.flags == 1);
|
||||||
|
|
||||||
|
simple_archiver_free_parsed(&parsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Checks checked: %u\n", checks_checked);
|
||||||
|
printf("Checks passed: %u\n", checks_passed);
|
||||||
|
return checks_passed == checks_checked ? 0 : 1;
|
||||||
|
}
|
Loading…
Reference in a new issue