mirror of
https://github.com/lhearachel/narc.git
synced 2025-06-18 21:45:34 -04:00
refactor(cli): Extract strvec interface
This commit is contained in:
parent
ee982cadfd
commit
aa488232cf
32
cli/include/strvec.h
Normal file
32
cli/include/strvec.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2024 <lhearachel@proton.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef NARC_STRVEC_H
|
||||
#define NARC_STRVEC_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct strvec {
|
||||
char **s;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
struct strvec *strvec_new(size_t capacity);
|
||||
void strvec_del(struct strvec *strvec);
|
||||
int strvec_push(struct strvec *strvec, char *s);
|
||||
int strvec_from_file(struct strvec *strvec, const char *fname);
|
||||
|
||||
#endif // NARC_STRVEC_H
|
@ -27,6 +27,7 @@
|
||||
#include "defs/narc.h"
|
||||
#include "defs/vfs.h"
|
||||
|
||||
#include "strvec.h"
|
||||
#include "utils.h"
|
||||
|
||||
typedef intptr_t ssize_t;
|
||||
@ -71,14 +72,9 @@ struct array {
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
static struct array *build_pack_list(DIR *dir, const char *order_fname, const char *ignore_fname);
|
||||
static ssize_t read_line(char **lineptr, size_t *n, FILE *stream);
|
||||
static int read_file_lines(const char *fname, struct array *out_array);
|
||||
static void free_array(struct array *arr);
|
||||
|
||||
static int parse_opts(int *argc, const char ***argv, struct options *opts);
|
||||
|
||||
static int pack(struct options *opts);
|
||||
static struct strvec *build_pack_list(DIR *dir, const char *order_fname, const char *ignore_fname);
|
||||
|
||||
int create(int argc, const char **argv)
|
||||
{
|
||||
@ -159,14 +155,14 @@ static int pack(struct options *opts)
|
||||
FAIL("narc create: could not get current working directory: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
struct array *to_pack = build_pack_list(dir, opts->order, opts->ignore);
|
||||
struct strvec *to_pack = build_pack_list(dir, opts->order, opts->ignore);
|
||||
|
||||
chdir(opts->input);
|
||||
ctx = narc_pack_start();
|
||||
for (size_t i = 0; i < to_pack->count; i++) {
|
||||
FILE *f = fopen(to_pack->elems[i], "rb");
|
||||
FILE *f = fopen(to_pack->s[i], "rb");
|
||||
if (f == NULL) {
|
||||
FAIL("narc create: error while opening file “%s” for reading: %s\n", to_pack->elems[i], strerror(errno));
|
||||
FAIL("narc create: error while opening file “%s” for reading: %s\n", to_pack->s[i], strerror(errno));
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
@ -175,7 +171,7 @@ static int pack(struct options *opts)
|
||||
|
||||
unsigned char *image = malloc(fsize);
|
||||
if (image == NULL) {
|
||||
FAIL("narc create: error while reading file “%s”: %s\n", to_pack->elems[i], strerror(errno));
|
||||
FAIL("narc create: error while reading file “%s”: %s\n", to_pack->s[i], strerror(errno));
|
||||
}
|
||||
|
||||
fread(image, 1, fsize, f);
|
||||
@ -213,135 +209,18 @@ fail:
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static ssize_t read_line(char **lineptr, size_t *n, FILE *stream)
|
||||
static struct strvec *build_pack_list(DIR *dir, const char *order_fname, const char *ignore_fname)
|
||||
{
|
||||
if (lineptr == NULL || n == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
struct strvec *all_files = NULL, *ignored = NULL;
|
||||
|
||||
int c = fgetc(stream);
|
||||
if (c == EOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*lineptr == NULL) {
|
||||
*lineptr = malloc(128);
|
||||
if (*lineptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*n = 128;
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
do {
|
||||
if (pos + 1 >= *n) {
|
||||
size_t new_size = *n + (*n >> 2);
|
||||
if (new_size < 128) {
|
||||
new_size = 128;
|
||||
}
|
||||
|
||||
char *new_ptr = realloc(*lineptr, new_size);
|
||||
if (new_ptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*n = new_size;
|
||||
*lineptr = new_ptr;
|
||||
}
|
||||
|
||||
((unsigned char *)(*lineptr))[pos++] = c;
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
} while ((c = fgetc(stream)) != EOF);
|
||||
|
||||
(*lineptr)[pos] = '\0';
|
||||
return pos;
|
||||
}
|
||||
|
||||
static void free_array(struct array *arr)
|
||||
{
|
||||
for (size_t i = 0; i < arr->count; i++) {
|
||||
free(arr->elems[i]);
|
||||
}
|
||||
|
||||
free(arr->elems);
|
||||
free(arr);
|
||||
}
|
||||
|
||||
static int append_array(struct array *arr, char *elem)
|
||||
{
|
||||
if (arr->count + 1 == arr->capacity) {
|
||||
char **tmp = realloc(arr->elems, arr->capacity * 2);
|
||||
if (tmp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
arr->elems = tmp;
|
||||
arr->capacity *= 2;
|
||||
}
|
||||
|
||||
arr->elems[arr->count] = elem;
|
||||
arr->count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_file_lines(const char *fname, struct array *out_array)
|
||||
{
|
||||
if (fname == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *buf = NULL;
|
||||
size_t buf_size = 0;
|
||||
ssize_t read_size;
|
||||
|
||||
while ((read_size = read_line(&buf, &buf_size, f)) != -1) {
|
||||
// Skip over empty lines
|
||||
if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n') || buf[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *line = malloc(read_size);
|
||||
strncpy(line, buf, read_size - 1);
|
||||
line[read_size] = '\0';
|
||||
if (append_array(out_array, line)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct array *build_pack_list(DIR *dir, const char *order_fname, const char *ignore_fname)
|
||||
{
|
||||
struct array *all_files = NULL, *ignored = NULL;
|
||||
|
||||
all_files = malloc(sizeof(struct array));
|
||||
all_files->elems = malloc(sizeof(char *) * 5000);
|
||||
all_files->count = 0;
|
||||
all_files->capacity = 5000;
|
||||
|
||||
// Collect pre-orderd files first. These don't need to be validated against ignored entries.
|
||||
if (read_file_lines(order_fname, all_files)) {
|
||||
all_files = strvec_new(5000);
|
||||
if (strvec_from_file(all_files, order_fname)) {
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
// Load the list of `ignored` names/patterns. This list is kept separate.
|
||||
ignored = malloc(sizeof(struct array));
|
||||
ignored->elems = malloc(sizeof(char *) * 100);
|
||||
ignored->count = 0;
|
||||
ignored->capacity = 100;
|
||||
|
||||
if (read_file_lines(ignore_fname, ignored)) {
|
||||
ignored = strvec_new(100);
|
||||
if (strvec_from_file(ignored, ignore_fname)) {
|
||||
goto cleanup_error;
|
||||
}
|
||||
|
||||
@ -356,7 +235,7 @@ static struct array *build_pack_list(DIR *dir, const char *order_fname, const ch
|
||||
// Check the ignored list first, since it should be much smaller
|
||||
bool exclude = false;
|
||||
for (size_t i = 0; i < ignored->count; i++) {
|
||||
if (fnmatch(ignored->elems[i], entry->d_name, FNM_PERIOD) == 0) {
|
||||
if (fnmatch(ignored->s[i], entry->d_name, FNM_PERIOD) == 0) {
|
||||
exclude = true;
|
||||
break;
|
||||
}
|
||||
@ -368,7 +247,7 @@ static struct array *build_pack_list(DIR *dir, const char *order_fname, const ch
|
||||
|
||||
// Now check the ordered list, to avoid double includes
|
||||
for (size_t i = 0; i < all_files->count; i++) {
|
||||
if (strcmp(all_files->elems[i], entry->d_name) == 0) {
|
||||
if (strcmp(all_files->s[i], entry->d_name) == 0) {
|
||||
exclude = true;
|
||||
break;
|
||||
}
|
||||
@ -381,13 +260,13 @@ static struct array *build_pack_list(DIR *dir, const char *order_fname, const ch
|
||||
char *fname = malloc(strlen(entry->d_name) + 1);
|
||||
strcpy(fname, entry->d_name);
|
||||
fname[strlen(entry->d_name)] = '\0';
|
||||
append_array(all_files, fname);
|
||||
strvec_push(all_files, fname);
|
||||
}
|
||||
|
||||
return all_files;
|
||||
|
||||
cleanup_error:
|
||||
free_array(all_files);
|
||||
free_array(ignored);
|
||||
strvec_del(all_files);
|
||||
strvec_del(ignored);
|
||||
return NULL;
|
||||
}
|
||||
|
144
cli/src/strvec.c
Normal file
144
cli/src/strvec.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2024 <lhearachel@proton.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "strvec.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef intptr_t ssize_t;
|
||||
|
||||
struct strvec *strvec_new(size_t capacity)
|
||||
{
|
||||
struct strvec *vec = malloc(sizeof(struct strvec));
|
||||
|
||||
vec->s = malloc(capacity * sizeof(char *));
|
||||
vec->count = 0;
|
||||
vec->capacity = capacity;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
void strvec_del(struct strvec *strvec)
|
||||
{
|
||||
for (size_t i = 0; i < strvec->count; i++) {
|
||||
free(strvec->s[i]);
|
||||
}
|
||||
|
||||
free(strvec->s);
|
||||
free(strvec);
|
||||
}
|
||||
|
||||
int strvec_push(struct strvec *strvec, char *s)
|
||||
{
|
||||
if (strvec->count + 1 > strvec->capacity) {
|
||||
char **p = realloc(strvec->s, strvec->capacity * sizeof(char *));
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strvec->s = p;
|
||||
strvec->capacity *= 2;
|
||||
}
|
||||
|
||||
strvec->s[strvec->count] = s;
|
||||
strvec->count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t read_line(char **lineptr, size_t *n, FILE *stream)
|
||||
{
|
||||
if (lineptr == NULL || n == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int c = fgetc(stream);
|
||||
if (c == EOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*lineptr == NULL) {
|
||||
*lineptr = malloc(128);
|
||||
if (*lineptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*n = 128;
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
do {
|
||||
if (pos + 1 >= *n) {
|
||||
size_t new_size = *n + (*n >> 2);
|
||||
if (new_size < 128) {
|
||||
new_size = 128;
|
||||
}
|
||||
|
||||
char *new_ptr = realloc(*lineptr, new_size);
|
||||
if (new_ptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*n = new_size;
|
||||
*lineptr = new_ptr;
|
||||
}
|
||||
|
||||
((unsigned char *)(*lineptr))[pos++] = c;
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
} while ((c = fgetc(stream)) != EOF);
|
||||
|
||||
(*lineptr)[pos] = '\0';
|
||||
return pos;
|
||||
}
|
||||
|
||||
int strvec_from_file(struct strvec *strvec, const char *fname)
|
||||
{
|
||||
if (fname == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *buf = NULL;
|
||||
size_t buf_size = 0;
|
||||
ssize_t read_size;
|
||||
|
||||
while ((read_size = read_line(&buf, &buf_size, f)) != -1) {
|
||||
// Skip over empty lines
|
||||
if (buf[0] == '\n' || (buf[0] == '\r' && buf[1] == '\n') || buf[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
char *line = malloc(read_size);
|
||||
strncpy(line, buf, read_size - 1);
|
||||
line[read_size] = '\0';
|
||||
if (strvec_push(strvec, line)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user