Subject:
Re: [nanogui] Terminal program for Nano-X
From:
Klaus Foerster ####@####.####
Date:
26 May 2005 21:33:18 +0100
Message-Id: <42963282.8000103@dungeon.de>
Hi Greg,
perhaps the linux termcaps in my distribution are broken for
vt52 and wterm.
I'm no Expert. I did just change nxterm to parse the -g settings and to
run the passed executable for
the non BSD-unix case.
when typing 'clear; in the TERM I do just see the characters
'H' and 'J' in a new line
I do receive the output the variable TERM is set to vt52.
Perhaps one of my 'patches' broke something.
As I do have problems connecting to the CVS server
I can no more check if I did make any accidental changes
bye
Klaus
P.S. Is there any way to force an nxterm to a certain screen position ?
or I shoud Greg Haerr wrote:
>: Basically I'm looking for a nxterm application with vt100 or xterm support
>: support does not have to be complete, but good enough to run vi after
>: having set the terminal sizes manually.
>
>I started with nxterm and nterm, both included in the
>distribution. I thought that nxterm was complete enough
>to run vi.
>
>
>
>: I'm alittle confused about the state of Nano-X.
>: It seems to be quite interesting for small applications, but I'm a
>: little unsure if Nano-X is still alive
>: or if I'm betting on a dead end.
>
>Quite a few people are using nano-X. However, it hasn't
>been updated recently, although it works well.
>
>
>: Is there any place where people post their Nona-X applications?
>
>I've asked people to post their applications, very few do.
>At Century Software, we posted all our nano-X apps on
>www.pixil.org, there's quite a few PDA-style apps there.
>
>Regards,
>
>Greg
>
>
/*
* nxterm - terminal emulator for Nano-X
*
* (C) 1994,95,96 by Torsten Scherer (TeSche)
* ####@####.####
*
* - quite some changes for W1R1
* - yet more changes for W1R2
*
* TeSche 01/96:
* - supports W_ICON & W_CLOSE
* - supports /etc/utmp logging for SunOS4 and Linux
* - supports catching of console output for SunOS4
* Phx 02-06/96:
* - supports NetBSD-Amiga
* Eero 11/97:
* - unsetenv(DISPLAY), setenv(LINES, COLUMNS).
* - Add new text modes (you need to use terminfo...).
* Eero 2/98:
* - Implemented fg/bgcolor setting. With monochrome server it changes
* bgmode variable, which tells in which mode to draw to screen
* (M_CLEAR/M_DRAW) and affects F_REVERSE settings.
* - Added a couple of checks.
*
* TODO:
* - Allocate and set sensible window palette for fg/bg color setting.
* - add scroll-region ('cs') command. Fairly many programs
* can take advantage of that.
* - Add xterm like mouse event to terminfo key event conversion... :)
* - check if current NetBSD really needs ifdefs below with
* current W server/library.
*/
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <utmp.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <pwd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MWINCLUDECOLORS
#include "nano-X.h"
#include "nxterm.h"
#define TITLE "nxterm"
#define SMALLBUFFER 80
#define LARGEBUFFER 1024
/*
* some pty helper functions
*/
#ifdef linux
#define NSIG _NSIG
#endif
#ifdef __FreeBSD__
#include <libutil.h>
#endif
/*
* some global variables
*/
static GR_WINDOW_ID w1; /* id for window */
static GR_GC_ID gc1; /* graphics context */
static GR_FONT_ID regFont;
/*static GR_FONT_ID boldFont;*/
static GR_SCREEN_INFO si; /* screen info */
static GR_FONT_INFO fi; /* Font Info */
static GR_WINDOW_INFO wi;
static GR_GC_INFO gi;
static GR_BOOL havefocus = GR_FALSE;
static pid_t pid;
static short winw, winh, console;
static int pipeh;
static short cblink = 0, visualbell = 0, debug = 0;
#ifdef __FreeBSD__
static char pty[SMALLBUFFER];
static struct winsize winsz;
#endif
#define fonh fi.height
#define fonw fi.maxwidth
int term_init(void);
void maximize(void);
void sigpipe(int sig);
void sigchld(int sig);
void sigquit(int sig);
void sflush(void);
void lineRedraw(void);
void sadd (char c);
void show_cursor (void);
void draw_cursor (void);
void hide_cursor (void);
void vscroll(int lines);
void esc5(unsigned char c);
void esc4(unsigned char c);
void esc3(unsigned char c);
void esc2(unsigned char c);
void esc1(unsigned char c);
void esc0(unsigned char c);
void printc(unsigned char c);
void init(void);
void term(void);
void usage(char *s);
void *mysignal(int signum, void *handler);
void sigchild(int signo);
/* **************************************************************************/
/*
*
*/
/* static int isIconified; */
static int isMaximized=0;
void maximize(void)
{
static short x0, y0, w, h, w_max,h_max;
if (!isMaximized)
{
w_max=si.cols-wi.bordersize;
h_max=si.rows-wi.bordersize;
GrMoveWindow(w1,0,0);
GrResizeWindow(w1,w_max, h_max);
isMaximized=1;
}
else
{
GrResizeWindow(w1, w, h);
GrMoveWindow(w1, x0, y0);
isMaximized=0;
}
}
/* **************************************************************************/
/*
* some common tool functions
*/
void sigpipe(int sig)
{
/* this one musn't close the window */
/* _write_utmp(pty, "", "", 0); */
kill(-pid, SIGHUP);
_exit(sig);
}
void sigchld(int sig)
{
/* _write_utmp(pty, "", "", 0); */
_exit(sig);
}
void sigquit(int sig)
{
signal(sig, SIG_IGN);
kill(-pid, SIGHUP);
}
/*
* this is the wterm terminal code, almost like VT52
*/
short bgmode, escstate, curx, cury, curon, curvis;
short savx, savy, wrap, style;
short col, row, colmask = 0x7f, rowmask = 0x7f;
/*
* something to buffer plain text output
*/
short sbufcnt = 0;
short sbufx, sbufy;
char lineBuffer[SMALLBUFFER+1];
char *sbuf=lineBuffer;
void sflush(void)
{
if (sbufcnt)
{
GrText(w1,gc1, sbufx*fonw, sbufy*fonh, sbuf, sbufcnt, GR_TFTOP);
sbufcnt = 0;
}
}
void lineRedraw(void)
{
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1, gc1, curx*fonw, cury*fonh, (col-curx)*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
if (sbufcnt)
{
sbuf[sbufcnt] = 0;
GrText(w1,gc1, sbufx*fonw, sbufy*fonh, sbuf, sbufcnt, GR_TFTOP);
}
}
void sadd (char c)
{
if (sbufcnt == SMALLBUFFER)
{
sflush ();
}
if (!sbufcnt)
{
sbufx = curx;
sbufy = cury;
}
sbuf[sbufcnt++] = c;
}
void show_cursor (void)
{
GrSetGCMode(gc1,GR_MODE_XOR);
GrSetGCForeground(gc1, WHITE);
GrFillRect(w1, gc1, curx*fonw, cury*fonh+1, fonw, fonh-1);
GrSetGCForeground(gc1, gi.foreground);
GrSetGCMode(gc1,GR_MODE_COPY);
}
void draw_cursor (void)
{
if (!curvis)
{
curvis = 1;
show_cursor();
}
}
void hide_cursor (void)
{
if (curvis)
{
curvis = 0;
show_cursor();
}
}
void vscroll(int lines)
{
hide_cursor();
GrCopyArea(w1,gc1,0, 0, winw, winh-(lines*fonh),
w1, 0, (lines*fonh), MWROP_SRCCOPY);
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1, gc1, 0, winh-(lines*fonh),
winw, (lines*fonh));
GrSetGCForeground(gc1,gi.foreground);
}
void esc5(unsigned char c) /* setting background color */
{
GrSetGCBackground(gc1, c);
GrGetGCInfo(gc1,&gi);
escstate = 0;
}
void esc4(unsigned char c) /* setting foreground color */
{
GrSetGCForeground(gc1,c);
GrGetGCInfo(gc1,&gi);
escstate = 0;
}
void esc3(unsigned char c) /* cursor position x axis */
{
curx = (c - 32) & colmask;
if (curx >= col)
curx = col - 1;
else if (curx < 0)
curx = 0;
escstate = 0;
}
void esc2(unsigned char c) /* cursor position y axis */
{
cury = (c - 32) & rowmask;
if (cury >= row)
cury = row - 1;
else if (cury < 0)
cury = 0;
escstate = 3;
}
void esc1(unsigned char c) /* various control codes */
{
static int ReverseMode=0;
escstate = 0;
switch(c)
{
case 'A':/* cursor up */
hide_cursor();
if ((cury -= 1) < 0)
cury = 0;
break;
case 'B':/* cursor down */
hide_cursor();
if ((cury += 1) >= row)
cury = row - 1;
break;
case 'C':/* cursor right */
hide_cursor();
if ((curx += 1) >= col)
curx = col - 1;
break;
case 'D':/* cursor left */
hide_cursor();
if ((curx -= 1) < 0)
curx = 0;
break;
case 'E':/* clear screen & home */
GrClearWindow(w1, 0);
curx = 0;
cury = 0;
break;
case 'H':/* cursor home */
curx = 0;
cury = 0;
break;
case 'I':/* reverse index */
if ((cury -= 1) < 0)
{
cury = 0;
vscroll(1);
}
break;
case 'J':/* erase to end of page */
if (cury < row-1)
{
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1,gc1, 0,(cury+1)*fonh, winw, (row-1-cury)*fonh);
GrSetGCForeground(gc1,gi.foreground);
}
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1, gc1, curx*fonw, cury*fonh, (col-curx)*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
break;
case 'K':/* erase to end of line */
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1, gc1, curx*fonw, cury*fonh, (col-curx)*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
break;
case 'L':/* insert line */
if (cury < row-1)
{
vscroll(1);
}
curx = 0;
break;
case 'M':/* delete line */
if (cury < row-1)
{
vscroll(1);
}
curx = 0;
break;
case 'Y':/* position cursor */
escstate = 2;
break;
case 'b':/* set foreground color */
escstate = 4;
break;
case 'c':/* set background color */
escstate = 5;
break;
case 'd':/* erase beginning of display */
/* w_setmode(win, bgmode); */
if (cury > 0)
{
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1,gc1, 0, 0, winw, cury*fonh);
GrSetGCForeground(gc1,gi.foreground);
}
if (curx > 0)
{
GrSetGCForeground(gc1,gi.background);
GrFillRect(w1,gc1, 0, cury*fonh, curx*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
}
break;
case 'e':/* enable cursor */
curon = 1;
break;
case 'f':/* disable cursor */
curon = 0;
break;
case 'j':/* save cursor position */
savx = curx;
savy = cury;
break;
case 'k':/* restore cursor position */
curx = savx;
cury = savy;
break;
case 'l':/* erase entire line */
GrSetGCForeground(gc1,gi.background);
GrRect(w1,gc1, 0, cury*fonh, winw, fonh);
GrSetGCForeground(gc1,gi.foreground);
curx = 0;
break;
case 'o':/* erase beginning of line */
if (curx > 0)
{
GrSetGCForeground(gc1,gi.background);
GrRect(w1,gc1,0, cury*fonh, curx*fonw, fonh);
GrSetGCForeground(gc1,gi.foreground);
}
break;
case 'p':/* enter reverse video mode */
{
if(!ReverseMode)
{
GrSetGCForeground(gc1,gi.background);
GrSetGCBackground(gc1,gi.foreground);
ReverseMode=1;
}
}
break;
case 'q':/* exit reverse video mode */
{
if(ReverseMode)
{
GrSetGCForeground(gc1,gi.foreground);
GrSetGCBackground(gc1,gi.background);
ReverseMode=0;
}
}
break;
case 'v':/* enable wrap at end of line */
wrap = 1;
break;
case 'w':/* disable wrap at end of line */
wrap = 0;
break;
/* and these are the extentions not in VT52 */
case 'G': /* clear all attributes */
break;
case 'g': /* enter bold mode */
/* GrSetGCFont(gc1, boldFont); */
break;
case 'h': /* exit bold mode */
/* GrSetGCFont(gc1, regFont); */
break;
case 'i': /* enter underline mode */
break;
/* j, k and l are already used */
case 'm': /* exit underline mode */
break;
/* these ones aren't yet on the termcap entries */
case 'n': /* enter italic mode */
break;
/* o, p and q are already used */
case 'r': /* exit italic mode */
break;
case 's': /* enter light mode */
break;
case 't': /* exit ligth mode */
break;
default: /* unknown escape sequence */
break;
}
}
/*
* un-escaped character print routine
*/
void esc0 (unsigned char c)
{
switch (c)
{
case 0:
/*
* printing \000 on a terminal means "do nothing".
* But since we use \000 as string terminator none
* of the characters that follow were printed.
*
* perl -e 'printf("a%ca", 0);'
*
* said 'a' in a wterm, but should say 'aa'. This
* bug screwed up most ncurses programs.
*
* kay.
*/
break;
case 7: /* bell */
if (visualbell)
{
/* w_setmode(win, M_INVERS); */
/* w_pbox(win, 0, 0, winw, winh); */
/* w_test(win, 0, 0); */
/* w_pbox(win, 0, 0, winw, winh); */
;
}
else
{
;
GrBell();
}
break;
case 8: /* backspace */
lineRedraw();
if (--curx < 0)
{
curx = 0;
}
break;
case 9: /* tab */
{
int borg,i;
borg=(((curx >> 3) + 1) << 3);
if(borg >= col)
{
borg=col-1;
}
borg=borg-curx;
for(i=0; i < borg; ++i){sadd(' ');}
if ((curx = ((curx >> 3) + 1) << 3) >= col)
{
curx = col - 1;
}
}
break;
case 10: /* line feed */
sflush();
if (++cury >= row)
{
vscroll(1);
cury = row-1;
}
break;
case 13: /* carriage return */
sflush();
curx = 0;
break;
case 27: /* escape */
sflush();
escstate = 1;
break;
case 127: /* delete */
break;
default: /* any printable char */
sadd(c);
if (++curx >= col)
{
sflush();
if (!wrap)
{
curx = col-1;
}
else
{
curx = 0;
if (++cury >= row)
{
vscroll(1);
}
}
}
break;
}
}
void printc(unsigned char c)
{
switch(escstate)
{
case 0:
esc0(c);
break;
case 1:
sflush();
esc1(c);
break;
case 2:
sflush();
esc2(c);
break;
case 3:
sflush();
esc3(c);
break;
case 4:
sflush();
esc4(c);
break;
case 5:
sflush();
esc5(c);
break;
default:
escstate = 0;
break;
}
}
void init(void)
{
curx = savx = 0;
cury = savy = 0;
wrap = 1;
curon = 1;
curvis = 0;
escstate = 0;
}
/*
* general code...
*/
void
term(void)
{
long in, l;
GR_EVENT wevent;
GR_EVENT_KEYSTROKE *kp;
unsigned char buf[LARGEBUFFER];
GrRegisterInput(pipeh);
while (42) {
if (havefocus)
draw_cursor();
GrGetNextEvent(&wevent);
switch(wevent.type) {
case GR_EVENT_TYPE_CLOSE_REQ:
GrClose();
exit(0);
break;
case GR_EVENT_TYPE_KEY_DOWN:
kp=(GR_EVENT_KEYSTROKE *)&wevent;
/* toss all special keys*/
if (kp->ch & MWKEY_NONASCII_MASK)
break;
*buf = kp->ch & 0xff;
write(pipeh, buf,1);
break;
case GR_EVENT_TYPE_FOCUS_IN:
havefocus = GR_TRUE;
break;
case GR_EVENT_TYPE_FOCUS_OUT:
havefocus = GR_FALSE;
hide_cursor();
break;
case GR_EVENT_TYPE_UPDATE:
/*
* if we get temporarily unmapped (moved),
* set cursor state off.
*/
if (wevent.update.utype == GR_UPDATE_UNMAPTEMP)
curvis = 0;
break;
case GR_EVENT_TYPE_FDINPUT:
hide_cursor();
while ((in = read(pipeh, buf, sizeof(buf))) > 0) {
for (l=0; l<in; l++) {
printc(buf[l]);
if (buf[l] == '\n')
printc('\r');
}
sflush();
}
break;
}
}
}
void usage(char *s)
{
if (s)
fprintf(stderr, "error: %s\n", s);
printf("usage: nxterm [-b] [-d] [-f <font family>] [-s <font size>]\n");
printf(" [-g <geometry>] [-v] [-c] [-h] [program {args}]\n");
printf("\n");
printf("-b blinking cursor (not implemented)\n");
printf("-d debug (not implemented)\n");
printf("-f <font family> not implemented\n");
printf("-s <font size> not implemented\n");
printf("-g <x_y_x0_y0> partially implemented\n");
printf("-v visualbell not implemented)\n");
printf("-g shows this help text\n");
exit(0);
}
void *mysignal(int signum, void *handler)
{
struct sigaction sa, so;
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(signum, &sa, &so);
return so.sa_handler;
}
/*
* guess what... :)
*/
#if ELKS
static char * nargv[2] = {"/bin/sash", NULL};
#else
#if DOS_DJGPP
static char * nargv[2] = {"bash", NULL};
#else
static char * nargv[2] = {"/bin/sh", NULL};
#endif
#endif
static char nargv0[128];
int main(int argc, char **argv)
{
GR_BITMAP bitmap1fg[7]; /* mouse cursor */
GR_BITMAP bitmap1bg[7];
GR_WM_PROPERTIES props;
short xp, yp, fsize;
char *family, *shell = NULL, *cptr, *geometry = NULL;
struct passwd *pw;
char buf[80];
short uid;
char thesh[128];
#ifdef __FreeBSD__
char *ptr;
#endif
#ifdef SIGTTOU
/* just in case we're started in the background */
signal(SIGTTOU, SIG_IGN);
#endif
/* who am I? */
if (!(pw = getpwuid((uid = getuid()))))
{
fprintf(stderr, "error: wterm can't determine determine your login name\n");
exit(-1);
}
if (GrOpen() < 0)
{
fprintf(stderr, "cannot open graphics\n");
exit(1);
}
GrGetScreenInfo(&si);
/*
* scan arguments...
*/
console = 0;
argv++;
while (*argv && **argv=='-')
switch (*(*argv+1))
{
case 'b':
cblink = 1;
argv++;
break;
case 'c':
console = 1;
argv++;
break;
case 'd':
debug = 1;
argv++;
break;
case 'f':
if (*++argv) {
family = *argv++;
} else {
usage("-f option requires an argument");
}
break;
case 's':
if (*++argv) {
fsize = atoi(*argv++);
} else {
usage("-s option requires an argument");
}
break;
case 'g':
if (*++argv) {
geometry = *argv++;
} else {
usage("-g option requires an argument");
}
break;
case 'h':
/* this will never return */
usage("");
case 'v':
visualbell = 1;
argv++;
break;
default:
usage("unknown option");
}
/*
* now *argv either points to a program to start or is zero
*/
if (*argv) {
shell = *argv;
printf("SHELL from cmdline is <%s>\n",shell);
}
if (!shell) {
shell = getenv("SHELL");
printf("SHELL from ENV is <%s>\n",shell);
}
if (!shell) {
shell = pw->pw_shell;
printf("SHELL from pw->pw)shell is <%s>\n",shell);
}
if (!shell) {
shell = "/bin/sh";
printf("default shell is <%s>\n",shell);
}
if (!*argv) {
/*
* the '-' makes the shell think it is a login shell,
* we leave argv[0] alone if it isn`t a shell (ie.
* the user specified the program to run as an argument
* to wterm.
*/
cptr = strrchr(shell, '/');
sprintf (thesh, "-%s", cptr ? cptr + 1 : shell);
*--argv = thesh;
printf("THESH is <%s>\n",thesh);
}
strncpy(nargv0,shell,127);
nargv[0]=nargv0;
col = 30;
row = 10;
xp = 0;
yp = 0;
if (geometry)
{
int tcol,trow,txp,typ;
char *p=geometry;
for(p=geometry;*p != 0;p++){
if(*p < '0' || *p >'9')
*p=' ';
}
sscanf(geometry,"%d %d %d %d",&tcol,&trow,&txp,&typ);
col=tcol;
row=trow;
xp=txp;
yp=typ;
if (col < 1)
{
col = 80;
}
if (row < 1)
{
row = 25;
}
if (col > 0x7f)
colmask = 0xffff;
if (row > 0x7f)
rowmask = 0xffff;
}
regFont=GrCreateFont(GR_FONT_SYSTEM_FIXED, 0, NULL);
/*regFont=GrCreateFont(GR_FONT_OEM_FIXED, 0, NULL);*/
/*boldFont=GrCreateFont(GR_FONT_SYSTEM_FIXED, 0, NULL);*/
GrGetFontInfo(regFont, &fi);
winw=col*fi.maxwidth;
winh=row*fi.height;
w1 = GrNewWindow(GR_ROOT_WINDOW_ID, xp,yp,winw, winh,0,BLACK,LTBLUE);
GrGetWMProperties(w1, &props);
props.flags = GR_WM_FLAGS_TITLE;
props.title = TITLE;
GrSetWMProperties(w1, &props);
GrSelectEvents(w1, GR_EVENT_MASK_BUTTON_DOWN |
GR_EVENT_MASK_KEY_DOWN |
GR_EVENT_MASK_FOCUS_IN | GR_EVENT_MASK_FOCUS_OUT |
GR_EVENT_MASK_UPDATE | GR_EVENT_MASK_CLOSE_REQ);
GrMapWindow(w1);
gc1 = GrNewGC();
GrSetGCFont(gc1, regFont);
#define _ ((unsigned) 0) /* off bits */
#define X ((unsigned) 1) /* on bits */
#define MASK(a,b,c,d,e,f,g) \
(((((((((((((a * 2) + b) * 2) + c) * 2) + d) * 2) \
+ e) * 2) + f) * 2) + g) << 9)
bitmap1fg[0] = MASK(_,_,X,_,X,_,_);
bitmap1fg[1] = MASK(_,_,_,X,_,_,_);
bitmap1fg[2] = MASK(_,_,_,X,_,_,_);
bitmap1fg[3] = MASK(_,_,_,X,_,_,_);
bitmap1fg[4] = MASK(_,_,_,X,_,_,_);
bitmap1fg[5] = MASK(_,_,_,X,_,_,_);
bitmap1fg[6] = MASK(_,_,X,_,X,_,_);
bitmap1bg[0] = MASK(_,X,X,X,X,X,_);
bitmap1bg[1] = MASK(_,_,X,X,X,_,_);
bitmap1bg[2] = MASK(_,_,X,X,X,_,_);
bitmap1bg[3] = MASK(_,_,X,X,X,_,_);
bitmap1bg[4] = MASK(_,_,X,X,X,_,_);
bitmap1bg[5] = MASK(_,_,X,X,X,_,_);
bitmap1bg[6] = MASK(_,X,X,X,X,X,_);
GrSetCursor(w1, 7, 7, 3, 3, GREEN, BLACK, bitmap1fg, bitmap1bg);
GrSetGCForeground(gc1, GREEN);
GrSetGCBackground(gc1, BLACK);
GrGetWindowInfo(w1,&wi);
GrGetGCInfo(gc1,&gi);
nargv[0]=shell;
sprintf(buf, "wterm: %s", shell);
/*
* what kind of terminal do we want to emulate?
*/
#ifdef __FreeBSD__
putenv ("TERM=wterm");
#else
putenv ("TERM=vt52");
#endif
/*
* this one should enable us to get rid of an /etc/termcap entry for
* both curses and ncurses, hopefully...
*/
if (termcap_string)
{
sprintf (termcap_string + strlen (termcap_string), "li#%d:co#%d:",
row, col);
putenv (termcap_string);
}
/* in case program absolutely needs terminfo entry, these 'should'
* transmit the screen size of correctly (at least xterm sets these
* and everything seems to work correctly...). Unlike putenv(),
* setenv() allocates also the given string not just a pointer.
*/
sprintf (buf, "%d", col);
setenv ("COLUMNS", buf, 1);
sprintf (buf, "%d", row);
setenv ("LINES", buf, 1);
init();
/*
* create a pty
*/
#ifdef __FreeBSD__
winsz.ws_col = col;
winsz.ws_row = row;
if ((pid = forkpty(&pipeh, pty, NULL, &winsz)) < 0)
{
fprintf(stderr,"wterm: can't create pty\r\n");
perror("wterm");
sleep(2);
GrKillWindow(w1);
exit(-1);
}
if ((ptr = rindex(pty, '/')))
{
strcpy(pty, ptr + 1);
}
if (!pid)
{
int i;
for (i = getdtablesize(); --i >= 3; )
close (i);
/*
* SIG_IGN are not reset on exec()
*/
for (i = NSIG; --i >= 0; )
signal (i, SIG_DFL);
/* caution: start shell with correct user id! */
seteuid(getuid());
setegid(getgid());
/* this shall not return */
printf("NOW RUNNING SHELL <%s> with following args:\n",shell);
for(i=0;argv[i] == NULL;i++){
printf("\t<%s>\n",argv[i]);
}
execvp(shell, argv);
/* oops? */
fprintf(stderr,"wterm: can't start shell\r\n");
sleep(3);
GrKillWindow(w1);
_exit(-1);
}
#else
pipeh = term_init();
printf("TERMINIT called\n");
#endif
/* _write_utmp(pty, pw->pw_name, "", time(0)); */
#if 0
/* catch some signals */
mysignal(SIGTERM, sigquit);
mysignal(SIGHUP, sigquit);
mysignal(SIGINT, SIG_IGN);
mysignal(SIGQUIT, sigquit);
mysignal(SIGPIPE, sigpipe);
mysignal(SIGCHLD, sigchld);
#endif
/* prepare to catch console output */
if (console)
{
/* for any OS chr$(7) might cause endless loops if
* catched from console
*/
visualbell = 1;
console = 0; /* data will come to normal pipe handle */
ioctl(pipeh, TIOCCONS, 0);
}
term();
return 0;
}
void sigchild(int signo)
{
GrClose();
exit(0);
}
int term_init(void)
{
int tfd;
int n = 0;
pid_t pid;
char pty_name[12];
again:
sprintf(pty_name, "/dev/ptyp%d", n);
if ((tfd = open(pty_name, O_RDWR | O_NONBLOCK)) < 0) {
if ((errno == EBUSY || errno == EIO) && n < 10) {
n++;
goto again;
}
fprintf(stderr, "Can't create pty %s\n", pty_name);
return -1;
}
signal(SIGCHLD, sigchild);
signal(SIGINT, sigchild);
if ((pid = fork()) == -1) {
fprintf(stderr, "No processes\n");
return -1;
}
if (!pid) {
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(tfd);
setsid();
pty_name[5] = 't';
if ((tfd = open(pty_name, O_RDWR)) < 0) {
fprintf(stderr, "Child: Can't open pty %s\n", pty_name);
exit(1);
}
close(STDERR_FILENO);
dup2(tfd, STDIN_FILENO);
dup2(tfd, STDOUT_FILENO);
dup2(tfd, STDERR_FILENO);
execv(nargv[0], nargv);
exit(1);
}
return tfd;
}
#if 0
void _write_utmp(char *line, char *user, char *host, int time)
{
int fh, offset, isEmpty, isLine;
struct utmp ut;
if ((fh = open("/etc/utmp", O_RDWR)) < 0) {
return;
}
/* first of all try to find an entry with the same line */
offset = 0;
isEmpty = -1;
isLine = -1;
while ((isLine < 0) && (read(fh, &ut, sizeof(ut)) == sizeof(ut))) {
if (!ut.ut_line[0])
{
if (isEmpty < 0)
{
isEmpty = offset;
}
}
else
{
if (!strncmp(ut.ut_line, line, sizeof(ut.ut_line))) {
isLine = offset;
}
}
offset += sizeof(ut);
}
if (isLine != -1) {
/* we've found a match */
lseek(fh, isLine, SEEK_SET);
} else if (isEmpty != -1) {
/* no match found, but at least an empty entry */
lseek(fh, isLine, SEEK_SET);
} else {
/* not even an empty entry found, assume we can append to the file */
}
if (time)
{
strncpy(ut.ut_line, line, sizeof(ut.ut_line));
strncpy(ut.ut_name, user, sizeof(ut.ut_name));
strncpy(ut.ut_host, host, sizeof(ut.ut_host));
ut.ut_time = time;
}
else
{
memset(&ut, 0, sizeof(ut));
}
write(fh, &ut, sizeof(ut));
close(fh);
}
#endif
/* These contained 'pt:re=\\EC' entries. I deleted them from MiNT and linux
* because neither of my (linux) termcap nor terminfo manual pages listed
* them.
* ++eero
*/
#ifdef __MINT__
static char termcap_string[1024] =
"TERMCAP=wterm|WTerm terminal:al=\\EL:am:bc=\\ED:bl=^G:bs:cd=\\EJ:\
ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :cr=^M:dl=\\EM:do=\\EB:ho=\\EH:is=\\Ev\\Eq:\
l0=F10:le=\\ED:ms:nd=\\EC:rc=\\Ek:rs=\\Ev\\Eq\\EE:sc=\\Ej:sr=\\EI:\
ti=\\Ev\\Ee\\EG:up=\\EA:ve=\\Ee:vi=\\Ef:so=\\Ep:se=\\Eq:mb=\\Ei:md=\\Eg:\
mr=\\Ep:me=\\EG:te=\\EG:us=\\Ei:ue=\\EG:\
kb=^H:kl=\\ED:kr=\\EC:ku=\\EA:kd=\\EB:kI=\\EI:kh=\\EE:kP=\\Ea:kN=\\Eb:k0=\\EY:\
k1=\\EP:k2=\\EQ:k3=\\ER:k4=\\ES:k5=\\ET:k6=\\EU:k7=\\EV:k8=\\EW:k9=\\EX:\
s0=\\Ey:s1=\\Ep:s2=\\Eq:s3=\\Er:s4=\\Es:s5=\\Et:s6=\\Eu:s7=\\Ev:s8=\\Ew:\
s9=\\Ex:";
#elif defined(linux) || defined(__FreeBSD__)
static char termcap_string[1024] =
"TERMCAP=wterm|WTerm terminal:al=\\EL:am:bc=\\ED:bl=^G:bs:cd=\\EJ:\
ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :cr=^M:dl=\\EM:do=\\EB:ho=\\EH:is=\\Ev\\Eq:\
l0=F10:le=\\ED:ms:nd=\\EC:rc=\\Ek:rs=\\Ev\\Eq\\EE:sc=\\Ej:sr=\\EI:\
ti=\\Ev\\Ee\\EG:up=\\EA:ve=\\Ee:vi=\\Ef:so=\\Ep:se=\\Eq:mb=\\Ei:md=\\Eg:\
mr=\\Ep:me=\\EG:te=\\EG:us=\\Ei:ue=\\EG:\
kb=^H:kl=\\E[D:kr=\\E[C:ku=\\E[A:kd=\\E[B:kI=\\EI:kh=\\EE:kP=\\Ea:kN=\\Eb:\
k0=\\EY:k1=\\EP:k2=\\EQ:k3=\\ER:k4=\\ES:k5=\\ET:k6=\\EU:k7=\\EV:k8=\\EW:\
k9=\\EX:s0=\\Ey:s1=\\Ep:s2=\\Eq:s3=\\Er:s4=\\Es:s5=\\Et:s6=\\Eu:s7=\\Ev:\
s8=\\Ew:s9=\\Ex:";
#elif defined(sun)
/* only very basic cursor keys so far... */
static char termcap_string[1024] =
"TERMCAP=wterm|WTerm terminal:al=\\EL:am:bc=\\ED:bl=^G:bs:cd=\\EJ:\
ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :cr=^M:dl=\\EM:do=\\EB:ho=\\EH:is=\\Ev\\Eq:\
l0=F10:le=\\ED:ms:nd=\\EC:pt:re=\\EC:rc=\\Ek:rs=\\Ev\\Eq\\EE:sc=\\Ej:sr=\\EI:\
ti=\\Ev\\Ee\\EG:up=\\EA:ve=\\Ee:vi=\\Ef:so=\\Ep:se=\\Eq:mb=\\Ei:md=\\Eg:\
mr=\\Ep:me=\\EG:te=\\EG:us=\\Ei:ue=\\EG:\
kb=^H:kl=\\E[D:kr=\\E[C:ku=\\E[A:kd=\\E[B:\
k1=\\E[224z:k2=\\E[225z:k3=\\E[226z:k4=\\E[227z:k5=\\E[228z:\
k6=\\E[229z:k7=\\E[230z:k8=\\E[231z:k9=\\E[232z:k0=\\E[233z:\
kN=\\E[222z:kP=\\E[216z:kh=\\E[214z:kH=\\E220z:";
#elif defined(__NetBSD__)
static char termcap_string[1024] =
"TERMCAP=wterm|WTerm terminal:al=\\EL:am:bc=\\ED:bl=^G:bs:cd=\\EJ:\
ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :cr=^M:dl=\\EM:do=\\EB:ho=\\EH:is=\\Ev\\Eq:\
l0=F10:le=\\ED:ms:nd=\\EC:pt:re=\\EC:rc=\\Ek:rs=\\Ev\\Eq\\EE:sc=\\Ej:sr=\\EI:\
ti=\\Ev\\Ee\\EG:up=\\EA:ve=\\Ee:vi=\\Ef:so=\\Ep:se=\\Eq:mb=\\Ei:md=\\Eg:\
mr=\\Ep:me=\\EG:te=\\EG:us=\\Ei:ue=\\EG:\
kb=^H:kl=\\E[D:kr=\\E[C:ku=\\E[A:kd=\\E[B:\
k1=\\E[224z:k2=\\E[225z:k3=\\E[226z:k4=\\E[227z:k5=\\E[228z:\
k6=\\E[229z:k7=\\E[230z:k8=\\E[231z:k9=\\E[232z:k0=\\E[233z:\
kN=\\E[222z:kP=\\E[216z:kh=\\E[214z:kH=\\E220z:";
#else
#error oops, a new operating system?
This is a compile time error
#endif