220 lines
3.8 KiB
C
220 lines
3.8 KiB
C
/*
|
|
* 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);
|
|
}
|