openenvutils/commandshell/shell/src/modules/zpty.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 #ifndef __SYMBIAN32__
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * zpty.c - sub-processes with pseudo terminals
       
     7  *
       
     8  * This file is part of zsh, the Z shell.
       
     9  *
       
    10  * Copyright (c) 2000 Sven Wischnowsky
       
    11  * All rights reserved.
       
    12  *
       
    13  * Permission is hereby granted, without written agreement and without
       
    14  * license or royalty fees, to use, copy, modify, and distribute this
       
    15  * software and to distribute modified versions of this software for any
       
    16  * purpose, provided that the above copyright notice and the following
       
    17  * two paragraphs appear in all copies of this software.
       
    18  *
       
    19  * In no event shall Sven Wischnowsky or the Zsh Development Group be liable
       
    20  * to any party for direct, indirect, special, incidental, or consequential
       
    21  * damages arising out of the use of this software and its documentation,
       
    22  * even if Sven Wischnowsky and the Zsh Development Group have been advised of
       
    23  * the possibility of such damage.
       
    24  *
       
    25  * Sven Wischnowsky and the Zsh Development Group specifically disclaim any
       
    26  * warranties, including, but not limited to, the implied warranties of
       
    27  * merchantability and fitness for a particular purpose.  The software
       
    28  * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the
       
    29  * Zsh Development Group have no obligation to provide maintenance,
       
    30  * support, updates, enhancements, or modifications.
       
    31  *
       
    32  */
       
    33 #include "zpty.mdh"
       
    34 #include "zpty.pro"
       
    35 
       
    36 #ifdef __SYMBIAN32__
       
    37 #ifdef __WINSCW__
       
    38 #pragma warn_unusedarg off
       
    39 #pragma warn_possunwant off
       
    40 #endif//__WINSCW__
       
    41 #endif//__SYMBIAN32__
       
    42 
       
    43 #ifdef __SYMBIAN32__
       
    44 #include "dummy.h"
       
    45 #endif //__SYMBIAN32__
       
    46 
       
    47 /* The number of bytes we normally read when given no pattern and the
       
    48  * upper bound on the number of bytes we read (even if we are give a
       
    49  * pattern). */
       
    50 
       
    51 #define READ_MAX (1024 * 1024)
       
    52 
       
    53 typedef struct ptycmd *Ptycmd;
       
    54 
       
    55 struct ptycmd {
       
    56     Ptycmd next;
       
    57     char *name;
       
    58     char **args;
       
    59     int fd;
       
    60     int pid;
       
    61     int echo;
       
    62     int nblock;
       
    63     int fin;
       
    64     int read;
       
    65     char *old;
       
    66     int olen;
       
    67 };
       
    68 
       
    69 static Ptycmd ptycmds;
       
    70 
       
    71 static int
       
    72 ptynonblock(int fd)
       
    73 {
       
    74 #ifdef O_NDELAY
       
    75 # ifdef O_NONBLOCK
       
    76 #  define NONBLOCK (O_NDELAY|O_NONBLOCK)
       
    77 # else /* !O_NONBLOCK */
       
    78 #  define NONBLOCK O_NDELAY
       
    79 # endif /* !O_NONBLOCK */
       
    80 #else /* !O_NDELAY */
       
    81 # ifdef O_NONBLOCK
       
    82 #  define NONBLOCK O_NONBLOCK
       
    83 # else /* !O_NONBLOCK */
       
    84 #  define NONBLOCK 0
       
    85 # endif /* !O_NONBLOCK */
       
    86 #endif /* !O_NDELAY */
       
    87 
       
    88 #if NONBLOCK
       
    89     long mode;
       
    90 
       
    91     mode = fcntl(fd, F_GETFL, 0);
       
    92     if (mode != -1 && !(mode & NONBLOCK) &&
       
    93 	!fcntl(fd, F_SETFL, mode | NONBLOCK))
       
    94 	return 1;
       
    95 
       
    96 #endif /* NONBLOCK */
       
    97     return 0;
       
    98 
       
    99 #undef NONBLOCK
       
   100 }
       
   101 
       
   102 /**/
       
   103 static int
       
   104 ptygettyinfo(int fd, struct ttyinfo *ti)
       
   105 {
       
   106     if (fd != -1) {
       
   107 #ifdef HAVE_TERMIOS_H
       
   108 # ifdef HAVE_TCGETATTR
       
   109 	if (tcgetattr(fd, &ti->tio) == -1)
       
   110 # else
       
   111 	if (ioctl(fd, TCGETS, &ti->tio) == -1)
       
   112 # endif
       
   113 	    return 1;
       
   114 #else
       
   115 # ifdef HAVE_TERMIO_H
       
   116 	ioctl(fd, TCGETA, &ti->tio);
       
   117 # else
       
   118 	ioctl(fd, TIOCGETP, &ti->sgttyb);
       
   119 	ioctl(fd, TIOCLGET, &ti->lmodes);
       
   120 	ioctl(fd, TIOCGETC, &ti->tchars);
       
   121 	ioctl(fd, TIOCGLTC, &ti->ltchars);
       
   122 # endif
       
   123 #endif
       
   124 	return 0;
       
   125     }
       
   126     return 1;
       
   127 }
       
   128 
       
   129 /**/
       
   130 static void
       
   131 ptysettyinfo(int fd, struct ttyinfo *ti)
       
   132 {
       
   133     if (fd != -1) {
       
   134 #ifdef HAVE_TERMIOS_H
       
   135 # ifdef HAVE_TCGETATTR
       
   136 #  ifndef TCSADRAIN
       
   137 #   define TCSADRAIN 1	/* XXX Princeton's include files are screwed up */
       
   138 #  endif
       
   139 	tcsetattr(fd, TCSADRAIN, &ti->tio);
       
   140     /* if (tcsetattr(SHTTY, TCSADRAIN, &ti->tio) == -1) */
       
   141 # else
       
   142 	ioctl(fd, TCSETS, &ti->tio);
       
   143     /* if (ioctl(SHTTY, TCSETS, &ti->tio) == -1) */
       
   144 # endif
       
   145 	/*	zerr("settyinfo: %e",NULL,errno)*/ ;
       
   146 #else
       
   147 # ifdef HAVE_TERMIO_H
       
   148 	ioctl(fd, TCSETA, &ti->tio);
       
   149 # else
       
   150 	ioctl(fd, TIOCSETN, &ti->sgttyb);
       
   151 	ioctl(fd, TIOCLSET, &ti->lmodes);
       
   152 	ioctl(fd, TIOCSETC, &ti->tchars);
       
   153 	ioctl(fd, TIOCSLTC, &ti->ltchars);
       
   154 # endif
       
   155 #endif
       
   156     }
       
   157 }
       
   158 
       
   159 static Ptycmd
       
   160 getptycmd(char *name)
       
   161 {
       
   162     Ptycmd p;
       
   163 
       
   164     for (p = ptycmds; p; p = p->next)
       
   165 	if (!strcmp(p->name, name))
       
   166 	    return p;
       
   167 
       
   168     return NULL;
       
   169 }
       
   170 
       
   171 #ifdef USE_DEV_PTMX
       
   172 
       
   173 #ifdef HAVE_SYS_STROPTS_H
       
   174 #ifndef __SYMBIAN32__
       
   175 #include <sys/stropts.h> 
       
   176 #endif//__SYMBIAN32__
       
   177 #endif
       
   178 
       
   179 #if defined(I_FIND) && defined(I_PUSH)
       
   180 /*
       
   181  * These tests are ad hoc.  Unfortunately if you get the wrong ioctl,
       
   182  * STREAMS simply hangs up, so there's no obvious way of doing this
       
   183  * more systematically.
       
   184  *
       
   185  * Apparently Solaris needs all three ioctls, but HP-UX doesn't need
       
   186  * ttcompat.  The Solaris definition has been extended to all __SVR4
       
   187  * as a guess; I have no idea if this is right.
       
   188  */
       
   189 #ifdef __SVR4
       
   190 #define USE_STREAMS_IOCTLS
       
   191 #define USE_STREAMS_TTCOMPAT
       
   192 #endif
       
   193 #ifdef __hpux
       
   194 #define USE_STREAMS_IOCTLS
       
   195 #endif
       
   196 #endif
       
   197 
       
   198 static int
       
   199 get_pty(int master, int *retfd)
       
   200 {
       
   201     static char *name;
       
   202     static int mfd, sfd;
       
   203 #ifdef USE_STREAMS_IOCTLS
       
   204     int ret;
       
   205 #endif
       
   206 
       
   207     if (master) {
       
   208 	if ((mfd = open("/dev/ptmx", O_RDWR|O_NOCTTY)) < 0)
       
   209 	    return 1;
       
   210 
       
   211 	if (grantpt(mfd) || unlockpt(mfd) || !(name = (char*)ptsname(mfd))) {
       
   212 	    close(mfd);
       
   213 	    return 1;
       
   214 	}
       
   215 	*retfd = mfd;
       
   216 
       
   217 	return 0;
       
   218     }
       
   219     if ((sfd = open(name, O_RDWR
       
   220 #ifndef __CYGWIN__
       
   221 		    /* It is not clear whether this flag is actually needed. */
       
   222 		    |O_NOCTTY
       
   223 #endif
       
   224 	)) < 0) {
       
   225 	close(mfd);
       
   226 	return 1;
       
   227     }
       
   228 #ifdef USE_STREAMS_IOCTLS
       
   229     if ((ret = ioctl(sfd, I_FIND, "ptem")) != 1)
       
   230        if (ret == -1 || ioctl(sfd, I_PUSH, "ptem") == -1) {
       
   231 	   close(mfd);
       
   232 	   close(sfd);
       
   233 	   return 1;
       
   234        }
       
   235     if ((ret = ioctl(sfd, I_FIND, "ldterm")) != 1)
       
   236        if (ret == -1 || ioctl(sfd, I_PUSH, "ldterm") == -1) {
       
   237 	   close(mfd);
       
   238 	   close(sfd);
       
   239 	   return 1;
       
   240        }
       
   241 #ifdef USE_STREAMS_TTCOMPAT
       
   242     if ((ret = ioctl(sfd, I_FIND, "ttcompat")) != 1)
       
   243        if (ret == -1 || ioctl(sfd, I_PUSH, "ttcompat") == -1) {
       
   244 	   close(mfd);
       
   245 	   close(sfd);
       
   246 	   return 1;
       
   247        }
       
   248 #endif
       
   249 #endif
       
   250 
       
   251     *retfd = sfd;
       
   252 
       
   253     return 0;
       
   254 }
       
   255 
       
   256 #else /* No /dev/ptmx or no pt functions */
       
   257 
       
   258 static int
       
   259 get_pty(int master, int *retfd)
       
   260 {
       
   261 
       
   262 #ifdef __linux
       
   263     static char char1[] = "abcdefghijklmnopqrstuvwxyz";
       
   264     static char char2[] = "0123456789abcdef";
       
   265 #elif defined(__FreeBSD__) || defined(__DragonFly__)
       
   266     static char char1[] = "pqrsPQRS";
       
   267     static char char2[] = "0123456789abcdefghijklmnopqrstuv";
       
   268 #else /* __FreeBSD__ || __DragonFly__ */
       
   269     static char char1[] = "pqrstuvwxyzPQRST";
       
   270     static char char2[] = "0123456789abcdef";
       
   271 #endif
       
   272 
       
   273     static char name[11];
       
   274     static int mfd, sfd;
       
   275     char *p1, *p2;
       
   276 
       
   277     if (master) {
       
   278 	strcpy(name, "/dev/ptyxx");
       
   279 
       
   280 	for (p1 = char1; *p1; p1++) {
       
   281 	    name[8] = *p1;
       
   282 	    for (p2 = char2; *p2; p2++) {
       
   283 		name[9] = *p2;
       
   284 		if ((mfd = open(name, O_RDWR|O_NOCTTY)) >= 0) {
       
   285 		    *retfd = mfd;
       
   286 
       
   287 		    return 0;
       
   288 		}
       
   289 	    }
       
   290 	}
       
   291     }
       
   292     name[5] = 't';
       
   293     if ((sfd = open(name, O_RDWR|O_NOCTTY)) >= 0) {
       
   294 	*retfd = sfd;
       
   295 
       
   296 	return 0;
       
   297     }
       
   298     close(mfd);
       
   299 
       
   300     return 1;
       
   301 }
       
   302 
       
   303 #endif /* /dev/ptmx or alternatives */
       
   304 
       
   305 static int
       
   306 newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
       
   307 {
       
   308     Ptycmd p;
       
   309     int master, slave, pid;
       
   310     Eprog prog;
       
   311 
       
   312     prog = parse_string(zjoin(args, ' ', 1));
       
   313     if (!prog) {
       
   314 	errflag = 0;
       
   315 	return 1;
       
   316     }
       
   317 
       
   318     if (get_pty(1, &master)) {
       
   319 	zwarnnam(nam, "can't open pseudo terminal: %e", NULL, errno);
       
   320 	return 1;
       
   321     }
       
   322     if ((pid = fork()) == -1) {
       
   323 	zwarnnam(nam, "can't create pty command %s: %e", pname, errno);
       
   324 	close(master);
       
   325 	return 1;
       
   326     } else if (!pid) {
       
   327 	/* This code copied from the clone module, except for getting *
       
   328 	 * the descriptor from get_pty() and duplicating it to 0/1/2. */
       
   329 
       
   330 	clearjobtab(0);
       
   331 	ppid = getppid();
       
   332 	mypid = getpid();
       
   333 #ifdef HAVE_SETSID
       
   334 	if (setsid() != mypid) {
       
   335 	    zwarnnam(nam, "failed to create new session: %e", NULL, errno);
       
   336 #endif
       
   337 #ifdef TIOCNOTTY
       
   338 	    if (ioctl(SHTTY, TIOCNOTTY, 0))
       
   339 		zwarnnam(nam, "%e", NULL, errno);
       
   340 	    setpgrp(0L, mypid);
       
   341 #endif
       
   342 #ifdef HAVE_SETSID
       
   343 	}
       
   344 #endif
       
   345 
       
   346 	if (get_pty(0, &slave))
       
   347 	    exit(1);
       
   348 #ifdef TIOCGWINSZ
       
   349 	/* Set the window size before associating with the terminal *
       
   350 	 * so that we don't get hit with a SIGWINCH.  I'm paranoid. */
       
   351 	if (interact) {
       
   352 	    struct ttyinfo info;
       
   353 
       
   354 	    if (ioctl(slave, TIOCGWINSZ, (char *) &info.winsize) == 0) {
       
   355 		info.winsize.ws_row = lines;
       
   356 		info.winsize.ws_col = columns;
       
   357 		ioctl(slave, TIOCSWINSZ, (char *) &info.winsize);
       
   358 	    }
       
   359 	}
       
   360 #endif /* TIOCGWINSZ */
       
   361 
       
   362 	if (!echo) {
       
   363 	    struct ttyinfo info;
       
   364 
       
   365 	    if (!ptygettyinfo(slave, &info)) {
       
   366 #ifdef HAVE_TERMIOS_H
       
   367 		info.tio.c_lflag &= ~ECHO;
       
   368 #else
       
   369 #ifdef HAVE_TERMIO_H
       
   370 		info.tio.c_lflag &= ~ECHO;
       
   371 #else
       
   372 		info.tio.lmodes &= ~ECHO; /**** dunno if this is right */
       
   373 #endif
       
   374 #endif
       
   375 		ptysettyinfo(slave, &info);
       
   376 	    }
       
   377 	}
       
   378 
       
   379 #ifdef TIOCSCTTY
       
   380 	ioctl(slave, TIOCSCTTY, 0);
       
   381 #endif
       
   382 
       
   383 	close(0);
       
   384 	close(1);
       
   385 	close(2);
       
   386 
       
   387 	dup2(slave, 0);
       
   388 	dup2(slave, 1);
       
   389 	dup2(slave, 2);
       
   390 
       
   391 	closem(0);
       
   392 	close(slave);
       
   393 	close(master);
       
   394 	close(coprocin);
       
   395 	close(coprocout);
       
   396 	init_io();
       
   397 	setsparam("TTY", ztrdup(ttystrname));
       
   398 
       
   399 	opts[INTERACTIVE] = 0;
       
   400 	execode(prog, 1, 0);
       
   401 	stopmsg = 2;
       
   402 	zexit(lastval, 0);
       
   403     }
       
   404     master = movefd(master);
       
   405 
       
   406     p = (Ptycmd) zalloc(sizeof(*p));
       
   407 
       
   408     p->name = ztrdup(pname);
       
   409     p->args = zarrdup(args);
       
   410     p->fd = master;
       
   411     p->pid = pid;
       
   412     p->echo = echo;
       
   413     p->nblock = nblock;
       
   414     p->fin = 0;
       
   415     p->read = -1;
       
   416     p->old = NULL;
       
   417     p->olen = 0;
       
   418 
       
   419     p->next = ptycmds;
       
   420     ptycmds = p;
       
   421 
       
   422     if (nblock)
       
   423 	ptynonblock(master);
       
   424 
       
   425     return 0;
       
   426 }
       
   427 
       
   428 static void
       
   429 deleteptycmd(Ptycmd cmd)
       
   430 {
       
   431     Ptycmd p, q;
       
   432 
       
   433     for (q = NULL, p = ptycmds; p != cmd; q = p, p = p->next);
       
   434 
       
   435     if (p != cmd)
       
   436 	return;
       
   437 
       
   438     if (q)
       
   439 	q->next = p->next;
       
   440     else
       
   441 	ptycmds = p->next;
       
   442 
       
   443     zsfree(p->name);
       
   444     freearray(p->args);
       
   445 
       
   446     zclose(cmd->fd);
       
   447 
       
   448     /* We kill the process group the command put itself in. */
       
   449 
       
   450     kill(-(p->pid), SIGHUP);
       
   451 
       
   452     zfree(p, sizeof(*p));
       
   453 }
       
   454 
       
   455 static void
       
   456 deleteallptycmds(void)
       
   457 {
       
   458     Ptycmd p, n;
       
   459 
       
   460     for (p = ptycmds; p; p = n) {
       
   461 	n = p->next;
       
   462 	deleteptycmd(p);
       
   463     }
       
   464 }
       
   465 
       
   466 /**** a better process handling would be nice */
       
   467 
       
   468 static void
       
   469 checkptycmd(Ptycmd cmd)
       
   470 {
       
   471     char c;
       
   472     int r;
       
   473 
       
   474     if (cmd->read != -1 || cmd->fin)
       
   475 	return;
       
   476     if ((r = read(cmd->fd, &c, 1)) < 0) {
       
   477 	if (kill(cmd->pid, 0) < 0) {
       
   478 	    cmd->fin = 1;
       
   479 	    zclose(cmd->fd);
       
   480 	}
       
   481 	return;
       
   482     }
       
   483     if (r) cmd->read = (int) c;
       
   484 }
       
   485 
       
   486 static int
       
   487 ptyread(char *nam, Ptycmd cmd, char **args)
       
   488 {
       
   489     int blen, used, seen = 0, ret = 0;
       
   490     char *buf;
       
   491     Patprog prog = NULL;
       
   492 
       
   493     if (*args && args[1]) {
       
   494 	char *p;
       
   495 
       
   496 	if (args[2]) {
       
   497 	    zwarnnam(nam, "too many arguments", NULL, 0);
       
   498 	    return 1;
       
   499 	}
       
   500 	p = dupstring(args[1]);
       
   501 	tokenize(p);
       
   502 	remnulargs(p);
       
   503 	if (!(prog = patcompile(p, PAT_STATIC, NULL))) {
       
   504 	    zwarnnam(nam, "bad pattern: %s", args[1], 0);
       
   505 	    return 1;
       
   506 	}
       
   507     } else
       
   508 	fflush(stdout);
       
   509 
       
   510     if (cmd->old) {
       
   511 	used = cmd->olen;
       
   512 	buf = (char *) zhalloc((blen = 256 + used) + 1);
       
   513 	memcpy(buf, cmd->old, cmd->olen);
       
   514 	zfree(cmd->old, cmd->olen);
       
   515 	cmd->old = NULL;
       
   516 	cmd->olen = 0;
       
   517     } else {
       
   518 	used = 0;
       
   519 	buf = (char *) zhalloc((blen = 256) + 1);
       
   520     }
       
   521     if (cmd->read != -1) {
       
   522 	buf[used] = (char) cmd->read;
       
   523 	buf[used + 1] = '\0';
       
   524 	seen = used = 1;
       
   525 	cmd->read = -1;
       
   526     }
       
   527     do {
       
   528 	if (!ret) {
       
   529 	    checkptycmd(cmd);
       
   530 	    if (cmd->fin)
       
   531 		break;
       
   532 	}
       
   533 	if (cmd->read != -1 || (ret = read(cmd->fd, buf + used, 1)) == 1) {
       
   534 	    if (cmd->read != -1) {
       
   535 		ret = 1;
       
   536 		buf[used] = (char) cmd->read;
       
   537 		cmd->read = -1;
       
   538 	    }
       
   539 	    seen = 1;
       
   540 	    if (++used == blen) {
       
   541 		if (!*args) {
       
   542 		    write(1, buf, used);
       
   543 		    used = 0;
       
   544 		} else {
       
   545 		    buf = hrealloc(buf, blen, blen << 1);
       
   546 		    blen <<= 1;
       
   547 		}
       
   548 	    }
       
   549 	}
       
   550 	buf[used] = '\0';
       
   551 
       
   552 	if (!prog && (ret <= 0 || (*args && buf[used - 1] == '\n')))
       
   553 	    break;
       
   554     } while (!(errflag || breaks || retflag || contflag) &&
       
   555 	     used < READ_MAX && !(prog && ret && pattry(prog, buf)));
       
   556 
       
   557     if (prog && ret < 0 &&
       
   558 #ifdef EWOULDBLOCK
       
   559 	errno == EWOULDBLOCK
       
   560 #else
       
   561 #ifdef EAGAIN
       
   562 	errno == EAGAIN
       
   563 #endif
       
   564 #endif
       
   565 	) {
       
   566 	cmd->old = (char *) zalloc(cmd->olen = used);
       
   567 	memcpy(cmd->old, buf, cmd->olen);
       
   568 
       
   569 	return 1;
       
   570     }
       
   571     if (*args)
       
   572 	setsparam(*args, ztrdup(metafy(buf, used, META_HREALLOC)));
       
   573     else if (used)
       
   574 	write(1, buf, used);
       
   575 
       
   576     return (seen ? 0 : cmd->fin + 1);
       
   577 }
       
   578 
       
   579 static int
       
   580 ptywritestr(Ptycmd cmd, char *s, int len)
       
   581 {
       
   582     int written, all = 0;
       
   583 
       
   584     for (; !errflag && !breaks && !retflag && !contflag && len;
       
   585 	 len -= written, s += written) {
       
   586 	if ((written = write(cmd->fd, s, len)) < 0 && cmd->nblock &&
       
   587 #ifdef EWOULDBLOCK
       
   588 	    errno == EWOULDBLOCK
       
   589 #else
       
   590 #ifdef EAGAIN
       
   591 	    errno == EAGAIN
       
   592 #endif
       
   593 #endif
       
   594 	    )
       
   595 	    return !all;
       
   596 	if (written < 0) {
       
   597 	    checkptycmd(cmd);
       
   598 	    if (cmd->fin)
       
   599 		break;
       
   600 	    written = 0;
       
   601 	}
       
   602 	if (written > 0)
       
   603 	    all += written;
       
   604     }
       
   605     return (all ? 0 : cmd->fin + 1);
       
   606 }
       
   607 
       
   608 static int
       
   609 ptywrite(Ptycmd cmd, char **args, int nonl)
       
   610 {
       
   611     if (*args) {
       
   612 	char sp = ' ', *tmp;
       
   613 	int len;
       
   614 
       
   615 	while (*args) {
       
   616 	    unmetafy((tmp = dupstring(*args)), &len);
       
   617 	    if (ptywritestr(cmd, tmp, len) ||
       
   618 		(*++args && ptywritestr(cmd, &sp, 1)))
       
   619 		return 1;
       
   620 	}
       
   621 	if (!nonl) {
       
   622 	    sp = '\n';
       
   623 	    if (ptywritestr(cmd, &sp, 1))
       
   624 		return 1;
       
   625 	}
       
   626     } else {
       
   627 	int n;
       
   628 	char buf[BUFSIZ];
       
   629 
       
   630 	while ((n = read(0, buf, BUFSIZ)) > 0)
       
   631 	    if (ptywritestr(cmd, buf, n))
       
   632 		return 1;
       
   633     }
       
   634     return 0;
       
   635 }
       
   636 
       
   637 /**/
       
   638 static int
       
   639 bin_zpty(char *nam, char **args, Options ops, UNUSED(int func))
       
   640 {
       
   641     if ((OPT_ISSET(ops,'r') && OPT_ISSET(ops,'w')) ||
       
   642 	((OPT_ISSET(ops,'r') || OPT_ISSET(ops,'w')) && 
       
   643 	 (OPT_ISSET(ops,'d') || OPT_ISSET(ops,'e') ||
       
   644 	  OPT_ISSET(ops,'b') || OPT_ISSET(ops,'L'))) ||
       
   645 	(OPT_ISSET(ops,'w') && OPT_ISSET(ops,'t')) ||
       
   646 	(OPT_ISSET(ops,'n') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') ||
       
   647 				OPT_ISSET(ops,'r') || OPT_ISSET(ops,'t') ||
       
   648 				OPT_ISSET(ops,'d') || OPT_ISSET(ops,'L'))) ||
       
   649 	(OPT_ISSET(ops,'d') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') ||
       
   650 				OPT_ISSET(ops,'L') || OPT_ISSET(ops,'t'))) ||
       
   651 	(OPT_ISSET(ops,'L') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e')))) {
       
   652 	zwarnnam(nam, "illegal option combination", NULL, 0);
       
   653 	return 1;
       
   654     }
       
   655     if (OPT_ISSET(ops,'r') || OPT_ISSET(ops,'w')) {
       
   656 	Ptycmd p;
       
   657 
       
   658 	if (!*args) {
       
   659 	    zwarnnam(nam, "missing pty command name", NULL, 0);
       
   660 	    return 1;
       
   661 	} else if (!(p = getptycmd(*args))) {
       
   662 	    zwarnnam(nam, "no such pty command: %s", *args, 0);
       
   663 	    return 1;
       
   664 	}
       
   665 	if (p->fin)
       
   666 	    return 2;
       
   667 	if (OPT_ISSET(ops,'t') && p->read == -1 &&
       
   668 	    !read_poll(p->fd, &p->read, 0, 0))
       
   669 	    return 1;
       
   670 
       
   671 	return (OPT_ISSET(ops,'r') ?
       
   672 		ptyread(nam, p, args + 1) :
       
   673 		ptywrite(p, args + 1, OPT_ISSET(ops,'n')));
       
   674     } else if (OPT_ISSET(ops,'d')) {
       
   675 	Ptycmd p;
       
   676 	int ret = 0;
       
   677 
       
   678 	if (*args) {
       
   679 	    while (*args)
       
   680 		if ((p = getptycmd(*args++)))
       
   681 		    deleteptycmd(p);
       
   682 		else {
       
   683 		    zwarnnam(nam, "no such pty command: %s", args[-1], 0);
       
   684 		    ret = 1;
       
   685 		}
       
   686 	} else
       
   687 	    deleteallptycmds();
       
   688 
       
   689 	return ret;
       
   690     } else if (OPT_ISSET(ops,'t')) {
       
   691 	Ptycmd p;
       
   692 
       
   693 	if (!*args) {
       
   694 	    zwarnnam(nam, "missing pty command name", NULL, 0);
       
   695 	    return 1;
       
   696 	} else if (!(p = getptycmd(*args))) {
       
   697 	    zwarnnam(nam, "no such pty command: %s", *args, 0);
       
   698 	    return 1;
       
   699 	}
       
   700 	checkptycmd(p);
       
   701 	return p->fin;
       
   702     } else if (*args) {
       
   703 	if (!args[1]) {
       
   704 	    zwarnnam(nam, "missing command", NULL, 0);
       
   705 	    return 1;
       
   706 	}
       
   707 	if (getptycmd(*args)) {
       
   708 	    zwarnnam(nam, "pty command name already used: %s", *args, 0);
       
   709 	    return 1;
       
   710 	}
       
   711 	return newptycmd(nam, *args, args + 1, OPT_ISSET(ops,'e'), 
       
   712 			 OPT_ISSET(ops,'b'));
       
   713     } else {
       
   714 	Ptycmd p;
       
   715 	char **a;
       
   716 
       
   717 	for (p = ptycmds; p; p = p->next) {
       
   718 	    checkptycmd(p);
       
   719 	    if (OPT_ISSET(ops,'L'))
       
   720 		printf("%s %s%s%s ", nam, (p->echo ? "-e " : ""),
       
   721 		       (p->nblock ? "-b " : ""), p->name);
       
   722 	    else if (p->fin)
       
   723 		printf("(finished) %s: ", p->name);
       
   724 	    else
       
   725 		printf("(%d) %s: ", p->pid, p->name);
       
   726 	    for (a = p->args; *a; ) {
       
   727 		quotedzputs(*a++, stdout);
       
   728 		if (*a)
       
   729 		    putchar(' ');
       
   730 	    }
       
   731 	    putchar('\n');
       
   732 	}
       
   733 	return 0;
       
   734     }
       
   735 }
       
   736 
       
   737 static int
       
   738 ptyhook(UNUSED(Hookdef d), UNUSED(void *dummy))
       
   739 {
       
   740     deleteallptycmds();
       
   741     return 0;
       
   742 }
       
   743 
       
   744 static struct builtin bintab[] = {
       
   745     BUILTIN("zpty", 0, bin_zpty, 0, -1, 0, "ebdrwLnt", NULL),
       
   746 };
       
   747 
       
   748 /**/
       
   749 int
       
   750 setup_(UNUSED(Module m))
       
   751 {
       
   752     return 0;
       
   753 }
       
   754 
       
   755 /**/
       
   756 int
       
   757 boot_(Module m)
       
   758 {
       
   759     ptycmds = NULL;
       
   760 
       
   761     addhookfunc("exit", ptyhook);
       
   762     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
   763 }
       
   764 
       
   765 /**/
       
   766 int
       
   767 cleanup_(Module m)
       
   768 {
       
   769     deletehookfunc("exit", ptyhook);
       
   770     deleteallptycmds();
       
   771     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
   772     return 0;
       
   773 }
       
   774 
       
   775 /**/
       
   776 int
       
   777 finish_(UNUSED(Module m))
       
   778 {
       
   779     return 0;
       
   780 }
       
   781 
       
   782 #endif //__SYMBIAN32__