alot of renaming...
[k8sterm.git] / src / sterm.c
blob68d386ed8ad73f16e6976240ab53979350a8f874
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;
410 ////////////////////////////////////////////////////////////////////////////////
411 #include "globals.c"
414 ////////////////////////////////////////////////////////////////////////////////
415 #include "utf8.c"
416 #include "utils.c"
417 #include "keymaps.c"
420 ////////////////////////////////////////////////////////////////////////////////
421 static void executeCommands (const char *str);
422 static const char *findCommandCompletion (const char *str, int slen, const char *prev);
425 static void k8t_ttyResize (K8Term *term);
426 static void k8t_tmSetAttr (K8Term *term, int *attr, int l);
427 static void k8t_tmResetAttrs (K8Term *term);
428 static int k8t_tmDoWrap (K8Term *term);
429 static void k8t_tmPutC (K8Term *term, const char *c); // `c` is utf-8
430 static void k8t_ttyWrite (K8Term *term, const char *s, size_t n);
431 static void k8t_ttyWriteNoEnc (K8Term *term, const char *s, size_t n);
432 static void k8t_tmDirty (K8Term *term, int top, int bot);
433 static void k8t_tmFullDirty (K8Term *term);
436 static void tdrawfatalmsg (K8Term *term, const char *msg);
438 static void xclearunused (void);
439 static void xseturgency (int add);
440 static void xfixsel (void);
441 static void xblankPointer (void);
442 static void xunblankPointer (void);
443 static void xdrawTabBar (void);
446 static void k8t_Draw (K8Term *term, int forced);
449 static void tcmdput (K8Term *term, K8TCmdLine *cmdline, const char *s, int len);
451 #include "decls.c"
454 ////////////////////////////////////////////////////////////////////////////////
455 static inline void k8t_ttyWriteStr (K8Term *term, const char *s) { if (s != NULL && s[0]) k8t_ttyWrite(term, s, strlen(s)); }
456 static inline void k8t_ttyWriteStrNoEnc (K8Term *term, const char *s) { if (s != NULL && s[0]) k8t_ttyWriteNoEnc(term, s, strlen(s)); }
458 //FIXME: do utf-8!
459 static inline void k8t_ttyPutStr (K8Term *term, const char *s) { if (s != NULL) while (*s) { k8t_tmPutC(term, s); ++s; } }
462 static inline uint32_t getColor (int idx) {
463 if (globalBW && (curterm == NULL || !curterm->blackandwhite)) return dc.clrs[globalBW][idx];
464 if (curterm != NULL) return dc.clrs[curterm->blackandwhite%3][idx];
465 return dc.clrs[0][idx];
469 ////////////////////////////////////////////////////////////////////////////////
470 #include "iniparse.c"
471 #include "locales.c"
474 ////////////////////////////////////////////////////////////////////////////////
475 #include "termswitch.c"
478 ////////////////////////////////////////////////////////////////////////////////
479 #include "selection.c"
480 #include "tabmouseutils.c"
481 #include "mouseevents.c"
484 ////////////////////////////////////////////////////////////////////////////////
485 #include "ttyinit.c"
486 #include "ttyrw.c"
487 #include "ttyutils.c"
488 #include "ttyputc.c"
489 #include "ttyresize.c"
492 ////////////////////////////////////////////////////////////////////////////////
493 #include "tcmdline.c"
494 #include "tfatalbox.c"
497 ////////////////////////////////////////////////////////////////////////////////
498 #include "x11misc.c"
499 #include "x11drawstr.c"
500 #include "x11drawcur.c"
501 #include "x11drawtabs.c"
502 #include "x11drawcmdline.c"
503 #include "x11draw.c"
506 ////////////////////////////////////////////////////////////////////////////////
507 #include "x11evtvis.c"
508 #include "x11evtkbd.c"
511 ////////////////////////////////////////////////////////////////////////////////
512 // xembed?
513 static void xevtcbcmessage (XEvent *e) {
514 /* See xembed specs http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */
515 if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
516 if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
517 xw.state |= K8T_WIN_FOCUSED;
518 xseturgency(0);
519 k8t_tmSendFocusEvent(curterm, 1);
520 } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
521 xw.state &= ~K8T_WIN_FOCUSED;
522 k8t_tmSendFocusEvent(curterm, 0);
524 k8t_DrawCursor(curterm);
525 xdrawTabBar();
526 k8t_DrawCopy(curterm, 0, 0, curterm->col, curterm->row);
527 return;
530 if (e->xclient.data.l[0] == XA_WM_DELETE_WINDOW) {
531 closeRequestComes = 1;
532 return;
537 ////////////////////////////////////////////////////////////////////////////////
538 static inline int last_draw_too_old (void) {
539 MSTime tt = mclock_ticks();
541 if (curterm != NULL) {
542 if (curterm->dead || !curterm->wantRedraw) return 0;
544 return
545 (tt-curterm->lastDrawTime >= opt_drawtimeout ||
546 tt-lastDrawTime >= (curterm->justSwapped ? opt_swapdrawtimeout : opt_maxdrawtimeout));
548 return (tt-lastDrawTime >= opt_maxdrawtimeout);
552 ////////////////////////////////////////////////////////////////////////////////
553 // main loop
554 static void (*handler[LASTEvent])(XEvent *) = {
555 [KeyPress] = xevtcbkpress,
556 [ClientMessage] = xevtcbcmessage,
557 [ConfigureNotify] = xevtcbresise,
558 [VisibilityNotify] = xevtcbvisibility,
559 [UnmapNotify] = xevtcbunmap,
560 [Expose] = xevtcbexpose,
561 [FocusIn] = xevtcbfocus,
562 [FocusOut] = xevtcbfocus,
563 [MotionNotify] = xevtcbbmotion,
564 [ButtonPress] = xevtcbbpress,
565 [ButtonRelease] = xevtcbbrelease,
566 [SelectionNotify] = xevtcbselnotify,
567 [SelectionRequest] = xevtcbselrequest,
568 [SelectionClear] = xevtcbselclear,
572 static void run (void) {
573 //int stuff_to_print = 0;
574 int xfd = XConnectionNumber(xw.dpy);
576 ptrLastMove = mclock_ticks();
577 while (term_count > 0) {
578 XEvent ev;
579 fd_set rfd, wfd;
580 struct timeval timeout;
581 int maxfd = xfd;
582 int dodraw;
584 FD_ZERO(&rfd);
585 FD_ZERO(&wfd);
586 FD_SET(xfd, &rfd);
587 //FD_SET(curterm->cmdfd, &rfd);
588 // have something to write?
589 for (int f = 0; f < term_count; ++f) {
590 K8Term *t = term_array[f];
592 if (!t->dead && t->cmdfd >= 0) {
593 if (t->cmdfd > maxfd) maxfd = t->cmdfd;
594 FD_SET(t->cmdfd, &rfd);
595 if (t->pid != 0 && t->wrbufpos < t->wrbufused) FD_SET(t->cmdfd, &wfd);
599 timeout.tv_sec = 0;
600 timeout.tv_usec = (opt_drawtimeout+2)*1000;
601 //fprintf(stderr, "before select...\n");
602 if (select(maxfd+1, &rfd, &wfd, NULL, &timeout) < 0) {
603 if (errno == EINTR) continue;
604 die("select failed: %s", strerror(errno));
606 //fprintf(stderr, "after select...\n");
607 // process terminals i/o
608 for (int f = 0; f < term_count; ++f) {
609 K8Term *t = term_array[f];
611 if (!t->dead && t->cmdfd >= 0) {
612 int rd = -1;
614 if (t->pid != 0 && FD_ISSET(t->cmdfd, &wfd)) k8t_ttyFlushWriteBuf(t);
615 if (FD_ISSET(t->cmdfd, &rfd)) rd = k8t_ttyRead(t);
617 if (t->waitkeypress && t->exitmsg != NULL && rd < 0) {
618 // there will be no more data
619 close(t->cmdfd);
620 t->cmdfd = -1;
622 tdrawfatalmsg(t, t->exitmsg);
623 free(t->exitmsg);
624 t->exitmsg = NULL;
625 k8t_tmWantRedraw(t, 1);
630 //fprintf(stderr, "000: term=%p; dead=%d; waitkeypress=%d\n", term, (term ? term->dead : 666), (term ? term->waitkeypress : 666));
631 termcleanup();
632 //fprintf(stderr, "001: term=%p; dead=%d; waitkeypress=%d\n", term, (term ? term->dead : 666), (term ? term->waitkeypress : 666));
633 if (term_count == 0) exit(exitcode);
635 dodraw = 0;
636 if (curterm != NULL && curterm->curblink > 0) {
637 MSTime tt = mclock_ticks();
639 if (tt-curterm->lastBlinkTime >= curterm->curblink) {
640 curterm->lastBlinkTime = tt;
641 if ((xw.state&K8T_WIN_FOCUSED) || curterm->curblinkinactive) {
642 curterm->curbhidden = (curterm->curbhidden ? 0 : -1);
643 dodraw = 1;
644 } else {
645 curterm->curbhidden = 0;
649 if (updateTabBar) xdrawTabBar();
650 if (dodraw || last_draw_too_old()) k8t_Draw(curterm, 0);
652 if (XPending(xw.dpy)) {
653 while (XPending(xw.dpy)) {
654 XNextEvent(xw.dpy, &ev);
655 switch (ev.type) {
656 //case VisibilityNotify:
657 //case UnmapNotify:
658 //case FocusIn:
659 //case FocusOut:
660 case MotionNotify:
661 case ButtonPress:
662 case ButtonRelease:
663 xunblankPointer();
664 ptrLastMove = mclock_ticks();
665 break;
666 default: ;
668 if (XFilterEvent(&ev, xw.win)) continue;
669 if (handler[ev.type]) (handler[ev.type])(&ev);
673 if (curterm != NULL) {
674 switch (closeRequestComes) {
675 case 1: // just comes
676 if (opt_ignoreclose == 0) {
677 tcmdlinehide(curterm, &curterm->cmdline);
678 tcmdlineinitex(curterm, &curterm->cmdline, "Do you really want to close sterm [Y/n]? ");
679 curterm->cmdline.cmdexecfn = cmdline_closequeryexec;
680 } else if (opt_ignoreclose < 0) {
681 //FIXME: kill all clients?
682 return;
684 closeRequestComes = 0;
685 break;
686 case 2: // ok, die now
687 //FIXME: kill all clients?
688 return;
692 if (!ptrBlanked && opt_ptrblank > 0 && mclock_ticks()-ptrLastMove >= opt_ptrblank) {
693 xblankPointer();
699 ////////////////////////////////////////////////////////////////////////////////
700 #include "inifile.c"
701 #include "commands.c"
704 ////////////////////////////////////////////////////////////////////////////////
705 #include "childkiller.c"
708 ////////////////////////////////////////////////////////////////////////////////
709 int main (int argc, char *argv[]) {
710 char *configfile = NULL;
711 char *runcmd = NULL;
713 //dbgLogInit();
715 for (int f = 1; f < argc; f++) {
716 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
717 if (strcmp(argv[f], "-into") == 0) { ++f; continue; }
718 if (strcmp(argv[f], "-embed") == 0) { ++f; continue; }
719 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
720 case 'e': f = argc+1; break;
721 case 't':
722 case 'c':
723 case 'w':
724 case 'b':
725 case 'R':
726 ++f;
727 break;
728 case 'T':
729 if (++f < argc) {
730 free(opt_term);
731 opt_term = strdup(argv[f]);
732 opt_term_locked = 1;
734 break;
735 case 'C':
736 if (++f < argc) {
737 if (configfile != NULL) free(configfile);
738 configfile = strdup(argv[f]);
740 break;
741 case 'l':
742 if (++f < argc) cliLocale = argv[f];
743 break;
744 case 'S': // single-tab mode
745 opt_disabletabs = 1;
746 break;
747 case 'v':
748 fprintf(stderr, "%s", USAGE_VERSION);
749 exit(EXIT_FAILURE);
750 case 'h':
751 default:
752 fprintf(stderr, "%s%s", USAGE_VERSION, USAGE);
753 exit(EXIT_FAILURE);
757 initDefaultOptions();
758 if (configfile == NULL) {
759 const char *home = getenv("HOME");
761 if (home != NULL) {
762 configfile = SPrintf("%s/.sterm.rc", home);
763 if (loadConfig(configfile) == 0) goto cfgdone;
764 free(configfile); configfile = NULL;
766 configfile = SPrintf("%s/.config/sterm.rc", home);
767 if (loadConfig(configfile) == 0) goto cfgdone;
768 free(configfile); configfile = NULL;
771 configfile = SPrintf("/etc/sterm.rc");
772 if (loadConfig(configfile) == 0) goto cfgdone;
773 free(configfile); configfile = NULL;
775 configfile = SPrintf("/etc/sterm/sterm.rc");
776 if (loadConfig(configfile) == 0) goto cfgdone;
777 free(configfile); configfile = NULL;
779 configfile = SPrintf("./.sterm.rc");
780 if (loadConfig(configfile) == 0) goto cfgdone;
781 free(configfile); configfile = NULL;
782 // no config
783 } else {
784 if (loadConfig(configfile) < 0) die("config file '%s' not found!", configfile);
786 cfgdone:
787 if (configfile != NULL) free(configfile); configfile = NULL;
789 for (int f = 1; f < argc; f++) {
790 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
791 if (strcmp(argv[f], "-into") == 0 || strcmp(argv[f], "-embed") == 0) {
792 if (opt_embed) free(opt_embed);
793 opt_embed = strdup(argv[f]);
794 continue;
796 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
797 case 't':
798 if (++f < argc) {
799 free(opt_title);
800 opt_title = strdup(argv[f]);
802 break;
803 case 'c':
804 if (++f < argc) {
805 free(opt_class);
806 opt_class = strdup(argv[f]);
808 break;
809 case 'w':
810 if (++f < argc) {
811 if (opt_embed) free(opt_embed);
812 opt_embed = strdup(argv[f]);
814 break;
815 case 'R':
816 if (++f < argc) runcmd = argv[f];
817 break;
818 case 'e':
819 /* eat all remaining arguments */
820 if (++f < argc) opt_cmd = &argv[f];
821 f = argc+1;
822 case 'T':
823 case 'C':
824 case 'l':
825 ++f;
826 break;
827 case 'S':
828 break;
832 setenv("TERM", opt_term, 1);
833 mclock_init();
834 setlocale(LC_ALL, "");
835 initLCConversion();
836 summonChildKiller();
837 updateTabBar = 1;
838 termidx = 0;
839 curterm = k8t_termalloc();
840 if (curterm->execcmd != NULL) { free(curterm->execcmd); curterm->execcmd = NULL; }
841 k8t_tmInitialize(curterm, 80, 25);
842 if (k8t_ttyNew(curterm) != 0) die("can't run process");
843 opt_cmd = NULL;
844 xinit();
845 k8t_selInit(curterm);
846 if (runcmd != NULL) executeCommands(runcmd);
847 run();
848 return 0;