feat(cli-create): Implement naix output

This commit is contained in:
Rachel 2024-12-30 16:14:24 -08:00
parent aa488232cf
commit 2d6a269985
5 changed files with 209 additions and 9 deletions

32
cli/include/strbuild.h Normal file
View 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_STRBUILD_H
#define NARC_STRBUILD_H
#include <stddef.h>
struct strbuild {
char *s;
size_t len;
size_t capacity;
};
struct strbuild *strbuild_new(size_t capacity);
void strbuild_del(struct strbuild *strbuild);
int strbuild_cat(struct strbuild *strbuild, const char *s);
int strbuild_sprintf(struct strbuild *strbuild, const char *fmt, ...);
#endif // NARC_STRBUILD_H

View File

@ -30,8 +30,9 @@
bool match_either(const char *s, const char *a, const char *b);
char *basename(const char *path);
// NOTE: This routine performs a string allocation! The calling client is
// NOTE: These routines perform a string allocation! The calling client is
// responsible for freeing the result when they are finished with it!
char *basename_extend(const char *path, const char *ext);
char *basename_stem_extend(const char *path, const char *ext);
#endif // NARC_UTILS_H

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
@ -27,6 +28,7 @@
#include "defs/narc.h"
#include "defs/vfs.h"
#include "strbuild.h"
#include "strvec.h"
#include "utils.h"
@ -56,6 +58,20 @@ static const char *options = ""
" patterns which may be present in DIRECTORY but should\n"
" not be added to the output."
"";
static const char *naix_header = ""
"/*\n"
" * THIS FILE WAS AUTOMATICALLY GENERATED BY narc\n"
" * DO NOT MODIFY!!!\n"
" */\n"
"#ifndef %s\n"
"#define %s\n"
"\n"
"";
static const char *naix_member = "#define %s %d\n";
static const char *naix_footer = "\n#endif /* %s */\n";
// clang-format on
struct options {
@ -66,15 +82,12 @@ struct options {
const char *ignore;
};
struct array {
char **elems;
size_t count;
size_t capacity;
};
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);
static struct strbuild *start_index(const char *target_fname, char **out_guard);
static void add_to_index(struct strbuild *index, const char *fname, const size_t i);
static void finish_index(struct strbuild *index, const char *guard);
int create(int argc, const char **argv)
{
@ -140,10 +153,11 @@ static int parse_opts(int *argc, const char ***argv, struct options *opts)
static int pack(struct options *opts)
{
DIR *dir = NULL;
FILE *fout = NULL;
FILE *fout = NULL, *fnaix = NULL;
char *cwd = NULL;
struct narc *narc = NULL;
struct vfs_pack_ctx *ctx = NULL;
char *naix = basename_stem_extend(opts->output, "naix");
dir = opendir(opts->input);
if (dir == NULL) {
@ -155,6 +169,9 @@ static int pack(struct options *opts)
FAIL("narc create: could not get current working directory: %s\n", strerror(errno));
}
char guard[256] = {0};
char *guard_p = &guard[0]; // just to make the compiler happy
struct strbuild *index = start_index(naix, &guard_p);
struct strvec *to_pack = build_pack_list(dir, opts->order, opts->ignore);
chdir(opts->input);
@ -176,18 +193,29 @@ static int pack(struct options *opts)
fread(image, 1, fsize, f);
narc_pack_file(ctx, image, fsize);
add_to_index(index, to_pack->s[i], i);
fclose(f);
}
narc = narc_pack(ctx);
finish_index(index, guard);
chdir(cwd);
if (opts->naix) {
fnaix = fopen(naix, "w");
if (fnaix == NULL) {
FAIL("narc create: error while opening file “%s” for writing: %s\n", opts->output, strerror(errno));
}
fwrite(index->s, 1, index->len, fnaix);
fclose(fnaix);
}
fout = fopen(opts->output, "wb");
if (fout == NULL) {
FAIL("narc create: error while opening file “%s” for writing: %s\n", opts->output, strerror(errno));
}
fwrite(narc, narc->size, 1, fout);
free(naix);
free(cwd);
free(narc);
fclose(fout);
@ -199,11 +227,16 @@ fail:
fclose(fout);
}
if (fnaix) {
fclose(fnaix);
}
if (dir) {
closedir(dir);
}
narc_pack_halt(ctx);
free(naix);
free(cwd);
free(narc);
return EXIT_FAILURE;
@ -213,6 +246,7 @@ static struct strvec *build_pack_list(DIR *dir, const char *order_fname, const c
{
struct strvec *all_files = NULL, *ignored = NULL;
// Build the list of ordered files first. These are never ignored.
all_files = strvec_new(5000);
if (strvec_from_file(all_files, order_fname)) {
goto cleanup_error;
@ -270,3 +304,50 @@ cleanup_error:
strvec_del(ignored);
return NULL;
}
static struct strbuild *start_index(const char *target_fname, char **out_guard)
{
char guard[256] = "NARC_";
size_t i;
char c, *p = &guard[5];
for (i = 0; i < 250 && (c = target_fname[i]) != '\0'; i++) {
if (c == '-' || c == '.' || c == '_') {
*p = '_';
p++;
} else if (islower(c)) {
*p = toupper(c);
p++;
} else if (isupper(c)) {
*p = c;
p++;
}
}
*p = '\0';
strcpy(*out_guard, guard);
struct strbuild *str = strbuild_new(65536);
strbuild_sprintf(str, naix_header, guard, guard);
return str;
}
static void add_to_index(struct strbuild *index, const char *fname, const size_t i)
{
char def_name[256];
size_t j;
char c, *p = def_name;
for (j = 0; j < 256 && (c = fname[j]) != '\0'; j++, p++) {
if (ispunct(c)) {
*p = '_';
} else {
*p = c;
}
}
*p = '\0';
strbuild_sprintf(index, naix_member, def_name, i);
}
static void finish_index(struct strbuild *index, const char *guard)
{
strbuild_sprintf(index, naix_footer, guard);
}

70
cli/src/strbuild.c Normal file
View File

@ -0,0 +1,70 @@
/*
* 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 "strbuild.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct strbuild *strbuild_new(size_t capacity)
{
struct strbuild *s = malloc(sizeof(struct strbuild));
s->s = malloc(capacity);
s->s[0] = '\0';
s->len = 0;
s->capacity = capacity;
return s;
}
void strbuild_del(struct strbuild *strbuild)
{
free(strbuild->s);
free(strbuild);
}
int strbuild_cat(struct strbuild *strbuild, const char *s)
{
size_t next_len = strlen(s);
if (strbuild->len + next_len > strbuild->capacity) {
size_t next_cap = (strbuild->capacity + next_len) * 2;
char *p = realloc(strbuild->s, next_cap);
if (p == NULL) {
return -1;
}
strbuild->s = p;
strbuild->capacity = next_cap;
}
strcat(strbuild->s, s);
strbuild->len += next_len;
return 0;
}
int strbuild_sprintf(struct strbuild *strbuild, const char *fmt, ...)
{
char buf[1024];
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
return strbuild_cat(strbuild, buf);
}

View File

@ -41,6 +41,22 @@ char *basename_extend(const char *path, const char *ext)
return buf;
}
char *basename_stem_extend(const char *path, const char *ext)
{
char *p = strrchr(path, '/');
if (p == NULL) {
p = (char *)path;
}
char *s = strrchr(p, '.');
size_t stem_len = (s == NULL) ? strlen(p) : s - p;
char *buf = malloc(stem_len + strlen(ext) + 2);
strncpy(buf, p, stem_len);
sprintf(buf + stem_len, ".%s", ext);
return buf;
}
bool match_either(const char *s, const char *a, const char *b)
{
return (a != NULL && strcmp(s, a) == 0)