Initial commit of 2.0. - thinglaunch - A simple command and password promtper f… | |
git clone git://bitreich.org/thinglaunch | |
Log | |
Files | |
Refs | |
Tags | |
LICENSE | |
--- | |
commit 606c0f24754b284bacbb8de22ef5d0c73f065e8f | |
Author: Christoph Lohmann <[email protected]> | |
Date: Sun, 27 Mar 2011 18:50:19 +0200 | |
Initial commit of 2.0. | |
Diffstat: | |
A LICENSE | 23 +++++++++++++++++++++++ | |
A LICENSE.orig | 41 +++++++++++++++++++++++++++++… | |
A Makefile | 58 ++++++++++++++++++++++++++++++ | |
A README.md | 36 +++++++++++++++++++++++++++++… | |
A config.h | 5 +++++ | |
A config.mk | 26 ++++++++++++++++++++++++++ | |
A thinglaunch.c | 466 +++++++++++++++++++++++++++++… | |
7 files changed, 655 insertions(+), 0 deletions(-) | |
--- | |
diff --git a/LICENSE b/LICENSE | |
@@ -0,0 +1,23 @@ | |
+MIT/X Consortium License | |
+ | |
+© 2011 Christoph Lohmann <[email protected]> | |
+ | |
+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. | |
+ | |
+SEE LICENSE.orig FOR FURTHER APPLYING LICENSE TERMS. | |
diff --git a/LICENSE.orig b/LICENSE.orig | |
@@ -0,0 +1,41 @@ | |
+/* This program is a quick little launcher program for X. | |
+ * | |
+ * You run the program, it grabs the display (hopefully nothing else has it | |
+ * grabbed), and you type what you want to run. The styling is minimalist. | |
+ * | |
+ * (c) 2003 Matt Johnston | |
+ * matt (at) ucc.asn.au | |
+ * | |
+ * Compile it with | |
+ * cc thinglaunch.c -o thinglaunch -lX11 -L/usr/X11R6/lib -lpthread | |
+ * (works for Linux and OSF/1 anyway, for static you might need -ldl, and you | |
+ * mightn't need -lpthread.) | |
+ * | |
+ * This program can be freely distributed in source or binary form, under a | |
+ * quite permissive license. See the bottom of this file for the full license. | |
+ * If that license is too restrictive, mail me and you can choose another one. | |
+ * | |
+ * $Id: thinglaunch.c,v 1.8 2004/09/20 14:27:48 matt Exp $ | |
+ */ | |
+/* | |
+Copyright (c) 2003 Matt Johnston | |
+All rights reserved. | |
+ | |
+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. | |
+*/ | |
diff --git a/Makefile b/Makefile | |
@@ -0,0 +1,58 @@ | |
+# thinglaunch | |
+# See LICENSE file for copyright and license details. | |
+ | |
+include config.mk | |
+ | |
+SRC = ${NAME}.c | |
+ | |
+OBJ = ${SRC:.c=.o} | |
+ | |
+all: options ${NAME} | |
+ | |
+options: | |
+ @echo ${NAME} build options: | |
+ @echo "CFLAGS = ${CFLAGS}" | |
+ @echo "LDFLAGS = ${LDFLAGS}" | |
+ @echo "CC = ${CC}" | |
+ | |
+.c.o: | |
+ @echo CC $< | |
+ @${CC} -c ${CFLAGS} $< | |
+ | |
+${OBJ}: config.mk | |
+ | |
+${NAME}: ${OBJ} | |
+ @echo CC -o $@ | |
+ @${CC} -o $@ ${OBJ} ${LDFLAGS} | |
+ @ln -s ${NAME} thingaskpass | |
+ | |
+clean: | |
+ @echo cleaning | |
+ @rm -f ${NAME} thingaskpass ${OBJ} ${NAME}-${VERSION}.tar.gz | |
+ | |
+dist: clean | |
+ @echo creating dist tarball | |
+ @mkdir -p ${NAME}-${VERSION} | |
+ @cp -R LICENSE LICENSE.orig Makefile README.md config.mk \ | |
+ ${SRC} *.h ${NAME}-${VERSION} | |
+ @tar -cf ${NAME}-${VERSION}.tar ${NAME}-${VERSION} | |
+ @gzip ${NAME}-${VERSION}.tar | |
+ @rm -rf ${NAME}-${VERSION} | |
+ | |
+etc: | |
+ @echo installing etc files into ${DESTDIR}/etc/${NAME} | |
+ @mkdir -p ${DESTDIR}/etc/${NAME} | |
+ @cp -R etc/${NAME}/* ${DESTDIR}/etc/${NAME} | |
+ | |
+install: all | |
+ @echo installing executable file to ${DESTDIR}${PREFIX}/bin | |
+ @mkdir -p ${DESTDIR}${PREFIX}/bin | |
+ @cp -f ${NAME} thingaskpass ${DESTDIR}${PREFIX}/bin | |
+ @chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} | |
+ | |
+uninstall: | |
+ @echo removing executable file from ${DESTDIR}${PREFIX}/bin | |
+ @rm -f ${DESTDIR}${PREFIX}/bin/${NAME} | |
+ @rm -f ${DESTDIR}${PREFIX}/bin/thingaskpass | |
+ | |
+.PHONY: all options clean dist install uninstall | |
diff --git a/README.md b/README.md | |
@@ -0,0 +1,36 @@ | |
+# Thinglaunch - a simple entry box for X11 | |
+ | |
+The first intention, as done by the original creator Matt Johnston | |
+<[email protected]>, was to launch simple commandlines. | |
+ | |
+In 2011 the single file project was extended by features like Unicode | |
+support, a prompt and an ssh-askpass compatibility layer. | |
+ | |
+## Installation | |
+ | |
+ % tar -xzvf thinglaunch-*.tar.gz | |
+ % cd thinglaunch | |
+ % make | |
+ % sudo PREFIX=/usr make install | |
+ | |
+This will create the executable »thinglaunch« and »thingaskpass« in | |
+»/usr/bin«. Thinglaunch will ask for a command and execute it and | |
+thingaskpass can be used as a SSH_ASKPASS parameter value, which will | |
+be used by ssh-agent to gather the password for private keys. | |
+ | |
+## Usage | |
+ | |
+ # Get some input string and print it to stdout. There will | |
+ # be the prompt prepended "to stdout> ". | |
+ % thinglaunch -o -p "to stdout> " | |
+ | |
+ # Ask for a command, which will be executed. During entering | |
+ # the command, the entered string will be replaced by asterisks. | |
+ % thinglaunch -s -p "secret cmd> " | |
+ | |
+ # This symlink predefines -s, -o and -p "secret> ". | |
+ % ln -s thinglaunch thingaskpass | |
+ % ./thingaskpass | |
+ | |
+Have fun! | |
+ | |
diff --git a/config.h b/config.h | |
@@ -0,0 +1,5 @@ | |
+static const char *font = "-*-*-medium-*-*-*-14-*-*-*-*-*-*-*"; | |
+static const char *prompt = "exec> "; | |
+static const char *normbgcolor = "#222222"; | |
+static const char *normfgcolor = "#cccccc"; | |
+ | |
diff --git a/config.mk b/config.mk | |
@@ -0,0 +1,26 @@ | |
+# thinglaunch metadata | |
+NAME = thinglaunch | |
+VERSION = 2.00 | |
+ | |
+# Customize below to fit your system | |
+ | |
+# paths | |
+PREFIX ?= /usr | |
+MANPREFIX = ${PREFIX}/share/man | |
+ | |
+X11INC = /usr/X11R6/include | |
+X11LIB = /usr/X11R6/lib | |
+ | |
+# includes and libs | |
+INCS = -I. -I/usr/include | |
+LIBS = -L/usr/lib -L${X11LIB} -lc -lX11 | |
+ | |
+# flags | |
+CPPFLAGS = -DVERSION=\"${VERSION}\" | |
+CFLAGS = -g -std=gnu99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} | |
+LDFLAGS = -g ${LIBS} | |
+#LDFLAGS = -s ${LIBS} | |
+ | |
+# compiler and linker | |
+CC = cc | |
+ | |
diff --git a/thinglaunch.c b/thinglaunch.c | |
@@ -0,0 +1,466 @@ | |
+/* | |
+ * Copy me if you can. | |
+ * by 20h | |
+ * | |
+ * For now this is a slightly modified version of the original from | |
+ * Matt Johnston <[email protected]>. See LICENSE.orig for his messages. | |
+ */ | |
+#include <unistd.h> | |
+#include <X11/Xlib.h> | |
+#include <X11/Xatom.h> | |
+#include <X11/Xutil.h> | |
+#include <X11/Xlocale.h> | |
+#include <locale.h> | |
+#include <unistd.h> | |
+#include <stdio.h> | |
+#include <stdlib.h> | |
+#include <stdarg.h> | |
+#include <string.h> | |
+#include <strings.h> | |
+#include <libgen.h> | |
+#include <wchar.h> | |
+ | |
+#include "config.h" | |
+ | |
+unsigned long getcolor(const char *colstr); | |
+void createwindow(void); | |
+void setupgc(void); | |
+void eventloop(void); | |
+void grabhack(void); | |
+void redraw(void); | |
+void keypress(XKeyEvent *keyevent); | |
+void execcmd(void); | |
+void die(char *errstr, ...); | |
+ | |
+Display *dpy; | |
+GC gc; | |
+GC rectgc; | |
+XIM im; | |
+XIC ic; | |
+Window win; | |
+XFontStruct *font_info; | |
+XFontSet fontset; | |
+int screen, issecret = 0, tostdout = 0; | |
+unsigned long fgcol, bgcol; | |
+ | |
+#define MAXCMD 255 | |
+#define WINWIDTH 640 | |
+#define WINHEIGHT 25 | |
+ | |
+/* the actual commandline */ | |
+wchar_t command[MAXCMD+1]; | |
+wchar_t secret[MAXCMD+1]; | |
+char cbuf[MAXCMD*4+1]; | |
+ | |
+void | |
+usage(char *argv0) | |
+{ | |
+ fprintf(stderr, "usage: %s [-hos] [-p prompt]\n", argv0); | |
+ exit(1); | |
+} | |
+ | |
+int | |
+main(int argc, char *argv[]) | |
+{ | |
+ int i; | |
+ | |
+ if (strstr(argv[0], "thingaskpass")) { | |
+ issecret = 1; | |
+ tostdout = 1; | |
+ prompt = "secret> "; | |
+ } | |
+ if (argc > 1) { | |
+ for (i = 1; argv[i]; i++) { | |
+ if (argv[i][0] == '-') { | |
+ switch (argv[i][1]) { | |
+ case 'o': | |
+ tostdout = 1; | |
+ break; | |
+ case 's': | |
+ issecret = 1; | |
+ break; | |
+ case 'p': | |
+ if (!argv[i+1]) | |
+ usage(argv[0]); | |
+ prompt = argv[i+1]; | |
+ i++; | |
+ break; | |
+ default: | |
+ case 'h': | |
+ usage(argv[0]); | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ bzero(command, sizeof(command)); | |
+ bzero(secret, sizeof(secret)); | |
+ | |
+ createwindow(); | |
+ setupgc(); | |
+ grabhack(); | |
+ eventloop(); | |
+ | |
+ return 0; | |
+} | |
+ | |
+unsigned long | |
+getcolor(const char *colstr) | |
+{ | |
+ Colormap cmap = DefaultColormap(dpy, screen); | |
+ XColor color; | |
+ | |
+ if (!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) | |
+ die("error, canno allocate color '%s'\n", colstr); | |
+ return color.pixel; | |
+} | |
+ | |
+/* | |
+ * Stolen from: | |
+ * http://menehune.opt.wfu.edu/Kokua/Irix_6.5.21_doc_cd/usr/share/\ | |
+ * Insight/library/SGI_bookshelves/SGI_Developer/books/XLib_PG/sgi_\ | |
+ * html/ch11.html#S2-1002-11-11 | |
+ */ | |
+XIMStyle | |
+choosebetterstyle(XIMStyle style1, XIMStyle style2) | |
+{ | |
+ XIMStyle s,t; | |
+ XIMStyle preedit = XIMPreeditArea | XIMPreeditCallbacks | | |
+ XIMPreeditPosition | XIMPreeditNothing | XIMPreeditNone; | |
+ XIMStyle status = XIMStatusArea | XIMStatusCallbacks | | |
+ XIMStatusNothing | XIMStatusNone; | |
+ if (style1 == 0) return style2; | |
+ if (style2 == 0) return style1; | |
+ if ((style1 & (preedit | status)) == (style2 & (preedit | status))) | |
+ return style1; | |
+ s = style1 & preedit; | |
+ t = style2 & preedit; | |
+ if (s != t) { | |
+ if (s | t | XIMPreeditCallbacks) | |
+ return (s == XIMPreeditCallbacks)?style1:style2; | |
+ else if (s | t | XIMPreeditPosition) | |
+ return (s == XIMPreeditPosition)?style1:style2; | |
+ else if (s | t | XIMPreeditArea) | |
+ return (s == XIMPreeditArea)?style1:style2; | |
+ else if (s | t | XIMPreeditNothing) | |
+ return (s == XIMPreeditNothing)?style1:style2; | |
+ } | |
+ else { /* if preedit flags are the same, compare status flags */ | |
+ s = style1 & status; | |
+ t = style2 & status; | |
+ if (s | t | XIMStatusCallbacks) | |
+ return (s == XIMStatusCallbacks)?style1:style2; | |
+ else if (s | t | XIMStatusArea) | |
+ return (s == XIMStatusArea)?style1:style2; | |
+ else if (s | t | XIMStatusNothing) | |
+ return (s == XIMStatusNothing)?style1:style2; | |
+ } | |
+} | |
+ | |
+void | |
+initim(void) | |
+{ | |
+ XIMStyles *im_supported_styles; | |
+ XIMStyle app_supported_styles; | |
+ XIMStyle style; | |
+ XIMStyle best_style; | |
+ XVaNestedList list; | |
+ char **missing_charsets; | |
+ int num_missing_charsets = 0; | |
+ char *default_string; | |
+ int i; | |
+ | |
+ fontset = XCreateFontSet(dpy, font, &missing_charsets, | |
+ &num_missing_charsets, &default_string); | |
+ if (num_missing_charsets > 0) | |
+ XFreeStringList(missing_charsets); | |
+ | |
+ if (!(im = XOpenIM(dpy, NULL, NULL, NULL))) | |
+ die("Couldn't open input method.\n"); | |
+ | |
+ XGetIMValues(im, XNQueryInputStyle, &im_supported_styles, NULL); | |
+ app_supported_styles = XIMPreeditNone | XIMPreeditNothing \ | |
+ | XIMPreeditArea; | |
+ app_supported_styles |= XIMStatusNone | XIMStatusNothing \ | |
+ | XIMStatusArea; | |
+ | |
+ for(i = 0, best_style = 0; i < im_supported_styles->count_styles; | |
+ i++) { | |
+ style = im_supported_styles->supported_styles[i]; | |
+ if ((style & app_supported_styles) == style) | |
+ best_style = choosebetterstyle(style, best_style); | |
+ } | |
+ if (best_style == 0) | |
+ die("no common shared interaction style found.\n"); | |
+ XFree(im_supported_styles); | |
+ | |
+ list = XVaCreateNestedList(0, XNFontSet, fontset, NULL); | |
+ ic = XCreateIC(im, XNInputStyle, best_style, XNClientWindow, win, | |
+ XNPreeditAttributes, list, XNStatusAttributes, | |
+ list, NULL); | |
+ XFree(list); | |
+ if (ic == NULL) | |
+ die("Could not create input context.\n"); | |
+} | |
+ | |
+void | |
+createwindow(void) | |
+{ | |
+ char *display_name; | |
+ int display_width, display_height; | |
+ int top, left; | |
+ XSizeHints *win_size_hints; | |
+ XSetWindowAttributes attrib; | |
+ | |
+ if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) | |
+ fprintf(stderr, "warning: no locale support.\n"); | |
+ | |
+ display_name = getenv("DISPLAY"); | |
+ if (display_name == NULL) | |
+ die("DISPLAY not set"); | |
+ | |
+ dpy = XOpenDisplay(display_name); | |
+ if (dpy == NULL) | |
+ die("Couldn't connect to DISPLAY"); | |
+ | |
+ if (!XSetLocaleModifiers("")) | |
+ fprintf(stderr, "warning: could not set local modifiers.\n"); | |
+ | |
+ initim(); | |
+ | |
+ screen = DefaultScreen(dpy); | |
+ display_width = DisplayWidth(dpy, screen); | |
+ display_height = DisplayHeight(dpy, screen); | |
+ | |
+ top = (display_height/2 - WINHEIGHT/2); | |
+ left = (display_width/2 - WINWIDTH/2); | |
+ | |
+ bgcol = getcolor(normbgcolor); | |
+ fgcol = getcolor(normfgcolor); | |
+ | |
+ /*win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), | |
+ left, top, WINWIDTH, WINHEIGHT, borderwidth, | |
+ bgcol, bgcol);*/ | |
+ | |
+ attrib.override_redirect= True; | |
+ win = XCreateWindow(dpy, RootWindow(dpy, screen), | |
+ left, top, WINWIDTH, WINHEIGHT, | |
+ 0, CopyFromParent,InputOutput,CopyFromParent, | |
+ CWOverrideRedirect,&attrib); | |
+ | |
+ /* set up the window hints etc */ | |
+ win_size_hints = XAllocSizeHints(); | |
+ if (!win_size_hints) | |
+ die("out of memory allocating hints"); | |
+ | |
+ win_size_hints->flags = PMaxSize | PMinSize; | |
+ win_size_hints->min_width = win_size_hints->max_width = WINWIDTH; | |
+ | |
+ win_size_hints->min_height = win_size_hints->max_height = WINHEIGHT; | |
+ XSetWMNormalHints(dpy, win, win_size_hints); | |
+ | |
+ XFree(win_size_hints); | |
+ | |
+ XMapWindow(dpy, win); | |
+} | |
+ | |
+void | |
+setupgc(void) | |
+{ | |
+ XGCValues values; | |
+ int valuemask = 0; | |
+ int line_width = 1; | |
+ int line_style = LineSolid; | |
+ int cap_style = CapButt; | |
+ int join_style = JoinBevel; | |
+ | |
+ gc = XCreateGC(dpy, win, valuemask, &values); | |
+ rectgc = XCreateGC(dpy, win, valuemask, &values); | |
+ XSetForeground(dpy, gc, fgcol); | |
+ XSetBackground(dpy, gc, bgcol); | |
+ | |
+ XSetForeground(dpy, rectgc, bgcol); | |
+ XSetBackground(dpy, rectgc, bgcol); | |
+ | |
+ XSetLineAttributes(dpy, gc, line_width, line_style, | |
+ cap_style, join_style); | |
+ | |
+ /* setup the font */ | |
+ font_info = XLoadQueryFont(dpy, font); | |
+ if (!font_info) | |
+ die("couldn't load font"); | |
+ | |
+ XSetFont(dpy, gc, font_info->fid); | |
+} | |
+ | |
+void | |
+eventloop(void) | |
+{ | |
+ XEvent e; | |
+ | |
+ redraw(); | |
+ | |
+ XSelectInput(dpy, win, ExposureMask | KeyPressMask); | |
+ | |
+ for (;;) { | |
+ XNextEvent(dpy, &e); | |
+ switch(e.type) { | |
+ case Expose: | |
+ redraw(); | |
+ break; | |
+ case KeyPress: | |
+ keypress(&e.xkey); | |
+ break; | |
+ default: | |
+ break; | |
+ } | |
+ | |
+ } | |
+} | |
+ | |
+/* this loop is required since pwm grabs the keyboard during the event loop */ | |
+void | |
+grabhack(void) | |
+{ | |
+ int maxwait = 3000000; /* 3 seconds */ | |
+ int interval = 5000; /* 5 millisec */ | |
+ int i, x; | |
+ | |
+ redraw(); | |
+ | |
+ /* if it takes longer than maxwait, just die */ | |
+ for (i = 0; i < (maxwait / interval); i++) { | |
+ usleep(interval); | |
+ x = XGrabKeyboard(dpy, win, False, GrabModeAsync, | |
+ GrabModeAsync, CurrentTime); | |
+ if (x == 0) | |
+ return; | |
+ } | |
+ | |
+ die("Couldn't grab keyboard"); | |
+} | |
+ | |
+void | |
+redraw(void) | |
+{ | |
+ int font_height, textwidth, promptwidth, dir, ascent, descent; | |
+ XCharStruct cs; | |
+ XRectangle ink, logical; | |
+ | |
+ font_height = font_info->ascent + font_info->descent; | |
+ XTextExtents(font_info, prompt, strlen(prompt), &dir, &ascent, | |
+ &descent, &cs); | |
+ promptwidth = cs.width; | |
+ XwcTextExtents(fontset, command, wcslen(command), &ink, &logical); | |
+ textwidth = logical.width; | |
+ textwidth += promptwidth; | |
+ | |
+ XFillRectangle(dpy, win, rectgc, 0, 0, WINWIDTH, WINHEIGHT); | |
+ XDrawRectangle(dpy, win, gc, 0, 0, WINWIDTH-1, WINHEIGHT-1); | |
+ XDrawString(dpy, win, gc, 2, font_height+2, prompt, | |
+ strlen(prompt)); | |
+ XwcDrawString(dpy, win, fontset, gc, 4 + promptwidth, | |
+ font_height+2, command, wcslen(command)); | |
+ XDrawLine(dpy, win, gc, 4 + textwidth, font_height + 2, | |
+ 4 + textwidth + 10, font_height+2); | |
+ | |
+ XFlush(dpy); | |
+} | |
+ | |
+void | |
+keypress(XKeyEvent *keyevent) | |
+{ | |
+ KeySym key_symbol; | |
+ int len; | |
+ wchar_t buffer[3]; | |
+ | |
+ len = XwcLookupString(ic, keyevent, buffer, 3, &key_symbol, NULL); | |
+ buffer[len] = L'\0'; | |
+ | |
+ switch(key_symbol) { | |
+ case XK_Escape: | |
+ exit(0); | |
+ break; | |
+ case XK_BackSpace: | |
+ len = wcslen(command); | |
+ if (len > 0) { | |
+ command[len-1] = L'\0'; | |
+ if (issecret) | |
+ secret[len-1] = L'\0'; | |
+ } | |
+ break; | |
+ case XK_Return: | |
+ case XK_KP_Enter: | |
+ execcmd(); | |
+ break; | |
+ default: | |
+ if (key_symbol > 255) | |
+ break; | |
+ | |
+ len = wcslen(command); | |
+ if (len < MAXCMD) { | |
+ if (issecret) { | |
+ secret[len] = buffer[0]; | |
+ secret[len+1] = L'\0'; | |
+ command[len] = L'*'; | |
+ command[len+1] = L'\0'; | |
+ } else { | |
+ command[len] = buffer[0]; | |
+ command[len+1] = L'\0'; | |
+ } | |
+ } | |
+ break; | |
+ } | |
+ redraw(); | |
+} | |
+ | |
+void | |
+execcmd(void) | |
+{ | |
+ char *shell; | |
+ char *argv[4]; | |
+ | |
+ XDestroyWindow(dpy, win); | |
+ | |
+ bzero(cbuf, sizeof(cbuf)); | |
+ if (issecret) | |
+ wcstombs(cbuf, secret, sizeof(cbuf)-1); | |
+ else | |
+ wcstombs(cbuf, command, sizeof(cbuf)-1); | |
+ | |
+ if (tostdout) { | |
+ printf("%s\n", cbuf); | |
+ exit(0); | |
+ } | |
+ | |
+ if (fork()) | |
+ exit(0); | |
+ | |
+ shell = getenv("SHELL"); | |
+ if (!shell) | |
+ shell = "/bin/sh"; | |
+ | |
+ argv[0] = basename(shell); | |
+ argv[1] = "-c"; | |
+ argv[2] = cbuf; | |
+ argv[3] = NULL; | |
+ | |
+ execv(shell, argv); | |
+ die("aiee, after exec"); | |
+ | |
+} | |
+ | |
+ | |
+void | |
+die(char *errstr, ...) | |
+{ | |
+ va_list ap; | |
+ | |
+ va_start(ap, errstr); | |
+ vfprintf(stderr, errstr, ap); | |
+ va_end(ap); | |
+ | |
+ exit(1); | |
+} | |
+ |