summaryrefslogtreecommitdiff
path: root/luit.c
diff options
context:
space:
mode:
Diffstat (limited to 'luit.c')
-rw-r--r--luit.c593
1 files changed, 593 insertions, 0 deletions
diff --git a/luit.c b/luit.c
new file mode 100644
index 0000000..41db6ff
--- /dev/null
+++ b/luit.c
@@ -0,0 +1,593 @@
+/*
+Copyright (c) 2001 by Juliusz Chroboczek
+
+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.
+*/
+/* $XFree86: xc/programs/luit/luit.c,v 1.10 2003/02/24 01:10:25 dawes Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+
+#ifdef SVR4
+#include <stropts.h>
+#endif
+
+#include <X11/fonts/fontenc.h>
+#include "luit.h"
+#include "sys.h"
+#include "other.h"
+#include "charset.h"
+#include "iso2022.h"
+
+static Iso2022Ptr inputState = NULL, outputState = NULL;
+
+static char *child_argv0 = NULL;
+static char *locale_name = NULL;
+int ilog = -1;
+int olog = -1;
+int verbose = 0;
+int converter = 0;
+int exitOnChild = 0;
+
+volatile int sigwinch_queued = 0;
+volatile int sigchld_queued = 0;
+
+static int convert(int, int);
+static int condom(int, char**);
+
+static void
+ErrorF(char *f, ...)
+{
+ va_list args;
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+}
+
+static void
+FatalError(char *f, ...)
+{
+ va_list args;
+ va_start(args, f);
+ vfprintf(stderr, f, args);
+ va_end(args);
+ exit(1);
+}
+
+
+static void
+help(void)
+{
+ fprintf(stderr,
+ "luit\n"
+ " [ -h ] [ -list ] [ -v ] [ -argv0 name ]\n"
+ " [ -gl gn ] [-gr gk] "
+ "[ -g0 set ] [ -g1 set ] "
+ "[ -g2 set ] [ -g3 set ]\n"
+ " [ -encoding encoding ] "
+ "[ +oss ] [ +ols ] [ +osl ] [ +ot ]\n"
+ " [ -kgl gn ] [-kgr gk] "
+ "[ -kg0 set ] [ -kg1 set ] "
+ "[ -kg2 set ] [ -kg3 set ]\n"
+ " [ -k7 ] [ +kss ] [ +kssgr ] [ -kls ]\n"
+ " [ -c ] [ -x ] [ -ilog filename ] [ -olog filename ] [ -- ]\n"
+ " [ program [ args ] ]\n");
+
+}
+
+
+static int
+parseOptions(int argc, char **argv)
+{
+ int i = 1;
+ while(i < argc) {
+ if(argv[i][0] != '-' && argv[i][0] != '+') {
+ break;
+ } else if(!strcmp(argv[i], "--")) {
+ i++;
+ break;
+ } else if(!strcmp(argv[i], "-v")) {
+ verbose++;
+ i++;
+ } else if(!strcmp(argv[i], "-h")) {
+ help();
+ exit(0);
+ } else if(!strcmp(argv[i], "-list")) {
+ reportCharsets();
+ exit(0);
+ } else if(!strcmp(argv[i], "+oss")) {
+ outputState->outputFlags &= ~OF_SS;
+ i++;
+ } else if(!strcmp(argv[i], "+ols")) {
+ outputState->outputFlags &= ~OF_LS;
+ i++;
+ } else if(!strcmp(argv[i], "+osl")) {
+ outputState->outputFlags &= ~OF_SELECT;
+ i++;
+ } else if(!strcmp(argv[i], "+ot")) {
+ outputState->outputFlags = OF_PASSTHRU;
+ i++;
+ } else if(!strcmp(argv[i], "-k7")) {
+ inputState->inputFlags &= ~IF_EIGHTBIT;
+ i++;
+ } else if(!strcmp(argv[i], "+kss")) {
+ inputState->inputFlags &= ~IF_SS;
+ i++;
+ } else if(!strcmp(argv[1], "+kssgr")) {
+ inputState->inputFlags &= ~IF_SSGR;
+ i++;
+ } else if(!strcmp(argv[i], "-kls")) {
+ inputState->inputFlags |= IF_LS;
+ i++;
+ } else if(!strcmp(argv[i], "-g0")) {
+ if(i + 1 >= argc)
+ FatalError("-g0 requires an argument\n");
+ G0(outputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-g1")) {
+ if(i + 1 >= argc)
+ FatalError("-g1 requires an argument\n");
+ G1(outputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-g2")) {
+ if(i + 1 >= argc)
+ FatalError("-g2 requires an argument\n");
+ G2(outputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-g3")) {
+ if(i + 1 >= argc)
+ FatalError("-g3 requires an argument\n");
+ G3(outputState) = getCharsetByName(argv[i + 1]);
+
+ i += 2;
+ } else if(!strcmp(argv[i], "-gl")) {
+ int j;
+ if(i + 1 >= argc)
+ FatalError("-gl requires an argument\n");
+ if(strlen(argv[i + 1]) != 2 ||
+ argv[i + 1][0] != 'g')
+ j = -1;
+ else
+ j = argv[i + 1][1] - '0';
+ if(j < 0 || j > 3)
+ FatalError("The argument of -gl "
+ "should be one of g0 through g3,\n"
+ "not %s\n", argv[i + 1]);
+ else
+ outputState->glp = &outputState->g[j];
+ i += 2;
+ } else if(!strcmp(argv[i], "-gr")) {
+ int j;
+ if(i + 1 >= argc)
+ FatalError("-gr requires an argument\n");
+ if(strlen(argv[i + 1]) != 2 ||
+ argv[i + 1][0] != 'g')
+ j = -1;
+ else
+ j = argv[i + 1][1] - '0';
+ if(j < 0 || j > 3)
+ FatalError("The argument of -gl "
+ "should be one of g0 through g3,\n"
+ "not %s\n", argv[i + 1]);
+ else
+ outputState->grp = &outputState->g[j];
+ i += 2;
+ } else if(!strcmp(argv[i], "-kg0")) {
+ if(i + 1 >= argc)
+ FatalError("-kg0 requires an argument\n");
+ G0(inputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-kg1")) {
+ if(i + 1 >= argc)
+ FatalError("-kg1 requires an argument\n");
+ G1(inputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-kg2")) {
+ if(i + 1 >= argc)
+ FatalError("-kg2 requires an argument\n");
+ G2(inputState) = getCharsetByName(argv[i + 1]);
+ i += 2;
+ } else if(!strcmp(argv[i], "-kg3")) {
+ if(i + 1 >= argc)
+ FatalError("-kg3 requires an argument\n");
+ G3(inputState) = getCharsetByName(argv[i + 1]);
+
+ i += 2;
+ } else if(!strcmp(argv[i], "-kgl")) {
+ int j;
+ if(i + 1 >= argc)
+ FatalError("-kgl requires an argument\n");
+ if(strlen(argv[i + 1]) != 2 ||
+ argv[i + 1][0] != 'g')
+ j = -1;
+ else
+ j = argv[i + 1][1] - '0';
+ if(j < 0 || j > 3)
+ FatalError("The argument of -kgl "
+ "should be one of g0 through g3,\n"
+ "not %s\n", argv[i + 1]);
+ else
+ inputState->glp = &inputState->g[j];
+ i += 2;
+ } else if(!strcmp(argv[i], "-kgr")) {
+ int j;
+ if(i + 1 >= argc)
+ FatalError("-kgl requires an argument\n");
+ if(strlen(argv[i + 1]) != 2 ||
+ argv[i + 1][0] != 'g')
+ j = -1;
+ else
+ j = argv[i + 1][1] - '0';
+ if(j < 0 || j > 3)
+ FatalError("The argument of -kgl "
+ "should be one of g0 through g3,\n"
+ "not %s\n", argv[i + 1]);
+ else
+ inputState->grp = &inputState->g[j];
+ i += 2;
+ } else if(!strcmp(argv[i], "-argv0")) {
+ if(i + 1 >= argc)
+ FatalError("-argv0 requires an argument\n");
+ child_argv0 = argv[i + 1];
+ i += 2;
+ } else if(!strcmp(argv[i], "-x")) {
+ exitOnChild = 1;
+ i++;
+ } else if(!strcmp(argv[i], "-c")) {
+ converter = 1;
+ i++;
+ } else if(!strcmp(argv[i], "-ilog")) {
+ if(i + 1 >= argc)
+ FatalError("-ilog requires an argument\n");
+ ilog = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
+ if(ilog < 0) {
+ perror("Couldn't open input log");
+ exit(1);
+ }
+ i += 2;
+ } else if(!strcmp(argv[i], "-olog")) {
+ if(i + 1 >= argc)
+ FatalError("-olog requires an argument\n");
+ olog = open(argv[i + 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
+ if(olog < 0) {
+ perror("Couldn't open output log");
+ exit(1);
+ }
+ i += 2;
+ } else if(!strcmp(argv[i], "-encoding")) {
+ int rc;
+ if(i + 1 >= argc)
+ FatalError("-encoding requires an argument\n");
+ rc = initIso2022(NULL, argv[i + 1], outputState);
+ if(rc < 0)
+ FatalError("Couldn't init output state\n");
+ i += 2;
+ } else {
+ FatalError("Unknown option %s\n", argv[i]);
+ }
+ }
+ return i;
+}
+
+static int
+parseArgs(int argc, char **argv, char *argv0,
+ char **path_return, char ***argv_return)
+{
+ char *path = NULL;
+ char **child_argv = NULL;
+
+ if(argc <= 0) {
+ char *shell;
+ shell = getenv("SHELL");
+ if(shell) {
+ path = malloc(strlen(shell) + 1);
+ if(!path)
+ goto bail;
+ strcpy(path, shell);
+ } else {
+ path = malloc(strlen("/bin/sh") + 1);
+ if(!path)
+ goto bail;
+ strcpy(path, "/bin/sh");
+ }
+ child_argv = malloc(2 * sizeof(char*));
+ if(!child_argv)
+ goto bail;
+ if(argv0)
+ child_argv[0] = argv0;
+ else
+ child_argv[0] = my_basename(path);
+ child_argv[1] = NULL;
+ } else {
+ path = malloc(strlen(argv[0]) + 1);
+ if(!path)
+ goto bail;
+ strcpy(path, argv[0]);
+ child_argv = malloc((argc + 1) * sizeof(char*));
+ if(!child_argv) {
+ goto bail;
+ }
+ if(child_argv0)
+ child_argv[0] = argv0;
+ else
+ child_argv[0] = my_basename(argv[0]);
+ memcpy(child_argv + 1, argv + 1, (argc - 1) * sizeof(char*));
+ child_argv[argc] = NULL;
+ }
+
+ *path_return = path;
+ *argv_return = child_argv;
+ return 0;
+
+ bail:
+ if(path)
+ free(path);
+ if(argv)
+ free(argv);
+ return -1;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int rc;
+ int i;
+ char *l;
+
+ l = setlocale(LC_ALL, "");
+ if(!l)
+ ErrorF("Warning: couldn't set locale.\n");
+
+ inputState = allocIso2022();
+ if(!inputState)
+ FatalError("Couldn't create input state\n");
+
+ outputState = allocIso2022();
+ if(!outputState)
+ FatalError("Couldn't create output state\n");
+
+ if(l) {
+ locale_name = setlocale(LC_CTYPE, NULL);
+ } else {
+ locale_name = getenv("LC_ALL");
+ if(locale_name == NULL) {
+ locale_name = getenv("LC_CTYPE");
+ if(locale_name == NULL) {
+ locale_name = getenv("LANG");
+ }
+ }
+ }
+
+ if(locale_name == NULL) {
+ ErrorF("Couldn't get locale name -- using C\n");
+ locale_name = "C";
+ }
+
+ rc = initIso2022(locale_name, NULL, outputState);
+ if(rc < 0)
+ FatalError("Couldn't init output state\n");
+
+ i = parseOptions(argc, argv);
+ if(i < 0)
+ FatalError("Couldn't parse options\n");
+
+ rc = mergeIso2022(inputState, outputState);
+ if(rc < 0)
+ FatalError("Couldn't init input state\n");
+
+ if(converter)
+ return convert(0, 1);
+ else
+ return condom(argc - i, argv + i);
+}
+
+static int
+convert(int ifd, int ofd)
+{
+ int rc, i;
+ unsigned char buf[BUFFER_SIZE];
+
+ rc = droppriv();
+ if(rc < 0) {
+ perror("Couldn't drop priviledges");
+ exit(1);
+ }
+
+ while(1) {
+ i = read(ifd, buf, BUFFER_SIZE);
+ if(i <= 0) {
+ if(i < 0) {
+ perror("Read error");
+ exit(1);
+ }
+ break;
+ }
+ copyOut(outputState, ofd, buf, i);
+ }
+ return 0;
+}
+
+
+static int
+condom(int argc, char **argv)
+{
+ int pty;
+ int pid;
+ char *line;
+ char *path;
+ char **child_argv;
+ int rc;
+
+ rc = parseArgs(argc, argv, child_argv0,
+ &path, &child_argv);
+ if(rc < 0)
+ FatalError("Couldn't parse arguments\n");
+
+ rc = allocatePty(&pty, &line);
+ if(rc < 0) {
+ perror("Couldn't allocate pty");
+ exit(1);
+ }
+
+ rc = droppriv();
+ if(rc < 0) {
+ perror("Couldn't drop priviledges");
+ exit(1);
+ }
+
+ pid = fork();
+ if(pid < 0) {
+ perror("Couldn't fork");
+ exit(1);
+ }
+
+ if(pid == 0) {
+ close(pty);
+ child(line, path, child_argv);
+ } else {
+ free(child_argv);
+ free(path);
+ free(line);
+ parent(pid, pty);
+ }
+
+ return 0;
+}
+
+void
+child(char *line, char *path, char **argv)
+{
+ int tty;
+ int pgrp;
+
+ close(0);
+ close(1);
+ close(2);
+ pgrp = setsid();
+ if(pgrp < 0) {
+ kill(getppid(), SIGABRT);
+ exit(1);
+ }
+
+ tty = openTty(line);
+ if(tty < 0) {
+ kill(getppid(), SIGABRT);
+ exit(1);
+ }
+
+ if(tty != 0)
+ dup2(tty, 0);
+ if(tty != 1)
+ dup2(tty, 1);
+ if(tty != 2)
+ dup2(tty, 2);
+
+ if(tty > 2)
+ close(tty);
+
+ execvp(path, argv);
+ perror("Couldn't exec");
+ exit(1);
+}
+
+static void
+sigwinchHandler(int sig) {
+ sigwinch_queued = 1;
+}
+
+static void
+sigchldHandler(int sig)
+{
+ sigchld_queued = 1;
+}
+
+void
+parent(int pid, int pty)
+{
+ unsigned char buf[BUFFER_SIZE];
+ int i;
+ int val;
+ int rc;
+
+ if(verbose) {
+ reportIso2022(outputState);
+ }
+
+#ifdef SIGWINCH
+ installHandler(SIGWINCH, sigwinchHandler);
+#endif
+ installHandler(SIGCHLD, sigchldHandler);
+
+ rc = setRawTermios();
+ if(rc < 0)
+ FatalError("Couldn't set terminal to raw\n");
+
+ val = fcntl(0, F_GETFL, 0);
+ if(val >= 0) {
+ fcntl(0, F_SETFL, val | O_NONBLOCK);
+ }
+ val = fcntl(pty, F_GETFL, 0);
+ if(val >= 0) {
+ fcntl(pty, F_SETFL, val | O_NONBLOCK);
+ }
+
+ setWindowSize(0, pty);
+
+ for(;;) {
+ rc = waitForInput(0, pty);
+
+ if(sigwinch_queued) {
+ sigwinch_queued = 0;
+ setWindowSize(0, pty);
+ }
+
+ if(sigchld_queued && exitOnChild)
+ break;
+
+ if(rc > 0) {
+ if(rc & 2) {
+ i = read(pty, buf, BUFFER_SIZE);
+ if((i == 0) || ((i < 0) && (errno != EAGAIN)))
+ break;
+ if(i > 0)
+ copyOut(outputState, 0, buf, i);
+ }
+ if(rc & 1) {
+ i = read(0, buf, BUFFER_SIZE);
+ if((i == 0) || ((i < 0) && (errno != EAGAIN)))
+ break;
+ if(i > 0)
+ copyIn(inputState, pty, buf, i);
+ }
+ }
+ }
+
+ restoreTermios();
+}