/* * genlib.c: generate unified LispLibrary.h for the various uLisp * platforms I work on. */ #include #include #include #include #include #include #include #include #include #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); }