loc<->utf conversion callbacks
[k8sterm.git] / src / sterm.c
blob17788e2eb54100ce6dd1294d8b36e1562b5ff83a
1 /* See LICENSE for licence details. */
2 #ifndef GIT_VERSION
3 # define VERSION "0.3.1.beta9"
4 #else
5 # define VERSION GIT_VERSION
6 #endif
8 #ifdef _XOPEN_SOURCE
9 # undef _XOPEN_SOURCE
10 #endif
11 #define _XOPEN_SOURCE 600
13 #include <alloca.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <iconv.h>
18 #include <limits.h>
19 #include <locale.h>
20 #include <pty.h>
21 #include <stdarg.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <strings.h>
27 #include <signal.h>
28 #include <sys/ioctl.h>
29 #include <sys/select.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <time.h>
35 #include <unistd.h>
36 #include <X11/Xatom.h>
37 #include <X11/Xlib.h>
38 #include <X11/Xutil.h>
39 #include <X11/cursorfont.h>
40 #include <X11/keysym.h>
42 //#include "dbglog.h"
45 // uncomment the following to use XCreateGlyphCursor() instead of XCreatePixmapCursor()
46 //#define BLANKPTR_USE_GLYPH_CURSOR
49 //#define PASTE_SELECTION_DEBUG
51 //#define DUMP_KEYSYMS
53 //#define KEYPAD_DUMP
55 //#define DUMP_PROG_OUTPUT
56 //#define DUMP_PROG_INPUT
58 //#define DUMP_IO_READ
59 //#define DUMP_IO_WRITE
61 #if defined(DUMP_IO_READ) || defined(DUMP_IO_WRITE)
62 # define DUMP_IO
63 #endif
65 #ifdef KEYPAD_DUMP
66 # define DUMP_KEYPAD_SWITCH(strflag,strstate) do { fprintf(stderr, "KEYPAD %s (%s)\n", (strstate), (strflag)); } while (0)
67 #else
68 # define DUMP_KEYPAD_SWITCH(strflag,strstate) ((void)(sizeof(strflag)+sizeof(strstate)))
69 #endif
72 ////////////////////////////////////////////////////////////////////////////////
73 #include "defaults.c"
74 #include "getticks.c"
77 ////////////////////////////////////////////////////////////////////////////////
78 #define USAGE_VERSION "k8sterm " VERSION "\n(c) 2010-2012 st engineers and Ketmar // Vampire Avalon\n"
79 #define USAGE \
80 "usage: sterm [options]\n" \
81 "options:\n" \
82 "-v show version and exit\n" \
83 "-h show this help and exit\n" \
84 "-S disable tabs\n" \
85 "-t title set window title\n" \
86 "-c class set window class\n" \
87 "-w windowid embed in window id given id\n" \
88 "-T termname set TERM name\n" \
89 "-C config_file use custom config file\n" \
90 "-l langiconv use given locale\n" \
91 "-R stcmd run this INTERNAL k8sterm command\n" \
92 "-e command... run given command and pass all following args to it\n"
95 ////////////////////////////////////////////////////////////////////////////////
96 /* masks for key translation */
97 #define XK_NO_MOD (UINT_MAX)
98 #define XK_ANY_MOD (0)
101 /* misc utility macros */
102 #ifdef K8T_MAX
103 # undef K8T_MAX
104 #endif
105 #define K8T_MAX(__a,__b) \
106 ({ typeof(__a)_a = (__a); \
107 typeof(__b)_b = (__b); \
108 _a > _b ? _a : _b; })
110 #ifdef K8T_MIN
111 # undef K8T_MIN
112 #endif
113 #define K8T_MIN(__a,__b) \
114 ({ typeof(__a)_a = (__a); \
115 typeof(__b)_b = (__b); \
116 _a < _b ? _a : _b; })
118 #define K8T_ARRLEN(a) (sizeof(a)/sizeof(a[0]))
119 #define K8T_DEFAULT(a, b) (a) = ((a) ? (a) : (b))
120 #define K8T_BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
121 #define K8T_LIMIT(x, a, b) ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x))
122 #define K8T_ATTRCMP(a, b) ((a).attr != (b).attr || (a).fg != (b).fg || (a).bg != (b).bg)
123 #define K8T_ISSET(_tr,flag) ((_tr)->mode&(flag))
124 #define K8T_X2COL(x) ((x)/xw.cw)
125 #define K8T_Y2ROW(_tr, y) ((y-(opt_tabposition==1 ? xw.tabheight : 0))/xw.ch-((_tr) != NULL ? (_tr)->topline : 0))
126 #define K8T_ISGFX(mode) ((mode)&K8T_ATTR_GFX)
129 ////////////////////////////////////////////////////////////////////////////////
130 enum {
131 K8T_BELL_AUDIO = 0x01,
132 K8T_BELL_URGENT = 0x02
135 enum {
136 K8T_CMDMODE_NONE,
137 K8T_CMDMODE_INPUT,
138 K8T_CMDMODE_MESSAGE
141 // glyph attributes (bitmask)
142 enum {
143 K8T_ATTR_NULL = 0x00,
144 K8T_ATTR_REVERSE = 0x01,
145 K8T_ATTR_UNDERLINE = 0x02,
146 K8T_ATTR_BOLD = 0x04,
147 K8T_ATTR_GFX = 0x08,
148 K8T_ATTR_DEFFG = 0x10,
149 K8T_ATTR_DEFBG = 0x20,
152 // cursor operations for k8t_tmCursor()
153 enum cursor_movement {
154 K8T_CURSOR_SAVE,
155 K8T_CURSOR_LOAD
158 // cursor state (bitmask)
159 enum {
160 K8T_CURSOR_DEFAULT = 0x00,
161 K8T_CURSOR_HIDE = 0x01,
162 K8T_CURSOR_WRAPNEXT = 0x02
165 // glyph state (bitmask)
166 enum {
167 K8T_GLYPH_SET = 0x01, /* for selection only */
168 K8T_GLYPH_DIRTY = 0x02,
169 K8T_GLYPH_WRAP = 0x10, /* can be set for the last line glyph */
172 // terminal mode flags (bitmask)
173 enum {
174 K8T_MODE_WRAP = 0x01,
175 K8T_MODE_INSERT = 0x02,
176 K8T_MODE_APPKEYPAD = 0x04,
177 K8T_MODE_ALTSCREEN = 0x08,
178 K8T_MODE_CRLF = 0x10,
179 K8T_MODE_MOUSEBTN = 0x20,
180 K8T_MODE_MOUSEMOTION = 0x40,
181 K8T_MODE_MOUSE = 0x20|0x40,
182 K8T_MODE_REVERSE = 0x80,
183 K8T_MODE_BRACPASTE = 0x100,
184 K8T_MODE_FOCUSEVT = 0x200,
185 K8T_MODE_DISPCTRL = 0x400, //TODO: not implemented yet
186 K8T_MODE_GFX0 = 0x1000,
187 K8T_MODE_GFX1 = 0x2000,
190 // escape sequence processor state
191 enum {
192 K8T_ESC_START = 0x01,
193 K8T_ESC_CSI = 0x02,
194 K8T_ESC_OSC = 0x04,
195 K8T_ESC_TITLE = 0x08,
196 K8T_ESC_ALTCHARSET = 0x10,
197 K8T_ESC_HASH = 0x20,
198 K8T_ESC_PERCENT = 0x40,
199 K8T_ESC_ALTG1 = 0x80,
202 // X11 window state flags
203 enum {
204 K8T_WIN_VISIBLE = 0x01,
205 K8T_WIN_REDRAW = 0x02,
206 K8T_WIN_FOCUSED = 0x04
210 ////////////////////////////////////////////////////////////////////////////////
211 typedef struct __attribute__((packed)) {
212 /* character code */
213 union __attribute__((packed)) {
214 uint32_t uc;
215 char c[UTF_SIZ];
217 uint8_t attr; /* attribute flags */
218 uint16_t fg; /* foreground */
219 uint16_t bg; /* background */
220 uint8_t state; /* state flags */
221 } K8TGlyph;
223 typedef K8TGlyph *K8TLine;
226 typedef struct {
227 K8TGlyph attr; /* current char attributes */
228 int x;
229 int y;
230 char state;
231 } K8TCursor;
234 /* CSI Escape sequence structs */
235 /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
236 typedef struct {
237 char buf[K8T_ESC_BUF_SIZ]; /* raw string */
238 int len; /* raw string length */
239 char priv;
240 int arg[K8T_ESC_ARG_SIZ];
241 int narg; /* nb of args */
242 char mode;
243 } K8TCSIEscape;
246 /* Purely graphic info */
247 typedef struct {
248 Display *dpy;
249 Colormap cmap;
250 Window win;
251 Cursor cursor;
252 Cursor blankPtr;
253 Atom xembed;
254 XIM xim;
255 XIC xic;
256 int scr;
257 int w; /* window width */
258 int h; /* window height */
259 int bufw; /* pixmap width */
260 int bufh; /* pixmap height */
261 int ch; /* char height */
262 int cw; /* char width */
263 char state; /* focus, redraw, visible */
265 int tch; /* tab text char height */
266 Pixmap pictab;
267 int tabheight;
268 //struct timeval lastdraw;
269 } K8TXWindow;
272 /* TODO: use better name for vars... */
273 typedef struct {
274 int mode;
275 int bx, by;
276 int ex, ey;
277 struct { int x, y; } b, e;
278 char *clip;
279 Atom xtarget;
280 MSTime tclick1;
281 MSTime tclick2;
282 } K8TSelection;
285 /* Drawing Context */
286 typedef struct {
287 uint32_t *ncol; // normal colors
288 uint32_t *bcol; // b/w colors
289 uint32_t *gcol; // green colors
290 uint32_t *clrs[3];
291 GC gc;
292 struct {
293 int ascent;
294 int descent;
295 short lbearing;
296 short rbearing;
297 XFontSet set;
298 Font fid;
299 } font[3];
300 } K8TXDC;
303 typedef struct K8TCmdLine K8TCmdLine;
304 typedef struct K8Term K8Term;
306 typedef void (*CmdLineExecFn) (K8Term *term, K8TCmdLine *cmdline, int cancelled);
308 struct K8TCmdLine {
309 int cmdMode; // K8T_CMDMODE_xxx
310 char cmdline[UTF_SIZ*CMDLINE_SIZE];
311 int cmdreslen; // byte length of 'reserved' (read-only) part
312 int cmdofs; // byte offset of the first visible UTF-8 char in cmdline
313 char cmdc[UTF_SIZ+1]; // buffer to collect UTF-8 char
314 int cmdcl; // index in cmdc, used to collect UTF-8 chars
315 int cmdtabpos; // # of bytes (not UTF-8 chars!) used in autocompletion or -1
316 const char *cmdcurtabc; // current autocompleted command
317 CmdLineExecFn cmdexecfn;
318 void *udata;
322 /* Internal representation of the screen */
323 struct K8Term {
324 int cmdfd;
325 int dead;
326 int exitcode;
327 int waitkeypress; /* child is dead, awaiting for keypress */
328 char *exitmsg; /* message for waitkeypress */
329 int needConv; /* 0: utf-8 locale */
330 int belltype;
331 int blackandwhite;
332 int fastredraw;
333 int justSwapped;
335 int curblink;
336 int curbhidden;
337 MSTime lastBlinkTime;
338 int curblinkinactive;
340 int row; /* nb row */
341 int col; /* nb col */
342 int topline; /* top line for drawing (0: no history; 1: show one history line; etc) */
343 int linecount; /* full, with history */
344 int maxhistory;/* max history lines; 0: none; <0: infinite */
345 K8TLine *line; /* screen */
346 K8TLine *alt; /* alternate screen */
347 char *dirty; /* dirtyness of lines */
348 K8TCursor c; /* cursor */
349 int top; /* top scroll limit */
350 int bot; /* bottom scroll limit */
351 int mode; /* terminal mode flags */
352 int mousemode; /* mouse mode: 1000, 1005, 1006, 1015 */
353 int esc; /* escape state flags */
354 int charset; /* K8T_MODE_GFX0 or K8T_MODE_GFX1 */
355 int ignoredecpad; /* ignore DEC keypad switching sequences */
357 K8TCursor csaved; /* saved cursor info */
358 // old cursor position
359 int oldcx;
360 int oldcy;
362 char title[K8T_ESC_TITLE_SIZ+1];
363 int titlelen;
365 int mouseob;
366 int mouseox;
367 int mouseoy;
369 char obuf[OBUFSIZ];
370 #ifdef DUMP_PROG_OUTPUT
371 int xobuflen;
372 #endif
373 int obuflen;
375 char ubuf[UTF_SIZ];
376 int ubufpos;
378 char drawbuf[DRAW_BUF_SIZ];
380 char wrbuf[WBUFSIZ];
381 int wrbufsize;
382 int wrbufused;
383 int wrbufpos;
385 K8TCSIEscape escseq;
386 K8TSelection sel;
387 pid_t pid;
388 MSTime lastDrawTime;
390 char *execcmd;
392 Pixmap picbuf;
393 int picbufw;
394 int picbufh;
396 uint16_t deffg;
397 uint16_t defbg;
399 int wantRedraw;
401 MSTime lastActiveTime;
403 K8TCmdLine cmdline;
405 int dumpescapes;
406 int dumpeskeys;
407 // callbacks
408 // locale conversions
409 // returns new length
410 int (*loc2utf) (char *dest, const char *src, int len);
411 int (*utf2loc) (char *dest, const char *src, int len);
415 ////////////////////////////////////////////////////////////////////////////////
416 #include "globals.c"
419 ////////////////////////////////////////////////////////////////////////////////
420 #include "utf8.c"
421 #include "utils.c"
422 #include "keymaps.c"
425 ////////////////////////////////////////////////////////////////////////////////
426 static void executeCommands (const char *str);
427 static const char *findCommandCompletion (const char *str, int slen, const char *prev);
430 static void k8t_ttyResize (K8Term *term);
431 static void k8t_tmSetAttr (K8Term *term, int *attr, int l);
432 static void k8t_tmResetAttrs (K8Term *term);
433 static int k8t_tmDoWrap (K8Term *term);
434 static void k8t_tmPutC (K8Term *term, const char *c); // `c` is utf-8
435 static void k8t_ttyWrite (K8Term *term, const char *s, size_t n);
436 static void k8t_ttyWriteNoEnc (K8Term *term, const char *s, size_t n);
437 static void k8t_tmDirty (K8Term *term, int top, int bot);
438 static void k8t_tmFullDirty (K8Term *term);
441 static void tdrawfatalmsg (K8Term *term, const char *msg);
443 static void xclearunused (void);
444 static void xseturgency (int add);
445 static void xfixsel (void);
446 static void xblankPointer (void);
447 static void xunblankPointer (void);
448 static void xdrawTabBar (void);
451 static void k8t_Draw (K8Term *term, int forced);
454 static void tcmdput (K8Term *term, K8TCmdLine *cmdline, const char *s, int len);
456 #include "decls.c"
459 ////////////////////////////////////////////////////////////////////////////////
460 static inline void k8t_ttyWriteStr (K8Term *term, const char *s) { if (s != NULL && s[0]) k8t_ttyWrite(term, s, strlen(s)); }
461 static inline void k8t_ttyWriteStrNoEnc (K8Term *term, const char *s) { if (s != NULL && s[0]) k8t_ttyWriteNoEnc(term, s, strlen(s)); }
463 //FIXME: do utf-8!
464 static inline void k8t_ttyPutStr (K8Term *term, const char *s) { if (s != NULL) while (*s) { k8t_tmPutC(term, s); ++s; } }
467 static inline uint32_t getColor (int idx) {
468 if (globalBW && (curterm == NULL || !curterm->blackandwhite)) return dc.clrs[globalBW][idx];
469 if (curterm != NULL) return dc.clrs[curterm->blackandwhite%3][idx];
470 return dc.clrs[0][idx];
474 ////////////////////////////////////////////////////////////////////////////////
475 #include "iniparse.c"
476 #include "locales.c"
479 ////////////////////////////////////////////////////////////////////////////////
480 #include "termswitch.c"
483 ////////////////////////////////////////////////////////////////////////////////
484 #include "selection.c"
485 #include "tabmouseutils.c"
486 #include "mouseevents.c"
489 ////////////////////////////////////////////////////////////////////////////////
490 #include "ttyinit.c"
491 #include "ttyrw.c"
492 #include "ttyutils.c"
493 #include "ttyputc.c"
494 #include "ttyresize.c"
497 ////////////////////////////////////////////////////////////////////////////////
498 #include "tcmdline.c"
499 #include "tfatalbox.c"
502 ////////////////////////////////////////////////////////////////////////////////
503 #include "x11misc.c"
504 #include "x11drawstr.c"
505 #include "x11drawcur.c"
506 #include "x11drawtabs.c"
507 #include "x11drawcmdline.c"
508 #include "x11draw.c"
511 ////////////////////////////////////////////////////////////////////////////////
512 #include "x11evtvis.c"
513 #include "x11evtkbd.c"
516 ////////////////////////////////////////////////////////////////////////////////
517 // xembed?
518 static void xevtcbcmessage (XEvent *e) {
519 /* See xembed specs http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */
520 if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
521 if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
522 xw.state |= K8T_WIN_FOCUSED;
523 xseturgency(0);
524 k8t_tmSendFocusEvent(curterm, 1);
525 } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
526 xw.state &= ~K8T_WIN_FOCUSED;
527 k8t_tmSendFocusEvent(curterm, 0);
529 k8t_DrawCursor(curterm);
530 xdrawTabBar();
531 k8t_DrawCopy(curterm, 0, 0, curterm->col, curterm->row);
532 return;
535 if (e->xclient.data.l[0] == XA_WM_DELETE_WINDOW) {
536 closeRequestComes = 1;
537 return;
542 ////////////////////////////////////////////////////////////////////////////////
543 static inline int last_draw_too_old (void) {
544 MSTime tt = mclock_ticks();
546 if (curterm != NULL) {
547 if (curterm->dead || !curterm->wantRedraw) return 0;
549 return
550 (tt-curterm->lastDrawTime >= opt_drawtimeout ||
551 tt-lastDrawTime >= (curterm->justSwapped ? opt_swapdrawtimeout : opt_maxdrawtimeout));
553 return (tt-lastDrawTime >= opt_maxdrawtimeout);
557 ////////////////////////////////////////////////////////////////////////////////
558 // main loop
559 static void (*handler[LASTEvent])(XEvent *) = {
560 [KeyPress] = xevtcbkpress,
561 [ClientMessage] = xevtcbcmessage,
562 [ConfigureNotify] = xevtcbresise,
563 [VisibilityNotify] = xevtcbvisibility,
564 [UnmapNotify] = xevtcbunmap,
565 [Expose] = xevtcbexpose,
566 [FocusIn] = xevtcbfocus,
567 [FocusOut] = xevtcbfocus,
568 [MotionNotify] = xevtcbbmotion,
569 [ButtonPress] = xevtcbbpress,
570 [ButtonRelease] = xevtcbbrelease,
571 [SelectionNotify] = xevtcbselnotify,
572 [SelectionRequest] = xevtcbselrequest,
573 [SelectionClear] = xevtcbselclear,
577 static void run (void) {
578 //int stuff_to_print = 0;
579 int xfd = XConnectionNumber(xw.dpy);
581 ptrLastMove = mclock_ticks();
582 while (term_count > 0) {
583 XEvent ev;
584 fd_set rfd, wfd;
585 struct timeval timeout;
586 int maxfd = xfd;
587 int dodraw;
589 FD_ZERO(&rfd);
590 FD_ZERO(&wfd);
591 FD_SET(xfd, &rfd);
592 //FD_SET(curterm->cmdfd, &rfd);
593 // have something to write?
594 for (int f = 0; f < term_count; ++f) {
595 K8Term *t = term_array[f];
597 if (!t->dead && t->cmdfd >= 0) {
598 if (t->cmdfd > maxfd) maxfd = t->cmdfd;
599 FD_SET(t->cmdfd, &rfd);
600 if (t->pid != 0 && t->wrbufpos < t->wrbufused) FD_SET(t->cmdfd, &wfd);
604 timeout.tv_sec = 0;
605 timeout.tv_usec = (opt_drawtimeout+2)*1000;
606 //fprintf(stderr, "before select...\n");
607 if (select(maxfd+1, &rfd, &wfd, NULL, &timeout) < 0) {
608 if (errno == EINTR) continue;
609 k8t_die("select failed: %s", strerror(errno));
611 //fprintf(stderr, "after select...\n");
612 // process terminals i/o
613 for (int f = 0; f < term_count; ++f) {
614 K8Term *t = term_array[f];
616 if (!t->dead && t->cmdfd >= 0) {
617 int rd = -1;
619 if (t->pid != 0 && FD_ISSET(t->cmdfd, &wfd)) k8t_ttyFlushWriteBuf(t);
620 if (FD_ISSET(t->cmdfd, &rfd)) rd = k8t_ttyRead(t);
622 if (t->waitkeypress && t->exitmsg != NULL && rd < 0) {
623 // there will be no more data
624 close(t->cmdfd);
625 t->cmdfd = -1;
627 tdrawfatalmsg(t, t->exitmsg);
628 free(t->exitmsg);
629 t->exitmsg = NULL;
630 k8t_tmWantRedraw(t, 1);
635 //fprintf(stderr, "000: term=%p; dead=%d; waitkeypress=%d\n", term, (term ? term->dead : 666), (term ? term->waitkeypress : 666));
636 termcleanup();
637 //fprintf(stderr, "001: term=%p; dead=%d; waitkeypress=%d\n", term, (term ? term->dead : 666), (term ? term->waitkeypress : 666));
638 if (term_count == 0) exit(exitcode);
640 dodraw = 0;
641 if (curterm != NULL && curterm->curblink > 0) {
642 MSTime tt = mclock_ticks();
644 if (tt-curterm->lastBlinkTime >= curterm->curblink) {
645 curterm->lastBlinkTime = tt;
646 if ((xw.state&K8T_WIN_FOCUSED) || curterm->curblinkinactive) {
647 curterm->curbhidden = (curterm->curbhidden ? 0 : -1);
648 dodraw = 1;
649 } else {
650 curterm->curbhidden = 0;
654 if (updateTabBar) xdrawTabBar();
655 if (dodraw || last_draw_too_old()) k8t_Draw(curterm, 0);
657 if (XPending(xw.dpy)) {
658 while (XPending(xw.dpy)) {
659 XNextEvent(xw.dpy, &ev);
660 switch (ev.type) {
661 //case VisibilityNotify:
662 //case UnmapNotify:
663 //case FocusIn:
664 //case FocusOut:
665 case MotionNotify:
666 case ButtonPress:
667 case ButtonRelease:
668 xunblankPointer();
669 ptrLastMove = mclock_ticks();
670 break;
671 default: ;
673 if (XFilterEvent(&ev, xw.win)) continue;
674 if (handler[ev.type]) (handler[ev.type])(&ev);
678 if (curterm != NULL) {
679 switch (closeRequestComes) {
680 case 1: // just comes
681 if (opt_ignoreclose == 0) {
682 tcmdlinehide(curterm, &curterm->cmdline);
683 tcmdlineinitex(curterm, &curterm->cmdline, "Do you really want to close sterm [Y/n]? ");
684 curterm->cmdline.cmdexecfn = cmdline_closequeryexec;
685 } else if (opt_ignoreclose < 0) {
686 //FIXME: kill all clients?
687 return;
689 closeRequestComes = 0;
690 break;
691 case 2: // ok, die now
692 //FIXME: kill all clients?
693 return;
697 if (!ptrBlanked && opt_ptrblank > 0 && mclock_ticks()-ptrLastMove >= opt_ptrblank) {
698 xblankPointer();
704 ////////////////////////////////////////////////////////////////////////////////
705 #include "inifile.c"
706 #include "commands.c"
709 ////////////////////////////////////////////////////////////////////////////////
710 #include "childkiller.c"
713 ////////////////////////////////////////////////////////////////////////////////
714 int main (int argc, char *argv[]) {
715 char *configfile = NULL;
716 char *runcmd = NULL;
718 //dbgLogInit();
720 for (int f = 1; f < argc; f++) {
721 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
722 if (strcmp(argv[f], "-into") == 0) { ++f; continue; }
723 if (strcmp(argv[f], "-embed") == 0) { ++f; continue; }
724 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
725 case 'e': f = argc+1; break;
726 case 't':
727 case 'c':
728 case 'w':
729 case 'b':
730 case 'R':
731 ++f;
732 break;
733 case 'T':
734 if (++f < argc) {
735 free(opt_term);
736 opt_term = strdup(argv[f]);
737 opt_term_locked = 1;
739 break;
740 case 'C':
741 if (++f < argc) {
742 if (configfile != NULL) free(configfile);
743 configfile = strdup(argv[f]);
745 break;
746 case 'l':
747 if (++f < argc) cliLocale = argv[f];
748 break;
749 case 'S': // single-tab mode
750 opt_disabletabs = 1;
751 break;
752 case 'v':
753 fprintf(stderr, "%s", USAGE_VERSION);
754 exit(EXIT_FAILURE);
755 case 'h':
756 default:
757 fprintf(stderr, "%s%s", USAGE_VERSION, USAGE);
758 exit(EXIT_FAILURE);
762 initDefaultOptions();
763 if (configfile == NULL) {
764 const char *home = getenv("HOME");
766 if (home != NULL) {
767 configfile = SPrintf("%s/.sterm.rc", home);
768 if (loadConfig(configfile) == 0) goto cfgdone;
769 free(configfile); configfile = NULL;
771 configfile = SPrintf("%s/.config/sterm.rc", home);
772 if (loadConfig(configfile) == 0) goto cfgdone;
773 free(configfile); configfile = NULL;
776 configfile = SPrintf("/etc/sterm.rc");
777 if (loadConfig(configfile) == 0) goto cfgdone;
778 free(configfile); configfile = NULL;
780 configfile = SPrintf("/etc/sterm/sterm.rc");
781 if (loadConfig(configfile) == 0) goto cfgdone;
782 free(configfile); configfile = NULL;
784 configfile = SPrintf("./.sterm.rc");
785 if (loadConfig(configfile) == 0) goto cfgdone;
786 free(configfile); configfile = NULL;
787 // no config
788 } else {
789 if (loadConfig(configfile) < 0) k8t_die("config file '%s' not found!", configfile);
791 cfgdone:
792 if (configfile != NULL) free(configfile); configfile = NULL;
794 for (int f = 1; f < argc; f++) {
795 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
796 if (strcmp(argv[f], "-into") == 0 || strcmp(argv[f], "-embed") == 0) {
797 if (opt_embed) free(opt_embed);
798 opt_embed = strdup(argv[f]);
799 continue;
801 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
802 case 't':
803 if (++f < argc) {
804 free(opt_title);
805 opt_title = strdup(argv[f]);
807 break;
808 case 'c':
809 if (++f < argc) {
810 free(opt_class);
811 opt_class = strdup(argv[f]);
813 break;
814 case 'w':
815 if (++f < argc) {
816 if (opt_embed) free(opt_embed);
817 opt_embed = strdup(argv[f]);
819 break;
820 case 'R':
821 if (++f < argc) runcmd = argv[f];
822 break;
823 case 'e':
824 /* eat all remaining arguments */
825 if (++f < argc) opt_cmd = &argv[f];
826 f = argc+1;
827 case 'T':
828 case 'C':
829 case 'l':
830 ++f;
831 break;
832 case 'S':
833 break;
837 setenv("TERM", opt_term, 1);
838 mclock_init();
839 setlocale(LC_ALL, "");
840 initLCConversion();
841 summonChildKiller();
842 updateTabBar = 1;
843 termidx = 0;
844 curterm = k8t_termalloc();
845 if (curterm->execcmd != NULL) { free(curterm->execcmd); curterm->execcmd = NULL; }
846 k8t_tmInitialize(curterm, 80, 25);
847 if (k8t_ttyNew(curterm) != 0) k8t_die("can't run process");
848 opt_cmd = NULL;
849 xinit();
850 k8t_selInit(curterm);
851 if (runcmd != NULL) executeCommands(runcmd);
852 run();
853 return 0;