do wrapping on screen swap
[k8sterm.git] / src / sterm.c
blob22acfe00c8d73bfb7bae8f2a56821a816d20162c
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 MAX
103 # undef MAX
104 #endif
105 #define MAX(__a,__b) \
106 ({ typeof(__a)_a = (__a); \
107 typeof(__b)_b = (__b); \
108 _a > _b ? _a : _b; })
110 #ifdef MIN
111 # undef MIN
112 #endif
113 #define MIN(__a,__b) \
114 ({ typeof(__a)_a = (__a); \
115 typeof(__b)_b = (__b); \
116 _a < _b ? _a : _b; })
118 #define SERRNO strerror(errno)
119 #define LEN(a) (sizeof(a)/sizeof(a[0]))
120 #define DEFAULT(a, b) (a) = ((a) ? (a) : (b))
121 #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
122 #define LIMIT(x, a, b) ((x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x))
123 #define ATTRCMP(a, b) ((a).attr != (b).attr || (a).fg != (b).fg || (a).bg != (b).bg)
124 #define IS_SET(_tr,flag) ((_tr)->mode&(flag))
125 #define X2COL(x) ((x)/xw.cw)
126 #define Y2ROW(_tr, y) ((y-(opt_tabposition==1 ? xw.tabheight : 0))/xw.ch-((_tr) != NULL ? (_tr)->topline : 0))
127 #define IS_GFX(mode) ((mode)&ATTR_GFX)
130 ////////////////////////////////////////////////////////////////////////////////
131 enum {
132 BELL_AUDIO = 0x01,
133 BELL_URGENT = 0x02
136 enum {
137 CMDMODE_NONE,
138 CMDMODE_INPUT,
139 CMDMODE_MESSAGE
142 // glyph attributes (bitmask)
143 enum {
144 ATTR_NULL = 0x00,
145 ATTR_REVERSE = 0x01,
146 ATTR_UNDERLINE = 0x02,
147 ATTR_BOLD = 0x04,
148 ATTR_GFX = 0x08,
149 ATTR_DEFFG = 0x10,
150 ATTR_DEFBG = 0x20,
153 // cursor operations for tcursor()
154 enum cursor_movement {
155 CURSOR_SAVE,
156 CURSOR_LOAD
159 // cursor state (bitmask)
160 enum {
161 CURSOR_DEFAULT = 0x00,
162 CURSOR_HIDE = 0x01,
163 CURSOR_WRAPNEXT = 0x02
166 // glyph state (bitmask)
167 enum {
168 GLYPH_SET = 0x01, /* for selection only */
169 GLYPH_DIRTY = 0x02,
170 GLYPH_WRAP = 0x10, /* can be set for the last line glyph */
173 // terminal mode flags (bitmask)
174 enum {
175 MODE_WRAP = 0x01,
176 MODE_INSERT = 0x02,
177 MODE_APPKEYPAD = 0x04,
178 MODE_ALTSCREEN = 0x08,
179 MODE_CRLF = 0x10,
180 MODE_MOUSEBTN = 0x20,
181 MODE_MOUSEMOTION = 0x40,
182 MODE_MOUSE = 0x20|0x40,
183 MODE_REVERSE = 0x80,
184 MODE_BRACPASTE = 0x100,
185 MODE_FOCUSEVT = 0x200,
186 MODE_DISPCTRL = 0x400, //TODO: not implemented yet
187 MODE_GFX0 = 0x1000,
188 MODE_GFX1 = 0x2000,
191 // escape sequence processor state
192 enum {
193 ESC_START = 0x01,
194 ESC_CSI = 0x02,
195 ESC_OSC = 0x04,
196 ESC_TITLE = 0x08,
197 ESC_ALTCHARSET = 0x10,
198 ESC_HASH = 0x20,
199 ESC_PERCENT = 0x40,
200 ESC_ALTG1 = 0x80,
203 // X11 window state flags
204 enum {
205 WIN_VISIBLE = 0x01,
206 WIN_REDRAW = 0x02,
207 WIN_FOCUSED = 0x04,
208 WIN_FIRSTTIME = 0x08
212 ////////////////////////////////////////////////////////////////////////////////
213 typedef unsigned char uchar;
214 typedef unsigned int uint;
215 typedef uint32_t uint32;
216 typedef uint16_t ushort;
219 typedef struct __attribute__((packed)) {
220 /* character code */
221 union __attribute__((packed)) {
222 uint32 uc;
223 char c[UTF_SIZ];
225 uchar attr; /* attribute flags */
226 ushort fg; /* foreground */
227 ushort bg; /* background */
228 uchar state; /* state flags */
229 } Glyph;
231 typedef Glyph *Line;
234 typedef struct {
235 Glyph attr; /* current char attributes */
236 int x;
237 int y;
238 char state;
239 } TCursor;
242 /* CSI Escape sequence structs */
243 /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
244 typedef struct {
245 char buf[ESC_BUF_SIZ]; /* raw string */
246 int len; /* raw string length */
247 char priv;
248 int arg[ESC_ARG_SIZ];
249 int narg; /* nb of args */
250 char mode;
251 } CSIEscape;
254 /* Purely graphic info */
255 typedef struct {
256 Display *dpy;
257 Colormap cmap;
258 Window win;
259 Cursor cursor;
260 Cursor blankPtr;
261 Atom xembed;
262 XIM xim;
263 XIC xic;
264 int scr;
265 int w; /* window width */
266 int h; /* window height */
267 int bufw; /* pixmap width */
268 int bufh; /* pixmap height */
269 int ch; /* char height */
270 int cw; /* char width */
271 char state; /* focus, redraw, visible */
273 int tch; /* tab text char height */
274 Pixmap pictab;
275 int tabheight;
276 //struct timeval lastdraw;
277 } XWindow;
280 /* TODO: use better name for vars... */
281 typedef struct {
282 int mode;
283 int bx, by;
284 int ex, ey;
285 struct { int x, y; } b, e;
286 char *clip;
287 Atom xtarget;
288 MSTime tclick1;
289 MSTime tclick2;
290 } Selection;
293 /* Drawing Context */
294 typedef struct {
295 uint32 *ncol; // normal colors
296 uint32 *bcol; // b/w colors
297 uint32 *gcol; // green colors
298 uint32 *clrs[3];
299 GC gc;
300 struct {
301 int ascent;
302 int descent;
303 short lbearing;
304 short rbearing;
305 XFontSet set;
306 Font fid;
307 } font[3];
308 } DC;
311 typedef struct CmdLine CmdLine;
312 typedef struct Term Term;
314 typedef void (*CmdLineExecFn) (Term *term, CmdLine *cmdline, int cancelled);
316 struct CmdLine {
317 int cmdMode; // CMDMODE_xxx
318 char cmdline[UTF_SIZ*CMDLINE_SIZE];
319 int cmdreslen; // byte length of 'reserved' (read-only) part
320 int cmdofs; // byte offset of the first visible UTF-8 char in cmdline
321 char cmdc[UTF_SIZ+1]; // buffer to collect UTF-8 char
322 int cmdcl; // index in cmdc, used to collect UTF-8 chars
323 int cmdtabpos; // # of bytes (not UTF-8 chars!) used in autocompletion or -1
324 const char *cmdcurtabc; // current autocompleted command
325 CmdLineExecFn cmdexecfn;
326 void *udata;
330 /* Internal representation of the screen */
331 struct Term {
332 int cmdfd;
333 int dead;
334 int exitcode;
335 int waitkeypress; /* child is dead, awaiting for keypress */
336 char *exitmsg; /* message for waitkeypress */
337 int needConv; /* 0: utf-8 locale */
338 int belltype;
339 int blackandwhite;
340 int fastredraw;
341 int justSwapped;
343 int curblink;
344 int curbhidden;
345 MSTime lastBlinkTime;
346 int curblinkinactive;
348 int row; /* nb row */
349 int col; /* nb col */
350 int topline; /* top line for drawing (0: no history; 1: show one history line; etc) */
351 int linecount; /* full, with history */
352 int maxhistory;/* max history lines; 0: none; <0: infinite */
353 Line *line; /* screen */
354 Line *alt; /* alternate screen */
355 char *dirty; /* dirtyness of lines */
356 TCursor c; /* cursor */
357 int top; /* top scroll limit */
358 int bot; /* bottom scroll limit */
359 int mode; /* terminal mode flags */
360 int mousemode; /* mouse mode: 1000, 1005, 1006, 1015 */
361 int esc; /* escape state flags */
362 int charset; /* 0 or 1 */
364 TCursor csaved; /* saved cursor info */
365 // old cursor position
366 int oldcx;
367 int oldcy;
369 char title[ESC_TITLE_SIZ+1];
370 int titlelen;
372 int mouseob;
373 int mouseox;
374 int mouseoy;
376 char obuf[OBUFSIZ];
377 #ifdef DUMP_PROG_OUTPUT
378 int xobuflen;
379 #endif
380 int obuflen;
382 char ubuf[UTF_SIZ];
383 int ubufpos;
385 char drawbuf[DRAW_BUF_SIZ];
387 char wrbuf[WBUFSIZ];
388 int wrbufsize;
389 int wrbufused;
390 int wrbufpos;
392 CSIEscape escseq;
393 Selection sel;
394 pid_t pid;
395 MSTime lastDrawTime;
397 char *execcmd;
399 Pixmap picbuf;
400 int picbufw;
401 int picbufh;
403 ushort deffg;
404 ushort defbg;
406 int wantRedraw;
408 MSTime lastActiveTime;
410 CmdLine cmdline;
414 ////////////////////////////////////////////////////////////////////////////////
415 #include "globals.c"
418 ////////////////////////////////////////////////////////////////////////////////
419 #include "utf8.c"
420 #include "utils.c"
421 #include "keymaps.c"
424 ////////////////////////////////////////////////////////////////////////////////
425 static void executeCommands (const char *str);
426 static const char *findCommandCompletion (const char *str, int slen, const char *prev);
428 static void ttyresize (Term *term);
429 static void tsetattr (Term *term, int *attr, int l);
430 static void tresetattrs (Term *term);
431 static int tdowrap (Term *term);
432 static void tputc (Term *term, const char *c); // `c` is utf-8
433 static void ttywrite (Term *term, const char *s, size_t n);
434 static void ttywritenoenc (Term *term, const char *s, size_t n);
435 static void tsetdirt (Term *term, int top, int bot);
436 static void tfulldirt (Term *term);
438 static void tdrawfatalmsg (Term *term, const char *msg);
440 static void xclearunused (void);
441 static void xseturgency (int add);
442 static void xfixsel (void);
443 static void xblankPointer (void);
444 static void xunblankPointer (void);
445 static void xdrawTabBar (void);
447 static void draw (Term *term, int forced);
449 static void tcmdput (Term *term, CmdLine *cmdline, const char *s, int len);
452 ////////////////////////////////////////////////////////////////////////////////
453 static inline void ttywritestr (Term *term, const char *s) { if (s != NULL && s[0]) ttywrite(term, s, strlen(s)); }
454 static inline void ttywritestrnoenc (Term *term, const char *s) { if (s != NULL && s[0]) ttywritenoenc(term, s, strlen(s)); }
456 //FIXME: do utf-8!
457 static inline void tputstr (Term *term, const char *s) { if (s != NULL) while (*s) { tputc(term, s); ++s; } }
460 static inline uint32 getColor (int idx) {
461 if (globalBW && (curterm == NULL || !curterm->blackandwhite)) return dc.clrs[globalBW][idx];
462 if (curterm != NULL) return dc.clrs[curterm->blackandwhite%3][idx];
463 return dc.clrs[0][idx];
467 ////////////////////////////////////////////////////////////////////////////////
468 #include "iniparse.c"
469 #include "locales.c"
472 ////////////////////////////////////////////////////////////////////////////////
473 #include "termswitch.c"
476 ////////////////////////////////////////////////////////////////////////////////
477 #include "selection.c"
478 #include "tabmouseutils.c"
479 #include "mouseevents.c"
482 ////////////////////////////////////////////////////////////////////////////////
483 #include "ttyinit.c"
484 #include "ttyrw.c"
485 #include "ttyresizeioctl.c"
486 #include "ttyutils.c"
487 #include "ttyputc.c"
488 #include "ttyresize.c"
491 ////////////////////////////////////////////////////////////////////////////////
492 #include "tcmdline.c"
493 #include "tfatalbox.c"
496 ////////////////////////////////////////////////////////////////////////////////
497 #include "x11misc.c"
498 #include "x11drawstr.c"
499 #include "x11drawcur.c"
500 #include "x11drawtabs.c"
501 #include "x11drawcmdline.c"
502 #include "x11draw.c"
505 ////////////////////////////////////////////////////////////////////////////////
506 #include "x11evtvis.c"
507 #include "x11evtkbd.c"
510 ////////////////////////////////////////////////////////////////////////////////
511 // xembed?
512 static void xevtcbcmessage (XEvent *e) {
513 /* See xembed specs http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */
514 if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
515 if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
516 xw.state |= WIN_FOCUSED;
517 xseturgency(0);
518 tsendfocusevent(curterm, 1);
519 } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
520 xw.state &= ~WIN_FOCUSED;
521 tsendfocusevent(curterm, 0);
523 xdrawcursor(curterm);
524 xdrawTabBar();
525 xcopy(curterm, 0, 0, curterm->col, curterm->row);
526 return;
529 if (e->xclient.data.l[0] == XA_WM_DELETE_WINDOW) {
530 closeRequestComes = 1;
531 return;
536 ////////////////////////////////////////////////////////////////////////////////
537 static inline int last_draw_too_old (void) {
538 MSTime tt = mclock_ticks();
540 if (curterm != NULL) {
541 if (curterm->dead || !curterm->wantRedraw) return 0;
543 return
544 (tt-curterm->lastDrawTime >= opt_drawtimeout ||
545 tt-lastDrawTime >= (curterm->justSwapped ? opt_swapdrawtimeout : opt_maxdrawtimeout));
547 return (tt-lastDrawTime >= opt_maxdrawtimeout);
551 ////////////////////////////////////////////////////////////////////////////////
552 // main loop
553 static void (*handler[LASTEvent])(XEvent *) = {
554 [KeyPress] = xevtcbkpress,
555 [ClientMessage] = xevtcbcmessage,
556 [ConfigureNotify] = xevtcbresise,
557 [VisibilityNotify] = xevtcbvisibility,
558 [UnmapNotify] = xevtcbunmap,
559 [Expose] = xevtcbexpose,
560 [FocusIn] = xevtcbfocus,
561 [FocusOut] = xevtcbfocus,
562 [MotionNotify] = xevtcbbmotion,
563 [ButtonPress] = xevtcbbpress,
564 [ButtonRelease] = xevtcbbrelease,
565 [SelectionNotify] = xevtcbselnotify,
566 [SelectionRequest] = xevtcbselrequest,
567 [SelectionClear] = xevtcbselclear,
571 static void run (void) {
572 //int stuff_to_print = 0;
573 int xfd = XConnectionNumber(xw.dpy);
575 ptrLastMove = mclock_ticks();
576 while (term_count > 0) {
577 XEvent ev;
578 fd_set rfd, wfd;
579 struct timeval timeout;
580 int maxfd = xfd;
581 int dodraw;
583 FD_ZERO(&rfd);
584 FD_ZERO(&wfd);
585 FD_SET(xfd, &rfd);
586 //FD_SET(curterm->cmdfd, &rfd);
587 // have something to write?
588 for (int f = 0; f < term_count; ++f) {
589 Term *t = term_array[f];
591 if (!t->dead && t->cmdfd >= 0) {
592 if (t->cmdfd > maxfd) maxfd = t->cmdfd;
593 FD_SET(t->cmdfd, &rfd);
594 if (t->pid != 0 && t->wrbufpos < t->wrbufused) FD_SET(t->cmdfd, &wfd);
598 timeout.tv_sec = 0;
599 timeout.tv_usec = (opt_drawtimeout+2)*1000;
600 //fprintf(stderr, "before select...\n");
601 if (select(maxfd+1, &rfd, &wfd, NULL, &timeout) < 0) {
602 if (errno == EINTR) continue;
603 die("select failed: %s", SERRNO);
605 //fprintf(stderr, "after select...\n");
606 // process terminals i/o
607 for (int f = 0; f < term_count; ++f) {
608 Term *t = term_array[f];
610 if (!t->dead && t->cmdfd >= 0) {
611 int rd = -1;
613 if (t->pid != 0 && FD_ISSET(t->cmdfd, &wfd)) ttyflushwrbuf(t);
614 if (FD_ISSET(t->cmdfd, &rfd)) rd = ttyread(t);
616 if (t->waitkeypress && t->exitmsg != NULL && rd < 0) {
617 // there will be no more data
618 close(t->cmdfd);
619 t->cmdfd = -1;
621 tdrawfatalmsg(t, t->exitmsg);
622 free(t->exitmsg);
623 t->exitmsg = NULL;
624 setWantRedraw(t, 1);
629 //fprintf(stderr, "000: term=%p; dead=%d; waitkeypress=%d\n", term, (term ? term->dead : 666), (term ? term->waitkeypress : 666));
630 termcleanup();
631 //fprintf(stderr, "001: term=%p; dead=%d; waitkeypress=%d\n", term, (term ? term->dead : 666), (term ? term->waitkeypress : 666));
632 if (term_count == 0) exit(exitcode);
634 dodraw = 0;
635 if (curterm != NULL && curterm->curblink > 0) {
636 MSTime tt = mclock_ticks();
638 if (tt-curterm->lastBlinkTime >= curterm->curblink) {
639 curterm->lastBlinkTime = tt;
640 if ((xw.state&WIN_FOCUSED) || curterm->curblinkinactive) {
641 curterm->curbhidden = (curterm->curbhidden ? 0 : -1);
642 dodraw = 1;
643 } else {
644 curterm->curbhidden = 0;
648 if (updateTabBar) xdrawTabBar();
649 if (dodraw || last_draw_too_old()) draw(curterm, 0);
651 if (XPending(xw.dpy)) {
652 while (XPending(xw.dpy)) {
653 XNextEvent(xw.dpy, &ev);
654 switch (ev.type) {
655 //case VisibilityNotify:
656 //case UnmapNotify:
657 //case FocusIn:
658 //case FocusOut:
659 case MotionNotify:
660 case ButtonPress:
661 case ButtonRelease:
662 xunblankPointer();
663 ptrLastMove = mclock_ticks();
664 break;
665 default: ;
667 if (XFilterEvent(&ev, xw.win)) continue;
668 if (handler[ev.type]) (handler[ev.type])(&ev);
672 if (curterm != NULL) {
673 switch (closeRequestComes) {
674 case 1: // just comes
675 if (opt_ignoreclose == 0) {
676 tcmdlinehide(curterm, &curterm->cmdline);
677 tcmdlineinitex(curterm, &curterm->cmdline, "Do you really want to close sterm [Y/n]? ");
678 curterm->cmdline.cmdexecfn = cmdline_closequeryexec;
679 } else if (opt_ignoreclose < 0) {
680 //FIXME: kill all clients?
681 return;
683 closeRequestComes = 0;
684 break;
685 case 2: // ok, die now
686 //FIXME: kill all clients?
687 return;
691 if (!ptrBlanked && opt_ptrblank > 0 && mclock_ticks()-ptrLastMove >= opt_ptrblank) {
692 xblankPointer();
698 ////////////////////////////////////////////////////////////////////////////////
699 #include "inifile.c"
700 #include "commands.c"
703 ////////////////////////////////////////////////////////////////////////////////
704 #include "childkiller.c"
707 ////////////////////////////////////////////////////////////////////////////////
708 int main (int argc, char *argv[]) {
709 char *configfile = NULL;
710 char *runcmd = NULL;
712 //dbgLogInit();
714 for (int f = 1; f < argc; f++) {
715 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
716 if (strcmp(argv[f], "-into") == 0) { ++f; continue; }
717 if (strcmp(argv[f], "-embed") == 0) { ++f; continue; }
718 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
719 case 'e': f = argc+1; break;
720 case 't':
721 case 'c':
722 case 'w':
723 case 'b':
724 case 'R':
725 ++f;
726 break;
727 case 'T':
728 if (++f < argc) {
729 free(opt_term);
730 opt_term = strdup(argv[f]);
731 opt_term_locked = 1;
733 break;
734 case 'C':
735 if (++f < argc) {
736 if (configfile != NULL) free(configfile);
737 configfile = strdup(argv[f]);
739 break;
740 case 'l':
741 if (++f < argc) cliLocale = argv[f];
742 break;
743 case 'S': // single-tab mode
744 opt_disabletabs = 1;
745 break;
746 case 'v':
747 fprintf(stderr, "%s", USAGE_VERSION);
748 exit(EXIT_FAILURE);
749 case 'h':
750 default:
751 fprintf(stderr, "%s%s", USAGE_VERSION, USAGE);
752 exit(EXIT_FAILURE);
756 initDefaultOptions();
757 if (configfile == NULL) {
758 const char *home = getenv("HOME");
760 if (home != NULL) {
761 configfile = SPrintf("%s/.sterm.rc", home);
762 if (loadConfig(configfile) == 0) goto cfgdone;
763 free(configfile); configfile = NULL;
765 configfile = SPrintf("%s/.config/sterm.rc", home);
766 if (loadConfig(configfile) == 0) goto cfgdone;
767 free(configfile); configfile = NULL;
770 configfile = SPrintf("/etc/sterm.rc");
771 if (loadConfig(configfile) == 0) goto cfgdone;
772 free(configfile); configfile = NULL;
774 configfile = SPrintf("/etc/sterm/sterm.rc");
775 if (loadConfig(configfile) == 0) goto cfgdone;
776 free(configfile); configfile = NULL;
778 configfile = SPrintf("./.sterm.rc");
779 if (loadConfig(configfile) == 0) goto cfgdone;
780 free(configfile); configfile = NULL;
781 // no config
782 } else {
783 if (loadConfig(configfile) < 0) die("config file '%s' not found!", configfile);
785 cfgdone:
786 if (configfile != NULL) free(configfile); configfile = NULL;
788 for (int f = 1; f < argc; f++) {
789 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
790 if (strcmp(argv[f], "-into") == 0 || strcmp(argv[f], "-embed") == 0) {
791 if (opt_embed) free(opt_embed);
792 opt_embed = strdup(argv[f]);
793 continue;
795 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
796 case 't':
797 if (++f < argc) {
798 free(opt_title);
799 opt_title = strdup(argv[f]);
801 break;
802 case 'c':
803 if (++f < argc) {
804 free(opt_class);
805 opt_class = strdup(argv[f]);
807 break;
808 case 'w':
809 if (++f < argc) {
810 if (opt_embed) free(opt_embed);
811 opt_embed = strdup(argv[f]);
813 break;
814 case 'R':
815 if (++f < argc) runcmd = argv[f];
816 break;
817 case 'e':
818 /* eat all remaining arguments */
819 if (++f < argc) opt_cmd = &argv[f];
820 f = argc+1;
821 case 'T':
822 case 'C':
823 case 'l':
824 ++f;
825 break;
826 case 'S':
827 break;
831 setenv("TERM", opt_term, 1);
832 mclock_init();
833 setlocale(LC_ALL, "");
834 initLCConversion();
835 summonChildKiller();
836 updateTabBar = 1;
837 termidx = 0;
838 curterm = termalloc();
839 if (curterm->execcmd != NULL) { free(curterm->execcmd); curterm->execcmd = NULL; }
840 tinitialize(curterm, 80, 25);
841 if (ttynew(curterm) != 0) die("can't run process");
842 opt_cmd = NULL;
843 xinit();
844 selinit(curterm);
845 if (runcmd != NULL) executeCommands(runcmd);
846 run();
847 return 0;