set up unified lisp library and extensions subsystem.
This commit is contained in:
219
common/genlib.c
Normal file
219
common/genlib.c
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* genlib.c: generate unified LispLibrary.h for the various uLisp
|
||||
* platforms I work on.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
#define MAX_FILENAME 256
|
||||
#define MAX_STRFTIME 32
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
|
||||
const char lisp_output[] = "LispLibrary.h";
|
||||
|
||||
|
||||
/*
|
||||
* Determines whether a directory exists.
|
||||
*/
|
||||
int
|
||||
path_exists(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
int rv;
|
||||
|
||||
rv = stat(path, &st);
|
||||
if (rv == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (st.st_mode & S_IFDIR) {
|
||||
return 1;
|
||||
}
|
||||
else if (st.st_mode & S_IFREG) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unlike some other functions, it is an error to call copy_library if the path
|
||||
* doesn't exist. Other functions (such as copy_platform_library) will validate
|
||||
* the file exists first and skip it if it doesn't.
|
||||
*/
|
||||
static int
|
||||
copy_library(const char *filename, int source_fd)
|
||||
{
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
ssize_t bytes_read = 0;
|
||||
ssize_t bytes_written = 0;
|
||||
int fd = -1;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
|
||||
bytes_written = write(source_fd, buffer, bytes_read);
|
||||
if (bytes_written != bytes_read) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes_read == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
copy_platform_library(const char *platform, int dest_fd) {
|
||||
char filename[MAX_FILENAME];
|
||||
|
||||
if (!platform || !*platform) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("[+] attempting to load %s-specific library...\n",
|
||||
platform);
|
||||
|
||||
if (snprintf(filename, sizeof(filename), "%s.lsp", platform) >=
|
||||
(int)sizeof(filename)) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!path_exists(filename)) {
|
||||
printf("\t[+] %s-specific library not found; skipping.\n",
|
||||
platform);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dprintf(dest_fd, "(when (eq (platform) :%s)", platform);
|
||||
|
||||
if (copy_library(filename, dest_fd) != 0) {
|
||||
perror("[!] copying failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dprintf(dest_fd, ")\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
write_preamble(int dest_fd)
|
||||
{
|
||||
char timestamp[MAX_STRFTIME+1];
|
||||
struct tm tm;
|
||||
time_t now = time(NULL);
|
||||
|
||||
localtime_r(&now, &tm);
|
||||
|
||||
dprintf(dest_fd,
|
||||
"/*\n"
|
||||
" * LispLibrary.h - builtin library of additional uLisp functions\n"
|
||||
" *\n"
|
||||
" * NOTE:\n"
|
||||
" * this file was automatically generated on %s\n"
|
||||
" *\n"
|
||||
" * Changes will not be persisted across builds or platforms.\n"
|
||||
" */\n\n"
|
||||
"const char LispLibrary[] PROGMEM = R\"lisplibrary(\n\n",
|
||||
timestamp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
write_epilogue(int dest_fd)
|
||||
{
|
||||
dprintf(dest_fd, "\n)lisplibrary\";\n");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usage(int status)
|
||||
{
|
||||
FILE *output = stdout;
|
||||
|
||||
if (status != 0) {
|
||||
output = stderr;
|
||||
}
|
||||
|
||||
fprintf(output, "Usage: genlib [-h]\n"
|
||||
""
|
||||
"Generates a unified LispLibrary.h for the various platforms.\n");
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, const char *argv[])
|
||||
{
|
||||
int fd = -1;
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, (char **)argv, "h")) != -1) {
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
usage(0);
|
||||
break;
|
||||
default:
|
||||
usage(1);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
fd = open(lisp_output, O_WRONLY|O_CREAT, 0644);
|
||||
if (fd == -1) {
|
||||
perror("[!] failed to open library for write");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
write_preamble(fd);
|
||||
if (copy_library("library.lsp", fd) != 0) {
|
||||
fprintf(stderr, "[!] failed to generate %s.\n", lisp_output);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (copy_platform_library("picocalc", fd) != 0) {
|
||||
fprintf(stderr, "[!] failed to generate the picocalc component.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (copy_platform_library("t-deck", fd) != 0) {
|
||||
fprintf(stderr, "[!] failed to generate the picocalc component.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (copy_platform_library("teensy", fd) != 0) {
|
||||
fprintf(stderr, "[!] failed to generate the picocalc component.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
write_epilogue(fd);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
Reference in New Issue
Block a user