1 ////////////////////////////////////////////////////////////////////////////////
2 typedef const char * (*IniHandlerFn
) (const char *optname
, const char *fmt
, char *argstr
, void *udata
);
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
) {
20 const char *err
= iniParseArguments(argstr
, fmt
, &s
);
22 if (err
!= NULL
) return err
;
23 if ((s
= strdup(s
)) == NULL
) return "out of memory";
25 char **ustr
= (char **)udata
;
27 if (*ustr
) free(*ustr
);
34 static const char *inifnTabPosition (const char *optname
, const char *fmt
, char *argstr
, void *udata
) {
36 const char *err
= 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
;
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) {
113 if (iniParseArguments(argstr
, "R!-", &argstr
) == NULL
) {
114 if (strcasecmp(argstr
, "reset") == 0 || strcasecmp(argstr
, "clear") == 0) {
115 if (unimap
) free(unimap
);
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";
129 if (alt
!= NULL
) unimap
[uni
] |= 0x8000;
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) {
142 if ((err
= iniParseArguments(argstr
, "s!-s!-", &src
, &dst
)) != NULL
) return err
;
143 keytrans_add(src
, dst
);
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) {
155 if ((err
= iniParseArguments(argstr
, "s!-R!", &key
, &act
)) != NULL
) return err
;
159 if ((err
= iniParseArguments(act
, "s!", &t
)) != NULL
) return err
;
162 keybind_add(key
, act
);
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) {
175 if ((err
= iniParseArguments(argstr
, "s!-s!-", &key
, &str
)) != NULL
) return err
;
176 keymap_add(key
, str
);
180 return MISC_CMD_NONE
;
184 #define INI_LINE_SIZE (32768)
186 // <0: file not found
187 // >0: file loading error
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
;
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
;
204 line
[INI_LINE_SIZE
-1] = 0;
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
;
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
);
216 if (*argstr
) ++argstr
;
218 if (!isalnum(optname
[0])) { err
= "invalid option name"; goto quit
; }
220 if (strcasecmp(optname
, "ifterm") == 0) {
223 if (inifelse
!= 0) { err
= "nested ifs are not allowed"; goto quit
; }
225 if ((err
= iniParseArguments(argstr
, "s", &val
)) != NULL
) goto quit
;
226 if (strcasecmp(opt_term
, val
) == 0) inifelse
= 1;
229 if (strcasecmp(optname
, "else") == 0) {
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;
237 if (strcasecmp(optname
, "endif") == 0) {
239 case -1: case -2: case 1: case 2: inifelse
= 0; break;
240 case 0: err
= "endif without if"; goto quit
;
247 //fprintf(stderr, "skip: [%s]\n", argstr);
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) {
257 if (!optname
[0]) { err
= "invalid color option"; goto quit
; }
259 if (!isdigit(*optname
)) { err
= "invalid color option"; goto quit
; }
260 n
= (n
*10)+(optname
[0]-'0');
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
;
272 if ((err
= processMiscCmds(optname
, argstr
)) != MISC_CMD_NONE
) {
273 if (err
!= NULL
) goto quit
;
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
;
287 fprintf(stderr
, "ini error at line %d: unknown option '%s'!\n", lineno
, optname
);
291 if (line
!= NULL
) free(line
);
293 if (err
== NULL
&& inifelse
!= 0) err
= "if without endif";
294 if (err
!= NULL
) k8t_die("ini error at line %d: %s", lineno
, err
);
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");