some redraw fixes
[k8sterm.git] / src / inifile.c
blobd7ba92357bd6554cb10b30ef5a80fdd603f936e9
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 {"fastupdate", "b", &opt_fastupdate, inifnGenericOneArg},
94 {"scrollclear", "i{-1,2}", &opt_scrollclear, inifnGenericOneArg},
95 {"tabellipsis", "i{0,3}", &opt_tabellipsis, inifnGenericOneArg},
96 {NULL, NULL, NULL, NULL}
100 #define MISC_CMD_NONE ((const char *)-1)
103 // NULL: command processed; MISC_CMD_NONE: unknown command; !NULL: error
104 static const char *processMiscCmds (const char *optname, char *argstr) {
105 const char *err = NULL;
107 if (strcasecmp(optname, "unimap") == 0) {
108 int uni, ch;
109 char *alt = NULL;
111 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
112 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
113 if (unimap) free(unimap);
114 unimap = NULL;
115 return NULL;
118 //unimap 0x2592 0x61 alt
119 if ((err = iniParseArguments(argstr, "i{0,65535}i{0,255}|s!-", &uni, &ch, &alt)) != NULL) return err;
120 if (alt != NULL && strcasecmp(alt, "alt") != 0) return "invalid unimap";
121 if (unimap == NULL) {
122 if ((unimap = calloc(65536, sizeof(unimap[0]))) == NULL) return "out of memory";
124 if (alt != NULL && ch == 0) alt = NULL;
125 if (alt != NULL && ch < 96) return "invalid unimap";
126 unimap[uni] = ch;
127 if (alt != NULL) unimap[uni] |= 0x8000;
128 return NULL;
131 if (strcasecmp(optname, "keytrans") == 0) {
132 char *src = NULL, *dst = NULL;
134 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
135 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
136 keytrans_reset();
137 return NULL;
140 if ((err = iniParseArguments(argstr, "s!-s!-", &src, &dst)) != NULL) return err;
141 keytrans_add(src, dst);
142 return NULL;
145 if (strcasecmp(optname, "keybind") == 0) {
146 char *key = NULL, *act = NULL;
147 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
148 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
149 keybinds_reset();
150 return NULL;
153 if ((err = iniParseArguments(argstr, "s!-R!", &key, &act)) != NULL) return err;
154 if (act[0] == '"') {
155 char *t;
157 if ((err = iniParseArguments(act, "s!", &t)) != NULL) return err;
158 act = t;
160 keybind_add(key, act);
161 return NULL;
164 if (strcasecmp(optname, "keymap") == 0) {
165 char *key = NULL, *str = NULL;
167 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
168 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
169 keymap_reset();
170 return NULL;
173 if ((err = iniParseArguments(argstr, "s!-s!-", &key, &str)) != NULL) return err;
174 keymap_add(key, str);
175 return NULL;
178 return MISC_CMD_NONE;
182 #define INI_LINE_SIZE (32768)
184 // <0: file not found
185 // >0: file loading error
186 // 0: ok
187 static int loadConfig (const char *fname) {
188 int inifelse = 0; // 0: not; 1: doing true; 2: doing false; -1: waiting else/endif; -2: waiting endif
189 FILE *fi = fopen(fname, "r");
190 const char *err = NULL;
191 char *line;
192 int lineno = 0;
194 if (fi == NULL) return -1;
195 if ((line = malloc(INI_LINE_SIZE)) == NULL) { err = "out of memory"; goto quit; }
197 while (fgets(line, INI_LINE_SIZE-1, fi) != NULL) {
198 char *optname, *argstr, *d;
199 int goodoption = 0;
201 ++lineno;
202 line[INI_LINE_SIZE-1] = 0;
203 // get option name
204 for (optname = line; *optname && isspace(*optname); ++optname) ;
205 if (!optname[0] || optname[0] == '#') continue; // comment
206 if (!isalnum(optname[0])) { err = "invalid option name"; goto quit; }
207 d = argstr = optname;
208 while (*argstr) {
209 if (!argstr[0] || isspace(argstr[0])) break;
210 if (!isalnum(argstr[0]) && argstr[0] != '_' && argstr[0] != '.') { err = "invalid option name"; goto quit; }
211 if (argstr[0] != '_') *d++ = tolower(*argstr);
212 ++argstr;
214 if (*argstr) ++argstr;
215 *d = 0;
216 if (!isalnum(optname[0])) { err = "invalid option name"; goto quit; }
218 if (strcasecmp(optname, "ifterm") == 0) {
219 char *val;
221 if (inifelse != 0) { err = "nested ifs are not allowed"; goto quit; }
222 inifelse = -1;
223 if ((err = iniParseArguments(argstr, "s", &val)) != NULL) goto quit;
224 if (strcasecmp(opt_term, val) == 0) inifelse = 1;
225 continue;
227 if (strcasecmp(optname, "else") == 0) {
228 switch (inifelse) {
229 case -1: inifelse = 2; break;
230 case 2: case -2: case 0: err = "else without if"; goto quit;
231 case 1: inifelse = -2; break;
233 continue;
235 if (strcasecmp(optname, "endif") == 0) {
236 switch (inifelse) {
237 case -1: case -2: case 1: case 2: inifelse = 0; break;
238 case 0: err = "endif without if"; goto quit;
240 continue;
243 if (inifelse < 0) {
244 //trimstr(argstr);
245 //fprintf(stderr, "skip: [%s]\n", argstr);
246 continue;
248 if (opt_term_locked && strcasecmp(optname, "term") == 0) continue; // termname given in command line
249 // ok, we have option name in `optname` and arguments in `argstr`
250 if (strncmp(optname, "color.", 6) == 0) {
251 int n = 0;
252 char *s = NULL;
254 optname += 6;
255 if (!optname[0]) { err = "invalid color option"; goto quit; }
256 while (*optname) {
257 if (!isdigit(*optname)) { err = "invalid color option"; goto quit; }
258 n = (n*10)+(optname[0]-'0');
259 ++optname;
261 if (n < 0 || n > 511) { err = "invalid color index"; goto quit; }
263 if ((err = iniParseArguments(argstr, "s!-", &s)) != NULL) goto quit;
264 if ((s = strdup(s)) == NULL) { err = "out of memory"; goto quit; }
265 if (opt_colornames[n] != NULL) free(opt_colornames[n]);
266 opt_colornames[n] = s;
267 continue;
270 if ((err = processMiscCmds(optname, argstr)) != MISC_CMD_NONE) {
271 if (err != NULL) goto quit;
272 continue;
273 } else {
274 err = NULL;
277 for (int f = 0; iniCommands[f].name != NULL; ++f) {
278 if (strcmp(iniCommands[f].name, optname) == 0) {
279 if ((err = iniCommands[f].fn(optname, iniCommands[f].fmt, argstr, iniCommands[f].udata)) != NULL) goto quit;
280 goodoption = 1;
281 break;
284 if (!goodoption) {
285 fprintf(stderr, "ini error at line %d: unknown option '%s'!\n", lineno, optname);
288 quit:
289 if (line != NULL) free(line);
290 fclose(fi);
291 if (err == NULL && inifelse != 0) err = "if without endif";
292 if (err != NULL) k8t_die("ini error at line %d: %s", lineno, err);
293 return 0;
297 static void initDefaultOptions (void) {
298 opt_title = strdup("sterm");
299 opt_class = strdup("sterm");
300 opt_term = strdup(TNAME);
301 opt_fontnorm = strdup(FONT);
302 opt_fontbold = strdup(FONTBOLD);
303 opt_fonttab = strdup(FONTTAB);
304 opt_shell = strdup(SHELL);
306 memset(opt_colornames, 0, sizeof(opt_colornames));
307 for (int f = 0; f < K8T_ARRLEN(defcolornames); ++f) opt_colornames[f] = strdup(defcolornames[f]);
308 for (int f = 0; f < K8T_ARRLEN(defextcolornames); ++f) opt_colornames[f+256] = strdup(defextcolornames[f]);
310 keytrans_add("KP_Home", "Home");
311 keytrans_add("KP_Left", "Left");
312 keytrans_add("KP_Up", "Up");
313 keytrans_add("KP_Right", "Right");
314 keytrans_add("KP_Down", "Down");
315 keytrans_add("KP_Prior", "Prior");
316 keytrans_add("KP_Next", "Next");
317 keytrans_add("KP_End", "End");
318 keytrans_add("KP_Begin", "Begin");
319 keytrans_add("KP_Insert", "Insert");
320 keytrans_add("KP_Delete", "Delete");
322 keybind_add("shift+Insert", "PastePrimary");
323 keybind_add("alt+Insert", "PasteCliboard");
324 keybind_add("ctrl+alt+t", "NewTab");
325 keybind_add("ctrl+alt+Left", "SwitchToTab prev");
326 keybind_add("ctrl+alt+Right", "SwitchToTab next");
328 keymap_add("BackSpace", "\177");
329 keymap_add("Insert", "\x1b[2~");
330 keymap_add("Delete", "\x1b[3~");
331 keymap_add("Home", "\x1b[1~");
332 keymap_add("End", "\x1b[4~");
333 keymap_add("Prior", "\x1b[5~");
334 keymap_add("Next", "\x1b[6~");
335 keymap_add("F1", "\x1bOP");
336 keymap_add("F2", "\x1bOQ");
337 keymap_add("F3", "\x1bOR");
338 keymap_add("F4", "\x1bOS");
339 keymap_add("F5", "\x1b[15~");
340 keymap_add("F6", "\x1b[17~");
341 keymap_add("F7", "\x1b[18~");
342 keymap_add("F8", "\x1b[19~");
343 keymap_add("F9", "\x1b[20~");
344 keymap_add("F10", "\x1b[21~");
345 keymap_add("Up", "\x1bOA");
346 keymap_add("Down", "\x1bOB");
347 keymap_add("Right", "\x1bOC");
348 keymap_add("Left", "\x1bOD");