experimental hackfix for non-existing problem ;-)
[k8sterm.git] / src / sterm.c
blob59acd0a532f9d08162352f1638ae0e5844d7070a
1 /* See LICENSE for licence details. */
2 #ifndef GIT_VERSION
3 # define VERSION "0.4.0.beta3"
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>
21 #ifdef __MACH__
22 #include <util.h>
23 #else
24 #include <pty.h>
25 #endif
27 #include <stdarg.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <signal.h>
34 #include <sys/ioctl.h>
35 #include <sys/select.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <sys/wait.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include <X11/Xatom.h>
43 #include <X11/Xlib.h>
44 #include <X11/Xutil.h>
45 #include <X11/cursorfont.h>
46 #include <X11/keysym.h>
48 ////////////////////////////////////////////////////////////////////////////////
49 #include "libk8sterm/k8sterm.h"
52 ////////////////////////////////////////////////////////////////////////////////
53 #include "defaults.c"
56 ////////////////////////////////////////////////////////////////////////////////
57 #define USAGE_VERSION "k8sterm " VERSION "\n(c) 2010-2012 st engineers and Ketmar // Vampire Avalon\n"
58 #define USAGE \
59 "usage: sterm [options]\n" \
60 "options:\n" \
61 "-v show version and exit\n" \
62 "-h show this help and exit\n" \
63 "-S disable tabs\n" \
64 "-t title set window title\n" \
65 "-c class set window class\n" \
66 "-w windowid embed in window id given id\n" \
67 "-T termname set TERM name\n" \
68 "-C config_file use custom config file\n" \
69 "-l langiconv use given locale\n" \
70 "-R stcmd run this INTERNAL k8sterm command\n" \
71 "-e command... run given command and pass all following args to it\n"
74 ////////////////////////////////////////////////////////////////////////////////
75 /* masks for key translation */
76 #define XK_NO_MOD (UINT_MAX)
77 #define XK_ANY_MOD (0)
80 ////////////////////////////////////////////////////////////////////////////////
81 // internal command line mode
82 enum {
83 K8T_CMDMODE_NONE,
84 K8T_CMDMODE_INPUT,
85 K8T_CMDMODE_MESSAGE
89 // X11 window state flags
90 enum {
91 K8T_WIN_VISIBLE = 0x01,
92 K8T_WIN_REDRAW = 0x02,
93 K8T_WIN_FOCUSED = 0x04
97 ////////////////////////////////////////////////////////////////////////////////
98 /* Purely graphic info */
99 typedef struct {
100 Display *dpy;
101 Colormap cmap;
102 Window win;
103 Cursor cursor; // text cursor
104 Cursor defcursor; // 'default' cursor
105 Cursor lastcursor; // last used cursor before blanking
106 Cursor blankPtr;
107 Atom xembed;
108 XIM xim;
109 XIC xic;
110 int scr;
111 int w; /* window width */
112 int h; /* window height */
113 int bufw; /* pixmap width */
114 int bufh; /* pixmap height */
115 int ch; /* char height */
116 int cw; /* char width */
117 char state; /* focus, redraw, visible */
119 int tch; /* tab text char height */
120 Pixmap pictab;
121 int tabheight;
122 //struct timeval lastdraw;
123 } K8TXWindow;
126 /* Drawing Context */
127 typedef struct {
128 uint32_t *ncol; // normal colors
129 uint32_t *bcol; // b/w colors
130 uint32_t *gcol; // green colors
131 uint32_t *clrs[3];
132 GC gc;
133 struct {
134 int ascent;
135 int descent;
136 short lbearing;
137 short rbearing;
138 XFontSet set;
139 Font fid;
140 } font[3];
141 } K8TXDC;
144 typedef struct K8TCmdLine K8TCmdLine;
146 typedef void (*CmdLineExecFn) (K8Term *term, K8TCmdLine *cmdline, int cancelled);
148 struct K8TCmdLine {
149 int cmdMode; // K8T_CMDMODE_xxx
150 char cmdline[K8T_UTF_SIZ*CMDLINE_SIZE];
151 int cmdreslen; // byte length of 'reserved' (read-only) part
152 int cmdofs; // byte offset of the first visible UTF-8 char in cmdline
153 char cmdc[K8T_UTF_SIZ+1]; // buffer to collect UTF-8 char
154 int cmdcl; // index in cmdc, used to collect UTF-8 chars
155 int cmdtabpos; // # of bytes (not UTF-8 chars!) used in autocompletion or -1
156 const char *cmdcurtabc; // current autocompleted command
157 CmdLineExecFn cmdexecfn;
158 void *udata;
162 /* internal terminal data */
163 typedef struct {
164 pid_t pid;
165 int exitcode;
167 int waitkeypress; /* child is dead, awaiting for keypress */
168 char *exitmsg; /* message for waitkeypress */
170 char *execcmd;
172 int picalloced;
173 Pixmap picbuf;
174 int picbufw;
175 int picbufh;
177 K8TCmdLine cmdline;
178 } K8TermData;
180 #define K8T_DATA(_term) ((K8TermData *)(_term->udata))
183 ////////////////////////////////////////////////////////////////////////////////
184 #include "globals.c"
185 #include "getticks.c"
188 ////////////////////////////////////////////////////////////////////////////////
189 #include "utils.c"
190 #include "keymaps.c"
193 ////////////////////////////////////////////////////////////////////////////////
194 static void executeCommands (const char *str);
195 static const char *findCommandCompletion (const char *str, int slen, const char *prev);
197 static void tdrawfatalmsg (K8Term *term, const char *msg);
199 static void tcmdput (K8Term *term, K8TCmdLine *cmdline, const char *s, int len);
201 static void xclearunused (void);
202 static void xseturgency (int add);
203 static void xfixsel (void);
204 static void xblankPointer (void);
205 static void xunblankPointer (void);
206 static void xdrawTabBar (void);
207 static void xdrawcmdline (K8Term *term, K8TCmdLine *cmdline, int scry);
209 static void termCreateXPixmap (K8Term *term);
210 static void termSetCallbacks (K8Term *term);
211 static void termSetDefaults (K8Term *term);
213 static void getButtonInfo (K8Term *term, XEvent *e, int *b, int *x, int *y);
215 static void fixWindowTitle (const K8Term *t);
217 static void scrollHistory (K8Term *term, int delta);
220 ////////////////////////////////////////////////////////////////////////////////
221 static inline uint32_t getColor (int idx) {
222 if (globalBW && (curterm == NULL || !curterm->blackandwhite)) return dc.clrs[globalBW][idx];
223 if (curterm != NULL) return dc.clrs[curterm->blackandwhite%3][idx];
224 return dc.clrs[0][idx];
228 ////////////////////////////////////////////////////////////////////////////////
229 #include "iniparse.c"
230 #include "locales.c"
233 ////////////////////////////////////////////////////////////////////////////////
234 #include "termswitch.c"
235 #include "ttyinit.c"
238 ////////////////////////////////////////////////////////////////////////////////
239 #include "tcmdline.c"
240 #include "tfatalbox.c"
243 ////////////////////////////////////////////////////////////////////////////////
244 #include "x11init.c"
245 #include "x11misc.c"
246 #include "x11drawtabs.c"
247 #include "x11drawcmdline.c"
250 ////////////////////////////////////////////////////////////////////////////////
251 #include "x11evtvis.c"
252 #include "x11evtkbd.c"
253 #include "x11evtsel.c"
254 #include "x11evtmouse.c"
257 ////////////////////////////////////////////////////////////////////////////////
258 #include "x11CB.c"
261 ////////////////////////////////////////////////////////////////////////////////
262 // xembed?
263 static void xevtcbcmessage (XEvent *e) {
264 /* See xembed specs http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html */
265 if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) {
266 if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) {
267 xw.state |= K8T_WIN_FOCUSED;
268 xseturgency(0);
269 k8t_tmSendFocusEvent(curterm, 1);
270 } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) {
271 xw.state &= ~K8T_WIN_FOCUSED;
272 k8t_tmSendFocusEvent(curterm, 0);
274 k8t_drawCursor(curterm, 0);
275 xdrawTabBar();
276 k8t_drawCopy(curterm, 0, 0, curterm->col, curterm->row);
277 return;
280 if (e->xclient.data.l[0] == XA_WM_DELETE_WINDOW) {
281 closeRequestComes = 1;
282 return;
287 ////////////////////////////////////////////////////////////////////////////////
288 static inline int last_draw_too_old (void) {
289 K8TTimeMSec tt = mclock_ticks();
291 if (curterm != NULL) {
292 if (curterm->dead || !curterm->wantRedraw) return 0;
294 return
295 (tt-curterm->lastDrawTime >= opt_drawtimeout ||
296 tt-lastDrawTime >= (curterm->justSwapped ? opt_swapdrawtimeout : opt_maxdrawtimeout));
298 return (tt-lastDrawTime >= opt_maxdrawtimeout);
302 ////////////////////////////////////////////////////////////////////////////////
303 // main loop
304 static void (*handler[LASTEvent])(XEvent *) = {
305 [KeyPress] = xevtcbkpress,
306 [ClientMessage] = xevtcbcmessage,
307 [ConfigureNotify] = xevtcbresise,
308 [VisibilityNotify] = xevtcbvisibility,
309 [UnmapNotify] = xevtcbunmap,
310 [Expose] = xevtcbexpose,
311 [FocusIn] = xevtcbfocus,
312 [FocusOut] = xevtcbfocus,
313 [MotionNotify] = xevtcbbmotion,
314 [ButtonPress] = xevtcbbpress,
315 [ButtonRelease] = xevtcbbrelease,
316 [SelectionNotify] = xevtcbselnotify,
317 [SelectionRequest] = xevtcbselrequest,
318 [SelectionClear] = xevtcbselclear,
322 static void run (void) {
323 //int stuff_to_print = 0;
324 int xfd = XConnectionNumber(xw.dpy);
326 ptrLastMove = mclock_ticks();
327 while (term_count > 0) {
328 XEvent ev;
329 fd_set rfd, wfd;
330 struct timeval timeout;
331 int maxfd = xfd;
332 int dodraw;
334 FD_ZERO(&rfd);
335 FD_ZERO(&wfd);
336 FD_SET(xfd, &rfd);
337 //FD_SET(curterm->cmdfd, &rfd);
338 // have something to write?
339 for (int f = 0; f < term_count; ++f) {
340 K8Term *t = term_array[f];
342 if (!t->dead && t->cmdfd >= 0) {
343 if (t->cmdfd > maxfd) maxfd = t->cmdfd;
344 FD_SET(t->cmdfd, &rfd);
345 if (K8T_DATA(t)->pid != 0 && t->wrbufpos < t->wrbufused) FD_SET(t->cmdfd, &wfd);
349 timeout.tv_sec = 0;
350 timeout.tv_usec = (opt_drawtimeout+2)*1000;
351 //fprintf(stderr, "before select...\n");
352 if (select(maxfd+1, &rfd, &wfd, NULL, &timeout) < 0) {
353 if (errno == EINTR) continue;
354 k8t_die("select failed: %s", strerror(errno));
356 //fprintf(stderr, "after select...\n");
357 // process terminals i/o
358 for (int f = 0; f < term_count; ++f) {
359 K8Term *t = term_array[f];
361 if (!t->dead && t->cmdfd >= 0) {
362 int rd = -1;
364 if (K8T_DATA(t)->pid != 0 && FD_ISSET(t->cmdfd, &wfd)) k8t_ttyFlushWriteBuf(t);
365 if (FD_ISSET(t->cmdfd, &rfd)) rd = k8t_ttyRead(t);
367 if (K8T_DATA(t)->waitkeypress && K8T_DATA(t)->exitmsg != NULL && rd < 0) {
368 // there will be no more data
369 close(t->cmdfd);
370 t->cmdfd = -1;
372 tdrawfatalmsg(t, K8T_DATA(t)->exitmsg);
373 free(K8T_DATA(t)->exitmsg);
374 K8T_DATA(t)->exitmsg = NULL;
375 k8t_tmWantRedraw(t, 1);
380 termcleanup();
381 if (term_count == 0) exit(exitcode);
383 dodraw = 0;
384 if (curterm != NULL && curterm->curblink > 0) {
385 K8TTimeMSec tt = mclock_ticks();
387 if (tt-curterm->lastBlinkTime >= curterm->curblink) {
388 curterm->lastBlinkTime = tt;
389 if ((xw.state&K8T_WIN_FOCUSED) || curterm->curblinkinactive) {
390 curterm->curbhidden = (curterm->curbhidden ? 0 : -1);
391 dodraw = 1;
392 } else {
393 curterm->curbhidden = 0;
397 if (updateTabBar) xdrawTabBar();
398 if (dodraw || last_draw_too_old()) k8t_drawTerm(curterm, 0);
400 if (XPending(xw.dpy)) {
401 while (XPending(xw.dpy)) {
402 XNextEvent(xw.dpy, &ev);
403 switch (ev.type) {
404 //case VisibilityNotify:
405 //case UnmapNotify:
406 //case FocusIn:
407 //case FocusOut:
408 case MotionNotify:
409 case ButtonPress:
410 case ButtonRelease:
411 xunblankPointer();
412 ptrLastMove = mclock_ticks();
413 break;
414 default: ;
416 if (XFilterEvent(&ev, xw.win)) continue;
417 if (handler[ev.type]) (handler[ev.type])(&ev);
421 if (curterm != NULL) {
422 switch (closeRequestComes) {
423 case 1: // just comes
424 if (opt_ignoreclose == 0) {
425 tcmdlinehide(curterm, &K8T_DATA(curterm)->cmdline);
426 tcmdlineinitex(curterm, &K8T_DATA(curterm)->cmdline, "Do you really want to close sterm [Y/n]? ");
427 K8T_DATA(curterm)->cmdline.cmdexecfn = cmdline_closequeryexec;
428 } else if (opt_ignoreclose < 0) {
429 //FIXME: kill all clients?
430 return;
432 closeRequestComes = 0;
433 break;
434 case 2: // ok, die now
435 //FIXME: kill all clients?
436 return;
440 if (!ptrBlanked && opt_ptrblank > 0 && mclock_ticks()-ptrLastMove >= opt_ptrblank) {
441 xblankPointer();
447 ////////////////////////////////////////////////////////////////////////////////
448 static void termSetDefaults (K8Term *term) {
449 term->deffg = defaultFG;
450 term->defbg = defaultBG;
451 term->defboldfg = defaultBoldFG;
452 term->defunderfg = defaultUnderlineFG;
454 term->defcurfg = defaultCursorFG;
455 term->defcurbg = defaultCursorBG;
456 term->defcurinactivefg = defaultCursorInactiveFG;
457 term->defcurinactivebg = defaultCursorInactiveBG;
459 term->tabsize = opt_tabsize;
460 term->wrapOnCtrlChars = 0;
464 static void termSetCallbacks (K8Term *term) {
465 K8TermData *td = calloc(1, sizeof(K8TermData));
467 if (td == NULL) k8t_die("out of memory!");
468 term->udata = td;
470 term->clockTicks = clockTicksCB;
471 term->setLastDrawTime = setLastDrawTimeCB;
473 term->isConversionNecessary = isConversionNecessaryCB;
474 term->loc2utf = loc2utfCB;
475 term->utf2loc = utf2locCB;
477 term->isFocused = isFocusedCB;
478 term->isVisible = isVisibleCB;
480 term->drawSetFG = drawSetFGCB;
481 term->drawSetBG = drawSetBGCB;
482 term->drawRect = drawRectCB;
483 term->drawFillRect = drawFillRectCB;
484 term->drawCopyArea = drawCopyAreaCB;
485 term->drawString = drawStringCB;
486 term->drawOverlay = drawOverlayCB;
488 term->fixSelection = fixSelectionCB;
489 term->clearSelection = clearSelectionCB;
491 term->titleChanged = titleChangedCB;
492 term->doBell = doBellCB;
494 term->isUnderOverlay = isUnderOverlayCB;
495 term->clipToOverlay = clipToOverlayCB;
497 term->unimap = unimap;
498 td->execcmd = NULL;
502 static void termCreateXPixmap (K8Term *term) {
503 K8TermData *td = K8T_DATA(term);
504 Pixmap newbuf;
505 //int oldw = td->picbufw, oldh = td->picbufh;
507 td->picbufw = K8T_MAX(1, term->col*xw.cw);
508 td->picbufh = K8T_MAX(1, term->row*xw.ch);
510 newbuf = XCreatePixmap(xw.dpy, xw.win, td->picbufw, td->picbufh, XDefaultDepth(xw.dpy, xw.scr));
512 if (td->picalloced) {
513 //XCopyArea(xw.dpy, td->picbuf, newbuf, dc.gc, 0, 0, td->picbufw, td->picbufh, 0, 0);
514 XFreePixmap(xw.dpy, td->picbuf);
517 term->drawSetFG(term, term->defbg);
520 if (td->picalloced) {
521 if (td->picbufw > oldw) {
522 XFillRectangle(xw.dpy, newbuf, dc.gc, oldw, 0, td->picbufw-oldw, K8T_MIN(td->picbufh, oldh));
523 } else if (td->picbufw < oldw && xw.w > td->picbufw) {
524 XClearArea(xw.dpy, xw.win, td->picbufw, 0, xw.w-td->picbufh, K8T_MIN(td->picbufh, oldh), False);
527 if (td->picbufh > oldh) {
528 XFillRectangle(xw.dpy, newbuf, dc.gc, 0, oldh, td->picbufw, td->picbufh-oldh);
529 } else if (td->picbufh < oldh && xw.h > td->picbufh) {
530 XClearArea(xw.dpy, xw.win, 0, td->picbufh, xw.w, xw.h-td->picbufh, False);
532 } else {
533 XFillRectangle(xw.dpy, newbuf, dc.gc, 0, 0, td->picbufw, td->picbufh);
536 XFillRectangle(xw.dpy, newbuf, dc.gc, 0, 0, td->picbufw, td->picbufh);
538 td->picalloced = 1;
539 td->picbuf = newbuf;
541 k8t_tmFullDirty(term);
545 ////////////////////////////////////////////////////////////////////////////////
546 #include "inifile.c"
547 #include "commands.c"
550 ////////////////////////////////////////////////////////////////////////////////
551 #include "childkiller.c"
554 ////////////////////////////////////////////////////////////////////////////////
555 #define PUSH_BACK(_c) (*ress)[dpos++] = (_c)
556 #define DECODE_TUPLE(tuple,bytes) \
557 for (tmp = bytes; tmp > 0; tmp--, tuple = (tuple & 0x00ffffff)<<8) \
558 PUSH_BACK((char)((tuple >> 24)&0xff))
560 // returns ress length
561 static int ascii85Decode (char **ress, const char *srcs/*, int start, int length*/) {
562 static uint32_t pow85[5] = { 85*85*85*85UL, 85*85*85UL, 85*85UL, 85UL, 1UL };
563 const uint8_t *data = (const uint8_t *)srcs;
564 int len = strlen(srcs);
565 uint32_t tuple = 0;
566 int count = 0, c = 0;
567 int dpos = 0;
568 int start = 0, length = len;
569 int tmp;
571 if (start < 0) start = 0; else { len -= start; data += start; }
572 if (length < 0 || len < length) length = len;
574 if (length > 0) {
575 int xlen = 4*((length+4)/5);
576 kstringReserve(ress, xlen);
580 *ress = (char *)calloc(1, len+1);
581 for (int f = length; f > 0; --f, ++data) {
582 c = *data;
583 if (c <= ' ') continue; // skip blanks
584 switch (c) {
585 case 'z': // zero tuple
586 if (count != 0) {
587 //fprintf(stderr, "%s: z inside ascii85 5-tuple\n", file);
588 free(*ress);
589 *ress = NULL;
590 return -1;
592 PUSH_BACK('\0');
593 PUSH_BACK('\0');
594 PUSH_BACK('\0');
595 PUSH_BACK('\0');
596 break;
597 case '~': // '~>': end of sequence
598 if (f < 1 || data[1] != '>') { free(*ress); return -2; } // error
599 if (count > 0) { f = -1; break; }
600 default:
601 if (c < '!' || c > 'u') {
602 //fprintf(stderr, "%s: bad character in ascii85 region: %#o\n", file, c);
603 free(*ress);
604 return -3;
606 tuple += ((uint8_t)(c-'!'))*pow85[count++];
607 if (count == 5) {
608 DECODE_TUPLE(tuple, 4);
609 count = 0;
610 tuple = 0;
612 break;
615 // write last (possibly incomplete) tuple
616 if (count-- > 0) {
617 tuple += pow85[count];
618 DECODE_TUPLE(tuple, count);
620 return dpos;
623 #undef PUSH_BACK
624 #undef DECODE_TUPLE
627 static void decodeBA (char *str, int len) {
628 char pch = 42;
630 for (int f = 0; f < len; ++f, ++str) {
631 char ch = *str;
633 ch = (ch-f-1)^pch;
634 *str = ch;
635 pch = ch;
640 static void printEC (const char *txt) {
641 char *dest;
642 int len;
644 if ((len = ascii85Decode(&dest, txt)) >= 0) {
645 decodeBA(dest, len);
646 fprintf(stderr, "%s\n", dest);
647 free(dest);
652 static int isStr85Equ (const char *txt, const char *str) {
653 char *dest;
654 int len, res = 0;
656 if (str != NULL && str[0] && (len = ascii85Decode(&dest, txt)) >= 0) {
657 if (len > 0) res = (strcmp(dest+1, str+1) == 0);
658 free(dest);
660 return res;
664 static int checkEGG (const char *str) {
665 if (isStr85Equ("06:]JASq", str) || isStr85Equ("0/i", str)) {
666 printEC(
667 "H8lZV&6)1>+AZ>m)Cf8;A1/cP+CnS)0OJ`X.QVcHA4^cc5r3=m1c%0D3&c263d?EV6@4&>"
668 "3DYQo;c-FcO+UJ;MOJ$TAYO@/FI]+B?C.L$>%:oPAmh:4Au)>AAU/H;ZakL2I!*!%J;(AK"
669 "NIR#5TXgZ6c'F1%^kml.JW5W8e;ql0V3fQUNfKpng6ppMf&ip-VOX@=jKl;#q\"DJ-_>jG"
670 "8#L;nm]!q;7c+hR6p;tVY#J8P$aTTK%c-OT?)<00,+q*8f&ff9a/+sbU,:`<H*[fk0o]7k"
671 "^l6nRkngc6Tl2Ngs!!P2I%KHG=7n*an'bsgn>!*8s7TLTC+^\\\"W+<=9^%Ol$1A1eR*Be"
672 "gqjEag:M0OnrC4FBY5@QZ&'HYYZ#EHs8t4$5]!22QoJ3`;-&=\\DteO$d6FBqT0E@:iu?N"
673 "a5ePUf^_uEEcjTDKfMpX/9]DFL8N-Ee;*8C5'WgbGortZuh1\\N0;/rJB6'(MSmYiS\"6+"
674 "<NK)KDV3e+Ad[@).W:%.dd'0h=!QUhghQaNNotIZGrpHr-YfEuUpsKW<^@qlZcdTDA!=?W"
675 "Yd+-^`'G8Or)<0-T&CT.i+:mJp(+/M/nLaVb#5$p2jR2<rl7\"XlngcN`mf,[4oK5JLr\\"
676 "m=X'(ue;'*1ik&/@T4*=j5t=<&/e/Q+2=((h`>>uN(#>&#i>2/ajK+=eib1coVe3'D)*75"
677 "m_h;28^M6p6*D854Jj<C^,Q8Wd\"O<)&L/=C$lUAQNN<=eTD:A6kn-=EItXSss.tAS&!;F"
678 "EsgpJTHIYNNnh'`kmX^[`*ELOHGcWbfPOT`J]A8P`=)AS;rYlR$\"-.RG440lK5:Dg?G'2"
679 "['dE=nEm1:k,,Se_=%-6Z*L^J[)EC"
681 return 1;
683 if (isStr85Equ("04Jj?B)", str)) {
684 printEC(
685 "IPaSa(`c:T,o9Bq3\\)IY++?+!-S9%P0/OkjE&f$l.OmK'Ai2;ZHn[<,6od7^8;)po:HaP"
686 "m<'+&DRS:/1L7)IA7?WI$8WKTUB2tXg>Zb$.?\"@AIAu;)6B;2_PB5M?oBPDC.F)606Z$V"
687 "=ONd6/5P*LoWKTLQ,d@&;+Ru,\\ESY*rg!l1XrhpJ:\"WKWdOg?l;=RHE:uU9C?aotBqj]"
688 "=k8cZ`rp\"ZO=GjkfD#o]Z\\=6^]+Gf&-UFthT*hN"
690 return 1;
692 if (isStr85Equ("04o69A7Tr", str)) {
693 printEC(
694 "Ag7d[&R#Ma9GVV5,S(D;De<T_+W).?,%4n+3cK=%4+0VN@6d\")E].np7l?8gF#cWF7SS_m"
695 "4@V\\nQ;h!WPD2h#@\\RY&G\\LKL=eTP<V-]U)BN^b.DffHkTPnFcCN4B;]8FCqI!p1@H*_"
696 "jHJ<%g']RG*MLqCrbP*XbNL=4D1R[;I(c*<FuesbWmSCF1jTW+rplg;9[S[7eDVl6YsjT"
698 return 1;
700 return 0;
704 ////////////////////////////////////////////////////////////////////////////////
705 int main (int argc, char *argv[]) {
706 char *configfile = NULL;
707 char *runcmd = NULL;
709 //dbgLogInit();
711 for (int f = 1; f < argc; f++) {
712 if (argv[f][0] == '-' && checkEGG(argv[f])) exit(1);
713 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
714 if (strcmp(argv[f], "-into") == 0) { ++f; continue; }
715 if (strcmp(argv[f], "-embed") == 0) { ++f; continue; }
716 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
717 case 'e': f = argc+1; break;
718 case 't':
719 case 'c':
720 case 'w':
721 case 'b':
722 case 'R':
723 ++f;
724 break;
725 case 'T':
726 if (++f < argc) {
727 free(opt_term);
728 opt_term = strdup(argv[f]);
729 opt_term_locked = 1;
731 break;
732 case 'C':
733 if (++f < argc) {
734 if (configfile != NULL) free(configfile);
735 configfile = strdup(argv[f]);
737 break;
738 case 'l':
739 if (++f < argc) cliLocale = argv[f];
740 break;
741 case 'S': // single-tab mode
742 opt_disabletabs = 1;
743 break;
744 case 'v':
745 fprintf(stderr, "%s", USAGE_VERSION);
746 exit(EXIT_FAILURE);
747 case 'h':
748 default:
749 fprintf(stderr, "%s%s", USAGE_VERSION, USAGE);
750 exit(EXIT_FAILURE);
754 initDefaultOptions();
755 if (configfile == NULL) {
756 const char *home = getenv("HOME");
758 if (home != NULL) {
759 configfile = SPrintf("%s/.sterm.rc", home);
760 if (loadConfig(configfile) == 0) goto cfgdone;
761 free(configfile); configfile = NULL;
763 configfile = SPrintf("%s/.config/sterm.rc", home);
764 if (loadConfig(configfile) == 0) goto cfgdone;
765 free(configfile); configfile = NULL;
768 configfile = SPrintf("/etc/sterm.rc");
769 if (loadConfig(configfile) == 0) goto cfgdone;
770 free(configfile); configfile = NULL;
772 configfile = SPrintf("/etc/sterm/sterm.rc");
773 if (loadConfig(configfile) == 0) goto cfgdone;
774 free(configfile); configfile = NULL;
776 configfile = SPrintf("./.sterm.rc");
777 if (loadConfig(configfile) == 0) goto cfgdone;
778 free(configfile); configfile = NULL;
779 // no config
780 } else {
781 if (loadConfig(configfile) < 0) k8t_die("config file '%s' not found!", configfile);
783 cfgdone:
784 if (configfile != NULL) free(configfile); configfile = NULL;
786 for (int f = 1; f < argc; f++) {
787 if (strcmp(argv[f], "-name") == 0) { ++f; continue; }
788 if (strcmp(argv[f], "-into") == 0 || strcmp(argv[f], "-embed") == 0) {
789 if (opt_embed) free(opt_embed);
790 opt_embed = strdup(argv[f]);
791 continue;
793 switch (argv[f][0] != '-' || argv[f][2] ? -1 : argv[f][1]) {
794 case 't':
795 if (++f < argc) {
796 free(opt_title);
797 opt_title = strdup(argv[f]);
799 break;
800 case 'c':
801 if (++f < argc) {
802 free(opt_class);
803 opt_class = strdup(argv[f]);
805 break;
806 case 'w':
807 if (++f < argc) {
808 if (opt_embed) free(opt_embed);
809 opt_embed = strdup(argv[f]);
811 break;
812 case 'R':
813 if (++f < argc) runcmd = argv[f];
814 break;
815 case 'e':
816 /* eat all remaining arguments */
817 if (++f < argc) opt_cmd = &argv[f];
818 f = argc+1;
819 case 'T':
820 case 'C':
821 case 'l':
822 ++f;
823 break;
824 case 'S':
825 break;
829 setenv("TERM", opt_term, 1);
830 mclock_init();
831 setlocale(LC_ALL, "");
832 initLCConversion();
833 summonChildKiller();
834 updateTabBar = 1;
835 termidx = 0;
836 curterm = k8t_termalloc();
837 k8t_tmInitialize(curterm, 80, 25, opt_maxhistory);
838 // pixmap will be created in xinit()
839 if (K8T_DATA(curterm)->execcmd != NULL) { free(K8T_DATA(curterm)->execcmd); K8T_DATA(curterm)->execcmd = NULL; }
840 if (k8t_ttyNew(curterm) != 0) k8t_die("can't run process");
841 opt_cmd = NULL;
842 xinit();
843 k8t_selInit(curterm);
844 if (runcmd != NULL) executeCommands(runcmd);
845 run();
846 return 0;