fixed "-e" command (it should use all following args); some cosmetic fixes
[k8sterm.git] / src / inifile.c
blob53e59463572374691c0911c5cd61a13ff3f7c83a
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 {"defaultcursorfg1", "i{0,511}", &defaultCursorFG1, inifnGenericOneArg},
72 {"defaultcursorbg1", "i{-1,511}", &defaultCursorBG1, inifnGenericOneArg},
73 {"defaultinactivecursorfg", "i{0,511}", &defaultCursorInactiveFG, inifnGenericOneArg},
74 {"defaultinactivecursorbg", "i{-1,511}", &defaultCursorInactiveBG, inifnGenericOneArg},
75 {"defaultboldfg", "i{-1,511}", &defaultBoldFG, inifnGenericOneArg},
76 {"defaultunderlinefg", "i{-1,511}", &defaultUnderlineFG, inifnGenericOneArg},
77 {"normaltabfg", "i{0,511}", &normalTabFG, inifnGenericOneArg},
78 {"normaltabbg", "i{0,511}", &normalTabBG, inifnGenericOneArg},
79 {"activetabfg", "i{0,511}", &activeTabFG, inifnGenericOneArg},
80 {"activetabbg", "i{0,511}", &activeTabBG, inifnGenericOneArg},
81 {"maxhistory", "i{0,65535}", &opt_maxhistory, inifnGenericOneArg},
82 {"ptrblank", "i{0,65535}", &opt_ptrblank, inifnGenericOneArg},
83 {"tabcount", "i{1,128}", &opt_tabcount, inifnGenericOneArg},
84 {"tabposition", "i{0,1}", &opt_tabposition, inifnTabPosition},
85 {"drawtimeout", "i{5,30000}", &opt_drawtimeout, inifnGenericOneArg},
86 {"audiblebell", "b", &opt_audiblebell, inifnGenericOneArg},
87 {"urgentbell", "b", &opt_urgentbell, inifnGenericOneArg},
88 {"cursorblink", "i{0,10000}", &opt_cursorBlink, inifnGenericOneArg},
89 {"cursorblinkinactive", "b", &opt_cursorBlinkInactive, inifnGenericOneArg},
90 {"drawunderline", "b", &opt_drawunderline, inifnGenericOneArg},
91 {"ignoreclose", "i{-1,1}", &opt_ignoreclose, inifnGenericOneArg},
92 {"maxdrawtimeout", "i{10,60000}", &opt_maxdrawtimeout, inifnGenericOneArg},
93 {"swapdrawtimeout", "i{10,60000}", &opt_swapdrawtimeout, inifnGenericOneArg},
94 {"fastredraw", "b", &opt_fastredraw, inifnGenericOneArg},
95 {"fastupdate", "b", &opt_fastupdate, inifnGenericOneArg},
96 {"scrollclear", "i{-1,2}", &opt_scrollclear, inifnGenericOneArg},
97 {"tabellipsis", "i{0,3}", &opt_tabellipsis, inifnGenericOneArg},
98 {NULL, NULL, NULL, NULL}
102 #define MISC_CMD_NONE ((const char *)-1)
105 // NULL: command processed; MISC_CMD_NONE: unknown command; !NULL: error
106 static const char *processMiscCmds (const char *optname, char *argstr) {
107 const char *err = NULL;
109 if (strcasecmp(optname, "unimap") == 0) {
110 int uni, ch;
111 char *alt = NULL;
113 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
114 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
115 if (unimap) free(unimap);
116 unimap = NULL;
117 return NULL;
120 //unimap 0x2592 0x61 alt
121 if ((err = iniParseArguments(argstr, "i{0,65535}i{0,255}|s!-", &uni, &ch, &alt)) != NULL) return err;
122 if (alt != NULL && strcasecmp(alt, "alt") != 0) return "invalid unimap";
123 if (unimap == NULL) {
124 if ((unimap = calloc(65536, sizeof(unimap[0]))) == NULL) return "out of memory";
126 if (alt != NULL && ch == 0) alt = NULL;
127 if (alt != NULL && ch < 96) return "invalid unimap";
128 unimap[uni] = ch;
129 if (alt != NULL) unimap[uni] |= 0x8000;
130 return NULL;
133 if (strcasecmp(optname, "keytrans") == 0) {
134 char *src = NULL, *dst = NULL;
136 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
137 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
138 keytrans_reset();
139 return NULL;
142 if ((err = iniParseArguments(argstr, "s!-s!-", &src, &dst)) != NULL) return err;
143 keytrans_add(src, dst);
144 return NULL;
147 if (strcasecmp(optname, "keybind") == 0) {
148 char *key = NULL, *act = NULL;
149 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
150 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
151 keybinds_reset();
152 return NULL;
155 if ((err = iniParseArguments(argstr, "s!-R!", &key, &act)) != NULL) return err;
156 if (act[0] == '"') {
157 char *t;
159 if ((err = iniParseArguments(act, "s!", &t)) != NULL) return err;
160 act = t;
162 keybind_add(key, act);
163 return NULL;
166 if (strcasecmp(optname, "keymap") == 0) {
167 char *key = NULL, *str = NULL;
169 if (iniParseArguments(argstr, "R!-", &argstr) == NULL) {
170 if (strcasecmp(argstr, "reset") == 0 || strcasecmp(argstr, "clear") == 0) {
171 keymap_reset();
172 return NULL;
175 if ((err = iniParseArguments(argstr, "s!-s!-", &key, &str)) != NULL) return err;
176 keymap_add(key, str);
177 return NULL;
180 return MISC_CMD_NONE;
184 #define INI_LINE_SIZE (32768)
186 // <0: file not found
187 // >0: file loading error
188 // 0: ok
189 static int loadConfig (const char *fname) {
190 int inifelse = 0; // 0: not; 1: doing true; 2: doing false; -1: waiting else/endif; -2: waiting endif
191 FILE *fi = fopen(fname, "r");
192 const char *err = NULL;
193 char *line;
194 int lineno = 0;
196 if (fi == NULL) return -1;
197 if ((line = malloc(INI_LINE_SIZE)) == NULL) { err = "out of memory"; goto quit; }
199 while (fgets(line, INI_LINE_SIZE-1, fi) != NULL) {
200 char *optname, *argstr, *d;
201 int goodoption = 0;
203 ++lineno;
204 line[INI_LINE_SIZE-1] = 0;
205 // get option name
206 for (optname = line; *optname && isspace(*optname); ++optname) ;
207 if (!optname[0] || optname[0] == '#') continue; // comment
208 if (!isalnum(optname[0])) { err = "invalid option name"; goto quit; }
209 d = argstr = optname;
210 while (*argstr) {
211 if (!argstr[0] || isspace(argstr[0])) break;
212 if (!isalnum(argstr[0]) && argstr[0] != '_' && argstr[0] != '.') { err = "invalid option name"; goto quit; }
213 if (argstr[0] != '_') *d++ = tolower(*argstr);
214 ++argstr;
216 if (*argstr) ++argstr;
217 *d = 0;
218 if (!isalnum(optname[0])) { err = "invalid option name"; goto quit; }
220 if (strcasecmp(optname, "ifterm") == 0) {
221 char *val;
223 if (inifelse != 0) { err = "nested ifs are not allowed"; goto quit; }
224 inifelse = -1;
225 if ((err = iniParseArguments(argstr, "s", &val)) != NULL) goto quit;
226 if (strcasecmp(opt_term, val) == 0) inifelse = 1;
227 continue;
229 if (strcasecmp(optname, "else") == 0) {
230 switch (inifelse) {
231 case -1: inifelse = 2; break;
232 case 2: case -2: case 0: err = "else without if"; goto quit;
233 case 1: inifelse = -2; break;
235 continue;
237 if (strcasecmp(optname, "endif") == 0) {
238 switch (inifelse) {
239 case -1: case -2: case 1: case 2: inifelse = 0; break;
240 case 0: err = "endif without if"; goto quit;
242 continue;
245 if (inifelse < 0) {
246 //trimstr(argstr);
247 //fprintf(stderr, "skip: [%s]\n", argstr);
248 continue;
250 if (opt_term_locked && strcasecmp(optname, "term") == 0) continue; // termname given in command line
251 // ok, we have option name in `optname` and arguments in `argstr`
252 if (strncmp(optname, "color.", 6) == 0) {
253 int n = 0;
254 char *s = NULL;
256 optname += 6;
257 if (!optname[0]) { err = "invalid color option"; goto quit; }
258 while (*optname) {
259 if (!isdigit(*optname)) { err = "invalid color option"; goto quit; }
260 n = (n*10)+(optname[0]-'0');
261 ++optname;
263 if (n < 0 || n > 511) { err = "invalid color index"; goto quit; }
265 if ((err = iniParseArguments(argstr, "s!-", &s)) != NULL) goto quit;
266 if ((s = strdup(s)) == NULL) { err = "out of memory"; goto quit; }
267 if (opt_colornames[n] != NULL) free(opt_colornames[n]);
268 opt_colornames[n] = s;
269 continue;
272 if ((err = processMiscCmds(optname, argstr)) != MISC_CMD_NONE) {
273 if (err != NULL) goto quit;
274 continue;
275 } else {
276 err = NULL;
279 for (int f = 0; iniCommands[f].name != NULL; ++f) {
280 if (strcmp(iniCommands[f].name, optname) == 0) {
281 if ((err = iniCommands[f].fn(optname, iniCommands[f].fmt, argstr, iniCommands[f].udata)) != NULL) goto quit;
282 goodoption = 1;
283 break;
286 if (!goodoption) {
287 fprintf(stderr, "ini error at line %d: unknown option '%s'!\n", lineno, optname);
290 quit:
291 if (line != NULL) free(line);
292 fclose(fi);
293 if (err == NULL && inifelse != 0) err = "if without endif";
294 if (err != NULL) k8t_die("ini error at line %d: %s", lineno, err);
295 return 0;
299 static void initDefaultOptions (void) {
300 opt_title = strdup("sterm");
301 opt_class = strdup("sterm");
302 opt_term = strdup(TNAME);
303 opt_fontnorm = strdup(FONT);
304 opt_fontbold = strdup(FONTBOLD);
305 opt_fonttab = strdup(FONTTAB);
306 opt_shell = strdup(SHELL);
308 memset(opt_colornames, 0, sizeof(opt_colornames));
309 for (int f = 0; f < K8T_ARRLEN(defcolornames); ++f) opt_colornames[f] = strdup(defcolornames[f]);
310 for (int f = 0; f < K8T_ARRLEN(defextcolornames); ++f) opt_colornames[f+256] = strdup(defextcolornames[f]);
312 keytrans_add("KP_Home", "Home");
313 keytrans_add("KP_Left", "Left");
314 keytrans_add("KP_Up", "Up");
315 keytrans_add("KP_Right", "Right");
316 keytrans_add("KP_Down", "Down");
317 keytrans_add("KP_Prior", "Prior");
318 keytrans_add("KP_Next", "Next");
319 keytrans_add("KP_End", "End");
320 keytrans_add("KP_Begin", "Begin");
321 keytrans_add("KP_Insert", "Insert");
322 keytrans_add("KP_Delete", "Delete");
324 keybind_add("shift+Insert", "PastePrimary");
325 keybind_add("alt+Insert", "PasteCliboard");
326 keybind_add("ctrl+alt+t", "NewTab");
327 keybind_add("ctrl+alt+Left", "SwitchToTab prev");
328 keybind_add("ctrl+alt+Right", "SwitchToTab next");
330 keymap_add("BackSpace", "\177");
331 keymap_add("Insert", "\x1b[2~");
332 keymap_add("Delete", "\x1b[3~");
333 keymap_add("Home", "\x1b[1~");
334 keymap_add("End", "\x1b[4~");
335 keymap_add("Prior", "\x1b[5~");
336 keymap_add("Next", "\x1b[6~");
337 keymap_add("F1", "\x1bOP");
338 keymap_add("F2", "\x1bOQ");
339 keymap_add("F3", "\x1bOR");
340 keymap_add("F4", "\x1bOS");
341 keymap_add("F5", "\x1b[15~");
342 keymap_add("F6", "\x1b[17~");
343 keymap_add("F7", "\x1b[18~");
344 keymap_add("F8", "\x1b[19~");
345 keymap_add("F9", "\x1b[20~");
346 keymap_add("F10", "\x1b[21~");
347 keymap_add("Up", "\x1bOA");
348 keymap_add("Down", "\x1bOB");
349 keymap_add("Right", "\x1bOC");
350 keymap_add("Left", "\x1bOD");