#include "pistachio.h"
#define TEXTBOX_LEN 400
#define ERROR_MSG_LEN 400
#define SCREEN 0
bool render_glyphs(Glyph *renders, Screen_Info *dimensions, Settings *config) {
bool oblique = config->results_font.oblique;
bool bold = config->results_font.bold;
u32 color = config->back_color;
for (int i = 0; i < 8; i++) {
if (i == 4)
color = config->selected_color;
config->results_font.oblique = oblique ^ (i & 1);
config->results_font.bold = bold ^ ((i >> 1) & 1);
if (!render_font(
dimensions,
&config->results_font,
color,
&renders[i * N_CHARS]
))
return false;
}
if (!render_font(
dimensions,
&config->search_font,
config->back_color,
&renders[BAR_OFFSET]
))
return false;
return render_font(
dimensions,
&config->error_font,
config->back_color,
&renders[ERR_OFFSET]
);
}
char *parse_command(char *textbox, Settings *config, char *error, int error_len) {
int len = strlen(textbox);
int second = find_next_word(textbox, 0, len);
bool is_command =
second || (textbox[0] != '/' && textbox[0] != '~');
bool daemonize = true;
if (is_command) {
int name_len = second ? second - 1 : len;
char name[name_len + 1];
memcpy(name, textbox, name_len);
name[name_len] = 0;
char *msg;
if (!find_program(name, &msg)) {
bool is_exe = false;
char *path = get_desugared_path(textbox, name_len);
FILE *f = fopen(path, "rb");
if (f) {
char magic[4];
fread(magic, 1, 4, f);
is_exe =
((magic[0] == 0x7f && magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') ||
(magic[0] == '#' && magic[1] == '!' && magic[2] == '/'));
}
if (!is_exe) {
snprintf(error, error_len, "%s\"%s\"", msg, path);
return NULL;
}
}
if (name_len == 4 && (!memcmp(name, "sudo", 4) || !memcmp(name, "doas", 4))) {
// kind of risky!
// FIXME: pass in textbox size so that this can be done safely
textbox[len] = '"';
textbox[len+1] = 0;
memmove(&textbox[4], textbox, len+1);
textbox[0] = '-';
textbox[1] = 'e';
textbox[2] = ' ';
textbox[3] = '"';
prepend_word(config->terminal_program.command, textbox);
}
}
else {
struct stat s;
char *path = get_desugared_path(textbox, len);
if (stat(path, &s) != 0) {
snprintf(error, error_len, "file/folder not found: %s", textbox);
return NULL;
}
// If this is a folder
if ((s.st_mode & S_IFMT) == S_IFDIR) {
prepend_word(config->folder_program.command, textbox);
daemonize = config->folder_program.daemonize;
}
// Else if it's a file
else if ((s.st_mode & S_IFMT) == S_IFREG) {
Program *prog = config->programs;
while (prog) {
bool found = false;
char *ext = prog->extensions;
int ext_len = 0;
for (int i = 0; i < prog->n_extensions; i++, ext += ext_len + 1) {
ext_len = strlen(ext);
if (!strcmp(&textbox[len - ext_len], ext)) {
found = true;
break;
}
}
if (found)
break;
prog = prog->next;
}
if (!prog) {
bool is_exe = false;
if ((s.st_mode & S_IXUSR) && (s.st_mode & S_IRUSR)) {
char magic[4];
FILE *f = fopen(path, "rb");
fread(magic, 1, 4, f);
fclose(f);
is_exe =
((magic[0] == 0x7f && magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') ||
(magic[0] == '#' && magic[1] == '!' && magic[2] == '/'));
}
if (!is_exe) {
prog = &config->default_program;
}
}
if (prog) {
prepend_word(prog->command, textbox);
daemonize = prog->daemonize;
}
}
}
if (daemonize) {
len = strlen(textbox);
if (textbox[len-1] != '&' && len < TEXTBOX_LEN-3)
strcpy(&textbox[len], " &");
else
textbox[len-1] = 0;
}
return textbox;
}
int main(int argc, char **argv) {
defer_arena_destruction();
init_directory_arena();
Settings *config = load_config();
struct stat s = {0};
if (stat(config->font_path, &s) != 0 || (s.st_mode & S_IFREG) == 0) {
fprintf(stderr, "Could not find font (absolute path \"%s\" does not specify a file)\n", config->font_path);
return 2;
}
Screen_Info dimensions;
if (!open_display(SCREEN, &dimensions)) {
fprintf(stderr, "Failed to access the display\n");
return 3;
}
if (config->window_w > 1.0)
config->window_w /= (float)dimensions.w;
if (config->window_h > 1.0)
config->window_h /= (float)dimensions.h;
if (!open_font(config->font_path))
return 4;
Glyph *renders = malloc(N_RENDERS * sizeof(Glyph));
render_glyphs(renders, &dimensions, config);
close_font();
char textbox[TEXTBOX_LEN] = {0};
char error_buf[ERROR_MSG_LEN] = {0};
char *error_msg = NULL;
char *command = NULL;
while (!command) {
int res = run_gui(config, &dimensions, renders, textbox, TEXTBOX_LEN, error_msg);
if (res == STATUS_EXIT)
break;
command = parse_command(textbox, config, error_buf, ERROR_MSG_LEN);
error_msg = &error_buf[0];
}
close_display();
free(renders);
if (command)
system(command);
return 0;
}