clear selections in all tabs when selection ownership is lost
[k8sterm.git] / src / inifile.c
blob9a22ad91239e8d5c64ce0b4652144daaa24318ed
1 ////////////////////////////////////////////////////////////////////////////////
2 typedef const char * (*IniHandlerFn) (const char *optname, const char *fmt, char *argstr, void *udata);
5 typedef struct {
6 const char *name;
7 const char *fmt;
8 void *udata;
9 IniHandlerFn fn;
10 } IniCommand;
13 static const char *inifnGenericOneArg (const char *optname, const char *fmt, char *argstr, void *udata) {
14 return iniParseArguments(argstr, fmt, udata);
18 static const char *inifnGenericOneStr (const char *optname, const char *fmt, char *argstr, void *udata) {
19 char *s = NULL;
20 const char *err = iniParseArguments(argstr, fmt, &s);
22 if (err != NULL) return err;
23 if ((s = strdup(s)) == NULL) return "out of memory";
24 if (udata) {
25 char **ustr = (char **)udata;
27 if (*ustr) free(*ustr);
28 *ustr = s;
30 return NULL;
34 static const char *inifnTabPosition (const char *optname, const char *fmt, char *argstr, void *udata) {
35 int newpos = -1;
36 const char *err = NULL;
38 while (argstr[0]) {
39 char *s = NULL;
41 if ((err = iniParseArguments(argstr, "R-", &argstr)) != NULL) return err;
42 if (!argstr[0]) break;
44 if ((err = iniParseArguments(argstr, "s!-R-", &s, &argstr)) != NULL) return err;
45 if (tolower(s[0]) == 't') newpos = 1;
46 else if (tolower(s[0]) == 'b') newpos = 0;
47 else if ((err = iniParseArguments(s, fmt, &newpos)) != NULL) return err;
50 if (newpos == -1) return "invalid tabbar position";
51 opt_tabposition = newpos;
52 return NULL;
56 static const IniCommand iniCommands[] = {
57 {"term", "s!-", &opt_term, inifnGenericOneStr},
58 {"class", "s!-", &opt_class, inifnGenericOneStr},
59 {"title", "s!-", &opt_title, inifnGenericOneStr},
60 {"fontnorm", "s!-", &opt_fontnorm, inifnGenericOneStr},
61 {"fontbold", "s!-", &opt_fontbold, inifnGenericOneStr},
62 {"fonttab", "s!-", &opt_fonttab, inifnGenericOneStr},
63 {"shell", "s!-", &opt_shell, inifnGenericOneStr},
64 {"doubleclicktimeout", "i{0,10000}", &opt_doubleclick_timeout, inifnGenericOneArg},
65 {"tripleclicktimeout", "i{0,10000}", &opt_tripleclick_timeout, inifnGenericOneArg},
66 {"tabsize", "i{1,256}", &opt_tabsize, inifnGenericOneArg},
67 {"defaultfg", "i{0,511}", &defaultFG, inifnGenericOneArg},
68 {"defaultbg", "i{0,511}", &defaultBG, inifnGenericOneArg},
69 {"defaultcursorfg", "i{0,511}", &defaultCursorFG, inifnGenericOneArg},
70 {"defaultcursorbg", "i{0,511}", &defaultCursorBG, inifnGenericOneArg},
71 {"defaultinactivecursorfg", "i{0,511}", &defaultCursorInactiveFG, inifnGenericOneArg},
72 {"defaultinactivecursorbg", "i{-1,511}", &defaultCursorInactiveBG, inifnGenericOneArg},
73 {"defaultboldfg", "i{-1,511}", &defaultBoldFG, inifnGenericOneArg},
74 {"defaultunderlinefg", "i{-1,511}", &defaultUnderlineFG, inifnGenericOneArg},
75 {"normaltabfg", "i{0,511}", &normalTabFG, inifnGenericOneArg},
76 {"normaltabbg", "i{0,511}", &normalTabBG, inifnGenericOneArg},
77 {"activetabfg", "i{0,511}", &activeTabFG, inifnGenericOneArg},
78 {"activetabbg", "i{0,511}", &activeTabBG, inifnGenericOneArg},
79 {"maxhistory", "i{0,65535}", &opt_maxhistory, inifnGenericOneArg},
80 {"ptrblank", "i{0,65535}", &opt_ptrblank, inifnGenericOneArg},
81 {"tabcount", "i{1,128}", &opt_tabcount, inifnGenericOneArg},
82 {"tabposition", "i{0,1}", &opt_tabposition, inifnTabPosition},
83 {"drawtimeout", "i{5,30000}", &opt_drawtimeout, inifnGenericOneArg},
84 {"audiblebell", "b", &opt_audiblebell, inifnGenericOneArg},
85 {"urgentbell", "b", &opt_urgentbell, inifnGenericOneArg},
86 {"cursorblink", "i{0,10000}", &opt_cursorBlink, inifnGenericOneArg},
87 {"cursorblinkinactive", "b", &opt_cursorBlinkInactive, inifnGenericOneArg},
88 {"drawunderline", "b", &opt_drawunderline, inifnGenericOneArg},
89 {"ignoreclose", "i{-1,1}", &opt_ignoreclose, inifnGenericOneArg},
90 {"maxdrawtimeout", "i{10,60000}", &opt_maxdrawtimeout, inifnGenericOneArg},
91 {"swapdrawtimeout", "i{10,60000}", &opt_swapdrawtimeout, inifnGenericOneArg},
92 {"fastredraw", "b", &opt_fastredraw, inifnGenericOneArg},
93 {"tabellipsis", "i{0,3}", &opt_tabellipsis, inifnGenericOneArg},
94 {NULL, NULL, NULL, NULL}
98 #define MISC_CMD_NONE ((const char *)-1)
101 // NULL: command processed; MISC_CMD_NONE: unknown command; !NULL: error
102 static const char *processMiscCmds (const char *optname, char *argstr) {
103 const char *err = NULL;
105 if (strcasecmp(optname, "unimap") == 0) {
106 int uni, ch;
107 char *alt = NULL;
109 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
110 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
111 if (unimap) free(unimap);
112 unimap = NULL;
113 return NULL;
116 //unimap 0x2592 0x61 alt
117 if ((err = iniParseArguments(argstr, "i{0,65535}i{0,255}|s!-", &uni, &ch, &alt)) != NULL) return err;
118 if (alt != NULL && strcasecmp(alt, "alt") != 0) return "invalid unimap";
119 if (unimap == NULL) {
120 if ((unimap = calloc(65536, sizeof(unimap[0]))) == NULL) return "out of memory";
122 if (alt != NULL && ch == 0) alt = NULL;
123 if (alt != NULL && ch < 96) return "invalid unimap";
124 unimap[uni] = ch;
125 if (alt != NULL) unimap[uni] |= 0x8000;
126 return NULL;
129 if (strcasecmp(optname, "keytrans") == 0) {
130 char *src = NULL, *dst = NULL;
132 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
133 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
134 keytrans_reset();
135 return NULL;
138 if ((err = iniParseArguments(argstr, "s!-s!-", &src, &dst)) != NULL) return err;
139 keytrans_add(src, dst);
140 return NULL;
143 if (strcasecmp(optname, "keybind") == 0) {
144 char *key = NULL, *act = NULL;
145 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
146 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
147 keybinds_reset();
148 return NULL;
151 if ((err = iniParseArguments(argstr, "s!-R!", &key, &act)) != NULL) return err;
152 if (act[0] == '"') {
153 char *t;
155 if ((err = iniParseArguments(act, "s!", &t)) != NULL) return err;
156 act = t;
158 keybind_add(key, act);
159 return NULL;
162 if (strcasecmp(optname, "keymap") == 0) {
163 char *key = NULL, *str = NULL;
165 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
166 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
167 keymap_reset();
168 return NULL;
171 if ((err = iniParseArguments(argstr, "s!-s!-", &key, &str)) != NULL) return err;
172 keymap_add(key, str);
173 return NULL;
176 return MISC_CMD_NONE;
180 #define INI_LINE_SIZE (32768)
182 // <0: file not found
183 // >0: file loading error
184 // 0: ok
185 static int loadConfig (const char *fname) {
186 int inifelse = 0; // 0: not; 1: doing true; 2: doing false; -1: waiting else/endif; -2: waiting endif
187 FILE *fi = fopen(fname, "r");
188 const char *err = NULL;
189 char *line;
190 int lineno = 0;
192 if (fi == NULL) return -1;
193 if ((line = malloc(INI_LINE_SIZE)) == NULL) { err = "out of memory"; goto quit; }
195 while (fgets(line, INI_LINE_SIZE-1, fi) != NULL) {
196 char *optname, *argstr, *d;
197 int goodoption = 0;
199 ++lineno;
200 line[INI_LINE_SIZE-1] = 0;
201 // get option name
202 for (optname = line; *optname && isspace(*optname); ++optname) ;
203 if (!optname[0] || optname[0] == '#') continue; // comment
204 if (!isalnum(optname[0])) { err = "invalid option name"; goto quit; }
205 d = argstr = optname;
206 while (*argstr) {
207 if (!argstr[0] || isspace(argstr[0])) break;
208 if (!isalnum(argstr[0]) && argstr[0] != '_' && argstr[0] != '.') { err = "invalid option name"; goto quit; }
209 if (argstr[0] != '_') *d++ = tolower(*argstr);
210 ++argstr;
212 if (*argstr) ++argstr;
213 *d = 0;
214 if (!isalnum(optname[0])) { err = "invalid option name"; goto quit; }
216 if (strcasecmp(optname, "ifterm") == 0) {
217 char *val;
219 if (inifelse != 0) { err = "nested ifs are not allowed"; goto quit; }
220 inifelse = -1;
221 if ((err = iniParseArguments(argstr, "s", &val)) != NULL) goto quit;
222 if (strcasecmp(opt_term, val) == 0) inifelse = 1;
223 continue;
225 if (strcasecmp(optname, "else") == 0) {
226 switch (inifelse) {
227 case -1: inifelse = 2; break;
228 case 2: case -2: case 0: err = "else without if"; goto quit;
229 case 1: inifelse = -2; break;
231 continue;
233 if (strcasecmp(optname, "endif") == 0) {
234 switch (inifelse) {
235 case -1: case -2: case 1: case 2: inifelse = 0; break;
236 case 0: err = "endif without if"; goto quit;
238 continue;
241 if (inifelse < 0) {
242 //trimstr(argstr);
243 //fprintf(stderr, "skip: [%s]\n", argstr);
244 continue;
246 if (opt_term_locked && strcasecmp(optname, "term") == 0) continue; // termname given in command line
247 // ok, we have option name in `optname` and arguments in `argstr`
248 if (strncmp(optname, "color.", 6) == 0) {
249 int n = 0;
250 char *s = NULL;
252 optname += 6;
253 if (!optname[0]) { err = "invalid color option"; goto quit; }
254 while (*optname) {
255 if (!isdigit(*optname)) { err = "invalid color option"; goto quit; }
256 n = (n*10)+(optname[0]-'0');
257 ++optname;
259 if (n < 0 || n > 511) { err = "invalid color index"; goto quit; }
261 if ((err = iniParseArguments(argstr, "s!-", &s)) != NULL) goto quit;
262 if ((s = strdup(s)) == NULL) { err = "out of memory"; goto quit; }
263 if (opt_colornames[n] != NULL) free(opt_colornames[n]);
264 opt_colornames[n] = s;
265 continue;
268 if ((err = processMiscCmds(optname, argstr)) != MISC_CMD_NONE) {
269 if (err != NULL) goto quit;
270 continue;
271 } else {
272 err = NULL;
275 for (int f = 0; iniCommands[f].name != NULL; ++f) {
276 if (strcmp(iniCommands[f].name, optname) == 0) {
277 if ((err = iniCommands[f].fn(optname, iniCommands[f].fmt, argstr, iniCommands[f].udata)) != NULL) goto quit;
278 goodoption = 1;
279 break;
282 if (!goodoption) {
283 fprintf(stderr, "ini error at line %d: unknown option '%s'!\n", lineno, optname);
286 quit:
287 if (line != NULL) free(line);
288 fclose(fi);
289 if (err == NULL && inifelse != 0) err = "if without endif";
290 if (err != NULL) k8t_die("ini error at line %d: %s", lineno, err);
291 return 0;
295 static void initDefaultOptions (void) {
296 opt_title = strdup("sterm");
297 opt_class = strdup("sterm");
298 opt_term = strdup(TNAME);
299 opt_fontnorm = strdup(FONT);
300 opt_fontbold = strdup(FONTBOLD);
301 opt_fonttab = strdup(FONTTAB);
302 opt_shell = strdup(SHELL);
304 memset(opt_colornames, 0, sizeof(opt_colornames));
305 for (int f = 0; f < K8T_ARRLEN(defcolornames); ++f) opt_colornames[f] = strdup(defcolornames[f]);
306 for (int f = 0; f < K8T_ARRLEN(defextcolornames); ++f) opt_colornames[f+256] = strdup(defextcolornames[f]);
308 keytrans_add("KP_Home", "Home");
309 keytrans_add("KP_Left", "Left");
310 keytrans_add("KP_Up", "Up");
311 keytrans_add("KP_Right", "Right");
312 keytrans_add("KP_Down", "Down");
313 keytrans_add("KP_Prior", "Prior");
314 keytrans_add("KP_Next", "Next");
315 keytrans_add("KP_End", "End");
316 keytrans_add("KP_Begin", "Begin");
317 keytrans_add("KP_Insert", "Insert");
318 keytrans_add("KP_Delete", "Delete");
320 keybind_add("shift+Insert", "PastePrimary");
321 keybind_add("alt+Insert", "PasteCliboard");
322 keybind_add("ctrl+alt+t", "NewTab");
323 keybind_add("ctrl+alt+Left", "SwitchToTab prev");
324 keybind_add("ctrl+alt+Right", "SwitchToTab next");
326 keymap_add("BackSpace", "\177");
327 keymap_add("Insert", "\x1b[2~");
328 keymap_add("Delete", "\x1b[3~");
329 keymap_add("Home", "\x1b[1~");
330 keymap_add("End", "\x1b[4~");
331 keymap_add("Prior", "\x1b[5~");
332 keymap_add("Next", "\x1b[6~");
333 keymap_add("F1", "\x1bOP");
334 keymap_add("F2", "\x1bOQ");
335 keymap_add("F3", "\x1bOR");
336 keymap_add("F4", "\x1bOS");
337 keymap_add("F5", "\x1b[15~");
338 keymap_add("F6", "\x1b[17~");
339 keymap_add("F7", "\x1b[18~");
340 keymap_add("F8", "\x1b[19~");
341 keymap_add("F9", "\x1b[20~");
342 keymap_add("F10", "\x1b[21~");
343 keymap_add("Up", "\x1bOA");
344 keymap_add("Down", "\x1bOB");
345 keymap_add("Right", "\x1bOC");
346 keymap_add("Left", "\x1bOD");