ref: d9ed4b401e282991ce0c102d2b968e07ebb0f58d
parent: 14c8610315e980655e7e9db9e5907ca1a7a0c4e9
author: cancel <cancel@cancel.fm>
date: Sun Jan 12 03:51:52 EST 2020
Add basic test of loading prefs conf file
--- a/sysmisc.c
+++ b/sysmisc.c
@@ -1,5 +1,6 @@
#include "sysmisc.h"
#include "gbuffer.h"
+#include "oso.h"
#include <ctype.h>
ORCA_FORCE_NO_INLINE
@@ -167,4 +168,45 @@
*out_right = s + b0;
*out_rightsize = b1 - b0;
return Conf_read_left_and_right;
+}
+
+typedef enum {
+ Conf_dir_ok = 0,
+ Conf_dir_no_home,
+} Conf_dir_error;
+
+static char const* const xdg_config_home_env = "XDG_CONFIG_HOME";
+static char const* const home_env = "HOME";
+static char const* const conf_file_name = "/orca.conf";
+
+static Conf_dir_error try_get_conf_dir(oso** out) {
+ char const* xdgcfgdir = getenv(xdg_config_home_env);
+ if (xdgcfgdir) {
+ Usz xdgcfgdirlen = strlen(xdgcfgdir);
+ if (xdgcfgdirlen > 0) {
+ osoputlen(out, xdgcfgdir, xdgcfgdirlen);
+ return Conf_dir_ok;
+ }
+ }
+ char const* homedir = getenv(home_env);
+ if (homedir) {
+ Usz homedirlen = strlen(homedir);
+ if (homedirlen > 0) {
+ osoputprintf(out, "%s/.config", homedir);
+ return Conf_dir_ok;
+ }
+ }
+ return Conf_dir_no_home;
+}
+
+FILE* conf_file_open_for_reading(void) {
+ oso* path = NULL;
+ if (try_get_conf_dir(&path))
+ return NULL;
+ osocat(&path, conf_file_name);
+ if (!path)
+ return NULL;
+ FILE* file = fopen(osoc(path), "r");
+ osofree(path);
+ return file;
}
--- a/sysmisc.h
+++ b/sysmisc.h
@@ -27,3 +27,6 @@
Conf_read_result conf_read_line(FILE* file, char* buf, Usz bufsize,
char** out_left, Usz* out_leftlen,
char** out_right, Usz* out_rightlen);
+
+
+FILE* conf_file_open_for_reading(void);
--- a/tui_main.c
+++ b/tui_main.c
@@ -10,6 +10,8 @@
#include <getopt.h>
#include <locale.h>
+#include <assert.h>
+
#define SOKOL_IMPL
#include "sokol_time.h"
#undef SOKOL_IMPL
@@ -786,14 +788,41 @@
PmError midi_mode_init_portmidi(Midi_mode* mm, PmDeviceID dev_id) {
PmError e = portmidi_init_if_necessary();
if (e)
- return e;
+ goto fail;
e = Pm_OpenOutput(&mm->portmidi.stream, dev_id, NULL, 0, NULL, NULL, 0);
if (e)
- return e;
+ goto fail;
mm->portmidi.type = Midi_mode_type_portmidi;
mm->portmidi.device_id = dev_id;
return pmNoError;
+
+fail:
+ midi_mode_init_null(mm);
+ return e;
}
+// Returns true on success. todo currently output only
+bool portmidi_find_device_id_by_name(char const* name, Usz namelen,
+ PmError* out_pmerror, PmDeviceID* out_id) {
+ fprintf(stderr, "hi there\n");
+ *out_pmerror = portmidi_init_if_necessary();
+ if (*out_pmerror)
+ return false;
+ int num = Pm_CountDevices();
+ for (int i = 0; i < num; ++i) {
+ PmDeviceInfo const* info = Pm_GetDeviceInfo(i);
+ if (!info || !info->output)
+ continue;
+ Usz len = strlen(info->name);
+ fprintf(stderr, "trying: %s\n", info->name);
+ if (len != namelen)
+ continue;
+ if (strncmp(name, info->name, namelen) == 0) {
+ *out_id = i;
+ return true;
+ }
+ }
+ return false;
+}
#endif
void midi_mode_deinit(Midi_mode* mm) {
switch (mm->any.type) {
@@ -2340,6 +2369,64 @@
return errstr;
}
+typedef struct {
+ oso* portmidi_output_device;
+} Prefs;
+
+void prefs_init(Prefs* p) { memset(p, 0, sizeof(Prefs)); }
+void prefs_deinit(Prefs* p) { osofree(p->portmidi_output_device); }
+
+typedef enum {
+ Prefs_load_ok = 0,
+} Prefs_load_error;
+
+ORCA_FORCE_NO_INLINE
+Prefs_load_error prefs_load_from_conf_file(Prefs* p) {
+ (void)p;
+ FILE* conffile = conf_file_open_for_reading();
+ if (!conffile) {
+ return Prefs_load_ok;
+ }
+ char linebuff[512];
+ for (;;) {
+ char *left, *right;
+ Usz leftsz, rightsz;
+ Conf_read_result res = conf_read_line(conffile, linebuff, sizeof linebuff,
+ &left, &leftsz, &right, &rightsz);
+ switch (res) {
+ case Conf_read_left_and_right: {
+ if (strcmp("portmidi_output_device", left) == 0) {
+ osoput(&p->portmidi_output_device, right);
+ }
+ continue;
+ }
+ case Conf_read_irrelevant:
+ continue;
+ case Conf_read_buffer_too_small:
+ case Conf_read_eof:
+ case Conf_read_io_error:
+ break;
+ }
+ break;
+ }
+ fclose(conffile);
+ return Prefs_load_ok;
+}
+
+void print_loading_message(char const* s) {
+ Usz len = strlen(s);
+ if (len > INT_MAX)
+ return;
+ int h, w;
+ getmaxyx(stdscr, h, w);
+ int y = h / 2;
+ int x = (int)len < w ? (w - (int)len) / 2 : 0;
+ werase(stdscr);
+ wmove(stdscr, y, x);
+ waddstr(stdscr, s);
+ refresh();
+}
+
//
// main
//
@@ -2582,6 +2669,8 @@
osofree(file_name);
exit(1);
}
+ mbuf_reusable_ensure_size(&ged_state.mbuf_r, ged_state.field.height,
+ ged_state.field.width);
} else {
// Temp hacky stuff: we've crammed two code paths into the KEY_RESIZE event
// case. One of them is for the initial setup for an automatic grid size.
@@ -2595,6 +2684,8 @@
if (!should_autosize_grid) {
field_init_fill(&ged_state.field, (Usz)init_grid_dim_y,
(Usz)init_grid_dim_x, '.');
+ mbuf_reusable_ensure_size(&ged_state.mbuf_r, ged_state.field.height,
+ ged_state.field.width);
}
}
ged_state.filename = osolen(file_name) ? osoc(file_name) : "unnamed";
@@ -2641,6 +2732,34 @@
printf("\033[?2004h\n"); // Ask terminal to use bracketed paste.
+ Prefs prefs;
+ prefs_init(&prefs);
+ Prefs_load_error prefserr = prefs_load_from_conf_file(&prefs);
+ if (prefserr == Prefs_load_ok) {
+#ifdef FEAT_PORTMIDI
+ if (osolen(prefs.portmidi_output_device)) {
+ // PortMidi can be hilariously slow to initialize. Since it will be
+ // initialized automatically if the user has a prefs entry for PortMidi
+ // devices, we should show a message to the user letting them know why
+ // orca is locked up/frozen. (When it's done via menu action, that's
+ // fine, since they can figure out why.)
+ print_loading_message("Waiting on PortMidi...");
+ PmError pmerr;
+ PmDeviceID devid;
+ if (portmidi_find_device_id_by_name(osoc(prefs.portmidi_output_device),
+ osolen(prefs.portmidi_output_device),
+ &pmerr, &devid)) {
+ midi_mode_deinit(&midi_mode);
+ pmerr = midi_mode_init_portmidi(&midi_mode, devid);
+ if (pmerr) {
+ // todo stuff
+ }
+ }
+ }
+#endif
+ }
+ prefs_deinit(&prefs);
+
WINDOW* cont_window = NULL;
int key = KEY_RESIZE;
@@ -2995,6 +3114,7 @@
} break;
#ifdef FEAT_PORTMIDI
case Portmidi_output_device_menu_id: {
+ ged_stop_all_sustained_notes(&ged_state);
midi_mode_deinit(&midi_mode);
PmError pme = midi_mode_init_portmidi(&midi_mode, act.picked.id);
qnav_stack_pop();