config.c (3630B)


      1 #include <stdlib.h>
      2 #include <stdio.h>
      3 #include <unistd.h>
      4 #include <fcntl.h>
      5 #include <dirent.h>
      6 #include <string.h>
      7 #include <ini.h>
      8 
      9 #include "util.h"
     10 #include "config.h"
     11 
     12 #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
     13 
     14 int cfg_handler(void *user, const char *section,
     15 		const char *name, const char *value)
     16 {
     17     scout_cfg_t *pcfg = (scout_cfg_t *) user;
     18 
     19     if (MATCH("menu", "name")) {
     20 	pcfg->name = strdup(value);
     21     } else if (MATCH("theme", "bg")) {
     22 	int32_t color = parse_hex_color(value);
     23 	if (color >= 0)
     24 	    pcfg->bg = convert_hex_color(color);
     25     } else {
     26 	return 0;
     27     }
     28 
     29     return 1;
     30 }
     31 
     32 int card_handler(void *user, const char *section,
     33 		 const char *name, const char *value)
     34 {
     35     scout_card_t *pcard = (scout_card_t *) user;
     36 
     37     if (strcmp(section, "card") == 0) {
     38 	if (strcmp(name, "title") == 0)
     39 	    pcard->title = strdup(value);
     40 	else if (strcmp(name, "description") == 0)
     41 	    pcard->description = strdup(value);
     42 	else if (strcmp(name, "command") == 0)
     43 	    pcard->command = strdup(value);
     44 	else if (strcmp(name, "image") == 0)
     45 	    pcard->image_path = strdup(value);
     46 	else
     47 	    return 0;
     48     } else {
     49 	return 0;
     50     }
     51 
     52     return 1;
     53 }
     54 
     55 int is_ini(struct dirent *entry)
     56 {
     57     if (entry->d_type == DT_REG) {
     58 	size_t len_name = strlen(entry->d_name);
     59 
     60 	if (len_name < 5) {
     61 	    return 0;
     62 	}
     63 
     64 	if (strcmp(entry->d_name + (len_name - 4), ".ini") == 0) {
     65 	    return 1;
     66 	}
     67     }
     68 
     69     return 0;
     70 }
     71 
     72 /*
     73  * Load and parse configuration from the configuration file. Values found in the
     74  * config file will override the existing values in the passed configuration.
     75  * > $XDG_CONFIG_HOME/scout/scout.ini
     76  *
     77  * Also load and parse card files in the configuration directory.
     78  * > $XDG_CONFIG_HOME/scout/cards/card.ini
     79  */
     80 void load_config(scout_cfg_t *pcfg, unsigned int *num_cards,
     81 		 scout_card_t **pcards)
     82 {
     83     const char *path = getenv("XDG_CONFIG_HOME");
     84     if (!path) {
     85 	fprintf(stderr, "XDG_CONFIG_HOME not set\n");
     86 	return;
     87     }
     88 
     89     int xdg_dir_fd = open(path, O_RDONLY | O_DIRECTORY);
     90     if (xdg_dir_fd < 0) {
     91 	fprintf(stderr, "Unable to open XDG_CONFIG_HOME\n");
     92 	return;
     93     }
     94 
     95     int dir_fd = openat(xdg_dir_fd, "scout", O_RDONLY | O_DIRECTORY);
     96     if (dir_fd < 0) {
     97 	fprintf(stderr, "Unable to open scout config directory\n");
     98 	return;
     99     }
    100 
    101     close(xdg_dir_fd);
    102 
    103     /* Load and parse config file */
    104     int config_fd = openat(dir_fd, "scout.ini", O_RDONLY);
    105     if (config_fd < 0) {
    106 	fprintf(stderr, "Unable to open scout.ini\n");
    107 	close(dir_fd);
    108 	return;
    109     }
    110 
    111     char *buf = fdreadfile(config_fd);
    112     ini_parse_string(buf, cfg_handler, pcfg);
    113     free(buf);
    114 
    115     close(config_fd);
    116 
    117     /* Load and parse card files */
    118     int subdir_fd = openat(dir_fd, "cards", O_RDONLY | O_DIRECTORY);
    119     if (subdir_fd < 0) {
    120 	fprintf(stderr, "Unable to open scout/cards\n");
    121 	close(dir_fd);
    122 	return;
    123     }
    124     DIR *cards_dir = fdopendir(subdir_fd);
    125 
    126     struct dirent *entry;
    127 
    128     /* Count card entries */
    129     size_t count = 0;
    130     while ((entry = readdir(cards_dir)) != NULL)
    131 	if (is_ini(entry))
    132 	    count++;
    133 
    134     /* Allocate space for each card */
    135     *num_cards = (unsigned int) count;
    136     *pcards = malloc(count * sizeof(scout_card_t));
    137 
    138     /* Rewind and parse card entries */
    139     rewinddir(cards_dir);
    140 
    141     count = 0;
    142     while ((entry = readdir(cards_dir)) != NULL)
    143 	if (is_ini(entry)) {
    144 	    int fd = openat(subdir_fd, entry->d_name, O_RDONLY);
    145 	    char *buf = fdreadfile(fd);
    146 	    scout_card_t card = DEFAULT_CARD;
    147 	    ini_parse_string(buf, card_handler, &card);
    148 	    free(buf);
    149 
    150 	    (*pcards)[count++] = card;
    151 	}
    152 
    153     closedir(cards_dir);
    154 
    155     close(dir_fd);
    156 }