Introduction
Introduction Statistics Contact Development Disclaimer Help
tbackport of local changes - st - [fork] customized build of st, the simple ter…
git clone git://src.adamsgaard.dk/st
Log
Files
Refs
README
LICENSE
---
commit d58dd3b8bc42ed31232e4145696d7dacb117a31c
parent 802f1922f93aef1e4876719e107828a1fa15b1a6
Author: Anselm R Garbe <[email protected]>
Date: Sun, 10 May 2009 13:17:09 +0100
backport of local changes
Diffstat:
M LICENSE | 43 +++++++++++++++++------------…
M Makefile | 69 +++++++++++++++++------------…
A README | 28 ++++++++++++++++++++++++++++
A TODO | 9 +++++++++
A config.mk | 31 +++++++++++++++++++++++++++++…
M st.c | 926 +++++++++++++++++++++++++++++…
A st.h | 181 +++++++++++++++++++++++++++++…
A st.info | 54 +++++++++++++++++++++++++++++…
D std.c | 363 -----------------------------…
9 files changed, 1278 insertions(+), 426 deletions(-)
---
diff --git a/LICENSE b/LICENSE
t@@ -1,22 +1,25 @@
-MIT/X Consortium License
+Copyright (c) 2009, Aurélien APTEL <aurelien dot aptel at gmail dot com>
+Copyright (c) 2009, Anselm R Garbe <garbeam at gmail dot com>
-© 2007-2008 Anselm R Garbe <garbeam at gmail dot com>
-© 2008 Matthias Christian Ott <ott at enolink dot de>
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Makefile b/Makefile
t@@ -1,45 +1,50 @@
# st - simple terminal
# See LICENSE file for copyright and license details.
-VERSION = 0.0
+include config.mk
-PREFIX = /usr/local
-MANDIR = $(PREFIX)/share/man
+SRC = st.c
+OBJ = ${SRC:.c=.o}
-CFLAGS = -DVERSION=\"0.0\" -D_GNU_SOURCE
+all: options st
-all: st std
+options:
+ @echo st build options:
+ @echo "CFLAGS = ${CFLAGS}"
+ @echo "LDFLAGS = ${LDFLAGS}"
+ @echo "CC = ${CC}"
+
+.c.o:
+ @echo CC $<
+ @${CC} -c ${CFLAGS} $<
+
+${OBJ}: config.mk
+
+st: ${OBJ}
+ @echo CC -o $@
+ @${CC} -o $@ ${OBJ} ${LDFLAGS}
clean:
- rm -f st std
- rm -f st.o std.o
- rm -f st-$(VERSION).tar.gz
+ @echo cleaning
+ @rm -f st ${OBJ} st-${VERSION}.tar.gz
dist: clean
- mkdir st-$(VERSION)
- cp -f LICENSE README st-$(VERSION)
- cp -f Makefile config.mk st-$(VERSION)
- cp -f st.1 std.1 st-$(VERSION)
- cp -f st.c std.c st-$(VERSION)
- tar -czf st-$(VERSION).tar st-$(VERSION)
- rm -rf st-$(VERSION)
-
-install:
- mkdir -p $(DESTDIR)$(PREFIX)/bin
- cp -f st $(DESTDIR)$(PREFIX)/bin
- cp -f std $(DESTDIR)$(PREFIX)/bin
- chmod 755 $(DESTDIR)$(PREFIX)/bin/st
- chmod 755 $(DESTDIR)$(PREFIX)/bin/std
- mkdir -p $(DESTDIR)$(MANDIR)/man1
- sed 's/VERSION/$(VERSION)/g' < st.1 > $(DESTDIR)$(MANDIR)/man1/st.1
- chmod 644 $(DESTDIR)$(MANDIR)/man1/st.1
- sed 's/VERSION/$(VERSION)/g' < std.1 > $(DESTDIR)$(MANDIR)/man1/std.1
- chmod 644 $(DESTDIR)$(MANDIR)/man1/std.1
+ @echo creating dist tarball
+ @mkdir -p st-${VERSION}
+ @cp -R LICENSE Makefile README config.mk st.h ${SRC} st-${VERSION}
+ @tar -cf st-${VERSION}.tar st-${VERSION}
+ @gzip st-${VERSION}.tar
+ @rm -rf st-${VERSION}
+
+install: all
+ @echo installing executable file to ${DESTDIR}${PREFIX}/bin
+ @mkdir -p ${DESTDIR}${PREFIX}/bin
+ @cp -f st ${DESTDIR}${PREFIX}/bin
+ @chmod 755 ${DESTDIR}${PREFIX}/bin/st
+ @tic st.info
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/st
- rm -f $(DESTDIR)$(PREFIX)/bin/std
- rm -f $(DESTDIR)$(MANDIR)/man1/st.1
- rm -f $(DESTDIR)$(MANDIR)/man1/std.1
+ @echo removing executable file from ${DESTDIR}${PREFIX}/bin
+ @rm -f ${DESTDIR}${PREFIX}/bin/st
-.PHONY: all clean dist install uninstall
+.PHONY: all options clean dist install uninstall
diff --git a/README b/README
t@@ -0,0 +1,28 @@
+st - simple terminal
+--------------------
+st is a simple virtual terminal emulator for X which sucks less.
+
+
+Requirements
+------------
+In order to build st you need the Xlib header files.
+
+
+Installation
+------------
+Edit config.mk to match your local setup (st is installed into
+the /usr/local namespace by default).
+
+Afterwards enter the following command to build and install st (if
+necessary as root):
+
+ make clean install
+
+
+Running st
+----------
+See the man page for details.
+
+Credits
+-------
+Based on Aurélien APTEL <aurelien dot aptel at gmail dot com> bt source code.
diff --git a/TODO b/TODO
t@@ -0,0 +1,9 @@
+ - write a clean terminfo entry
+ - write global "setup" func
+ - try to split more logic/gfx
+ - optimize drawing
+ - handle copy/paste
+ - fix fork/child exit problem
+ - fix resize (shrinking should move last line up)
+ - handle utf8
+ - refactor/clean code
diff --git a/config.mk b/config.mk
t@@ -0,0 +1,31 @@
+# st version
+VERSION = 0.0
+
+# Customize below to fit your system
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = ${PREFIX}/share/man
+
+X11INC = /usr/X11R6/include
+X11LIB = /usr/X11R6/lib
+
+# Xinerama, comment if you don't want it
+#XINERAMALIBS = -L${X11LIB} -lXinerama
+#XINERAMAFLAGS = -DXINERAMA
+
+# includes and libs
+INCS = -I. -I/usr/include -I${X11INC}
+LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 ${XINERAMALIBS}
+
+# flags
+CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
+LDFLAGS = -s ${LIBS}
+
+# Solaris
+#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
+#LDFLAGS = ${LIBS}
+
+# compiler and linker
+CC = cc
diff --git a/st.c b/st.c
t@@ -1,17 +1,921 @@
-/* See LICENSE file for copyright and license details. */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+/* See LICENSE for licence details. */
+#include "st.h"
+
+/* Globals */
+DC dc;
+XWindow xw;
+Term term;
+Escseq escseq;
+int cmdfd;
+int running;
+
+void
+die(const char *errstr, ...) {
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
+void
+execsh(void) {
+ char *args[3] = {SHELL, "-i", NULL};
+ putenv("TERM=" TNAME);
+ execvp(SHELL, args);
+}
+
+void
+xbell(void) { /* visual bell */
+ XRectangle r = { 0, 0, xw.w, xw.h };
+ XSetForeground(xw.dis, dc.gc, dc.col[BellCol]);
+ XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
+ XFlush(xw.dis);
+ usleep(30000);
+ draw(SCredraw);
+}
+
+void
+ttynew(void) {
+ int m, s;
+ pid_t pid;
+ char *pts;
+
+ if((m = posix_openpt(O_RDWR | O_NOCTTY)) < 0)
+ die("openpt");
+ if(grantpt(m) == -1)
+ die("grandpt");
+ if(unlockpt(m) == -1)
+ die("unlockpt");
+ if((pts = ptsname(m)) == NULL)
+ die("ptsname");
+ if((s = open(pts, O_RDWR | O_NOCTTY)) < 0)
+ die("slave open");
+ fcntl(s, F_SETFL, O_NDELAY);
+ switch(pid = fork()) {
+ case -1:
+ die("fork");
+ break;
+ case 0:
+ setsid(); /* create a new process group */
+ dup2(s, STDIN_FILENO);
+ dup2(s, STDOUT_FILENO);
+ dup2(s, STDERR_FILENO);
+ if(ioctl(s, TIOCSCTTY, NULL) < 0)
+ die("slave TTIOCSTTY");
+ execsh();
+ break;
+ default:
+ close(s);
+ cmdfd = m;
+ }
+}
+
+void
+dump(char c) {
+ static int col;
+ fprintf(stderr, " %02x %c ", c, isprint(c)?c:'.');
+ if(++col % 10 == 0)
+ fprintf(stderr, "\n");
+}
+
+void
+ttyread(void) {
+ char buf[BUFSIZ] = {0};
+ int ret;
+
+ switch(ret = read(cmdfd, buf, BUFSIZ)) {
+ case -1: /* error or exit */
+ /* XXX: be more precise */
+ running = 0;
+ break;
+ default:
+ tputs(buf, ret);
+ }
+}
+
+void
+ttywrite(char *s, size_t n) {
+ if(write(cmdfd, s, n) == -1)
+ die("write error on tty.");
+}
+
+void
+ttyresize(int x, int y) {
+ struct winsize w;
+
+ w.ws_row = term.row;
+ w.ws_col = term.col;
+ w.ws_xpixel = w.ws_ypixel = 0;
+ if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0)
+ fprintf(stderr, "Couldn't set window size: %m\n");
+}
int
-main(int argc, char *argv[]) {
- if(argc == 2 && !strcmp("-v", argv[1])) {
- fprintf(stderr, "st-"VERSION", © 2007-2008 st engineers, see …
- exit(EXIT_SUCCESS);
+escfinal(char c) {
+ if(escseq.len == 1)
+ switch(c) {
+ case '[':
+ case ']':
+ case '(':
+ return 0;
+ case '=':
+ case '>':
+ default:
+ return 1;
+ }
+ else if(BETWEEN(c, 0x40, 0x7E))
+ return 1;
+ return 0;
+}
+
+void
+tcpos(int mode) {
+ static int x = 0;
+ static int y = 0;
+
+ if(mode == CSsave)
+ x = term.c.x, y = term.c.y;
+ else if(mode == CSload)
+ tmoveto(x, y);
+}
+
+void
+tnew(int col, int row) { /* screen size */
+ term.row = row, term.col = col;
+ term.top = 0, term.bot = term.row - 1;
+ /* mode */
+ term.mode = TMwrap;
+ /* cursor */
+ term.c.attr.mode = ATnone;
+ term.c.attr.fg = DefaultFG;
+ term.c.attr.bg = DefaultBG;
+ term.c.x = term.c.y = 0;
+ term.c.hidden = 0;
+ /* allocate screen */
+ term.line = calloc(term.row, sizeof(Line));
+ for(row = 0 ; row < term.row; row++)
+ term.line[row] = calloc(term.col, sizeof(Glyph));
+}
+
+void
+tscroll(void) {
+ Line temp = term.line[term.top];
+ int i;
+
+ for(i = term.top; i < term.bot; i++)
+ term.line[i] = term.line[i+1];
+ memset(temp, 0, sizeof(Glyph) * term.col);
+ term.line[term.bot] = temp;
+ xscroll();
+}
+
+void
+tnewline(void) {
+ int y = term.c.y + 1;
+
+ if(y > term.bot) {
+ tscroll(), y = term.bot;
}
- else if(argc != 1) {
- fprintf(stderr, "usage: st [-v]\n");
- exit(EXIT_FAILURE);
+ tmoveto(0, y);
+}
+
+int
+escaddc(char c) {
+ escseq.buf[escseq.len++] = c;
+ if(escfinal(c) || escseq.len >= ESCSIZ) {
+ escparse(), eschandle();
+ return 0;
}
+ return 1;
+}
+
+void
+escparse(void) {
+ /* int noarg = 1; */
+ char *p = escseq.buf;
+
+ escseq.narg = 0;
+ switch(escseq.pre = *p++) {
+ case '[': /* CSI */
+ if(*p == '?')
+ escseq.priv = 1, p++;
+
+ while(p < escseq.buf+escseq.len) {
+ while(isdigit(*p)) {
+ escseq.arg[escseq.narg] *= 10;
+ escseq.arg[escseq.narg] += *(p++) - '0'/*, noa…
+ }
+ if(*p == ';')
+ escseq.narg++, p++;
+ else {
+ escseq.mode = *p;
+ escseq.narg++;
+ return;
+ }
+ }
+ break;
+ case '(':
+ /* humf charset stuff */
+ break;
+ }
+}
+
+void
+tmoveto(int x, int y) {
+ term.c.x = x < 0 ? 0 : x >= term.col ? term.col-1 : x;
+ term.c.y = y < 0 ? 0 : y >= term.row ? term.row-1 : y;
+}
+
+void
+tcursor(int dir) {
+ int xi = term.c.x, yi = term.c.y;
+ int xf = xi, yf = yi;
+
+ switch(dir) {
+ case CSup:
+ yf--;
+ break;
+ case CSdown:
+ yf++;
+ break;
+ case CSleft:
+ xf--;
+ if(xf < 0) {
+ xf = term.col-1, yf--;
+ if(yf < term.top)
+ yf = term.top, xf = 0;
+ }
+ break;
+ case CSright:
+ xf++;
+ if(xf >= term.col) {
+ xf = 0, yf++;
+ if(yf > term.bot)
+ yf = term.bot, tscroll();
+ }
+ break;
+ }
+ tmoveto(xf, yf);
+}
+
+void
+tsetchar(char c) {
+ term.line[term.c.y][term.c.x] = term.c.attr;
+ term.line[term.c.y][term.c.x].c = c;
+ term.line[term.c.y][term.c.x].state |= CRset | CRupdate;
+}
+
+void
+tclearregion(int x1, int y1, int x2, int y2) {
+ int x, y;
+
+ LIMIT(x1, 0, term.col-1);
+ LIMIT(x2, 0, term.col-1);
+ LIMIT(y1, 0, term.row-1);
+ LIMIT(y2, 0, term.row-1);
+
+ /* XXX: could be optimized */
+ for(x = x1; x <= x2; x++)
+ for(y = y1; y <= y2; y++)
+ memset(&term.line[y][x], 0, sizeof(Glyph));
+
+ xclear(x1, y1, x2, y2);
+}
+
+void
+tdeletechar(int n) {
+ int src = term.c.x + n;
+ int dst = term.c.x;
+ int size = term.col - src;
+
+ if(src >= term.col) {
+ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
+ return;
+ }
+ memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * s…
+ tclearregion(term.col-size, term.c.y, term.col-1, term.c.y);
+}
+
+void
+tinsertblank(int n) {
+ int src = term.c.x;
+ int dst = src + n;
+ int size = term.col - n - src;
+
+ if(dst >= term.col) {
+ tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
+ return;
+ }
+ memmove(&term.line[term.c.y][dst], &term.line[term.c.y][src], size * s…
+ tclearregion(src, term.c.y, dst, term.c.y);
+}
+
+void
+tinsertblankline (int n) {
+ int i;
+ Line blank;
+ int bot = term.bot;
+
+ if(term.c.y > term.bot)
+ bot = term.row - 1;
+ else if(term.c.y < term.top)
+ bot = term.top - 1;
+ if(term.c.y + n >= bot) {
+ tclearregion(0, term.c.y, term.col-1, bot);
+ return;
+ }
+ for(i = bot; i >= term.c.y+n; i--) {
+ /* swap deleted line <-> blanked line */
+ blank = term.line[i];
+ term.line[i] = term.line[i-n];
+ term.line[i-n] = blank;
+ /* blank it */
+ memset(blank, 0, term.col * sizeof(Glyph));
+ }
+}
+
+
+void
+tdeleteline(int n) {
+ int i;
+ Line blank;
+ int bot = term.bot;
+
+ if(term.c.y > term.bot)
+ bot = term.row - 1;
+ else if(term.c.y < term.top)
+ bot = term.top - 1;
+ if(term.c.y + n >= bot) {
+ tclearregion(0, term.c.y, term.col-1, bot);
+ return;
+ }
+ for(i = term.c.y; i <= bot-n; i++) {
+ /* swap deleted line <-> blanked line */
+ blank = term.line[i];
+ term.line[i] = term.line[i+n];
+ term.line[i+n] = blank;
+ /* blank it */
+ memset(blank, 0, term.col * sizeof(Glyph));
+ }
+}
+
+void
+tsetattr(int *attr, int l) {
+ int i;
+
+#ifdef TRUECOLOR /* ESC [ ? <fg/bg> ; <r> ; <g> ; <b> m */
+ Color col;
+ if(escseq.priv && escseq.len == 4) { /* True color extension :) */
+ col = (escseq.arg[1]<<16) + (escseq.arg[2]<<8) + escseq.arg[3];
+ switch(escseq.arg[0]) {
+ case 3: /* foreground */
+ term.c.attr.fg = col;
+ break;
+ case 4: /* background */
+ term.c.attr.bg = col;
+ break;
+ }
+ }
+ else
+#endif
+ for(i = 0; i < l; i++) {
+ switch(attr[i]) {
+ case 0:
+ memset(&term.c.attr, 0, sizeof(term.c.attr));
+ term.c.attr.fg = DefaultFG;
+ term.c.attr.bg = DefaultBG;
+ break;
+ case 1:
+ term.c.attr.mode |= ATbold;
+ break;
+ case 4:
+ term.c.attr.mode |= ATunderline;
+ break;
+ case 7:
+ term.c.attr.mode |= ATreverse;
+ break;
+ case 8:
+ term.c.hidden = CShide;
+ break;
+ case 22:
+ term.c.attr.mode &= ~ATbold;
+ break;
+ case 24:
+ term.c.attr.mode &= ~ATunderline;
+ break;
+ case 27:
+ term.c.attr.mode &= ~ATreverse;
+ break;
+ case 39:
+ term.c.attr.fg = DefaultFG;
+ break;
+ case 49:
+ term.c.attr.fg = DefaultBG;
+ break;
+ default:
+ if(BETWEEN(attr[i], 30, 37))
+ term.c.attr.fg = attr[i] - 30;
+ else if(BETWEEN(attr[i], 40, 47))
+ term.c.attr.bg = attr[i] - 40;
+ break;
+ }
+ }
+}
+
+void
+tsetscroll(int t, int b) {
+ int temp;
+
+ LIMIT(t, 0, term.row-1);
+ LIMIT(b, 0, term.row-1);
+ if(t > b) {
+ temp = t;
+ t = b;
+ b = temp;
+ }
+ term.top = t;
+ term.bot = b;
+}
+
+
+void
+eschandle(void) {
+ /* escdump(); */
+ switch(escseq.pre) {
+ case '[':
+ switch(escseq.mode) {
+ case '@': /* Insert <n> blank char */
+ DEFAULT(escseq.arg[0], 1);
+ tinsertblank(escseq.arg[0]);
+ break;
+ case 'A': /* Cursor <n> Up */
+ case 'e':
+ DEFAULT(escseq.arg[0], 1);
+ tmoveto(term.c.x, term.c.y-escseq.arg[0]);
+ break;
+ case 'B': /* Cursor <n> Down */
+ DEFAULT(escseq.arg[0], 1);
+ tmoveto(term.c.x, term.c.y+escseq.arg[0]);
+ break;
+ case 'C': /* Cursor <n> Forward */
+ case 'a':
+ DEFAULT(escseq.arg[0], 1);
+ tmoveto(term.c.x+escseq.arg[0], term.c.y);
+ break;
+ case 'D': /* Cursor <n> Backward */
+ DEFAULT(escseq.arg[0], 1);
+ tmoveto(term.c.x-escseq.arg[0], term.c.y);
+ break;
+ case 'E': /* Cursor <n> Down and first col */
+ DEFAULT(escseq.arg[0], 1);
+ tmoveto(0, term.c.y+escseq.arg[0]);
+ break;
+ case 'F': /* Cursor <n> Up and first col */
+ DEFAULT(escseq.arg[0], 1);
+ tmoveto(0, term.c.y-escseq.arg[0]);
+ break;
+ case 'G': /* Move to <col> */
+ case '`':
+ DEFAULT(escseq.arg[0], 1);
+ tmoveto(escseq.arg[0]-1, term.c.y);
+ break;
+ case 'H': /* Move to <row> <col> */
+ case 'f':
+ DEFAULT(escseq.arg[0], 1);
+ DEFAULT(escseq.arg[1], 1);
+ tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
+ break;
+ case 'J': /* Clear screen */
+ switch(escseq.arg[0]) {
+ case 0: /* below */
+ tclearregion(term.c.x, term.c.y, term.col-1, t…
+ break;
+ case 1: /* above */
+ tclearregion(0, 0, term.c.x, term.c.y);
+ break;
+ case 2: /* all */
+ tclearregion(0, 0, term.col-1, term.row-1);
+ break;
+ }
+ break;
+ case 'K': /* Clear line */
+ switch(escseq.arg[0]) {
+ case 0: /* right */
+ tclearregion(term.c.x, term.c.y, term.col-1, t…
+ break;
+ case 1: /* left */
+ tclearregion(0, term.c.y, term.c.x, term.c.y);
+ break;
+ case 2: /* all */
+ tclearregion(0, term.c.y, term.col-1, term.c.y…
+ break;
+ }
+ break;
+ case 'L': /* Insert <n> blank lines */
+ DEFAULT(escseq.arg[0], 1);
+ tinsertblankline(escseq.arg[0]);
+ break;
+ case 'M': /* Delete <n> lines */
+ DEFAULT(escseq.arg[0], 1);
+ tdeleteline(escseq.arg[0]);
+ break;
+ case 'P': /* Delete <n> char */
+ DEFAULT(escseq.arg[0], 1);
+ tdeletechar(escseq.arg[0]);
+ break;
+ case 'd': /* Move to <row> */
+ DEFAULT(escseq.arg[0], 1);
+ tmoveto(term.c.x, escseq.arg[0]-1);
+ break;
+ case 'h': /* Set terminal mode */
+ break;
+ case 'm': /* Terminal attribute (color) */
+ tsetattr(escseq.arg, escseq.narg);
+ break;
+ case 'r':
+ if(escseq.priv)
+ ;
+ else {
+ DEFAULT(escseq.arg[0], 1);
+ DEFAULT(escseq.arg[1], term.row);
+ tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
+ }
+ break;
+ case 's': /* Save cursor position */
+ tcpos(CSsave);
+ break;
+ case 'u': /* Load cursor position */
+ tcpos(CSload);
+ break;
+ }
+ break;
+ }
+}
+
+void
+escdump(void) {
+ int i;
+ puts("------");
+ printf("rawbuf : %s\n", escseq.buf);
+ printf("prechar : %c\n", escseq.pre);
+ printf("private : %c\n", escseq.priv ? '?' : ' ');
+ printf("narg : %d\n", escseq.narg);
+ if(escseq.narg) {
+ for(i = 0; i < escseq.narg; i++)
+ printf("\targ %d = %d\n", i, escseq.arg[i]);
+ }
+ printf("mode : %c\n", escseq.mode);
+}
+
+void
+escreset(void) {
+ memset(&escseq, 0, sizeof(escseq));
+}
+
+void
+tputc(char c) {
+ static int inesc = 0;
+
+ dump(c);
+ /* start of escseq */
+ if(c == '\033')
+ escreset(), inesc = 1;
+ else if(inesc) {
+ inesc = escaddc(c);
+ } /* normal char */
+ else switch(c) {
+ default:
+ tsetchar(c);
+ tcursor(CSright);
+ break;
+ case '\b':
+ tcursor(CSleft);
+ break;
+ case '\r':
+ tmoveto(0, term.c.y);
+ break;
+ case '\n':
+ tnewline();
+ break;
+ case '\a':
+ xbell();
+ break;
+ }
+}
+
+void
+tputs(char *s, int len) {
+ for(; len > 0; len--)
+ tputc(*s++);
+}
+
+void
+tdump(void) {
+ int row, col;
+ Glyph c;
+
+ for(row = 0; row < term.row; row++) {
+ for(col = 0; col < term.col; col++) {
+ if(col == term.c.x && row == term.c.y)
+ putchar('#');
+ else {
+ c = term.line[row][col];
+ putchar(c.state & CRset ? c.c : '.');
+ }
+ }
+ putchar('\n');
+ }
+}
+
+void
+tresize(int col, int row) {
+ int i;
+ Line *line;
+ int minrow = MIN(row, term.row);
+ int mincol = MIN(col, term.col);
+
+ if(col < 1 || row < 1)
+ return;
+ line = calloc(row, sizeof(Line));
+ for(i = 0 ; i < row; i++)
+ line[i] = calloc(col, sizeof(Glyph));
+ for(i = 0 ; i < minrow; i++) {
+ memcpy(line[i], term.line[i], mincol * sizeof(Glyph));
+ free(term.line[i]);
+ }
+ free(term.line);
+ LIMIT(term.c.x, 0, col-1);
+ LIMIT(term.c.y, 0, row-1);
+ LIMIT(term.top, 0, row-1);
+ LIMIT(term.bot, 0, row-1);
+ // if(term.bot == term.row-1)
+ term.bot = row-1;
+ term.line = line;
+ term.col = col, term.row = row;
+}
+
+unsigned long
+xgetcol(const char *s) {
+ XColor color;
+ Colormap cmap = DefaultColormap(xw.dis, xw.scr);
+
+ if(!XAllocNamedColor(xw.dis, cmap, s, &color, &color)) {
+ color.pixel = WhitePixel(xw.dis, xw.scr);
+ fprintf(stderr, "Could not allocate color '%s'\n", s);
+ }
+ return color.pixel;
+}
+
+
+void
+xclear(int x1, int y1, int x2, int y2) {
+ XClearArea(xw.dis, xw.win,
+ x1 * xw.cw, y1 * xw.ch,
+ (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch,
+ False);
+}
+
+
+void
+xscroll(void) {
+ int srcy = (term.top+1) * xw.ch;
+ int dsty = term.top * xw.ch;
+ int height = (term.bot-term.top) * xw.ch;
+
+ xcursor(CShide);
+ XCopyArea(xw.dis, xw.win, xw.win, dc.gc, 0, srcy, xw.w, height, 0, dst…
+ xclear(0, term.bot, term.col-1, term.bot);
+}
+
+
+
+
+void
+xinit(void) {
+ XGCValues values;
+ unsigned long valuemask;
+ XClassHint chint;
+ XWMHints wmhint;
+ XSizeHints shint;
+ char *args[] = {NULL};
+ int i;
+
+ xw.dis = XOpenDisplay(NULL);
+ xw.scr = XDefaultScreen(xw.dis);
+ /* font */
+ dc.font = XLoadQueryFont(xw.dis, FONT);
+ xw.cw = dc.font->max_bounds.rbearing - dc.font->min_bounds.lbearing;
+ xw.ch = dc.font->ascent + dc.font->descent + LINESPACE;
+ /* colors */
+ for(i = 0; i < LEN(colorname); i++)
+ dc.col[i] = xgetcol(colorname[i]);
+ term.c.attr.fg = DefaultFG;
+ term.c.attr.bg = DefaultBG;
+ term.c.attr.mode = ATnone;
+ /* windows */
+ xw.h = term.row * xw.ch;
+ xw.w = term.col * xw.cw;
+ /* XXX: this BORDER is useless after the first resize, handle it in xd…
+ xw.win = XCreateSimpleWindow(xw.dis, XRootWindow(xw.dis, xw.scr), 0, 0,
+ xw.w, xw.h, BORDER,
+ dc.col[DefaultBG],
+ dc.col[DefaultBG]);
+ /* gc */
+ values.foreground = XWhitePixel(xw.dis, xw.scr);
+ values.font = dc.font->fid;
+ valuemask = GCForeground | GCFont;
+ dc.gc = XCreateGC(xw.dis, xw.win, valuemask, &values);
+ XMapWindow(xw.dis, xw.win);
+ /* wm stuff */
+ chint.res_name = TNAME, chint.res_class = TNAME;
+ wmhint.input = 1, wmhint.flags = InputHint;
+ shint.height_inc = xw.ch, shint.width_inc = xw.cw;
+ shint.height = xw.h, shint.width = xw.w;
+ shint.flags = PSize | PResizeInc;
+ XSetWMProperties(xw.dis, xw.win, NULL, NULL, &args[0], 0, &shint, &wmh…
+ XStoreName(xw.dis, xw.win, TNAME);
+ XSync(xw.dis, 0);
+}
+
+void
+xdrawc(int x, int y, Glyph g) {
+ XRectangle r = { x * xw.cw, y * xw.ch, xw.cw, xw.ch };
+ unsigned long xfg, xbg;
+
+ /* reverse video */
+ if(g.mode & ATreverse)
+ xfg = dc.col[g.bg], xbg = dc.col[g.fg];
+ else
+ xfg = dc.col[g.fg], xbg = dc.col[g.bg];
+ /* background */
+ XSetForeground(xw.dis, dc.gc, xbg);
+ XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1);
+ /* string */
+ XSetForeground(xw.dis, dc.gc, xfg);
+ XDrawString(xw.dis, xw.win, dc.gc, r.x, r.y+dc.font->ascent, &(g.c), 1…
+ if(g.mode & ATbold) /* XXX: bold hack (draw again at x+1) */
+ XDrawString(xw.dis, xw.win, dc.gc, r.x+1, r.y+dc.font->ascent,…
+ /* underline */
+ if(g.mode & ATunderline) {
+ r.y += dc.font->ascent + 1;
+ XDrawLine(xw.dis, xw.win, dc.gc, r.x, r.y, r.x+r.width-1, r.y);
+ }
+}
+
+void
+xcursor(int mode) {
+ static int oldx = 0;
+ static int oldy = 0;
+ Glyph g = {' ', ATnone, DefaultBG, DefaultCS, 0};
+
+ if(term.line[term.c.y][term.c.x].state & CRset)
+ g.c = term.line[term.c.y][term.c.x].c;
+ /* remove the old cursor */
+ if(term.line[oldy][oldx].state & CRset)
+ xdrawc(oldx, oldy, term.line[oldy][oldx]);
+ else xclear(oldx, oldy, oldx, oldy); /* XXX: maybe a bug */
+ if(mode == CSdraw && !term.c.hidden) {
+ xdrawc(term.c.x, term.c.y, g);
+ oldx = term.c.x, oldy = term.c.y;
+ }
+}
+
+
+void
+draw(int redraw_all) {
+ int x, y;
+ int changed, set;
+
+ if(redraw_all)
+ XClearWindow(xw.dis, xw.win);
+ /* XXX: drawing could be optimised */
+ for(y = 0; y < term.row; y++) {
+ for(x = 0; x < term.col; x++) {
+ changed = term.line[y][x].state & CRupdate;
+ set = term.line[y][x].state & CRset;
+ if((changed && set) || (redraw_all && set)) {
+ term.line[y][x].state &= ~CRupdate;
+ xdrawc(x, y, term.line[y][x]);
+ }
+ }
+ }
+ xcursor(CSdraw);
+}
+
+void
+kpress(XKeyEvent *e) {
+ KeySym ksym;
+ char buf[32];
+ int len;
+ int meta;
+ int shift;
+
+ meta = e->state & Mod4Mask;
+ shift = e->state & ShiftMask;
+ len = XLookupString(e, buf, sizeof(buf), &ksym, NULL);
+ if(len > 0) {
+ buf[sizeof(buf)-1] = '\0';
+ if(meta && len == 1)
+ ttywrite("\033", 1);
+ ttywrite(buf, len);
+ return;
+ }
+ switch(ksym) {
+#ifdef DEBUG1
+ default:
+ printf("errkey: %d\n", (int)ksym);
+ break;
+#endif
+ case XK_Up:
+ case XK_Down:
+ case XK_Left:
+ case XK_Right:
+ sprintf(buf, "\033[%c", "DACB"[ksym - XK_Left]);
+ ttywrite(buf, 3);
+ break;
+ case XK_Delete: ttywrite(KEYDELETE, sizeof(KEYDELETE)-1); break;
+ case XK_Home: ttywrite( KEYHOME, sizeof( KEYHOME)-1); break;
+ case XK_End: ttywrite( KEYEND, sizeof( KEYEND)-1); break;
+ case XK_Prior: ttywrite( KEYPREV, sizeof( KEYPREV)-1); break;
+ case XK_Next: ttywrite( KEYNEXT, sizeof( KEYNEXT)-1); break;
+ case XK_Insert:
+ /* XXX: paste X clipboard */
+ if(shift);
+ break;
+ }
+}
+
+void
+resize(XEvent *e) {
+ int col, row;
+ col = e->xconfigure.width / xw.cw;
+ row = e->xconfigure.height / xw.ch;
+
+ if(term.col != col && term.row != row) {
+ tresize(col, row);
+ ttyresize(col, row);
+ xw.w = e->xconfigure.width;
+ xw.h = e->xconfigure.height;
+ draw(SCredraw);
+ }
+}
+
+
+void
+run(void) {
+ int ret;
+ XEvent ev;
+ fd_set rfd;
+ struct timeval tv = {0, 10000};
+
+ running = 1;
+ XSelectInput(xw.dis, xw.win, ExposureMask | KeyPressMask | StructureNo…
+ XResizeWindow(xw.dis, xw.win, xw.w , xw.h); /* seems to fix the resize…
+ while(running) {
+ while(XPending(xw.dis)) {
+ XNextEvent(xw.dis, &ev);
+ switch (ev.type) {
+ default:
+ break;
+ case KeyPress:
+ kpress(&ev.xkey);
+ break;
+ case Expose:
+ draw(SCredraw);
+ break;
+ case ConfigureNotify:
+ resize(&ev);
+ break;
+ }
+ }
+ FD_ZERO(&rfd);
+ FD_SET(cmdfd, &rfd);
+ ret = select(cmdfd+1, &rfd, NULL, NULL, &tv);
+ if(ret < 0) {
+ fprintf(stderr, "select: %m\n");
+ running = 0;
+ }
+ if(!ret)
+ continue;
+ if(FD_ISSET(cmdfd, &rfd)) {
+ ttyread();
+ draw(SCupdate);
+ }
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ if(argc == 2 && !strncmp("-v", argv[1], 3))
+ die("st-"VERSION", © 2009 st engineers\n");
+ else if(argc != 1)
+ die("usage: st [-v]\n");
+ setlocale(LC_CTYPE, "");
+ tnew(80, 24);
+ ttynew();
+ xinit();
+ run();
return 0;
}
diff --git a/st.h b/st.h
t@@ -0,0 +1,181 @@
+/* See LICENSE for licence details. */
+
+#define _XOPEN_SOURCE
+#include <ctype.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/ioctl.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/Xutil.h>
+
+/* special keys */
+#define KEYDELETE "\033[3~"
+#define KEYHOME "\033[1~"
+#define KEYEND "\033[4~"
+#define KEYPREV "\033[5~"
+#define KEYNEXT "\033[6~"
+
+#define TNAME "st"
+#define SHELL "/bin/bash"
+#define TAB 8
+
+#define FONT "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*"
+#define BORDER 3
+#define LINESPACE 1 /* additional pixel between each line */
+
+/* Default colors */
+#define DefaultFG 7
+#define DefaultBG 0
+#define DefaultCS 1
+#define BellCol DefaultFG /* visual bell color */
+
+static char* colorname[] = {
+ "black",
+ "red",
+ "green",
+ "yellow",
+ "blue",
+ "magenta",
+ "cyan",
+ "white",
+};
+
+
+/* Arbitrary sizes */
+#define ESCSIZ 256
+#define ESCARG 16
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) < (b) ? (b) : (a))
+#define LEN(a) (sizeof(a) / sizeof(a[0]))
+#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
+#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
+#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
+
+
+enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 }; /* Attribute */
+enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload }…
+enum { CRset=1 , CRupdate=2 }; /* Character state */
+enum { TMwrap=1 , TMinsert=2 }; /* Terminal mode */
+enum { SCupdate, SCredraw }; /* screen draw mode */
+
+#ifdef TRUECOLOR
+#error Truecolor not implemented yet
+typedef int Color;
+#else
+typedef char Color;
+#endif
+
+
+typedef struct {
+ char c; /* character code */
+ char mode; /* attribute flags */
+ Color fg; /* foreground */
+ Color bg; /* background */
+ char state; /* state flag */
+} Glyph;
+
+typedef Glyph* Line;
+
+typedef struct {
+ Glyph attr; /* current char attributes */
+ char hidden;
+ int x;
+ int y;
+} TCursor;
+
+/* Escape sequence structs */
+typedef struct {
+ char buf[ESCSIZ+1]; /* raw string */
+ int len; /* raw string length */
+ /* ESC <pre> [[ [<priv>] <arg> [;]] <mode>] */
+ char pre;
+ char priv;
+ int arg[ESCARG+1];
+ int narg; /* nb of args */
+ char mode;
+} Escseq;
+
+/* Internal representation of the screen */
+typedef struct {
+ int row; /* nb row */
+ int col; /* nb col */
+ Line* line; /* screen */
+ TCursor c; /* cursor */
+ int top; /* top scroll limit */
+ int bot; /* bottom scroll limit */
+ int mode; /* terminal mode */
+} Term;
+
+/* Purely graphic info */
+typedef struct {
+ Display* dis;
+ Window win;
+ int scr;
+ int w; /* window width */
+ int h; /* window height */
+ int ch; /* char height */
+ int cw; /* char width */
+} XWindow;
+
+/* Drawing Context */
+typedef struct {
+ unsigned long col[LEN(colorname)];
+ XFontStruct* font;
+ GC gc;
+} DC;
+
+
+void die(const char *errstr, ...);
+void draw(int);
+void execsh(void);
+void kpress(XKeyEvent *);
+void resize(XEvent *);
+void run(void);
+
+int escaddc(char);
+int escfinal(char);
+void escdump(void);
+void eschandle(void);
+void escparse(void);
+void escreset(void);
+
+void tclearregion(int, int, int, int);
+void tcpos(int);
+void tcursor(int);
+void tdeletechar(int);
+void tdeleteline(int);
+void tdump(void);
+void tinsertblank(int);
+void tinsertblankline(int);
+void tmoveto(int, int);
+void tnew(int, int);
+void tnewline(void);
+void tputc(char);
+void tputs(char*, int);
+void tresize(int, int);
+void tscroll(void);
+void tsetattr(int*, int);
+void tsetchar(char);
+void tsetscroll(int, int);
+
+void ttynew(void);
+void ttyread(void);
+void ttyresize(int, int);
+void ttywrite(char *, size_t);
+
+unsigned long xgetcol(const char *);
+void xclear(int, int, int, int);
+void xcursor(int);
+void xdrawc(int, int, Glyph);
+void xinit(void);
+void xscroll(void);
diff --git a/st.info b/st.info
t@@ -0,0 +1,54 @@
+# Reconstructed via infocmp from file: /lib/terminfo/p/pcansi
+st| simpleterm,
+ am,
+ ul,
+ mir,
+ msgr,
+ colors#8,
+ cols#80,
+ it#8,
+ lines#24,
+ ncv#3,
+ pairs#64,
+ acsc=*`#aof+g+j+k+l+m+n-o-p-q-r-s+t+u+v+w|x<y>z{{||}}-~,
+ bel=^G,
+ bold=\E[1m,
+ cbt=\E[Z,
+ clear=\E[H\E[2J,
+ cr=^M,
+ cub1=\E[D,
+ cud1=\E[B,
+ cuf1=\E[C,
+ cup=\E[%i%p1%d;%p2%dH,
+ cuu1=\E[A,
+ dch1=\E[P,
+ dl1=\E[M,
+ ed=\E[J,
+ el=\E[K,
+ home=\E[H,
+ ht=^I,
+ hts=\EH,
+ il1=\E[L,
+ ind=^J,
+ invis=\E[8m,
+ kbs=^H,
+ kcub1=\E[D,
+ kcud1=\E[B,
+ kcuf1=\E[C,
+ kcuu1=\E[A,
+ khome=\E[1~,
+ knp=\E[6~,
+ kpp=\E[5~,
+ op=\E[37;40m,
+ rev=\E[7m,
+ rmacs=\E[10m,
+ rmso=\E[m,
+ rmul=\E[m,
+ setab=\E[4%p1%dm,
+ setaf=\E[3%p1%dm,
+# sgr=\E[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p6%t;1%;%?%…
+ sgr0=\E[0m,
+ smacs=\E[12m,
+ smso=\E[7m,
+ smul=\E[4m,
+ tbc=\E[2g,
diff --git a/std.c b/std.c
t@@ -1,363 +0,0 @@
-/* See LICENSE file for copyright and license details.
- *
- * Simple terminal daemon is a terminal emulator. It can be used in
- * combination with simple terminal to emulate a mostly VT100-compatible
- * terminal.
- *
- * In this process std works like a filter. It reads data from a
- * pseudo-terminal and parses the escape sequences and transforms them
- * into an ed(1)-like language. The resulting data is buffered and
- * written to stdout.
- * Parallely it reads data from stdin and parses and executes the
- * commands. The resulting data is written to the pseudo-terminal.
- */
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#if !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
-#include <pty.h>
-#endif
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define LENGTH(x) (sizeof(x) / sizeof((x)[0]))
-#define MAX(a,b) (((a) > (b)) ? (a) : (b))
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-
-typedef struct {
- unsigned char data[BUFSIZ];
- int s, e;
- int n;
-} RingBuffer;
-
-static void buffer(char c);
-static void cmd(const char *cmdstr, ...);
-static void getpty(void);
-static void movea(int x, int y);
-static void mover(int x, int y);
-static void parsecmd(void);
-static void parseesc(void);
-static void scroll(int l);
-static void shell(void);
-static void sigchld(int n);
-static char unbuffer(void);
-
-static int cols = 80, lines = 25;
-static int cx = 0, cy = 0;
-static int c;
-static int ptm, pts;
-static _Bool bold, digit, qmark;
-static pid_t pid;
-static RingBuffer buf;
-static FILE *fptm;
-
-void
-buffer(char c) {
- if(buf.n < LENGTH(buf.data))
- buf.n++;
- else
- buf.s = (buf.s + 1) % LENGTH(buf.data);
- buf.data[buf.e++] = c;
- buf.e %= LENGTH(buf.data);
-}
-
-void
-cmd(const char *cmdstr, ...) {
- va_list ap;
-
- putchar('\n');
- putchar(':');
- va_start(ap, cmdstr);
- vfprintf(stdout, cmdstr, ap);
- va_end(ap);
-}
-
-void
-movea(int x, int y) {
- x = MAX(x, cols);
- y = MAX(y, lines);
- cx = x;
- cy = y;
- cmd("seek(%d,%d)", x, y);
-}
-
-void
-mover(int x, int y) {
- movea(cx + x, cy + y);
-}
-
-void
-parsecmd(void) {
-}
-
-void
-parseesc(void) {
- int i, j;
- int arg[16];
-
- memset(arg, 0, LENGTH(arg));
- c = getc(fptm);
- switch(c) {
- case '[':
- c = getc(fptm);
- for(j = 0; j < LENGTH(arg);) {
- if(isdigit(c)) {
- digit = 1;
- arg[j] *= 10;
- arg[j] += c - '0';
- }
- else if(c == '?')
- qmark = 1;
- else if(c == ';') {
- if(!digit)
- errx(EXIT_FAILURE, "syntax error");
- digit = 0;
- j++;
- }
- else {
- if(digit) {
- digit = 0;
- j++;
- }
- break;
- }
- c = getc(fptm);
- }
- switch(c) {
- case '@':
- break;
- case 'A':
- mover(0, j ? arg[0] : 1);
- break;
- case 'B':
- mover(0, j ? -arg[0] : -1);
- break;
- case 'C':
- mover(j ? arg[0] : 1, 0);
- break;
- case 'D':
- mover(j ? -arg[0] : -1, 0);
- break;
- case 'E':
- /* movel(j ? arg[0] : 1); */
- break;
- case 'F':
- /* movel(j ? -arg[0] : -1); */
- break;
- case '`':
- case 'G':
- movea(j ? arg[0] : 1, cy);
- break;
- case 'f':
- case 'H':
- movea(arg[1] ? arg[1] : 1, arg[0] ? arg[0] : 1);
- case 'L':
- /* insline(j ? arg[0] : 1); */
- break;
- case 'M':
- /* delline(j ? arg[0] : 1); */
- break;
- case 'P':
- break;
- case 'S':
- scroll(j ? arg[0] : 1);
- break;
- case 'T':
- scroll(j ? -arg[0] : -1);
- break;
- case 'd':
- movea(cx, j ? arg[0] : 1);
- break;
- case 'm':
- for(i = 0; i < j; i++) {
- if(arg[i] >= 30 && arg[i] <= 37)
- cmd("#%d", arg[i] - 30);
- if(arg[i] >= 40 && arg[i] <= 47)
- cmd("|%d", arg[i] - 40);
- /* xterm bright colors */
- if(arg[i] >= 90 && arg[i] <= 97)
- cmd("#%d", arg[i] - 90);
- if(arg[i] >= 100 && arg[i] <= 107)
- cmd("|%d", arg[i] - 100);
- switch(arg[i]) {
- case 0:
- case 22:
- if(bold)
- cmd("bold");
- case 1:
- if(!bold)
- cmd("bold");
- break;
- }
- }
- break;
- }
- break;
- default:
- putchar('\033');
- ungetc(c, fptm);
- }
-}
-
-void
-scroll(int l) {
- cmd("seek(%d,%d)", cx, cy + l);
-}
-
-void
-getpty(void) {
- char *ptsdev;
-
-#if defined(_GNU_SOURCE)
- ptm = getpt();
-#elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
- ptm = posix_openpt(O_RDWR);
-#else
- ptm = open("/dev/ptmx", O_RDWR);
- if(ptm == -1)
- if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1)
- err(EXIT_FAILURE, "cannot open pty");
-#endif
-#if defined(_XOPEN_SOURCE)
- if(ptm != -1) {
- if(grantpt(ptm) == -1)
- err(EXIT_FAILURE, "cannot grant access to pty");
- if(unlockpt(ptm) == -1)
- err(EXIT_FAILURE, "cannot unlock pty");
- ptsdev = ptsname(ptm);
- if(!ptsdev)
- err(EXIT_FAILURE, "slave pty name undefined");
- pts = open(ptsdev, O_RDWR);
- if(pts == -1)
- err(EXIT_FAILURE, "cannot open slave pty");
- }
- else
- err(EXIT_FAILURE, "cannot open pty");
-#endif
-}
-
-void
-shell(void) {
- static char *shell = NULL;
-
- if(!shell && !(shell = getenv("SHELL")))
- shell = "/bin/sh";
- pid = fork();
- switch(pid) {
- case -1:
- err(EXIT_FAILURE, "cannot fork");
- case 0:
- setsid();
- dup2(pts, STDIN_FILENO);
- dup2(pts, STDOUT_FILENO);
- dup2(pts, STDERR_FILENO);
- close(ptm);
- putenv("TERM=vt102");
- execvp(shell, NULL);
- break;
- default:
- close(pts);
- signal(SIGCHLD, sigchld);
- }
-}
-
-void
-sigchld(int n) {
- int ret;
-
- if(waitpid(pid, &ret, 0) == -1)
- err(EXIT_FAILURE, "waiting for child failed");
- if(WIFEXITED(ret))
- exit(WEXITSTATUS(ret));
- else
- exit(EXIT_SUCCESS);
-}
-
-char
-unbuffer(void) {
- char c;
-
- c = buf.data[buf.s++];
- buf.s %= LENGTH(buf.data);
- buf.n--;
- return c;
-}
-
-int
-main(int argc, char *argv[]) {
- fd_set rfds;
-
- if(argc == 2 && !strcmp("-v", argv[1]))
- errx(EXIT_SUCCESS, "std-"VERSION", © 2008 Matthias-Christian …
- else if(argc == 1)
- errx(EXIT_FAILURE, "usage: std [-v]");
- getpty();
- shell();
- FD_ZERO(&rfds);
- FD_SET(STDIN_FILENO, &rfds);
- FD_SET(ptm, &rfds);
- if(!(fptm = fdopen(ptm, "r+")))
- err(EXIT_FAILURE, "cannot open pty");
- if(fcntl(ptm, F_SETFL, O_NONBLOCK) == -1)
- err(EXIT_FAILURE, "cannot set pty to non-blocking mode");
- if(fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1)
- err(EXIT_FAILURE, "cannot set stdin to non-blocking mode");
- for(;;) {
- if(select(MAX(ptm, STDIN_FILENO) + 1, &rfds, NULL, NULL, NULL)…
- err(EXIT_FAILURE, "cannot select");
- if(FD_ISSET(ptm, &rfds)) {
- for(;;) {
- if((c = getc(fptm)) == EOF) {
- if(feof(fptm)) {
- FD_CLR(ptm, &rfds);
- fflush(fptm);
- break;
- }
- if(errno != EAGAIN)
- err(EXIT_FAILURE, "cannot read…
- fflush(stdout);
- break;
- }
- switch(c) {
- case '\033':
- parseesc();
- break;
- default:
- putchar(c);
- }
- }
- fflush(stdout);
- }
- if(FD_ISSET(STDIN_FILENO, &rfds)) {
- for(;;) {
- if((c = getchar()) == EOF) {
- if(feof(stdin)) {
- FD_CLR(STDIN_FILENO, &rfds);
- fflush(fptm);
- break;
- }
- if(errno != EAGAIN)
- err(EXIT_FAILURE, "cannot read…
- fflush(fptm);
- break;
- }
- switch(c) {
- case ':':
- parsecmd();
- break;
- default:
- putc(c, fptm);
- }
- }
- fflush(fptm);
- }
- }
- return 0;
-}
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.