progman.exe^H^H^H^H
1/*
2 * Copyright 2020 joshua stein <jcs@jcs.org>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22#include <err.h>
23#include <stdlib.h>
24#include <string.h>
25#include "progman.h"
26#include "parser.h"
27#include "progman_ini.h"
28
29/*
30 * If the user specifies an ini file, return NULL immediately if it's not
31 * found; otherwise, search for the usual suspects.
32 */
33FILE *
34open_ini(char *inifile)
35{
36 FILE *ini = NULL;
37 char buf[BUF_SIZE];
38
39 if (inifile) {
40 ini = fopen(inifile, "r");
41 if (!ini)
42 err(1, "can't open config file %s", inifile);
43
44 return ini;
45 }
46
47 snprintf(buf, sizeof(buf), "%s/.config/progman/progman.ini",
48 getenv("HOME"));
49 if ((ini = fopen(buf, "r")))
50 return ini;
51
52 /* load compiled-in defaults */
53 ini = fmemopen(progman_ini, sizeof(progman_ini), "r");
54 if (!ini || sizeof(progman_ini) == 0)
55 errx(1, "no compiled-in default config file");
56
57 return ini;
58}
59
60int
61find_ini_section(FILE *stream, char *section)
62{
63 char buf[BUF_SIZE], marker[BUF_SIZE];
64
65 snprintf(marker, sizeof(marker), "[%s]\n", section);
66
67 fseek(stream, 0, SEEK_SET);
68 while (fgets(buf, sizeof(buf), stream)) {
69 if (buf[0] == '#' || buf[0] == '\n')
70 continue;
71 if (strncmp(buf, marker, strlen(marker)) == 0)
72 return 1;
73 }
74
75 return 0;
76}
77
78int
79get_ini_kv(FILE *stream, char **key, char **val)
80{
81 char buf[BUF_SIZE], *tval;
82 long pos = ftell(stream);
83 int len;
84
85 buf[0] = '\0';
86
87 /* find next non-comment, non-section line */
88 while (fgets(buf, sizeof(buf), stream)) {
89 if (buf[0] == '#' || buf[0] == '\n') {
90 pos = ftell(stream);
91 continue;
92 }
93
94 if (buf[0] == '[') {
95 /* new section, rewind so find_ini_section can see it */
96 fseek(stream, pos, SEEK_SET);
97 return 0;
98 }
99
100 break;
101 }
102
103 if (!buf[0])
104 return 0;
105
106 tval = strchr(buf, '=');
107 if (tval == NULL) {
108 warnx("bad line in ini file: %s", buf);
109 return 0;
110 }
111
112 tval[0] = '\0';
113 tval++;
114
115 /* trim trailing spaces from key */
116 for (len = strlen(buf); len > 0 && buf[len - 1] == ' '; len--)
117 ;
118 buf[len] = '\0';
119
120 /* trim leading spaces from val */
121 while (tval[0] == ' ')
122 tval++;
123
124 /* and trailing spaces and newlines from val */
125 len = strlen(tval) - 1;
126 while (len) {
127 if (tval[len] == ' ' || tval[len] == '\r' || tval[len] == '\n')
128 len--;
129 else
130 break;
131 }
132 tval[len + 1] = '\0';
133
134 *key = strdup(buf);
135 *val = strdup(tval);
136
137 return 1;
138}