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 {"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) {
109 if (iniParseArguments(argstr
, "R!-", &argstr
) == NULL
) {
110 if (strcasecmp(argstr
, "reset") == 0 || strcasecmp(argstr
, "clear") == 0) {
111 if (unimap
) free(unimap
);
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";
125 if (alt
!= NULL
) unimap
[uni
] |= 0x8000;
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) {
138 if ((err
= iniParseArguments(argstr
, "s!-s!-", &src
, &dst
)) != NULL
) return err
;
139 keytrans_add(src
, dst
);
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) {
151 if ((err
= iniParseArguments(argstr
, "s!-R!", &key
, &act
)) != NULL
) return err
;
155 if ((err
= iniParseArguments(act
, "s!", &t
)) != NULL
) return err
;
158 keybind_add(key
, act
);
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) {
171 if ((err
= iniParseArguments(argstr
, "s!-s!-", &key
, &str
)) != NULL
) return err
;
172 keymap_add(key
, str
);
176 return MISC_CMD_NONE
;
180 #define INI_LINE_SIZE (32768)
182 // <0: file not found
183 // >0: file loading error
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
;
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
;
200 line
[INI_LINE_SIZE
-1] = 0;
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
;
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
);
212 if (*argstr
) ++argstr
;
214 if (!isalnum(optname
[0])) { err
= "invalid option name"; goto quit
; }
216 if (strcasecmp(optname
, "ifterm") == 0) {
219 if (inifelse
!= 0) { err
= "nested ifs are not allowed"; goto quit
; }
221 if ((err
= iniParseArguments(argstr
, "s", &val
)) != NULL
) goto quit
;
222 if (strcasecmp(opt_term
, val
) == 0) inifelse
= 1;
225 if (strcasecmp(optname
, "else") == 0) {
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;
233 if (strcasecmp(optname
, "endif") == 0) {
235 case -1: case -2: case 1: case 2: inifelse
= 0; break;
236 case 0: err
= "endif without if"; goto quit
;
243 //fprintf(stderr, "skip: [%s]\n", argstr);
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) {
253 if (!optname
[0]) { err
= "invalid color option"; goto quit
; }
255 if (!isdigit(*optname
)) { err
= "invalid color option"; goto quit
; }
256 n
= (n
*10)+(optname
[0]-'0');
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
;
268 if ((err
= processMiscCmds(optname
, argstr
)) != MISC_CMD_NONE
) {
269 if (err
!= NULL
) goto quit
;
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
;
283 fprintf(stderr
, "ini error at line %d: unknown option '%s'!\n", lineno
, optname
);
287 if (line
!= NULL
) free(line
);
289 if (err
== NULL
&& inifelse
!= 0) err
= "if without endif";
290 if (err
!= NULL
) k8t_die("ini error at line %d: %s", lineno
, err
);
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");