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 {"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) {
111 if (iniParseArguments(argstr
, "R!-", &argstr
) == NULL
) {
112 if (strcasecmp(argstr
, "reset") == 0 || strcasecmp(argstr
, "clear") == 0) {
113 if (unimap
) free(unimap
);
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";
127 if (alt
!= NULL
) unimap
[uni
] |= 0x8000;
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) {
140 if ((err
= iniParseArguments(argstr
, "s!-s!-", &src
, &dst
)) != NULL
) return err
;
141 keytrans_add(src
, dst
);
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) {
153 if ((err
= iniParseArguments(argstr
, "s!-R!", &key
, &act
)) != NULL
) return err
;
157 if ((err
= iniParseArguments(act
, "s!", &t
)) != NULL
) return err
;
160 keybind_add(key
, act
);
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) {
173 if ((err
= iniParseArguments(argstr
, "s!-s!-", &key
, &str
)) != NULL
) return err
;
174 keymap_add(key
, str
);
178 return MISC_CMD_NONE
;
182 #define INI_LINE_SIZE (32768)
184 // <0: file not found
185 // >0: file loading error
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
;
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
;
202 line
[INI_LINE_SIZE
-1] = 0;
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
;
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
);
214 if (*argstr
) ++argstr
;
216 if (!isalnum(optname
[0])) { err
= "invalid option name"; goto quit
; }
218 if (strcasecmp(optname
, "ifterm") == 0) {
221 if (inifelse
!= 0) { err
= "nested ifs are not allowed"; goto quit
; }
223 if ((err
= iniParseArguments(argstr
, "s", &val
)) != NULL
) goto quit
;
224 if (strcasecmp(opt_term
, val
) == 0) inifelse
= 1;
227 if (strcasecmp(optname
, "else") == 0) {
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;
235 if (strcasecmp(optname
, "endif") == 0) {
237 case -1: case -2: case 1: case 2: inifelse
= 0; break;
238 case 0: err
= "endif without if"; goto quit
;
245 //fprintf(stderr, "skip: [%s]\n", argstr);
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) {
255 if (!optname
[0]) { err
= "invalid color option"; goto quit
; }
257 if (!isdigit(*optname
)) { err
= "invalid color option"; goto quit
; }
258 n
= (n
*10)+(optname
[0]-'0');
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
;
270 if ((err
= processMiscCmds(optname
, argstr
)) != MISC_CMD_NONE
) {
271 if (err
!= NULL
) goto quit
;
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
;
285 fprintf(stderr
, "ini error at line %d: unknown option '%s'!\n", lineno
, optname
);
289 if (line
!= NULL
) free(line
);
291 if (err
== NULL
&& inifelse
!= 0) err
= "if without endif";
292 if (err
!= NULL
) k8t_die("ini error at line %d: %s", lineno
, err
);
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");