2025-04-09 Progress Report
Wrote some additional SD-card and platform-detection support. The platform is pretty straightforward. I asked in the forums about making this a variable, with no one who knew. I decided it wasn't worth figuring out compared to the other work I have to do, so I went with the "dumb" version.
object *
fn_platform(object *args, object *env)
{
    (void) args;
    (void) env;
#if defined(PLATFORM_PICOCALC)
    const char platformName[] = ":picocalc";
#elif defined(TDECK_PERI_POWERON) /* first t-deck define */
    const char platformName[] = ":t-deck";
#elif defined(ARDUINO_TEENSY41)
    const char platformName[] = ":teensy41";
#else
    const char platformName[] = ":unknown";
#endif
    return internlong((char *)platformName);
}
Writing the SD card functions, though, I learned some stuff about how
uLisp works internally. Namely, creating a filename is done with
MakeFilename.
object *
fn_sd_rename(object *args, object *env)
{
    (void) env;
    char buffer1[BUFFERSIZE];
    char buffer2[BUFFERSIZE];
    object *pathFrom = car(args);
    if (!stringp(pathFrom)) {
        error2("filenames must be strings.");
    }
    object *pathTo = car(cdr(args));
    if (!stringp(pathTo)) {
        error2("filenames must be strings.");
    }
    if (!SD.rename((const char *)MakeFilename(pathFrom, buffer1),
               (const char *)MakeFilename(pathTo, buffer2))) {
        return nil;
    }
    return tee;
}
Another useful thing I wanted was a list of all the symbols I'd
defined that I'd lost if I powered off. list-library will print the
list of symbols in the Lisp Library, but I wanted a list of
symbols. So, I wrote list-library2. Basically, I just copied the
core of list-library, then changed it to cons symbols to a return value:
// (list-library2)
// Return a list of all symbols in the current Lisp library.
object *
fn_listlibrary2(object *args, object *env)
{
    (void) args, (void) env;
    object *lst = nil;
    GlobalStringIndex = 0;
    object *line = read(glibrary);
    while (line != NULL) {
        builtin_t bname = builtin(first(line)->name);
        if (bname == DEFUN || bname == DEFVAR) {
            lst = cons(second(line), lst);
        }
        line = read(glibrary);
    }
    return lst;
}
Added some more code to the LispLibrary too, including a function to
return all the user-defined symbols. Also, added some functionality
that allows for loading platform-specific code
(e.g. "platform-name.lsp").
(defun user-symbols ()
  "(user-symbols)
Returns a list of all the symbols add by a user after boot."
  (let ((library (list-library2)))
   (remove-if (lambda (sym)
                 (member sym library))
              (globals))))
(defun reset-user-environment ()
  "(reset-user-environment)
Removes all user-defined symbols."
  (mapcar 'makunbound (user-symbols)))
(defun keyword-string (k)
  "(keyword-string k)
Returns the keyword as a string, or nil if the arg isn't a keyword."
  (when (keywordp k)
   (subseq (string k) 1)))
(defun load-platform ()
 "(load-platform)
Load-platform specific code if present, found on the SD card as
platform.lsp (e.g. picocalc.lsp)."
 (let ((platform-file (concatenate 'string (keyword-string (platform)) ".lsp")))
  (when (sd-exists-p platform-file)
   (load platform-file))))
I also asked on the forums about keeping the code for multiple devices synced (specifically, the extensions and Lisp library); the recommendation was to just keep separate trees. I think I'll spend some time investigating uLisp builder.
However, I ran into a snag tonight: it looks like my screen is broken.
I think it happened while I was updating the keyboard firmware, which is unfortunate. Might be relying on the T-Deck more in the near future. It will certainly put a damper on the PicoCalc work.

