/*
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;
}