/* lemon, an example C application using embedded Guile. Copyright (C) 2025 Nikolaos Chatzikonstantinou This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include struct pin { char digits[6]; size_t len; }; void help(void) { printf("\n"); printf("Welcome to the lemon PIN app.\n"); printf("You may enter your 6-digit PIN number.\n"); printf("You can also enter the following commands:\n"); printf("\t- b, go back one digit.\n"); printf("\t- c, clear all of the input.\n"); printf("\t- :, enter a unary Guile expression to process the PIN further.\n"); printf("\t- q, quit the app.\n"); printf("\t- ?, this help screen.\n"); printf("\n"); } void print_pin(const struct pin *pin) { size_t i = 0; printf("----------PIN----------\n"); while(i < pin->len) { printf("[%hhd]%c", pin->digits[i], i + 1 < 6 ? ' ' : '\n'); ++i; } while(i < 6) { printf("[ ]%c", i + 1 < 6 ? ' ' : '\n'); ++i; } printf("-----------------------\n\n"); } void *entry(void *data) { static int ret; struct pin *pin = data; char buf[BUFSIZ]; SCM pin_lisp, proc; size_t i; pin->len = 0; int c = 0; while(c != EOF && c != 'q') { print_pin(pin); printf("Enter PIN (? for help): "); fflush(stdout); do { c = getchar(); if(c == EOF || c == 'q') { break; } else if(isdigit(c) && pin->len < sizeof pin->digits) { pin->digits[pin->len] = c - '0'; pin->len += 1; } else if(c == '?') { help(); } else if(c == 'b' && pin->len > 0) { pin->len -= 1; } else if(c == 'c') { pin->len = 0; } else if(c == ':') { if(fgets(buf, sizeof buf, stdin)) { i = strlen(buf); if(i > 0 && buf[i-1] == '\n') { buf[i-1] = 0; ungetc('\n', stdin); } proc = scm_c_eval_string(buf); pin_lisp = scm_make_u8vector(scm_from_size_t(pin->len), SCM_UNDEFINED); for(i = 0; i < pin->len; ++i) { scm_u8vector_set_x(pin_lisp, scm_from_size_t(i), scm_from_char(pin->digits[i])); } pin_lisp = scm_u8vector_to_list(pin_lisp); pin_lisp = scm_call_1(proc, pin_lisp); pin->len = scm_to_size_t(scm_length(pin_lisp)); if(pin->len > 6) { pin->len = 6; } for(i = 0; i < pin->len; ++i) { pin->digits[i] = scm_to_char(scm_list_ref(pin_lisp, scm_from_size_t(i))); } } else { c = EOF; break; } } } while(c != '\n'); } ret = ferror(stdin) ? EXIT_FAILURE : EXIT_SUCCESS; return &ret; } int main(void) { struct pin pin; int *ret = scm_with_guile(entry, &pin); return *ret; }