summaryrefslogtreecommitdiff
path: root/src/kernel/settings.c
blob: 699196b27ac55d6a6fe72744f8262c6fdcfa48c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "window.h"
#include "drive.h"
#include "panic.h"
#include "util.h"

#include <stdint.h>

#define SETTINGS_FILE "sys/settings.pls"

static struct {
  uint32_t main_start;
  uint32_t main_entries;
  uint32_t names_start;
  uint32_t data_start;
} settings_header;

enum {
  ST_SZ_STRING = 0x00,
  ST_COLOR     = 0x01
};

struct main_entry {
  uint32_t name_offset;
  uint8_t name_len;
  uint8_t type;
  uint16_t pad;
  union {
    struct {
      uint32_t data_offset;
      uint32_t length;
    } as_string;
    struct pixel as_pixel;
  };
} __attribute__ ((__packed__));

static file_id_t fid;
static uint32_t main_end;

void init_settings() {
  fid = drives->get_file(drives, SETTINGS_FILE);
  if (!fid)
    PANIC("could not open settings file at \"" SETTINGS_FILE "\".");

  fmcpy(&settings_header, drives, fid, 0, 16);

  main_end = settings_header.main_start + settings_header.main_entries * sizeof(struct main_entry);
}

bool try_find_setting(const char *name, struct main_entry *entry_out) {
  uint16_t name_len = 0;
  while (name[name_len])
    if (++name_len == 256)
      return false;

  for (uint32_t i = settings_header.main_start; i < main_end; i += sizeof(struct main_entry)) {
    fmcpy(entry_out, drives, fid, i, sizeof(struct main_entry));
    if (entry_out->name_len != name_len)
      continue;
    char found_name[255];
    fmcpy(found_name, drives, fid, settings_header.names_start + entry_out->name_offset, name_len);
    for (uint8_t j = 0; j < name_len; ++j)
      if (found_name[j] != name[j])
        goto lc;
    return true;
  lc:
    ;
  }

  return false;
}

bool try_get_sz_setting(const char *name, char *out, uint32_t max_len, uint32_t *len_out) {
  struct main_entry entry;
  if (!try_find_setting(name, &entry) || (entry.type != ST_SZ_STRING))
    return false;

  const uint32_t len = entry.as_string.length > max_len ? max_len : entry.as_string.length;
  fmcpy(out, drives, fid, settings_header.data_start + entry.as_string.data_offset, len);
  out[len] = '\0';
  *len_out = len;
  return true;
}

bool try_get_color_setting(const char *name, struct pixel *out) {
  struct main_entry entry;
  if (!try_find_setting(name, &entry) || (entry.type != ST_COLOR))
    return false;

  *out = entry.as_pixel;
  return true;
}