Category : UNIX Files
Archive   : UWPC201.ZIP
Filename : UWSERVER.TAR
#
# Makefile for UW version 4.2
#
# Specify VERSION 4.3 for 4.3BSD, 4.2 for 4.2BSD (including Sun 3.x)
#
# DEFINES is a list of the site-dependent compile-time options:
# -DUTMP attempt to update "/etc/utmp" (who) file
# -DV7TTYS V7-format "/etc/ttys" (pre-4.3BSD)
# -DSETOWN_BUG fcntl(fd, F_SETOWN, pgrp) is broken (pre-4.3BSD)
# -Dvoid=int kludge around broken C compilers
#
# UTMP specifies that UW should attempt to update the "/etc/utmp" file.
# On some (foolish) systems this file is world-writeable. Other
# installations may wish AFTER CAREFUL EXAMINATION OF THE ISSUES to
# install the UW server with group write access to the utmp file.
#
# V7TTYS should be used for V7-derived systems that do not have 4.3BSD's
# "/etc/ttys" file. This includes 4.2BSD and Sun UNIX. There is no
# support for USG's "/etc/inittab".
#
# SETOWN_BUG should be defined if the fcntl(fd, F_SETOWN, pgrp) system
# call is broken (as it is in 4.2BSD and Sun 3.0 UNIX). On those
# machines the third argument must be negative to specify a process ID
# and positive to specify a process group.
#
# Some C compilers do not understand pointers to void functions. The
# common kludge around this problem is to substitute "int" for "void"
# everywhere. "lint" doesn't like this, but the program will compile
# into working code.
#
BINDIR = /usr/local/bin
INCDIR = /usr/include/uw
LIBDIR = /usr/local/lib
VERSION = 4.3
DEFINES = -DUTMP
MKFILES = server/Makefile lib/Makefile utility/Makefile
all: DEFINES $(MKFILES)
cd server; make
cd lib; make
cd utility; make
depend:
cd server; make depend
cd lib; make depend
cd utility; make depend
install: all
ln -s `pwd`/h $(INCDIR)
install -s server/uw $(BINDIR)/uw
install -s utility/uwtool $(BINDIR)/uwtool
install -s utility/uwtitle $(BINDIR)/uwtitle
install -s utility/uwterm $(BINDIR)/uwterm
install -s utility/uwplot $(BINDIR)/uwplot
cp lib/libuw.a $(LIBDIR); ranlib $(LIBDIR)/libuw.a
clean:
cd server; make clean
cd lib; make clean
cd utility; make clean
DEFINES: Makefile
echo "" $(DEFINES) > DEFINES
server/Makefile: Makefile server/Makefile_$(VERSION)
cd server; cp Makefile_$(VERSION) Makefile; make depend
lib/Makefile: Makefile lib/Makefile_$(VERSION)
cd lib; cp Makefile_$(VERSION) Makefile; make depend
utility/Makefile: Makefile utility/Makefile_$(VERSION)
cd utility; cp Makefile_$(VERSION) Makefile; make depend
README 600 11722 76400 7643 4750124212 5122 UW Version 4.2
31 January 1988
This is version 4.2 of UW, a multiple-window interface to UNIX for
the Macintosh computer. The distribution for UW consists of two
binary files for the Macintosh (in BinHex 4.0 format) and a number
of source files for the (BSD) UNIX server.
The distribution includes the following directories:
h - all UW include files
server - source code for the UW server
lib - source code for the UW programmer's library
utility - source code for miscellaneous utility programs
doc - [nt]roff documentation (-ms and -man formats)
hqx - Macintosh binary files
misc - other things of possible interest
The two Macintosh files are "uw.hqx", which is the executable binary
and "uw.doc.hqx", which is a MacWrite-format document describing the
Macintosh user interface.
UW was developed alternately on a Sun 3 and 4.3BSD VAX. It also
has been tested (more briefly) on a Sun 2 (release 2.0), Integrated
Solutions VME 68020 (release 3.05), and a Pyramid. It depends quite a
bit upon BSD-specific features such as interprocess communication and
will not run without modification on a System V UNIX system.
This distribution, like the version 3.4 distribution, includes
make files for both 4.2BSD and 4.3BSD. The choice of make files
and other configuration options is determined by the top-level
"Makefile". Comments in that file describe the configuration options.
A "make install" in the top-level directory will compile and install
all of the (UNIX) pieces of the UW distribution. As distributed,
this will create a link between the directory name "/usr/include/uw"
and the "h" subdirectory and will create a "/usr/local/bin/libuw.a"
library file. These two steps allow application program to use
#include
and
cc -o xyzzy xyzzy.o -luw
for greater convenience in creating programs that use the UW library.
If you do not have the "getopt" library routine, you will find the
source in "misc/getopt.c" This source code was publicly distributed by
AT&T and is also available in the "mod.sources" archive. You should
compile it and install it in your machine's "/lib/libc.a" (Note that
since it uses "strchr", you should compile it on a BSD system with the
command "cc -O -c getopt.c -Dstrchr=index".) [Sorry, I can't find a
manual page which I can (legally) include.] If you can't change
"libc.a", then you should add it to the makefiles in the "server"
and "lib" directories.
Version 4.2 is primarily a maintenance release. Because of constraints
on the author's time, few things have changed since version 4.1. Some
of the differences are:
1) UW v4.2 is compatible with Multifinder. It understands background
events, so it can receive input and update windows even when
another application's window is active.
2) Some problems relating to keyboard mapping have been fixed.
UW recognizes the Control and ESC keys. The mapping for the
numeric keypad still seems to be incomplete. The author is
hampered by the fact that his development machine still has
its original 512K Mac keyboard. (He dislikes the Mac+ and
SE keyboards.)
3) A new window type -- plot -- has been defined. This type of
window can only be created by the host. It interprets output
in UNIX v7 plot(5) format.
4) Windows may use 7, 9, 10, or 12 point fixed-width fonts.
UW includes non-Apple-copyrighted Mishawaka fonts for these sizes.
UW is not public domain. It is copyrighted. However, permission to
copy UW is given provided that the copies are not sold and that the
copyright notices are retained.
Comments about UW can be sent to the author (me) at the following
addresses:
ARPANET/MILNET: [email protected]
UUCP: {lll-crg,decwrl,caip}!mordor!jdb
U.S. Mail: John Bruner
Lawrence Livermore National Laboratory
P.O. Box 5503, L-276
Livermore, CA 94550
I try to answer all mail, but sometimes am unable to do so for reasons
beyond my control (e.g. incomplete or incorrect return addresses,
finicky mailers).
doc/ 700 11722 76400 0 4750124234 4712 doc/uwlib.ms 600 11722 76400 61566 4750124226 6523 .\" This file should be processed by nroff or troff with the -ms macro set
.ds uw \s-2UW\s0
.DA September 30, 1986
.TL
The UW Programmer's Library
.AU
John D. Bruner
.SH
Introduction
.PP
\*(uw is a multiple-window Macintosh interface to a 4.2BSD UNIX\**.
.FS
Macintosh is a trademark of McIntosh Laboratories which
is licensed to Apple Computer, Inc.
UNIX is a registered trademark of Bell Laboratories.
.FE
\*(uw version 3 comprises a server,
a set of utility programs,
and an program-level interface.
This manual describes the services which are available
in the \*(uw programmer's library.
This library allow programs to create,
communicate with,
and perform some control operations upon
windows on the Macintosh.
.SH
Background
.PP
Before the library routines themselves can be discussed,
it is necessary to consider some aspects of the \*(uw
server.
The server which was distributed with \*(uw versions 1.6 and 2.10
communicated with the Macintosh using a protocol which
is referred to as the ``original protocol.''
The version 3 server is capable of communicating in this protocol;
however,
it also supports an ``extended protocol.''
For convenience,
these protocols are assigned numbers:
protocol 1 is the original protocol
and protocol 2 is the extended protocol.
.PP
Protocol 1 provides a mechanism for
the creation and destruction of windows
as well as a means to multiplex a single
communications line among several windows.
It provides a mechanism for transmitting
control and ``meta'' characters,
and it also provides two ``maintenance functions''
which are used for startup and shutdown.
.PP
Protocol 2 provides two significant enhancements
relative to protocol 1.
First,
window creation messages specify the window emulation type
(\fIe.g.\fP adm-31, vt52).
Second,
additional information about windows,
called ``window options,''
is transmitted between the Macintosh client and the
server on the host.
.PP
Window options are an ``out-of-band'' channel of
information between the Macintosh and the host.
There are two types:
generic
(common to all window types)
and emulation-specific.
The following are generic:
.DS
window visibility
window type
window position (pixel address of top left corner)
window title
window size in pixels
.DE
The following window options are specific to
cursor-addressible terminal emulations:
.DS
terminal size (number of rows and columns)
font size index (small=0, large=1)
mouse handling (clipboard or encoded send-to-host)
bell characteristics (audible, visible)
cursor appearance (block or underscore)
.DE
.PP
The server distinguishes between two window classes \(em
internal and external.
Internal windows are handled entirely by the server.
They are always terminal emulations and are always
associated with a pseudo-terminal device.
.PP
By contrast,
an external window always involves some outside process.
The server communicates with this process through one
or two Internet domain network connections.
There is always a ``data'' connection,
through which the external process exchanges information
(indirectly, through the server)
with the Macintosh.
There may also be a ``control'' connection
through which the external process exchanges
window option information
(again indirectly)
with the Macintosh.
The server acts as a multiplexor and demultiplexor
for external windows.
It also caches window option information;
however,
it does not perform host-end emulation-specific tasks.
.PP
Internal and external windows meet different needs.
Terminal emulation on the local host is best performed
by internal windows,
because fewer processes are involved
(and response time is better).
External windows are suitable for remote processes
(\fIi.e.\fP those on another Internet host)
or for non-terminal tasks such as file transfer.
The \*(uw application library contains routines
to create and manipulate both classes of windows.
.SH
Window ID's and Network Addresses
.PP
A unique 32-bit identification number is associated
with each window that a server manipulates.
Some operations
(described below)
require the window number to be specified.
When the server creates a new internal window,
it passes the window ID as the environment variable
``UW_ID''.
.PP
The server creates two network sockets upon which to receive
incoming messages.
One socket receives UNIX-domain datagrams,
the other listens for Internet-domain stream connections.
The addresses of these sockets are placed in the environment
as the variables ``UW_UIPC''
(UNIX-domain)
and ``UW_INET''
(Internet domain).
.SH
Data Types and Data Structures
.PP
The \*(uw programmer's library uses a number
of simple and structured data types.
.IP uwid_t 1i
Unique window ID numbers are represented by the data type ``uwid_t''.
.IP UWIN
Library routines which operate upon external windows
put a range of window information into a structure.
The type ``UWIN'' is a pointer to the structure.
An object of this datatype is referred to as a ``window descriptor.''
This declaration is intended to be used as an abstract unit
(in the manner of the standard I/O library's ``FILE\ *'').
.IP uwtype_t
Window emulation types have the data type ``uwtype_t''.
The following emulation types are defined:
.DS
.ta 8n 24n 32n
#define UWT_ADM31 0 /* ADM-31 cursor-addressible terminal */
#define UWT_VT52 1 /* VT52 cursor-addressible terminal */
#define UWT_ANSI 2 /* ANSI-compatible terminal */
#define UWT_TEK4010 3 /* Tektronix 4010 graphics terminal */
#define UWT_FTP 4 /* File transfer */
#define UWT_PRINT 5 /* Output to Macintosh printer */
.DE
.IP uwopt_t
Window options are assigned numbers whose type is ``uwopt_t''.
The names of the options are:
.DS
.ta 8n 28n 32n
#define UWOP_VIS 1 /* visibility */
#define UWOP_TYPE 2 /* window type */
#define UWOP_POS 3 /* window position */
#define UWOP_TITLE 4 /* window title */
#define UWOP_WSIZE 5 /* window size (in bits) */
#define UWOP_TSIZE 8 /* terminal size (row,col) */
#define UWOP_TFONTSZ 9 /* small/large font size */
#define UWOP_TCLIPB 10 /* clipboard/mouse encoding */
#define UWOP_TBELL 11 /* audible, visual bell */
#define UWOP_TCURS 12 /* cursor shape */
.DE
.IP uwoptcmd_t
The window option commands
which are passed between the Macintosh and the host
have type ``uwoptcmd_t''.
These commands are:
.DS
.ta 8n 24n 32n
#define UWOC_SET 0 /* set value of option */
#define UWOC_ASK 2 /* ask for value of option */
#define UWOC_DO 4 /* report changes in value */
#define UWOC_DONT 5 /* don't report changes */
#define UWOC_WILL 6 /* will report changes */
#define UWOC_WONT 7 /* won't report changes */
.DE
.IP "union uwoptval"
When a function requires a window option value as an argument,
the value of the window option is placed into a
union declared as ``union uwoptval''.
The address of this union is passed to the function.
This union is declared as follows:
.DS
.ta 8n 16n 24n
union uwoptval {
unsigned char uwov_1bit;
unsigned char uwov_2bit;
unsigned char uwov_6bit;
unsigned short uwov_12bit;
struct {
unsigned short v,h;
} uwov_point;
char uwov_string[256];
};
.DE
The union member used for a particular option
depends upon the option number.
At present,
the types of the window options and
corresponding union members are:
.DS
.ta 1i
visibility uwov_1bit
type uwov_6bit
position uwov_point
title uwov_string (null terminated)
bit size uwov_point
tty size uwov_point
font size uwov_1bit
clipboard uwov_1bit
bell uwov_2bit
cursor type uwov_1bit
.DE
.IP "uwerr_t"
When a library routine returns an error indication,
further information about the type of error can be
obtained from the global variable ``uwerrno''.
(Depending upon the type of error,
the external variable ``errno'' may also contain
pertinent information.)
\*(uw error numbers have type ``uwerr_t'',
and are defined as follows:
.DS
.ta 8n 24n 32n
#define UWE_NONE 0 /* no error */
#define UWE_ERRNO 1 /* system call error, consult errno */
#define UWE_NXTYPE 2 /* nonexistent window type */
#define UWE_DUPID 3 /* window ID duplicated (in use) */
#define UWE_NOTIMPL 4 /* operation not implemented yet */
#define UWE_NXSERV 5 /* non-existent server */
#define UWE_NOMEM 6 /* unable to allocate required memory */
#define UWE_INVAL 7 /* invalid argument to function */
#define UWE_NOCTL 8 /* no control file descriptor */
.DE
.SH
Internal Window Interface
.PP
When an internal window is created by an external process,
a UNIX-domain datagram is sent to the server.
This datagram contains
(as ``access rights'')
a file descriptor for the ``master'' side of a pseudo-terminal.
The server assumes that the external process
has started some program on the ``slave'' side of the pseudo-terminal.
After sending the datagram,
the sender has no direct handle to manipulate
the window.
It has,
in effect,
relinquished all control.
(It should close the master side of the pseudo-terminal
after sending the datagram.)
To provide some additional flexibility,
it is possible to change the value of a window option
for any window
(even ``external'' windows)
if the window's unique ID is known.
The creator of the window has no special privileges
in this regard.
.LP
[One thing which the internal window routines
in the \*(uw library completely ignore
is the fact that datagrams are not guaranteed to be reliable.
UNIX-domain datagrams almost always seem to work,
but they can fail.
In the author's experience this has never been a problem,
but let the user beware.]
.LP
The following routines are available:
.IP uw_fork 1i
This routine is similar in concept to the system call ``fork''.
It creates a new process
and returns twice \(em
once in the parent and once in the child.
In addition to creating a new process,
``uw_fork'' also arranges for the new process to be
associated with an internal window.
It opens a pseudo-terminal,
redirects the child's standard input,
standard output,
and standard error,
and sends a UNIX-domain datagram to the \*(uw server.
It returns the unique ID associated with the window
in the parent,
and returns 0 in the child.
(\(mi1 is returned if the routine fails.)
.DS
uwid_t uw_fork(uwtype_t wtype, int *pidp);
.DE
The first argument specifies the type of the new window.
If the second argument to ``uw_fork'' is a non-NULL pointer,
the process-ID of the child will be stored at that address
in the parent process.
(In the child, ``*pidp'' will be zero.)
.IP uw_cmd
This routine builds upon the functionality of the ``uw_fork'' routine.
It creates a new window with ``uw_fork''
and then executes a specified command.
It takes the window type,
the name of an executable file,
and an argument list
as parameters;
it uses these as arguments to ``uw_fork''
and the C library routine ``execvp''.
It returns the window ID number to its caller:
.DS
uwid_t uw_cmd(uwtype_t wtype, char *file, char **argv);
.DE
(\(mi1 is returned if the routine fails.)
.IP uw_shell
``uw_shell'' is similar to ``uw_cmd'' except that it
executes an arbitrary shell command:
.DS
uwid_t uw_shell(uwtype_t wtype, char *cmd);
.DE
(\(mi1 is returned if the routine fails.)
By default the Bourne shell is used;
however,
the shell may be changed by patching the global variable ``uwshellname''.
.DS
char *uwshellname = "/bin/sh";
.DE
.IP uw_rsetopt
This routine changes the value of a window option
for an existing window
(named as a window ID).
The window may be either internal or external.
The specified window option is set to a desired value.
Zero is returned if the appropriate UNIX-domain message
was successfully sent;
\(mi1 is returned if the operation failed.
(Since ``uw_rsetopt'' does not receive a reply from the server,
it is unable to determine whether or not the command ``succeeded''.
Rather,
it returns zero if the command was successfully transmitted.)
.DS
int uw_rsetopt(uwid_t uwid, uwopt_t optnum, union uwoptval *optval);
.DE
``optval'' points to a ``union uwoptval'' structure
(described above)
in which the member corresponding to ``optnum''
has been initialized.
.IP "uw_perror"
When an error is reported by a \*(uw library routine,
the cause of the error is saved in the external variable
``uwerrno''.
If the error was UWE_ERRNO,
the standard external variable ``errno''
will also be meaningful.
(The routines which operate upon external windows,
described in the following section,
also save this information in the window descriptor.)
The routine ``uw_perror'' may be used to decode and print
error messages:
.DS
void uw_perror(char *usermesg, uwerr_t uwerr, int err)
.DE
where ``usermesg'' is a pointer to a user-specified string,
``uwerr'' is the \*(uw error code
(usually ``uwerrno''),
and ``err'' is the system call error code
(usually ``errno'').
[System call error numbers are defined in ``/usr/include/errno.h''.]
.sp
The \*(uw error messages may also be accessed directly.
Two external variables aid in user-formatted error messages:
.DS
extern char *uwerrlist[];
extern unsigned uwnerr;
.DE
If the error number is greater than or equal to ``uwnerr'',
no error message string exists.
(This ``cannot happen.'')
Otherwise,
the error message string is obtained by indexing into
``uwerrlist''.
.PP
The preceeding routines are sufficient to implement
a (simplified) version of the ``uwtool'' program,
which creates a new
(internal)
window running a specified command:
.DS
.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n
/*
* uwtool
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include "uwlib.h"
main(argc, argv)
int argc;
char **argv;
{
register uwid_t uwid;
register char *fname, *term;
register wtype_t wtype;
char *av[2];
union uwoptval optval;
extern int errno;
extern char *getenv();
/*
* If called with no arguments, create a new window using the
* current shell according to the SHELL environment variable
* (or "/bin/sh" if that doesn't exist). If called with
* arguments, argv[1] through argv[argc\-1] are the arguments
* to the command.
*/
if (argc == 1) {
if ((fname = getenv("SHELL")) == (char *)0)
fname = "/bin/sh";
av[0] = fname;
av[1] = (char *)0;
argv = av;
} else
fname = *++argv;
if ((term=getenv("TERM")) != (char *)0)
wtype = uw_ttype(term);
else
wtype = UWT_ADM31;
if ((uwid = uw_cmd(wtype, fname, argv)) < 0) {
(void)strncpy(optval.uwov_string, fname,
sizeof optval.uwov_string);
(void)uw_rsetopt(uwid, UWOP_TITLE, &optval);
return(0);
} else {
uw_perror("uwtool", uwerrno, errno);
return(1);
}
}
.DE
After the first part of the function has massaged the argument list,
the ``uw_cmd'' routine creates a new window
running the command ``fname'' with argument list ``argv''.
If the window ID is positive,
the window creation succeeded.
After copying the name of the program into a ``union uwoptval'',
the program calls ``uw_rsetopt'' to set the window title
to that string.
If the window ID returned by ``uw_cmd'' was \(mi1,
the window creation failed.
In this case,
the program calls ``uw_perror'' to report the error.
.SH
External Window Interface
.LP
The remainder of the \*(uw library routines provide access to
external windows.
In contrast to internal windows,
a client process creates an external window
by establishing an Internet-domain stream connection
to the server and sending the server a ``create window'' command.
The server will establish a second stream connection
back to the client.
Data is passed between the client and the server on the first connection,
while control information is passed through the second.
[Because the server and client communicate through one or
two stream connection(s)
instead of by sending datagrams,
the unreliability problems noted above for internal windows
do not apply to external windows.]
.LP
The \*(uw library provides mechanisms for creating external windows,
killing them,
and manipulating window options.
When a window is created a window descriptor
(item of type UWIN)
is returned;
this is used as an argument to all other external-window routines.
.LP
The following routines are provided:
.IP "uw_new" 1i
This function creates a new external window of the specified type.
The calling sequence is:
.DS
UWIN uw_new(uwtype_t uwtype, struct sockaddr_in *server)
.DE
where ``uwtype'' is the window type
and ``server'' is a pointer to a structure specifying
the Internet address of the server.
(If ``server'' is a NULL pointer,
the server will be determined by examining the
environment variable ``UW_INET''.)
If the window creation succeeded,
``uw_new'' will return a non-NULL window descriptor;
otherwise,
it will return NULL, and
the global variables ``uwerrno'' and ``errno''
may be examined to determine the cause of the error.
.IP "uw_detach"
This function ``detaches'' the window from the program
so that it no longer is able to perform control operations
upon the window.
The data connection to the window remains open.
This function should be used when the data connection to a window
will be handled by a different process
than the control connection,
.I e.g.
in a child process after a ``fork''.
It is strongly recommended that no more than one process
have control access to a window at any one time.
The calling sequence is
.DS
uw_detach(UWIN uwin);
.DE
where ``uwin'' is the window descriptor.
Zero is returned for success,
while \(mi1 is returned for failure.
If the routine fails,
the error status will be stored in the UWIN data item
as well as in the global variables ``uwerrno'' and ``errno''.
.IP "uw_close"
This function closes a window.
Both the control and data connections to the window are closed.
If multiple processes have access to a window
(\fIe.g.\fP because of a ``fork''),
then the window will be destroyed when the last connection
to it is closed.
The calling sequence is
.DS
uw_close(UWIN uwin);
.DE
where ``uwin'' is the window descriptor
.IP "uw_kill"
At times it may be desirable for one process to destroy
a window even if the window is in use by other processes.
The ``uw_kill'' function performs this task.
The caller must have control access to the window
(it must not be ``detached'').
The syntax is:
.DS
uw_kill(UWIN uwin);
.DE
where ``uwin'' is the window descriptor.
When a window is killed
(either by ``uw_kill'' or upon command from the Macintosh)
the server closes its data channel.
Any further attempts to read or write to the window
will produce end-of-file or error conditions,
respectively.
.IP "uw_optfn"
If a process has control access to a window,
then it will periodically receive
window option messages from the Macintosh client
(through the server).
The \*(uw library receives these messages by enabling
asynchronous I/O notification on the control channel
and providing a SIGIO signal handler.
Sometimes it is desirable for an external process
to field incoming option messages itself.
To do so,
it must notify the \*(uw library by calling the
routine ``uw_optfn'':
.DS
void (*uw_optfn(UWIN uwin, uwopt_t optnum, void (*optfn)())();
.DE
where ``uwin'' is the window descriptor,
``optnum'' is the desired window option,
and ``optfn'' is a pointer to a function which
will be called when a message about window option ``optnum''
is received.
``uw_optfn'' returns the previous function.
To disable processing for a window option,
specify a NULL pointer for ``optfn''.
The user-supplied ``optfn'' is called with the following arguments:
.DS
.ta 8n
void (*optfn)(UWIN uwin, uwopt_t optnum, uwoptcmd_t optcmd,
union uwoptval *optval);
.DE
where ``uwin'' is the window descriptor,
``optnum'' is the window option number,
``optcmd'' is the window option command,
and
(if ``optcmd'' is UWOC_SET)
``optval'' is a pointer to the new value of the window option.
.sp
Because the \*(uw library provides a signal handler for SIGIO,
if other portions of the program wish to catch SIGIO,
then some care must be taken
to ensure that all signal handlers are called.
The \*(uw library saves the return value from
``signal'' when it installs its handler.
If this is not SIG_IGN,
then that routine will be called after \*(uw has
completed its signal processing.
In a similar fashion,
if the calling program establishes a signal handler,
it should save the previous value and call the indicated
function
(if not SIG_IGN).
For example,
if the caller uses ``signal'':
.DS
.ta 8n 16n
oldhandler = signal(SIGIO, myhandler);
\&...
myhandler(sig, code, scp)
int sig, code;
struct sigcontext *scp;
{
... code to handle exception ...
if (oldhandler != SIG_IGN)
(*oldhandler)(sig, code, scp);
}
.DE
Although from time to time
the Macintosh may ask the server for the current
value of a window option,
the \*(uw server caches the current value of each
window option
and responds to these inquiries directly.
Therefore,
the major reason for establishing a window option function
with ``uw_optfn'' is to process incoming UWOC_SET messages,
.I i.e.
messages from the Macintosh that the value of a window
option has changed.
.IP "uw_optcmd"
This function allows a program with control access to a window
to send window option commands.
The calling sequence is
.DS
.ta 8n
uw_optcmd(UWIN uwin, uwopt_t optnum, uwoptcmd_t optcmd,
union uwoptval *optval);
.DE
where ``uwin'' is the window descriptor,
``optnum'' is the window option number,
``optcmd'' is the command,
and ``optval'' is a pointer to the option value.
Of the six window option messages,
only the UWOC_SET,
UWOC_DO,
and UWOC_DONT
messages are very useful.
UWOC_SET changes the value of a window option
(``optval'' points to the new value).
UWOC_DO and UWOC_DONT instruct the Macintosh to
report or not report
(respectively)
when a user action changes the value of a window option there.
When it creates a window,
the \*(uw server instructs the Macintosh to report all
changes to window options.
Most programs will probably not need to issue UWOC_DO or UWOC_DONT commands.
.IP uw_gvis
This function fetches the current visibility
status of a specified window:
.DS
int uw_gvis(UWIN uwin, int *vp);
.DE
``vp'' is a pointer to an integer where the visibility status
(0 or 1 for invisible or visible, respectively)
is returned.
Zero is returned for success,
while \(mi1 is returned for failure.
.IP uw_svis
This function changes the visibility status of a specified window:
.DS
int uw_svis(UWIN uwin, int v);
.DE
If ``v'' is nonzero then the window ``uwin'' will be made visible;
otherwise,
the specified window will be made invisible.
Zero is returned for success,
while \(mi1 is returned for failure.
.IP uw_gpos
This function returns the current position on the screen
of a specified window:
.DS
.ta 8n 20n 28n
struct uwpoint {
unsigned uwp_v; /* vertical component */
unsigned uwp_h; /* horizontal component */
};
int uw_gpos(UWIN uwin, struct uwpoint *pp);
.DE
Zero is returned for success,
while \(mi1 is returned for failure.
.IP uw_spos
This function sets the position of a specified window to
a desired location:
.DS
int uw_spos(UWIN uwin, struct uwpoint *pp);
.DE
Zero is returned for success,
while \(mi1 is returned for failure.
.IP uw_gwsize
This function returns the current size in pixels
of a specified window.
The size is expressed as a ``uwpoint'',
as defined above.
.DS
int uw_gwsize(UWIN uwin, struct uwpoint *pp);
.DE
Zero is returned for success,
while \(mi1 is returned for failure.
.IP uw_swsize
This function sets a specified window to a new size:
.DS
int uw_swsize(UWIN uwin, struct uwpoint *pp);
.DE
.IP uw_gtitle
This function returns the title of a specified window.
The title has type ``uwtitle_t'':
.DS
typedef char uwtitle_t[256];
int uw_gtitle(UWIN uwin, uwtitle_t ttl);
.DE
Zero is returned for success,
while \(mi1 is returned for failure.
.IP uw_stitle
This function sets the title of a specified window:
.DS
int uw_stitle(UWIN uwin, uwtitle_t ttl);
.DE
.IP uw_gtype
This function returns the type of a specified window:
.DS
int uw_gtype(UWIN uwin, uwtype_t *tp);
.DE
``tp'' points to a variable which receives the window type.
Zero is returned for success,
while \(mi1 is returned for failure.
.IP uw_stype
This function sets the type of a specified window:
.DS
int uw_stype(UWIN uwin, uwtype_t t);
.DE
``t'' is the new window type.
Zero is returned for success,
while \(mi1 is returned for failure.
.IP "UW_DATAFD"
This macro extracts the file descriptor for the data connection
from a window descriptor:
.DS
int UW_DATAFD(UWIN uwin);
.DE
.IP "UW_ID"
This macro returns the unique window ID associated with a
window descriptor:
.DS
uwid_t UW_ID(UWIN uwin);
.DE
.IP "UW_PERROR"
When the \*(uw library detects an error
it always places the error information into the
global variables ``uwerrno'' and ``errno''.
If the error is associated with a valid window descriptor,
it will also store the information in the window descriptor.
The macro ``UW_PERROR'' is used to print an error message
according to the error status in a window descriptor:
.DS
void UW_PERROR(char *message, UWIN uwin);
.DE
where ``message'' is any user-supplied message and
``uwin'' is a window descriptor.
.SH
Copyright
.LP
This document copyright 1986 by John D. Bruner.
Permission to copy is given,
provided that the copies are not sold
and that this copyright notice is included.
a window
will be handled by a different process
than the control connection,
.I e.g.
in a child process after a ``fork''.
It is strongly rdoc/uwproto.ms 600 11722 76400 60570 4750124227 7113 .\" This file should be processed by nroff or troff with the -ms macro set
.ds uw "\s-2UW\s0
.de T=
.ie t .ta 8n 28n 36n 44n
.el .ta 8n 24n 32n 40n
..
.DA September 30, 1986
.TL
UW Protocol
.AU
John D. Bruner
.SH
Introduction
.PP
\*(uw is a multiple-window interface to UNIX.\**
.FS
UNIX is a registered trademark of American Telephone and Telegraph.
.br
Macintosh is a trademark of McIntosh Laboratories,
and is licensed to Apple Computer.
.br
ADM-31 is a trademark of Lear Siegler, Inc.
.br
VT52 is a trademark of Digital Equipment Corporation.
.br
The Tektronix 4010 is a graphics terminal manufactured
by Tektronix, Inc.
.FE
It comprises two parts:
a program which runs on a Macintosh
(referred to hereafter as ``the client'')
and a server program which runs on the UNIX system
(``the host'').
These two programs exchange information by sending
data across a serial communications line.
This information consists of data
and control and status messages relating to its presentation.
The structure of this information is defined by
the \*(uw protocol
and is the subject matter of this document.
.PP
\*(uw version 3 actually defines three protocols.
Internally they are assigned numbered,
while the user interface and documentation refer to them
by name.
The correspondence is as follows:
.IP 0
Protocol 0 is referred to as the ``serverless protocol''
or ``single terminal emulator protocol,''
because its use does not require a server on the host.
.IP 1
Protocol 1 is called the ``original \*(uw protocol,''
because it was the only protocol supported by the first
versions of \*(uw
(versions 1.6 and 2.10).
.IP 2
Protocol 2 is called the ``extended \*(uw protocol,''
or (sometimes)
the ``\*(uw version 3 protocol.''
.SH
Protocol 0 \(em The Serverless Protocol
.PP
Protocol 0 is not really a \*(uw protocol at all.
The client speaks protocol 0 when it is communicating
directly with a host,
rather than communicating through a server program
running on the host.
Protocol 0 is simply 7-bit or 8-bit ASCII.
Every byte transmitted in protocol 0 represents itself,
with the possible exception of the two flow-control characters
XON (control-Q)
and
XOFF (control-S).
Protocol 0 does not specify whether these characters are
to be used for flow-control purposes or for data transmission.
The client program on the Macintosh and the host's terminal driver
can be configured to use or ignore flow-control.
.PP
Protocol 0 does not specify whether data is transmitted
using 8-bit ASCII or 7-bit ASCII.
The user must choose the appropriate transmission format
and is reponsible for configuring both the client and the host
accordingly.
.SH
Protocol 1 \(em The Original \*(uw Protocol
.PP
Protocol 1 was the only protocol which was used in
the first versions of \*(uw
(versions 1.6 and 2.10).
It defines seven ``windows,''
each of which is an independent data stream.
Through the transmission of appropriate commands,
windows may be created or destroyed,
and data may be directed to a particular window.
Data which is transmitted from the client to the host
is referred to as ``input data,''
while data transmitted from the host to the client
is referred to as ``output data.''
In each direction a ``current window'' specifies
the recipient of data bytes.
(For example,
if the client wishes to send data to window 4,
it first sends a ``select window 4 as input window''
command and then sends the data.
Until the client sends another ``select input window'' command,
all further data that it transmits will be received
as data for window 4.)
The current input window and current output window may be different.
.PP
Protocol 1 encodes all information into 7-bit symbols;
it does not depend upon the value of the most-significant bit
(sometimes used for parity purposes).
Commands are encoded into two bytes:
a prefix byte (P1_IAC)
and a command byte.
Bit 7
(the second most-significant bit, octal 0100)
specifies whether the command was sent from the host to the client or
.I "vice versa:"
.DS
.T=
#define P1_IAC 0001 /* intrepret following byte as a command */
#define P1_DIR 0100 /* command direction: */
#define P1_DIR_HTOM 0000 /* from host to Mac (client) */
#define P1_DIR_MTOH 0100 /* from Mac (client) to host */
.DE
The command's function is encoded into the next three bits.
There are only seven commands:
.DS
.T=
#define P1_FN 0070 /* function code: */
#define P1_FN_NEWW 0000 /* create new window */
#define P1_FN_KILLW 0010 /* kill (destroy) window */
#define P1_FN_ISELW 0020 /* select window for input data */
#define P1_FN_OSELW 0030 /* select window for output data */
#define P1_FN_META 0050 /* add META to next data character */
#define P1_FN_CTLCH 0060 /* send control character as data */
#define P1_FN_MAINT 0070 /* perform "maintenance function" */
.DE
(The client does not send the P1_FN_OSELW command;
similarly,
the host does not send the P1_FN_ISELW command.)
.PP
The least-significant three bits of the command byte
specify an argument to the function.
For the ``new window'' (P1_FN_NEWW),
``kill window'' (P1_FN_KILLW),
``select input'' (P1_FN_ISELW),
and
``select output'' (P1_FN_OSELW)
commands,
the low three bits specify a window number.
Window number zero is not used.
.PP
There are no arguments to the P1_FN_META command.
It directs that the next data byte to be transmitted
be considered a ``meta'' character;
.I i.e.
a byte with the most-significant bit
(octal 0200)
set.
.PP
The P1_FN_CTLCH command is used to encode three
data characters which cannot be transmitted directly as data.
These are P1_IAC
(which,
if encountered in a transmission,
indicates the start of a two-character command),
and the flow-control characters XON (021)
and XOFF (023).
The low-order three bits of the command byte specify the character:
.DS
.T=
#define P1_CC 7 /* control character specifier: */
#define P1_CC_IAC 1 /* P1_IAC (001) */
#define P1_CC_XON 2 /* XON (021) */
#define P1_CC_XOFF 3 /* XOFF (023) */
.DE
A meta-control character is transmitted as a P1_FN_META
command followed by the appropriate P1_FN_CTLCH command.
Thus,
the octal character 0201 would be transmitted from the
host to the client as
a four-byte sequence:
.DS
.T=
0001 (P1_IAC)
0050 (P1_DIR_HTOM|P1_FN_META)
0001 (P1_IAC)
0061 (P1_DIR_HTOM|P1_FN_CTLCH|P1_CC_IAC)
.DE
Note that since the host does not send P1_FN_OSELW commands
and the client sends commands with the 0100 bit set,
the XON and XOFF control characters will never be sent as command bytes.
.PP
``Maintenance functions'' are defined for operations
which are performed infrequently.
Protocol 1 defines two maintenance functions:
.DS
.T=
#define P1_MF 7 /* maintenance functions: */
#define P1_MF_ENTRY 0 /* start up */
#define P1_MF_EXIT 7 /* exit */
.DE
The server sends the P1_MF_ENTRY command when it starts up.
The client responds to this by killing any windows that it
has created
(silently,
.I i.e.
without sending P1_FN_KILLW messages to the host).
Either the client or the server may send the P1_MF_EXIT command
to terminate the session.
When the server on the host receives P1_MF_EXIT
it terminates;
when the client receives this command it will reset to a
simple known state.
.SH
Protocol 2
.PP
\*(uw version 3 provides a number of capabilities
that earlier versions of \*(uw did not.
Among these is an expansion of the host-client interaction.
In order to accomodate the increased flow of information
it was necessary to extend the \*(uw protocol.
One of the significant extensions in protocol 2
is support for a concept called ``window options.''
Window options are described in more detail in the next section.
.PP
Protocol 2 is very similar to protocol 1.
Like protocol 1,
protocol 2 multiplexes a single communications stream
among a maximum of seven windows.
Command bytes in protocol 2 are encoded in the same
fashion as in protocol 1:
a prefix byte
(P2_IAC)
followed by a command byte.
However,
unlike protocol 1,
some protocol 2 commands require more than one command byte.
.PP
The protocol 2 functions are:
.DS
.T=
#define P2_FN 0070 /* function code: */
#define P2_FN_NEWW 0000 /* create new window */
#define P2_FN_KILLW 0010 /* kill (destroy) window */
#define P2_FN_ISELW 0020 /* select window for input data */
#define P2_FN_OSELW 0030 /* select window for output data */
#define P2_FN_WOPT 0040 /* communicate window options */
#define P2_FN_META 0050 /* add META to next data character */
#define P2_FN_CTLCH 0060 /* send control character as data */
#define P2_FN_MAINT 0070 /* perform "maintenance function" */
.DE
The P2_FN_KILLW,
P2_FN_ISELW,
P2_FN_OSELW,
and P2_FN_CTLCH
commands are identical to their counterparts in protocol 1.
.PP
The low-order three bits of the P2_FN_META command
represent a control character.
(The low-order three bits of the P1_FN_META command are ignored.)
The encoding is identical to the encoding
for the P2_FN_CTLCH command:
.DS
.T=
#define P2_CC 7 /* control character specifier: */
#define P2_CC_IAC 1 /* P2_IAC (001) */
#define P2_CC_XON 2 /* XON (021) */
#define P2_CC_XOFF 3 /* XOFF (023) */
.DE
If the low-order three bits are zero,
then the P2_FN_META command acts like the P1_FN_META command \(em
the META bit is set in the next data byte.
If the low-order three bits are not all zero,
the the P2_FN_META command specifies a META-control character.
Thus, the following are all equivalent:
.DS
P1_IAC\ \ P1_FN_META\ \ P1_IAC\ \ P1_FN_CTLCH|P1_CC_IAC
P2_IAC\ \ P2_FN_META\ \ P2_IAC\ \ P2_FN_CTLCH|P2_CC_IAC
P2_IAC\ \ P2_FN_META|P2_CC_IAC
.DE
.PP
The P2_FN_NEWW command differs from the P1_FN_NEWW command
in that the protocol 2 command includes an extra byte.
The byte following the command byte
specifies the type of the window that is being created.
The numeric value of the window type is
added to the ASCII value for a space (blank);
hence,
the window type is always represented by a printable character.
As an example,
if the host wishes to create window 2
with window type 1 (VT-52),
the command sequence is:
.DS
.T=
0001 (P2_IAC)
0002 (P2_DIR_HTOM|P2_FN_NEWW|2)
0041 (`!')
.DE
.PP
The following maintenance functions (P2_FN_MAINT) are defined:
.DS
.T=
#define P2_MF 7 /* maintenance functions: */
#define P2_MF_ENTRY 0 /* start up */
#define P2_MF_ASKPCL 2 /* request protocol negotiation */
#define P2_MF_CANPCL 3 /* suggest protocol */
#define P2_MF_SETPCL 4 /* set new protocol */
#define P2_MF_EXIT 7 /* exit */
.DE
The representations of
P2_MF_ENTRY and P2_MF_EXIT are identical to those in protocol 1.
The definition of the ``entry'' function is extended
slightly in protocol 2.
In protocol 1,
the P1_MF_ENTRY command is only sent by the server when it starts up.
The client recognizes this command and initializes itself.
In protocol 2,
the client is permitted to send the P2_MF_ENTRY command
to the server.
Upon receipt of this command,
the server issues the sequence of P2_FN_NEWW commands
and P2_FN_WOPT commands
(described below)
which will reconstruct all of the existing windows
on the client in their current state.
The client uses this command to ``restart'' itself after a crash
or other interruption on its end of the connection.
The three new maintenance functions are used for protocol negotiation.
Protocol negotiation is described in detail below.
.PP
Protocol 2 defines the new command
P2_FN_WOPT
to transmit window option information
between the client and server.
The P2_FN_WOPT command is followed by a variable-length
string of bytes which encode the window options information.
The next section describes the meaning and encoding of
window option information.
.SH
Window Options
.PP
Window options are window attributes
(the latter is a more meaningful name).
For each window,
a maximum of 31 window options may be defined.
These are divided into two categories:
generic and emulation-specific.
Generic window options are attributes which are common
to all window emulation types.
Emulation-specific options are meaningful only for some
subset of the available emulation types.
The following options are generic:
.DS
.T=
#define WOG_END 0 /* [used as an endmarker] */
#define WOG_VIS 1 /* visibility */
#define WOG_TYPE 2 /* window emulation type */
#define WOG_POS 3 /* window position on screen */
#define WOG_TITLE 4 /* window title */
#define WOG_SIZE 5 /* window size (in pixels) */
#define WOG_6 6 /* [unassigned, reserved] */
#define WOG_7 7 /* [unassigned, reserved] */
.DE
Terminal emulations define the following emulation-specific options:
.DS
.T=
#define WOTTY_SIZE 8 /* (row,col) terminal size */
#define WOTTY_FONTSZ 9 /* font size index */
#define WOTTY_MOUSE 10 /* mouse interpretation */
#define WOTTY_BELL 11 /* audible, visual bell */
#define WOTTY_CURSOR 12 /* cursor shape */
.DE
Window option values are structured types composed
of the following primitive types:
.DS
fixed-length character vectors
variable-length character strings
specified-width unsigned integer data
.DE
.PP
The host and client may exchange the following commands
regarding window options:
.DS
.T=
#define WOC_SET 0 /* change value of option */
#define WOC_INQUIRE 2 /* ask about current option value */
#define WOC_DO 4 /* do report changes to option */
#define WOC_DONT 5 /* don't report changes to option */
#define WOC_WILL 6 /* will report changes to option */
#define WOC_WONT 7 /* won't report changes to option */
.DE
The ``set'' command is sent by either the client or the host
to specify the current value of a window option.
The ``inquire'' command is sent by either the client or the host
when it wishes to know the current value of an option.
The recipient of an ``inquire'' command responds with a
``set'' command that specifies the current option value.
.PP
The remaining four window option commands
are used by the host
to set up automatic reporting by the client
when the value of a window option changes.
If the host wishes to be informed
when the value of a window option changes
(\fIe.g.\fP when a window is retitled),
it sends a ``do'' command to the client.
The client responds to the ``do'' command
with a ``will'' command
followed immediately by a ``set'' command
(reporting the current value of the option).
Thereafter,
whenever the value of that option changes
the client will send a ``set'' command with the new value
to the host.
If the host wishes the client to stop sending
these ``set'' commands,
the host sends the client a ``don't'' command.
The client responds with a ``won't'' message.
.PP
The reporting status of generic window options is not affected
if the window emulation types changes;
however,
if the emulation type changes,
then reporting for emulation-specific options is ended.
If the host wishes the client to continue
reporting changes in some emulation-specific window options,
it must send the appropriate ``do'' commands.
.PP
Window option commands are grouped together and transmitted
collectively as part of a P2_FN_WOPT command.
That is,
the P2_IAC and P2_FN_WOPT command are immediately
followed by a variable-length string of bytes
which contain window option commands for one or
more options.
The end of a sequence of window option (sub)commands
is indicated by a command which specifies window option zero
(WOG_END).
.PP
All window option commands begin with a one or two
byte command specifier.
The one-byte form is called the ``short'' form,
while the two-byte form is the ``long'' form:
.DS
.ta 8n 32n 48n
#define WONUM_MIN 1 /* minimum option number */
#define WONUM_GENERIC 7 /* maximum generic option number */
#define WONUM_SHORT 14 /* maximum short option number */
#define WONUM_MAX 31 /* maximum option number */
#define WONUM_MASK (017<<3) /* mask for extraction */
#define WONUM_SENCODE(n) (((n)&017)<<3) /* short encoding function */
#define WONUM_SDECODE(b) (((b)>>3)&017) /* short decoding function */
#define WONUM_LPREFIX (017<<3) /*long encoding prefix */
#define WONUM_LENCODE(n) ((n)+' ') /* long encoding function */
#define WONUM_LDECODE(c) (((c)&0177)-' ') /* long decoding function */
.DE
Commands
specifing options whose numbers are in the range WONUM_MIN to WONUM_SHORT
may use the short form.
In this case,
the window option number is encoded according to WONUM_SENCODE:
it is shifted left by three bits.
The command byte consists of a bitwise ``or'' of
the window option command
(\fIe.g.\fP WOC_INQUIRE)
and the encoded short option number.
.PP
Commands which specify options whose numbers are greater than WONUM_SHORT
must use the long form.
(The long form may be used for options whose numbers are less than WONUM_SHORT,
but there is no reason to do so.)
In this case,
the first byte contains a bitwise ``or'' of
the window option command
(\fIe.g.\fP WOC_INQUIRE)
and the special prefix WONUM_LPREFIX.
The second byte is encoded by WONUM_LENCODE:
the window option number is added to the ASCII code for a space
(thus this byte is always printable).
.PP
All of the window option commands begin with the
one or two byte option command specifier.
Unlike the other window option commands
(which use no additional bytes),
the WOC_SET command is followed by encoded data
(the value of the option).
Option values are constructed from three primitive
data types
(as noted above).
.IP chars 8n
The simplest type of data is a fixed-length character vector.
This is represented directly.
The vector must consist of printable characters.
[This restriction may be eliminated in the future.
The current implementation is able to process non-printable
characters
(including XON and XOFF)
correctly.]
.IP string
Like character vectors,
strings have a maximum length.
However,
unlike character vectors,
strings may contain non-printing characters.
Also,
while all characters in a character vector are sent,
a string may be shorter than its maximum length.
It is terminated by a null (000) byte.
[Hence,
a string may not contain an embedded null byte.]
.IP udata
The remaining data type is unsigned integer data.
This data has a fixed width measured in bits.
The value is encoded in ``little-endian'' fashion
into the low six bits of successive characters.
The (octal) 0100 bit of each character is set.
The number of characters required to hold an integer
varies from one
(for data which is one to six bits wide)
to six
(for data which is thirty-two bits wide).
.PP
The window options defined above have arguments as follows
(all integers are unsigned):
.IP WOG_VIS 20n
This is a 1-bit integer
which is nonzero iff the window is visible.
.IP WOG_POS
This consists of two 12-bit integers
which respectively specify the vertical and horizontal
offsets of the window on the client's screen.
.IP WOG_TITLE
This is a string of maximum length 256
which specifies the window's title.
.IP WOG_SIZE
This consists of two 12-bit integers
which respectively specify the vertical and horizontal
size of the window on the client's screen
(in pixels).
.IP WOTTY_SIZE
This consists of two 12-bit integers
which respectively specify the window size in rows and columns.
.IP WOTTY_FONTSZ
This is a 6-bit integer which is a font size index.
At present,
it specifies a ``small'' font if zero
and a ``large'' font if nonzero.
.IP WOTTY_MOUSE
This is a 1-bit integer
which is nonzero iff
mouse events are to be encoded and sent
as data to the host.
.IP WOTTY_BELL
This is a 2-bit integer.
The low-order bit is set iff the window should
display bells visually;
the other bit is set iff the client should report
bells within this window audibly.
.IP WOTTY_CURSOR
This is a 1-bit integer
which is zero if the window is using a block cursor
and nonzero if the window is using an underscore cursor.
.PP
One design decision which the author now regrets
is an overloading of the WOTTY_SIZE option.
If the host can handle window size changes on pseudo-terminals
(\fIe.g.\fP 4.3BSD can),
then the client is capable of changing the view size of a window
or its actual size,
according to the user's preference.
If the host cannot handle window size changes,
the client does not allow the view size to be changed.
The client assumes that the host can handle window size
changes if it receives a WOC_DO command for the WOTTY_SIZE option.
.SH
Protocol Negotiation
.PP
It is possible that at some time the versions of a \*(uw server
and client will not match;
.I e.g.
a version 2.10 client will be used with a version 3.4 server.
It is desirable that such combinations will work ``correctly'' \(em
that the server will communicate with the client using protocol 1
rather than trying to use protocol 2.
In order to accomplish this,
three new maintenance functions
are defined by which the server and client
may negotiate the protocol which is to be used.
Version 3 clients and servers recognize these maintenance
functions in both protocol 1 and protocol 2.
Older clients and servers do not recognize these functions
at all.
.PP
The protocol negotiation maintenance functions were
described above for protocol 2.
They are repeated here for protocol 1
(the encodings are identical):
.DS
.T=
#define P1_MF_ASKPCL 2 /* request protocol negotiation */
#define P1_MF_CANPCL 3 /* suggest protocol */
#define P1_MF_SETPCL 4 /* set new protocol */
.DE
P1_MF_ASKPCL is encoded in a single command byte
(following P1_IAC).
The P1_MF_CANPCL and P1_MF_SETPCL command bytes are
followed by an additional byte which names a protocol.
For the purposes of protocol negotiation,
protocols 1 and 2 are represented by the ASCII
characters space and exclamation-mark,
respectively.
.PP
The client and server always start operation in protocol 1.
(The user may have instructed the client to use protocol 2;
nonetheless,
it will use protocol 1 until protocol negotiations are complete.)
When the server is started
it will send a P1_MF_ENTRY maintenance command to the client.
If the client knows about protocol 2 and wishes to use it,
it will send a P1_MF_ASKPCL to the server.
If the client does not know about protocol 2,
it will not send P1_MF_ASKPCL,
protocol negotiation will never be started,
and both sides will continue to use protocol 1.
.PP
If the server can support something other than protocol 1
it will respond to the P1_MF_ASKPCL with a
P1_MF_CANPCL which names the most extensive protocol that it can support.
(At present,
this will be protocol 2;
however,
in the future it might name some other protocol.)
Old servers,
which do not recognize P1_MF_ASKPCL,
will ignore the maintenance function.
The client will time out after five seconds
and retry several times
(three in the present implementation);
if the server never responds
the client will ``give up'' and will
continue to use protocol 1 indefinitely.
.PP
When the client receives P1_MF_CANPCL from the server,
it will examine the server's suggested protocol.
If this protocol is unacceptable to the client,
it will respond with its own P1_MF_CANPCL,
naming the most extensive protocol that it can support.
The server,
upon receipt of this P1_MF_CANPCL,
will examine the client's suggested protocol.
If it is unacceptable to the server,
it will name the second-most extensive protocol that it can support.
Each time that the client or server receives a
P1_MF_CANPCL that names a protocol it cannot support,
it will respond with a different,
less extensive suggestion of its own.
Since the number of protocols is finite,
eventually someone will suggest protocol 1,
which both sides are required to support.
.PP
When the client or server receives a P1_MF_CANPCL
that names a protocol that it
.I can
support,
it will instruct its counterpart to start using that protocol
by sending a P1_MF_SETPCL that names that protocol.
Henceforth,
the new protocol will be used.
.PP
Protocol 2 allows the client to send a P2_MF_ENTRY
maintenance command to the server.
(This is encoded identically to a P1_MF_ENTRY command.)
If the server receives this maintenance command and
it is using a protocol other than protocol 1,
it will immediately respond with a P1_FN_SETPCL which
names the protocol that it is using.
It will then proceed to send ``new window'' and
(if applicable)
``window option'' commands to the client
to reconstruct the client's current state.
.SH
Postscript
.PP
There are a number of obvious problems with the mechanism
for protocol negotiation.
It is possible for one party to send a SETPCL
command and begin listening for input in a new protocol
while it is still receiving buffered commands in the old protocol
from the other party.
It probably would have been better to have established
a ``current protocol'',
similar to the ``current window'' scheme used for data transfer.
This scheme was born out of the desire to allow
old servers and clients to work with new ones.
It ``works'' if things are relatively quiescent,
as they are when the server first starts up
(before it creates its first window).
.PP
This document is still incomplete.
At this time it is more useful as a conceptual guide
to the \*(uw protocol
than a definitive reference.
.SH
Copyright
.LP
This document copyright 1986 by John D. Bruner.
Permission to copy is given,
provided that the copies are not sold
and that this copyright notice is included.
ays printable).
.PP
All of the window option commands begin with the
one or two byte option command specifier.
Unlike the other window odoc/uw.l 600 11722 76400 4527 4750124230 5615 .TH UW 1 "14 September 1986"
.UC 4
.SH NAME
uw \- multiple-window Macintosh interface to UNIX
.SH SYNOPSIS
.B uw [
.BI \-f filename
] [
.B \-n
] [
.B \-s
]
.SH DESCRIPTION
.I Uw
is a server program on UNIX that works with the program
.I uw
on the Macintosh.
It provides the Macintosh program with access to
a maximum of seven independent I/O sessions.
An I/O session may be directly associated with a pseudo-terminal
or may simply be a communications channel to an external
UNIX process.
The host program multiplexes the input and output onto one RS\-232 line.
.PP
Most commonly,
sessions will be directly associated with pseudo-terminals.
The Macintosh program will emulate
a Lear Siegler ADM-31 terminal
(tset adm31),
a DEC VT52,
an ANSI-compatible terminal
(tset ansi or tset aaa-24),
and a Tektronix 4010.
Each window
(on the Macintosh)
has its own terminal emulation and can be resized at will.
Window size changes on the Macintosh can be propagated to the host,
or the Macintosh may be directed to display the lower left portion
of a larger logical terminal size.
.PP
If the file `.uwrc' exists in the user's home directory,
then
.I uw
will execute it when starting up.
If `.uwrc' is an executable file,
it will be directly invoked;
otherwise,
a shell will be spawned to interpret it.
An alternate startup file may be specified using the
`\-f' flag;
alternately,
the `\-n' flag instructs
.I uw
not to execute any startup file.
.PP
The `\-s' flag prevents
.I uw
from listening for UNIX-domain datagrams.
Thus,
it prevents external processes from manipulating
windows which they did not create.
This may be of value in an environment where
other users are considered `hostile.'
.SH LIMITATIONS
.I Uw
is of no use on unix unless
.I uw
is being run on the Macintosh.
.br
If there is a stream of output in one window there will be lag in
recognizing characters typed in another.
.SH SEE ALSO
uwtool(L), uwtitle(L), uwterm(L)
.br
.I uw
Macintosh documentation
(`UW \(em A Multiple-Window Interface to UNIX').
.br
`The UW Programmer's Library'
.SH AUTHOR
Program written by John Bruner, Lawrence Livermore Laboratories 7/85,11/85,9/86
.br
This document is based upon a document created by
by Chris Borton, UC San Diego 11/13/85,
edited 9/86 by John Bruner.
.SH BUGS
The `\-s' flag greatly reduces the utility of a `.uwrc' file,
since it prevents
.I uwtool
and
.I uwtitle
from working.
is copyright notice is included.
ays printable).
.PP
All of the window option commands begin with the
one or two byte option command specifier.
Unlike the other window odoc/uwplot.l 600 11722 76400 3772 4750124231 6516 .TH UWPLOT 1 "28 April 1987"
.UC 4
.SH NAME
uwplot \- plot filter for use with UW
.SH SYNOPSIS
.B uwplot
[
.BI \-t title
] [
.BI \-n serveraddr
]
.SH DESCRIPTION
.I Uwplot
is a utility program for use with the
.I uw
multiple-window interface to UNIX.
It creates a window,
reads plotting instructions from the standard input,
and displays the result in the window.
(The plotting commands are produced by programs
which use the standard UNIX
.I plot
package.)
.PP
The title of the newly-created window may be
specified with the `\-t' option.
If this option is omitted,
the title will be the name of the command
which created it
(\fIi.e.\fP `uwplot').
.PP
Normally
.I uwplot
will examine the environment for the variable `UW_INET'
and will connect to the
.I uw
server with that address.
The `\-n' flag can be used to specify an alternate
server network address.
The address should have the form `xxxxxxxx.ddd'
where `x' is a hexadecimal digit
and `d' is a decimal digit.
The hexadecimal number is the host's Internet address
and the decimal number is the port on which the
server is listening for connections.
.PP
`linemod' commands in the plot file are
intended to select the color in which the
plot is drawn;
however, this feature is untested.
The old-model Quickdraw colors may be
specified by name
(all lower-case).
The standard plot linemod names are mapped to
colors as follows:
.sp
.nf
.ta 1i
black solid
red shortdashed
green dotdashed
blue longdashed
yellow dotted
.fi
.PP
The present implementation on the Macintosh
is a square window with vertical and horizontal
dimensions of 300 pixels.
Arcs are not drawn correctly when
the vertical and horizontal scaling factors
are unequal.
.SH LIMITATIONS
.I Uwterm
is of no use on unix unless
the server is running and
.I uw
is being run on the Macintosh.
.SH SEE ALSO
plot(1G), plot(3X), plot(5), uw(L)
.br
.I uw
Macintosh documentation
(`UW \(em A Multiple-Window Interface to UNIX')
.br
`The UW Programmer's Library'
.SH AUTHOR
John Bruner, Lawrence Livermore National Laboratory, 10/86.
ibrarydoc/uwterm.l 600 11722 76400 5452 4750124233 6506 .TH UWTERM 1 "20 September 1986"
.UC 4
.SH NAME
uwterm \- (possibly remote) terminal emulation for UW
.SH SYNOPSIS
.B uwterm
[
.BI \-w type
] [
.BI \-t title
] [
.BI \-n serveraddr
] [
.BI \-l loginname
] [ host ]
.SH DESCRIPTION
.I Uwterm
is a utility program for use with the
.I uw
multiple-window interface to UNIX.
It creates a window in which a terminal session
is conducted.
If no arguments are given
the terminal is created on the local machine.
A hostname may be specified;
in this case,
the terminal is created on the remote host.
.RI ( Uwterm
must be installed on the remote host
and permissions for
.I rsh
must have been set up correctly
in order for this to work.)
.I Uwterm
examines the `SHELL' environment variable
and executes the program named there.
The `\-l' option
can be used to specify the login name under which
the remote process will be executed
(the default is the current account).
.PP
Unlike
.IR uwtool ,
.I uwterm
does not exit until the window it has created
is destroyed;
hence,
it will usually be desirable to run it in the background.
.PP
Normally,
the terminal type of the new window is inherited from
the window in which
.I uwterm
is run.
It is possible to override this with the `\-w' option
(`w' stands for `window emulation type').
The window types are the same as those accepted by the
.I uwtool
program.
.PP
The title of the newly-created window may be
specified with the `\-t' option.
If this option is omitted,
the title will be the host name.
.PP
Normally
.I uwterm
will examine the environment for the variable `UW_INET'
and will connect to the
.I uw
server with that address.
The `\-n' flag can be used to specify an alternate
server network address.
The address should have the form `xxxxxxxx.ddd'
where `x' is a hexadecimal digit
and `d' is a decimal digit.
The hexadecimal number is the host's Internet address
and the decimal number is the port on which the
server is listening for connections.
The `\-n' flag is used by
.I uwterm
itself:
it creates a remote terminal by invoking itself on
the remote machine
(using
.IR rsh )
and specifying the network address
of the local server.
.SH LIMITATIONS
.I Uwterm
is of no use on unix unless
the server is running and
.I uw
is being run on the Macintosh.
.br
If there is a stream of output in one window there will be lag in
recognizing characters typed in another.
.br
There are so many levels of buffering
that user-entered CTL-S/CTL-Q flow control is
practically useless,
even at relatively low baud rates.
.SH SEE ALSO
rsh(1), uw(L), uwtitle(L), uwtool(L)
.br
.I uw
Macintosh documentation
(`UW \(em A Multiple-Window Interface to UNIX')
.br
`The UW Programmer's Library'
.SH AUTHOR
John Bruner, Lawrence Livermore National Laboratory, 9/86.
.SH BUGS
There are so many levels of buffering that typing
XON and XOFF
to suspend output within a window
is futile.
directly.
The vector must consist of printable characters.
[This restriction may be eliminated in the future.
The current implementation is able to process non-printable
characters
(including XON and XOFF)
correctldoc/uwtitle.l 600 11722 76400 1522 4750124234 6653 .TH UWTITLE 1 "14 September 1986"
.UC 4
.SH NAME
uwtitle \- retitle UW window
.SH SYNOPSIS
.B uwtitle
[
.BI \-i id
]
string ...
.SH DESCRIPTION
.I Uwtitle
is a utility program for use with the
.I uw
multiple-window interface to UNIX.
It retitles an existing window.
The title is specified as one or more
strings
(in the same fashion as arguments to the
.I echo
program).
The `\-i' option can be used to specify
the ID of the window to be retitled;
otherwise,
the current window will be affected.
.SH LIMITATIONS
.I Uwtitle
is of no use on unix unless
the server is running and
.I uw
is being run on the Macintosh.
.SH SEE ALSO
echo(1), uw(L), uwtool(L), uwterm(L)
.br
.I uw
Macintosh documentation (`UW \(em A Multiple-Window Interface to UNIX')
.br
`The UW Programmer's Library'
.SH AUTHOR
John Bruner, Lawrence Livermore National Laboratory 9/86
ss will be executed
(the default is the current account).
.PP
Unlike
.IR uwtool ,
.I uwterm
does not exit until the window it has created
is destroyed;
hence,
it will usuallydoc/uwtool.l 600 11722 76400 4436 4750124235 6517 .TH UWTOOL 1 "14 September 1986"
.UC 4
.SH NAME
uwtool \- command-in-window utility for UW
.SH SYNOPSIS
.B uwtool
[
.BI \-w type
] [
.BI \-t title
] [
.B \-v
] [ command [ arg1 arg2 ... ] ]
.SH DESCRIPTION
.I Uwtool
is a utility program for use with the
.I uw
multiple-window interface to UNIX.
If no arguments are given,
it creates a new `terminal' running the shell named in the
environment variable `SHELL'.
If a process is named,
it will create a new window with that process running in it,
and when that process is terminated the window will disappear.
(i.e. `uwtool vi foo' will create a new window with vi,
editing the file foo,
but the window will go away when vi is exited)
Any arguments after the process name are passed as arguments to that process.
.I Uwtool
exits as soon as the window is created.
.PP
Normally,
the terminal type of the new window is inherited from
the window in which
.I uwtool
is run.
It is possible to override this with the `\-w' option
(`w' stands for `window emulation type').
The following values are recognized:
.TP 8n
adm31
Lear Siegler ADM-31
.TP
adm3a
Lear Siegler ADM-3a (uses ADM-31)
.TP
tek4010
Tektronix 4010
.TP
tek
Tektronix 4010
.TP
vt52
Digital Equipment Corporation VT-52
.TP
ansi
ANSI-compatible terminal
.TP
aaa-24
24-line Ann Arbor Ambassador
(uses ANSI emulation)
.PP
If an unknown type is specified,
the ADM-31 emulation will be used.
.PP
The title of the newly-created window may be
specified with the `\-t' option.
If this option is omitted,
the window title will be the command name.
.PP
The `\-v' flag causes
.I uwtool
to print the 32-bit window identifier on
the standard output.
This value can be used as an argument to a subsequent
command,
for example
.IR uwtitle .
.SH LIMITATIONS
.I Uwtool
is of no use on unix unless
the server is running and
.I uw
is being run on the Macintosh.
.br
If there is a stream of output in one window there will be lag in
recognizing characters typed in another.
.SH SEE ALSO
uw(L), uwtitle(L), uwterm(L)
.br
.I uw
Macintosh documentation
(`UW \(em A Multiple-Window Interface to UNIX')
.br
`The UW Programmer's Library'
.SH AUTHOR
Program written by John Bruner, Lawrence Livermore Laboratories 7/85,11/85,9/86
.br
This document is based upon a document created by
by Chris Borton, UC San Diego 11/13/85,
edited 9/86 by John Bruner.
aracters typed in another.
.br
There are so many levels of buffering
that user-entered CTL-S/CTL-Q flow control is
practically useless,
even at relatively low baud rates.
.SH SEE ALSO
rsh(1), uw(L), uwtitle(L), uwtool(L)
.br
.h/ 700 11722 76400 0 4750124243 4374 h/openpty.h 600 11722 76400 464 4750124235 6317 /*
* This file defines the "ptydesc" structure which is returned
* by the routine "openpty".
*/
struct ptydesc {
int pt_pfd; /* file descriptor of master side */
int pt_tfd; /* file descriptor of slave side */
char *pt_pname; /* master device name */
char *pt_tname; /* slave device name */
};
nts are given,
it creates a new `terminal' running the shell named in the
environment variable `SHELL'.
If a process is named,
it will create a new window with that process running in it,
and when that prh/uw_clk.h 600 11722 76400 2211 4750124236 6116 /*
* uw_clk - timer support for UW
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#ifndef UW_CLK
#define UW_CLK
/*
* Events which are supposed to occur at a certain time are handled by
* setting "timeout"s. The list of timeouts is sorted in order of
* occurrence. The "alarm" mechanism is used to send SIGALRM when the
* first timeout expires. However, the timeout is not processed
* immediately. Instead, it will be processed upon exit from the
* select() in main(). This prevents timeouts from happening at
* inappropriate times.
*
* The resolution of timeouts is in seconds. The server doesn't need
* any better resolution, and this allows all of the hair associated with
* (struct timeval) and (struct itimerval) types to be avoided.
*/
#define CLK_HZ 1 /* one tick/second */
typedef long toarg_t;
struct timeout {
struct timeout *to_next;
time_t to_when;
void (*to_fn)();
toarg_t to_arg;
};
extern int timer_rdy;
#define CLK_CHECK() if (timer_rdy) clk_service(); else
#endif
tek
Tektronix 4010
.TP
vt52
Digital Equipment Corporation VT-52
.TP
ansi
ANSI-compatible terminal
.TP
aaa-24
24-line Ann Arbor Ambassador
(uses ANSI emulation)
.PP
If an unknown type is specified,
the ADM-31 emulation will be used.
.PP
The title of the newly-created window may be
specified with the `\-t' option.
If this option is omitted,
the window title will be the commah/uw_err.h 600 11722 76400 1367 4750124236 6150 /*
* uw error codes
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#ifndef UW_ERR
#define UW_ERR
typedef int uwerr_t;
#define UWE_NONE 0 /* no error */
#define UWE_ERRNO 1 /* system call error, consult errno */
#define UWE_NXTYPE 2 /* nonexistent window type */
#define UWE_DUPID 3 /* window ID duplicated (in use) */
#define UWE_NOTIMPL 4 /* operation not implemented yet */
#define UWE_NXSERV 5 /* non-existent server */
#define UWE_NOMEM 6 /* unable to allocate required memory */
#define UWE_INVAL 7 /* invalid argument to function */
#define UWE_NOCTL 8 /* no control file descriptor */
#endif
t need
* any better resolution, and this allows all of the hair associated with
* (struct timeval) and (struct itimerval) types to be avoided.
*/
#define CLK_HZ 1 /* one tick/second */
typedef long toarg_t;
struct timeout {
struct timeout *to_next;
time_th/uw_fd.h 600 11722 76400 2720 4750124237 5744 /*
* uw_fd - file-descriptor/select data
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#ifndef UW_FD
#define UW_FD
#include "uw_param.h"
/*
* If FD_SET and friends aren't defined in
* provide simple definitions here.
*/
#ifndef FD_SET
#define FD_SET(n,p) ((p)->fds_bits[0] |= (1 << (n)))
#define FD_CLR(n,p) ((p)->fds_bits[0] &= ~(1 << (n)))
#define FD_ISSET(n,p) ((p)->fds_bits[0] & (1 << (n)))
#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
#define FD_SETSIZE (NBBY*sizeof(long))
#endif
/*
* We use file descriptors for several different things. "fdmap" associates
* a file descriptor number with its use.
*/
typedef enum { /* file descriptor type */
FDT_NONE, /* not in use */
FDT_DATA, /* data connection for window */
FDT_CTL, /* control connection for window */
FDT_MAC, /* tty line which talks to Mac */
FDT_UDSOCK, /* UNIX-domain datagram socket */
FDT_ISSOCK, /* Internet-domain stream sock */
FDT_DEBUG, /* debugging use */
FDT_OTHER /* other uses */
} fdtype_t;
struct fdmap {
fdtype_t f_type; /* file descriptor type */
struct window *f_win; /* associate window (if any) */
};
struct selmask {
struct fd_set sm_rd;
struct fd_set sm_wt;
struct fd_set sm_ex;
};
extern struct fdmap fdmap[FD_SETSIZE];
extern fildes_t nfds;
extern struct selmask selmask[2];
#endif
n is omitted,
the window title will be the commah/uw_ipc.h 600 11722 76400 12433 4750124237 6150 /*
* uw IPC definitions
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#ifndef UW_IPC
#define UW_IPC
/*
* UW accepts network connections in both the UNIX domain and the
* Internet domain. UNIX domain datagrams are used by processes on
* the local machine to create new windows and to change the value
* of window parameters (window options). TCP (Internet stream)
* connections are used by local and non-local processes which wish
* to handle their own host activity (e.g. pseudo-terminal handling).
*
* Some of the definitions in this file duplicate definitions in the
* UW server source code, because this file is also intended for use
* with the UW library.
*
* The code which performs byte-order conversions knows the size of the
* types defined in this file (since there is no typeof() operator).
*/
#define UIPC_ENV "UW_UIPC" /* Unix-domain port environment var */
#define INET_ENV "UW_INET" /* Internet-domain port environ var */
typedef long uwid_t; /* unique window identifier */
typedef short uwcmd_t; /* commands: */
#define UWC_NEWW 0 /* create new window */
#define UWC_NEWT 1 /* create new tty window */
#define UWC_STATUS 2 /* creation status message */
#define UWC_KILLW 3 /* kill existing window */
#define UWC_OPTION 4 /* act upon window option */
typedef short uwoptcmd_t; /* option subcommands: */
#define UWOC_SET 0 /* set value of option */
#define UWOC_ASK 2 /* ask for value of option */
#define UWOC_DO 4 /* report changes in value */
#define UWOC_DONT 5 /* don't report changes */
#define UWOC_WILL 6 /* will report changes */
#define UWOC_WONT 7 /* won't report changes */
typedef short uwtype_t; /* window type (see also uw_win.h): */
#define UWT_ADM31 0 /* ADM-31 */
#define UWT_VT52 1 /* VT-52 */
#define UWT_ANSI 2 /* ANSI */
#define UWT_TEK4010 3 /* Tektronix 4010 */
#define UWT_FTP 4 /* file transfer */
#define UWT_PRINT 5 /* output to Macintosh printer */
#define UWT_PLOT 6 /* plot window */
typedef short uwopt_t; /* window option number: */
#define UWOP_VIS 1 /* visibility */
#define UWOP_TYPE 2 /* window type */
#define UWOP_POS 3 /* window position */
#define UWOP_TITLE 4 /* window title */
#define UWOP_WSIZE 5 /* window size (in bits) */
#define UWOP_TSIZE 8 /* terminal size (row,col) */
#define UWOP_TFONTSZ 9 /* small/large font size */
#define UWOP_TCLIPB 10 /* clipboard/mouse encoding */
#define UWOP_TBELL 11 /* audible, visual bell */
#define UWOP_TCURS 12 /* cursor shape */
union uwoptval {
unsigned char uwov_1bit;
unsigned char uwov_6bit;
unsigned short uwov_12bit;
struct {
unsigned short v,h;
} uwov_point;
char uwov_string[256];
};
/*
* UWC_NEWW: create a new window
*
* This command is only valid when it is sent as the first message on an
* Internet stream socket. The remote port is the data fd for the window.
* If a control fd is desired, its port number is contained in "uwnt_ctlport"
*/
struct uwneww {
uwid_t uwnw_id; /* unique window identifier */
uwtype_t uwnw_type; /* window type */
short uwnw_ctlport; /* port number of control fd */
};
/*
* UWC_NEWT: create a new tty window
*
* This command is only valid when it is sent as a datagram to the Unix-domain
* socket. It must be accompanied by an access right (file descriptor) for
* the master side of a pty. The server takes over all responsibilities for
* this window. "uwnt_pty" is variable-length.
*/
struct uwnewt {
uwid_t uwnt_id; /* unique window identifier */
uwtype_t uwnt_type; /* window type */
char uwnt_pty[1]; /* name of associated pty */
};
/*
* UWC_STATUS: status report for UWC_NEWW
*
* This type of packet is sent by the server to the data fd in response
* to a UWC_NEWW. It specifies whether the window was successfully
* created and what unique ID was assigned.
*/
struct uwstatus {
uwid_t uwst_id; /* unique window identifier */
short uwst_err; /* error status */
short uwst_errno; /* UNIX error code (see
};
/*
* UWC_KILLW: kill the window
*
* This command may be sent to either the Unix-domain socket or the control
* file descriptor of an external window. In the latter case, "uwkw_id"
* must match the ID of the window associated with the file descriptor.
*/
struct uwkillw {
uwid_t uwkw_id; /* unique window identifier */
};
/*
* UWC_OPTION: act upon window option
*
* This command may be sent to either the Unix-domain socket or the control
* file descriptor of an external window. In the former case, only the
* UWOC_SET command is processed.
*/
struct uwoption {
uwid_t uwop_id; /* unique window identifier */
uwopt_t uwop_opt; /* option number */
uwoptcmd_t uwop_cmd; /* option subcommand */
union uwoptval uwop_val; /* option value (for UWOC_SET) */
};
struct uwipc {
unsigned short uwip_len; /* length of this message */
uwcmd_t uwip_cmd; /* command (message type) */
union {
struct uwneww uwipu_neww;
struct uwnewt uwipu_newt;
struct uwstatus uwipu_status;
struct uwkillw uwipu_killw;
struct uwoption uwipu_option;
} uwip_u;
#define uwip_neww uwip_u.uwipu_neww
#define uwip_newt uwip_u.uwipu_newt
#define uwip_status uwip_u.uwipu_status
#define uwip_killw uwip_u.uwipu_killw
#define uwip_option uwip_u.uwipu_option
};
#endif
play bells visually;
the other bit is set iff the client should report
bells within this window audibly.
.IP WOTTY_CURSOR
This is a 1-bit integer
which is zero if the window is using a block cursor
and nonzero if the window is ush/uw_opt.h 600 11722 76400 14457 4750124240 6201 /*
* uw window options
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*
* Some protocols support the transmission of window options. A window
* option is a parameter (or collection of related parameters) which
* describes the layout, appearance, or other characteristic of a
* window. Some options are common to all window types, while others
* are window emulation-specific.
*
* Window options may be "set" by one side on its own initiative or in
* response to an "inquiry" from the other side. In addition, one side
* may request that the other side "report" changes in options.
*
* Options are passed as part of a "new window" command or as part of
* an "option" command (as defined by the protocol, above). The option
* format has been chosen to minimize the need for protocol encoding
* of special or meta characters.
*/
#ifndef UW_OPT
#define UW_OPT
typedef unsigned int woptcmd_t; /* window option command: */
#define WOC_SET 0 /* request current option value */
#define WOC_INQUIRE 2 /* report current option value */
#define WOC_DO 4 /* do report changes to option */
#define WOC_DONT 5 /* don't report changes */
#define WOC_WILL 6 /* will report changes */
#define WOC_WONT 7 /* won't report changes */
#define WOC_MASK 7 /* mask */
#define WOC_BADCMD(n) ((n)==1 || (n)==3)
/*
* Option commands include an option number specifier. If the option
* number is in the range 1-14 a short-form specifier can be used;
* otherwise, a long-form specifier must be used. Option (sub)command
* bytes consist of 7 bits of data. The lower order 3 bits specify the
* option command. The next higher 4 bits specify the option number.
* The value zero is reserved (as described below). If the option
* number is greater than 14, these four bits specify 017 (15) and the
* option number is specified in a second byte. The value is encoded
* by adding ' ' to the option number. Multiple options may be specified
* in one command -- the last option is followed by a reference to
* "option" 0 (as an endmarker).
*/
typedef unsigned int woption_t; /* window option number: */
#define WONUM_MIN 1 /* minimum option number */
#define WONUM_GENERIC 7 /* maximum generic option number */
#define WONUM_SHORT 14 /* maximum short option number */
#define WONUM_MAX 31 /* maximum option number */
#define WONUM_MASK (017<<3) /* mask for extraction */
#define WONUM_USELONG(n) ((unsigned)(n) > WONUM_SHORT)
#define WONUM_SENCODE(n) (((n)&017)<<3) /* short encoding function */
#define WONUM_SDECODE(b) (((b)>>3)&017) /* short decoding function */
#define WONUM_LPREFIX (017<<3) /* long encoding prefix */
#define WONUM_LENCODE(n) ((n)+' ') /* long encoding function */
#define WONUM_LDECODE(c) (((c)&0177)-' ') /* long decoding function */
/*
* The following option numbers are generic (recognized for all window
* types):
*/
#define WOG_END 0 /* [endmarker] */
#define WOG_VIS 1 /* 0=invisible, 1=visible */
#define WOG_TYPE 2 /* window emulation type (see below) */
#define WOG_POS 3 /* window position on screen */
#define WOG_TITLE 4 /* window title */
#define WOG_SIZE 5 /* window size (in bits) */
#define WOG_6 6 /* unassigned, reserved */
#define WOG_7 7 /* unassigned, reserved */
/*
* Option arguments immediately follow option (sub)command bytes. They are
* encoded to prevent interference with flow-control and IAC recognition.
* Three types of options are recognized: non-graphic character strings of
* fixed length, general character strings of variable length, and binary
* numbers of fixed width.
*
* Non-graphic character strings are transmitted directly. They CANNOT
* include IAC, XON, or XOFF and should not include "meta" characters.
*
* General character strings are encoded in the UW protocol fashion: "meta"
* characters and special characters are escaped. The string is terminated
* with a null byte. The string may not exceed some predetermined maximum
* number of characters (which may be less than or equal to 256, including
* the terminating null byte).
*
* Binary numbers are transmitted in 6-bit chunks, least-significant bits
* first. The number of 6-bit chunks required depends upon the width of
* the number. The 0100 bit in each byte is always set to prevent
* collisions with special characters (such as flow control and IAC).
*/
/*
* Implementation:
*
* Arrays of type "woptarg_t" are used to describe the arguments associated
* with each option. (Note that arguments are associated only with
* the "set" option subcommand.)
*/
typedef unsigned woptarg_t; /* option argument type: */
#define WOA_END 0 /* endmarker */
#define WOA_CHARS(n) ((1<<8)|(n)) /* "n" untranslated characters */
#define WOA_STRING(m) ((2<<8)|(m)) /* string of max length "m" */
#define WOA_UDATA(b) ((3<<8)|(b)) /* binary number "b" bits wide */
#define WOA_CMDMASK 0177400 /* command mask */
typedef long woptbmask_t; /* option bitmask (>= 32 bits wide) */
#define WOPT_SET(mask,bit) ((mask) |= (1<<(bit)))
#define WOPT_CLR(mask,bit) ((mask) &= ~(1<<(bit)))
#define WOPT_ISSET(mask,bit) ((mask) & (1<<(bit)))
struct woptdefn {
woptbmask_t wod_pending; /* pending notifications to Mac */
woptbmask_t wod_inquire; /* pending inquiries from Mac */
woptbmask_t wod_do; /* pending DO commands to Mac */
woptbmask_t wod_dont; /* pending DONT commands to Mac */
woptbmask_t wod_askrpt; /* reports (of changes) we ask for */
struct woptlst {
woptarg_t *wol_argdefn; /* option argument definition */
char *(*wol_get)(); /* called to get option value */
void (*wol_set)(); /* called to set option value */
void (*wol_ext)(); /* called for external window */
} wod_optlst[WONUM_MAX+1];
};
/*
* The following structure is used by routines that fetch and set option
* values.
*/
union optvalue {
unsigned char ov_udata1;
unsigned char ov_udata2;
unsigned char ov_udata6;
unsigned short ov_udata12;
struct {
unsigned short v,h;
} ov_point;
char ov_string[256];
};
/*
* When it is necessary to convert between host byte order and network
* byte order, opt_netadj() is called. A pointer to the following
* structure is passed.
*/
struct netadj {
short (*na_short)();
long (*na_long)();
unsigned short (*na_ushort)();
unsigned long (*na_ulong)();
};
#endif
ct uwkillw {
uwid_t uwkw_id; /* unique window identifier */
};
/*
* UWC_OPTION: act upon window option
*
* This command may be sent to either the Unix-domain socket or the control
* file descriptor of ah/uw_param.h 600 11722 76400 1756 4750124241 6456 /*
* uw parameters
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
/*
* This file exists because #include file definitions aren't in the same
* place on all machines. Also, it seems pointless to drag in all of
*
* sufficiently global that this is the most logical place to put them.
*
* This file should be #included after all of the system include files
* (e.g.
*/
#ifndef UW_PARAM
#define UW_PARAM
typedef int fildes_t; /* this really should be in
#ifndef NBBY /* this is in
#define NBBY 8 /* (number of bits/byte) */
#endif
#ifndef NULL
#define NULL 0
#endif
extern char *malloc();
extern char *mktemp();
extern char *getenv();
extern void done();
extern void cwait();
#endif
options are recognh/uw_pcl.h 600 11722 76400 23111 4750124242 6142 /*
* uw protocol
*
* Copyright 1985,1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#ifndef UW_PCL
#define UW_PCL
#include "uw_win.h"
/* UW may operate over connections which speak one of several protocols.
* Internally these protocols are assigned numbers starting at zero.
* Three such protocols are currently defined:
*
* 0: no special protocol
* 1: original UW (v1.6, v2.10) protocol
* 2: extended protocol (v3.x)
*/
/*
* Protocol 0:
*
* The connection between the Macintosh and the host is simply a serial
* line. Flow control may be enabled, but no special commands are
* recognized. Only one active window is supported. This "protocol"
* does not require the UW server; hence, there is no need to support it.
*/
/*
* Protocol 1: (original UW protocol)
*
* Two types of information are exchanged through the 7-bit serial line:
* ordinary data and command bytes. Command bytes are preceeded by
* an IAC byte. IAC bytes and literal XON/XOFF characters (those which
* are not used for flow control) are sent by a P1_FN_CTLCH command.
* Characters with the eighth bit set (the "meta" bit) are prefixed with
* a P1_FN_META function.
*
* The next most-significant bit in the byte specifies the sender and
* recipient of the command. If this bit is clear (0), the command byte
* was sent from the host computer to the Macintosh; if it is set (1)
* the command byte was sent from the Macintosh to the host computer.
* This prevents confusion in the event that the host computer
* (incorrectly) echos a command back to the Macintosh.
*
* The remaining six bits are partitioned into two fields. The low-order
* three bits specify a window number from 1-7 (window 0 is reserved for
* other uses) or another type of command-dependent parameter. The next
* three bits specify the operation to be performed by the recipient of
* the command byte.
*
* Note that the choice of command bytes prevents the ASCII XON (021) and
* XOFF (023) characters from being sent as commands. P1_FN_ISELW commands
* are only sent by the Macintosh (and thus are tagged with the P1_DIR_MTOH
* bit). Since XON and XOFF data characters are handled via P1_FN_CTLCH,
* this allows them to be used for flow control purposes.
*/
#define P1_IAC 0001 /* interpret as command */
#define P1_DIR 0100 /* command direction: */
#define P1_DIR_HTOM 0000 /* from host to Mac */
#define P1_DIR_MTOH 0100 /* from Mac to host */
#define P1_FN 0070 /* function code: */
#define P1_FN_NEWW 0000 /* new window */
#define P1_FN_KILLW 0010 /* kill (delete) window */
#define P1_FN_ISELW 0020 /* select window for input */
#define P1_FN_OSELW 0030 /* select window for output */
#define P1_FN_META 0050 /* add meta to next data char */
#define P1_FN_CTLCH 0060 /* low 3 bits specify char */
#define P1_FN_MAINT 0070 /* maintenance functions */
#define P1_WINDOW 0007 /* window number mask */
#define P1_CC 0007 /* control character specifier: */
#define P1_CC_IAC 1 /* IAC */
#define P1_CC_XON 2 /* XON */
#define P1_CC_XOFF 3 /* XOFF */
#define P1_MF 0007 /* maintenance functions: */
#define P1_MF_ENTRY 0 /* beginning execution */
#define P1_MF_ASKPCL 2 /* request protocol negotiation */
#define P1_MF_CANPCL 3 /* suggest protocol */
#define P1_MF_SETPCL 4 /* set current protocol */
#define P1_MF_EXIT 7 /* execution terminating */
#define P1_NWINDOW 7 /* maximum number of windows */
/*
* Protocol 2: (extended UW protocol)
*
* Protocol 2 is an extension of protocol 1. The P2_FN_NEWW command and
* the new command P2_FN_WOPT communicate window options between the host
* and the Macintosh. (See "uw_opt.h" for details.)
*/
#define P2_IAC P1_IAC /* interpret as command */
#define P2_DIR P1_DIR /* command direction: */
#define P2_DIR_HTOM P1_DIR_HTOM /* from host to Mac */
#define P2_DIR_MTOH P1_DIR_MTOH /* from Mac to host */
#define P2_FN P1_FN /* function code: */
#define P2_FN_NEWW P1_FN_NEWW /* new window */
#define P2_FN_KILLW P1_FN_KILLW /* kill (delete) window */
#define P2_FN_ISELW P1_FN_ISELW /* select window for input */
#define P2_FN_OSELW P1_FN_OSELW /* select window for output */
#define P2_FN_WOPT 0040 /* communicate window options */
#define P2_FN_META P1_FN_META /* add meta to next data char */
#define P2_FN_CTLCH P1_FN_CTLCH /* low 3 bits specify char */
#define P2_FN_MAINT P1_FN_MAINT /* maintenance functions */
#define P2_WINDOW P1_WINDOW /* window number mask */
#define P2_CC P1_CC /* control character specifier: */
#define P2_CC_IAC P1_CC_IAC /* IAC */
#define P2_CC_XON P1_CC_XON /* XON */
#define P2_CC_XOFF P1_CC_XOFF /* XOFF */
#define P2_MF P1_MF /* maintenance functions: */
#define P2_MF_ENTRY P1_MF_ENTRY /* beginning execution */
#define P2_MF_ASKPCL P1_MF_ASKPCL /* request protocol negotiation */
#define P2_MF_CANPCL P1_MF_CANPCL /* suggest protocol */
#define P2_MF_SETPCL P1_MF_SETPCL /* set current protocol */
#define P2_MF_EXIT P1_MF_EXIT /* execution terminating */
#define P2_NWINDOW P1_NWINDOW /* maximum number of windows */
/*
* Protocol negotiation
*
* The server is not used for protocol 0. For the other protocols, the
* Macintosh and the server negotiate to select the active protocol. The
* basic idea is that the Macintosh will express its desire for a protocol
* and the server will attempt to satisfy that desire. Until negotiations
* are complete, protocol 1 is used.
*
* Protocols are identified by single-character names which are formed by
* adding the ASCII code for a space (040) to the protocol number minus 1
* (i.e. protocol 1 is ' ', protocol 2 is '!').
*
* P1_FN_CANPCL and P1_FN_SETPCL are three-byte commands: P1_IAC,
* P1_FN_XXXPCL, protocol-name.
*
* Macintosh:
* If UW v2.10 is used on the Macintosh or if a newer Macintosh program
* wishes to use protocol 1, it will never initiate protocol negotiation.
* Hence, all interaction will use protocol 1 by default.
*
* If the Macintosh program is capable of supporting protocol 2 and the
* user requests its use, the Mac will remember this fact but will
* continue to use protocol 1. The Mac program will assume that no
* server is present until instructed otherwise by the user or until a
* P1_FN_ENTRY command is received (e.g. when the server starts up).
* At this time, the Mac program issues P1_FN_ASKPCL. If the server
* cannot support protocol 2 (i.e. it is an old server), then it will
* ignore the P1_FN_ASKPCL. The Macintosh will retry the P1_FN_ASKPCL
* a couple of times (about five seconds apart) and, if there is no
* response from the server, will abandon negotiations. Protocol 1
* will be used for the remainder of the session.
*
* If the server recognizes the P1_FN_ASKPCL command it will respond
* with the name of the most complex protocol it can support (currently
* '!'). If this is acceptable to the Macintosh, it will instruct the
* server to use this protocol. If the Macintosh cannot support this
* protocol it will respond with a P1_FN_CANPCL suggesting a less-complex
* protocol. If the server agrees to this it will answer establish the
* protocol; otherwise, it will suggest an even weaker protocol.
* Eventually someone will suggest protocol 1 (which is universal) and
* the other side will issue a P1_FN_SETPCL command to establish its use.
*
* Host:
* If the host receives a P1_FN_ASKPCL it will respond with the most
* complex protocol it can support (using the P1_FN_CANPCL command).
* Negotiations will proceed as described above until one side
* establishes a new protocol with P1_FN_SETPCL. At this time, the
* host will switch to the new protocol.
*
* If the host receives a P1_FN_ENTRY (P2_FN_ENTRY) command, it will
* switch back to protocol 1. Receipt of this command indicates that
* the Macintosh program was restarted. The Macintosh must initiate
* protocol negotiations again.
*/
/*
* Although many of the functions are identical (and the code is shared
* between them), each protocol is accessed through a (struct protocol)
* which specifies the functions for various operations.
*
* In theory, the main program knows nothing about the protocol in use.
* In practice, the externally-visible functions are accessed as macros
* for greater efficiency.
*
* The protocol layer is aware of the (struct window) data structures.
*/
struct protocol {
char p_name; /* single-character protocol name */
nwin_t p_maxwin; /* maximum window number */
int *p_ctlch; /* control character map table */
unsigned p_szctlch; /* size (# of entries) in ctlch table */
void (*p_entry)(); /* start up (ENTRY maintenance fn) */
void (*p_exit)(); /* shut down (EXIT maintenance fn) */
void (*p_renew)(); /* renew (re-init) */
struct window *(*p_neww)(); /* create new window */
void (*p_killw)(); /* kill window */
void (*p_xmit)(); /* transmit to specified window */
void (*p_recv)(); /* receive from Macintosh */
void (*p_chkopt)(); /* check for pending option output */
void (*p_sendopt)(); /* send option string to Macintosh */
void (*p_askpcl)(); /* send an ASKPCL maintenance command */
void (*p_canpcl)(); /* send a CANPCL maintenance command */
void (*p_setpcl)(); /* send a SETPCL maintenance command */
};
extern struct protocol *protocol;
#define PCL_NEWW(mfd,class,wtype,wnum,wid,dfd,cfd) \
(*protocol->p_neww)(mfd,class,wtype,wnum,(long)wid,dfd,cfd)
#define PCL_KILLW(mfd,w) (*protocol->p_killw)(mfd,w)
#define PCL_RECV(mfd,buf,len) (*protocol->p_recv)(mfd,buf,len)
#define PCL_XMIT(mfd,w) (*protocol->p_xmit)(mfd,w)
#define PCL_SENDOPT(mfd,fn,buf,len) \
(protocol->p_sendopt ? (*protocol->p_sendopt)(mfd,fn,buf,len) : 0)
#endif
this will be protocol 2;
however,
in the future it might name some other protocol.)
Old servers,
which do not recognize P1_MF_ASKPCL,
will ignore the maintenance function.
The client will time out after five seconds
and retry several times
(three in the present implementation);
if the server never responds
the client will ``give up'' and will
continue to use protocol 1 indefinitely.
.PP
When the client receives P1_MF_CANPCL from the seh/uw_win.h 600 11722 76400 6575 4750124242 6160 /*
* uw window data definition
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#ifndef UW_WIN
#define UW_WIN
#include "uw_opt.h"
/*
* A "point" is a pair of 16-bit integers. This may specify the horizontal
* and vertical position or size of a window.
*/
typedef short npixel_t; /* number of pixels */
struct point {
npixel_t v,h;
};
/*
* The type of a window determines how it responds to I/O and which
* window options it supports. I'd like to declare these with an "enum",
* but the stupid PCC screams if I use enums as array indices, so they
* are defined via #define's instead.
*/
typedef unsigned int wtype_t; /* window type: */
#define WT_ADM31 0 /* ADM-31 terminal emulation */
#define WT_VT52 1 /* VT52 terminal emulation */
#define WT_ANSI 2 /* ANSI terminal emulation */
#define WT_TEK4010 3 /* Tek4010 terminal emulation */
#define WT_FTP 4 /* file transfer */
#define WT_PRINT 5 /* output to printer */
#define WT_PLOT 6 /* plot window */
#define WT_MAXTYPE 6 /* maximum window type */
extern wtype_t defwtype; /* default window type */
/*
* There are two basic classes of windows -- those which are processed
* directly by the server and those which are processed by outside
* programs. Directly-handled windows are always terminal emulations.
* Externally-handled windows may be any window type.
*/
typedef enum { /* window class: */
WC_INTERNAL, /* processed directly */
WC_EXTERNAL, /* processed externally */
} wclass_t;
struct window {
int w_alloc; /* window allocated if nonzero */
long w_id; /* window unique ID */
wtype_t w_type; /* window emulation type */
wclass_t w_class; /* window class */
fildes_t w_datafd; /* data file descriptor */
union {
struct winint {
char wi_tty[32]; /* terminal name */
} wu_int;
struct winext {
fildes_t we_ctlfd; /* control file descriptor */
} wu_ext;
} w_un;
struct woptdefn w_optdefn; /* window option definitions */
int w_visible; /* nonzero if window is visible */
struct point w_position; /* position of window on screen */
struct point w_size; /* size of window in pixels */
char w_title[256]; /* window title */
char *w_private; /* storage private to emulation type */
};
#define w_tty w_un.wu_int.wi_tty
#define w_ctlfd w_un.wu_ext.we_ctlfd
typedef int nwin_t; /* window index data type */
/*
* Some operations upon windows depend upon the window type. For each
* emulation type there is a "emulation" structure which specifies
* emulation-specific data.
*/
struct emulation {
struct woptdefn we_optdefn; /* window option definitions */
int (*we_start)(); /* emulation setup code */
void (*we_stop)(); /* emulation shutdown code */
void (*we_setext)(); /* make changes req'd for extern win */
};
extern struct window *win_neww(); /* create new window */
extern struct window *win_search(); /* convert window ID to window ptr */
/*
* The following macros convert between a window number and a pointer to
* the corresponding window structure (and vice versa).
*
* NWINDOW *must* be >= P1_NWINDOW and >= P2_NWINDOW (in "uw_pcl.h").
*/
#define NWINDOW 7 /* maximum number of windows */
#define WIN_NUM(wptr) ((wptr)-window+1)
#define WIN_PTR(wnum) (window+(wnum)-1)
extern struct window window[]; /* window data structures */
#endif
* are complete, protocol 1 is used.
*
* Protocols are identified by single-character names which are formed by
* adding the ASh/uwlib.h 600 11722 76400 3666 4750124243 5771 /*
* uw library definitions
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uw_err.h"
#include "uw_ipc.h"
#ifndef NBBY
#define NBBY 8 /* defined in
#endif
#define UW_NUMOPTS 32 /* number of window options */
#define UW_NWTYPES 6 /* number of window emulation types */
typedef char uwtitle_t[256];
struct uwpoint {
unsigned uwp_v; /* vertical component */
unsigned uwp_h; /* horizontal component */
};
struct uw_info {
uwid_t uwi_id; /* unique window ID */
int uwi_datafd; /* file descriptor for data */
int uwi_ctlfd; /* file descriptor for control */
uwerr_t uwi_uwerr; /* last error from UW */
int uwi_errno; /* last error from system call */
int uwi_vis; /* visiblility */
uwtype_t uwi_type; /* window type */
struct uwpoint uwi_pos; /* window position (in pixels) */
uwtitle_t uwi_title; /* window title */
struct uwpoint uwi_wsize; /* window size (in pixels) */
struct {
void (*uwi_optfn)(); /* option handler */
} uwi_options[UW_NUMOPTS];
int uwi_ipclen; /* length of data in IPC buffer */
struct uwipc uwi_ipcbuf; /* buffer for IPC messages */
};
#define UW_DATAFD(uwin) (uwin)->uwi_datafd
#define UW_ID(uwin) (uwin)->uwi_id
#define UW_PERROR(uwin, mesg) \
uw_perror(mesg, (uwin)->uwi_uwerr, (uwin)->uwi_errno)
typedef struct uw_info *UWIN;
typedef void (*uwfnptr_t)();
extern uwid_t uw_cmd();
extern UWIN uw_new();
extern uw_close(), uw_detach();
extern uw_optcmd();
extern uw_kill();
extern uwfnptr_t uw_optfn();
extern uw_rsetopt();
extern void uw_perror();
extern uwid_t uw_fork(), uw_cmd(), uw_shell();
extern uw_gvis(), uw_svis();
extern uw_gtype(), uw_stype();
extern uw_gtitle(), uw_stitle();
extern uw_gwsize(), uw_swsize();
extern uw_gpos(), uw_spos();
extern uwerr_t uwerrno;
extern char *uwerrlist[];
extern unsigned uwnerr;
t we_ctlfd; /* control file descriptor */
} wu_ext;
} w_un;
struct wolib/ 700 11722 76400 0 4750124300 4705 lib/Makefile_4.2 600 11722 76400 3256 4750124262 7034 #! /bin/make -f
#
# uw library makefile (4.2BSD)
#
# INCDIR names the directory in which header files are located.
# SERVERDIR names the directory containing the server source.
# SERVER_OBJS names the object files derived from sources in SERVERDIR.
# OBJECTS names all of the object files required for the library.
#
INCDIR = ../h
SERVERDIR = ../server
SERVER_OBJS = $(SERVERDIR)/openpty.o $(SERVERDIR)/uw_env.o
OBJECTS = uw_cmd.o uw_close.o uw_detach.o uw_fork.o uw_kill.o \
uw_netadj.o uw_new.o uw_optcmd.o uw_optfn.o uw_options.o \
uw_perror.o uw_ttype.o \
uw_rsetopt.o uw_shell.o \
uw_gvis.o uw_gtype.o uw_gtitle.o uw_gwsize.o uw_gpos.o \
$(SERVER_OBJS)
SOURCES = `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
DEFINES = `cat ../DEFINES`
CFLAGS = -O -I$(INCDIR) $(DEFINES)
TARGET = libuw.a
$(TARGET): $(OBJECTS)
ar cr $(TARGET) `lorder $(OBJECTS) | tsort`
ranlib $(TARGET)
-if [ ! -f uwlib.a ];then ln -s libuw.a uwlib.a;fi
$(SERVER_OBJS):
cd $(SERVERDIR); make `basename $@`
lint:
lint -uhbx -I$(INCDIR) $(DEFINES) $(SOURCES)
tags:
ctags $(SOURCES)
depend:
grep '^#include' $(SOURCES) | \
sed -e '/ -e 's/:[^"]*"\([^"]*\)".*/: ..\/h\/\1/' \
-e 's,^../[a-zA-Z0-9]*/\([^\.]*\)\.[cs],\1.o \1.L,' | \
awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
else { if (length(rec $$3) > 78) { print rec; rec = $$0; } \
else rec = rec " " $$3 } } \
END { print rec } ' > makedep
echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ex - Makefile < eddep
rm eddep makedep
clean:
-rm *.o
# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
a in IPC buffer */
struct uwipc uwi_ipcbuf; /* buffer for IPC messages */
};
#define UW_DATAFD(uwin) (uwin)->uwi_datafd
#define UW_ID(uwin) (uwin)->uwi_id
#define UW_PERROR(uwin, mesg) \
uw_perror(mesg, (uwin)->uwi_uwerr, (uwin)->uwi_errno)
typedef struct uw_info *UWIN;
typedef void (*uwfnptr_t)();
extern uwid_t uw_cmd();
extern lib/Makefile_4.3 600 11722 76400 3216 4750124263 7032 #! /bin/make -f
#
# uw library makefile (4.3BSD)
#
# INCDIR names the directory in which header files are located.
# SERVERDIR names the directory containing the server source.
# SERVER_OBJS names the object files derived from sources in SERVERDIR.
# OBJECTS names all of the object files required for the library.
#
INCDIR = ../h
SERVERDIR = ../server
SERVER_OBJS = $(SERVERDIR)/openpty.o $(SERVERDIR)/uw_env.o
OBJECTS = uw_cmd.o uw_close.o uw_detach.o uw_fork.o uw_kill.o \
uw_netadj.o uw_new.o uw_optcmd.o uw_optfn.o uw_options.o \
uw_perror.o uw_ttype.o \
uw_rsetopt.o uw_shell.o \
uw_gvis.o uw_gtype.o uw_gtitle.o uw_gwsize.o uw_gpos.o \
$(SERVER_OBJS)
SOURCES = `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
DEFINES = `cat ../DEFINES`
CFLAGS = -O -I$(INCDIR) $(DEFINES)
TARGET = libuw.a
$(TARGET): $(OBJECTS)
ar cr $(TARGET) `lorder $(OBJECTS) | tsort`
ranlib $(TARGET)
-if [ ! -f uwlib.a ];then ln -s libuw.a uwlib.a;fi
$(SERVER_OBJS):
cd $(SERVERDIR); make `basename $@`
lint:
lint -uhbx -I$(INCDIR) $(DEFINES) $(SOURCES)
tags:
ctags $(SOURCES)
depend:
$(CC) -M -I$(INCDIR) $(DEFINES) $(SOURCES) | \
sed -e ':loop' \
-e 's/\.\.\/[^ /]*\/\.\./../' \
-e 't loop' | \
awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
else rec = rec " " $$2 } } \
END { print rec } ' >> makedep
echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ex - Makefile < eddep
rm eddep makedep
clean:
-rm *.o
# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
void uw_perror();
extern uwid_t uw_fork(), uw_cmd(), uw_shell();
extern uw_gvis(), uw_svis();
extern uw_gtype(), uw_stype();
extern uw_gtitle(), uw_stitle();
extern uw_gwsize(), uw_swsize();
extern uw_gpos(), uw_spos();
extern uwerr_t uwerrno;
extern char *uwerrlist[];
extern unsigned uwnerr;
t we_ctlfd; /* control file descriptor */
} wu_ext;
} w_un;
struct wolib/uw_close.c 600 11722 76400 1077 4750124264 6776 /*
* uw library - uw_close
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
uw_close(uwin)
UWIN uwin;
{
/*
* Close all connections to an existing window, but do not kill it.
*/
if (uwin != (UWIN)0) {
if (uwin->uwi_ctlfd >= 0)
(void)uw_detach(uwin);
if (uwin->uwi_datafd >= 0)
(void)close(uwin->uwi_datafd);
free((char *)uwin);
return(0);
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
etopt.o uw_shell.o \
uw_gvis.o uw_gtype.o uw_gtitle.o uw_gwsize.o uw_gpos.o \
$(SERVER_OBJS)
SOURCES = `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
DEFINES = `cat ../DEFINES`
CFLAGS = -O -I$(INCDIR) $(DEFINES)
TARGET = libuw.a
$(TARGET): $(OBJECTS)
ar cr $(TARGET) `lorder $(OBJECTS) | tsort`
ranlib $(TARGET)
-if [ ! -f uwlib.a ];then ln -s libuw.a uwlib.a;fi
$(SERVER_OBJS):
cd $(SERVERDIR); make `basename $@`
lint:
lint -uhbx -I$(Ilib/uw_cmd.c 600 11722 76400 1437 4750124264 6434 /*
* uw library - uw_cmd
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
uwid_t
uw_cmd(wtype, file, argv)
uwtype_t wtype;
char *file;
char **argv;
{
register uwid_t uwid;
/*
* Create a new window (using uw_fork()) and run the specified
* command in it. Returns the window ID of the new window
* (or -1 if the window creation failed). There is no way to
* determine if the executed command failed (e.g. if the
* executable file did not exist).
*/
if ((uwid = uw_fork(wtype, (int *)0)) == 0) {
(void)execvp(file, argv);
uwerrno = UWE_ERRNO;
perror(file);
_exit(1);
/*NOTREACHED*/
} else
return(uwid);
}
libuw.a
$(TARGET): $(OBJECTS)
ar cr $(TARGET) `lorder $(OBJECTS) | tsort`
ranlib $(TARGET)
-if [ ! -f uwlib.a ];then ln -s libuw.a uwlib.a;fi
$(SERVER_OBJS):
cd $(SERVERDIR); make `basename $@`
lint:
lint -uhbx -I$(Ilib/uw_detach.c 600 11722 76400 1245 4750124265 7117 /*
* uw library - uw_detach
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
uw_detach(uwin)
UWIN uwin;
{
/*
* Detach the control file descriptor for a window, while still
* retaining access to the data file descriptor.
*/
if (uwin != (UWIN)0) {
if (uwin->uwi_ctlfd >= 0) {
uw_optdone(uwin->uwi_ctlfd);
(void)close(uwin->uwi_ctlfd);
uwin->uwi_ctlfd = -1;
return(0);
} else {
uwerrno = uwin->uwi_uwerr = UWE_NOCTL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
uw_detach(uwin)
UWIN uwin;
{
/*
* Detach the control file descriptor for a window, while still
* retaining access to the data file descriptor.
*/
if (uwin != (UWIN)0) {
if (uwin->uwi_ctlfd >= 0) {
uw_optdone(uwin->uwi_ctlfd);
(void)close(uwin->uwi_ctlfd)lib/uw_fork.c 600 11722 76400 11140 4750124265 6643 /*
* uw library - uw_fork
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "openpty.h"
#include "uwlib.h"
extern char *malloc();
extern char *getenv();
uwid_t
uw_fork(wtype, pidp)
uwtype_t wtype;
int *pidp;
{
register int pid;
register int sd;
register struct uwipc *uwip;
register uwid_t wid;
auto int fd;
char *portal;
int lmode, ldisc;
struct sgttyb sg;
struct tchars tc;
struct ltchars ltc;
struct iovec iov;
struct msghdr msg;
struct sockaddr_un sa;
struct ptydesc pt;
char idstr[20];
char *env[2];
extern char *ltoa();
/*
* Create a new window attached to a pseudo-terminal. This routine
* returns twice -- once in the parent and once in the (new) child.
* The parent receives the window ID of the child (or -1 if the
* window creation failed). Zero is returned to the child.
* If "pidp" is a non-NULL pointer, the process ID from the fork()
* is stored there.
*/
/*
* Get the terminal configuration for this tty. For now we
* assume that "/dev/tty" is defined. Eventually we'll have to
* provide defaults in case it is not.
*/
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
(void)ioctl(fd, (int)TIOCGETP, (char *)&sg);
(void)ioctl(fd, (int)TIOCGETC, (char *)&tc);
(void)ioctl(fd, (int)TIOCGLTC, (char *)<c);
(void)ioctl(fd, (int)TIOCLGET, (char *)&lmode);
(void)ioctl(fd, (int)TIOCGETD, (char *)&ldisc);
(void)close(fd);
} else {
/* ... */
}
/*
* Create a UNIX-domain socket.
*/
if (!(portal=getenv("UW_UIPC"))) {
uwerrno = UWE_NXSERV;
return(-1);
}
if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
uwerrno = UWE_ERRNO;
return(-1);
}
sa.sun_family = AF_UNIX;
(void)strncpy(sa.sun_path, portal, sizeof sa.sun_path-1);
sa.sun_path[sizeof sa.sun_path-1] = '\0';
/*
* Obtain a pseudo-tty and construct the datagram we will send later.
*/
if (openpty(&pt) < 0) {
uwerrno = UWE_ERRNO;
return(-1);
}
uwip = (struct uwipc *)malloc(sizeof(struct uwipc)+strlen(pt.pt_pname));
env[0] = malloc(sizeof "UW_ID=" + sizeof idstr);
if (uwip == (struct uwipc *)0 || env[0] == (char *)0) {
uwerrno = UWE_NOMEM;
return(-1);
}
uwip->uwip_cmd = UWC_NEWT;
uwip->uwip_len = (char *)&uwip->uwip_newt - (char *)uwip +
sizeof(struct uwnewt) + strlen(pt.pt_pname);
uwip->uwip_newt.uwnt_type = wtype;
(void)strcpy(uwip->uwip_newt.uwnt_pty, pt.pt_pname);
/*
* Fork a child process using this pseudo-tty. Initialize the
* terminal modes on the pseudo-tty to match those of the parent
* tty. We really want a fork() here, not a vfork().
*/
while ((pid=fork()) < 0)
sleep(5);
if (pidp != (int *)0)
*pidp = pid;
if (pid) {
wid = (long)pid << 16;
uwip->uwip_newt.uwnt_id = wid;
} else {
(void)setgid(getgid());
(void)setuid(getuid());
wid = (long)getpid() << 16;
(void)strcat(strcpy(env[0], "UW_ID="),
ltoa(wid, idstr, sizeof idstr));
env[1] = (char *)0;
env_set(env);
(void)signal(SIGTSTP, SIG_IGN);
(void)ioctl(open("/dev/tty", 2), (int)TIOCNOTTY, (char *)0);
(void)close(open(pt.pt_tname, 0)); /*set new ctrl tty */
(void)dup2(pt.pt_tfd, 0);
(void)dup2(0, 1);
(void)dup2(0, 2);
fd = getdtablesize();
while (--fd > 2)
(void)close(fd);
(void)ioctl(fd, (int)TIOCSETD, (char *)&ldisc);
(void)ioctl(0, (int)TIOCSETN, (char *)&sg);
(void)ioctl(0, (int)TIOCSETC, (char *)&tc);
(void)ioctl(0, (int)TIOCSLTC, (char *)<c);
(void)ioctl(0, (int)TIOCLSET, (char *)&lmode);
uwerrno = UWE_NONE;
return(0);
}
/*
* Pass the file descriptor to the window server.
*/
iov.iov_base = (char *)uwip;
iov.iov_len = uwip->uwip_len;
msg.msg_name = (caddr_t)&sa;
msg.msg_namelen = sizeof sa.sun_family + strlen(sa.sun_path);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_accrights = (caddr_t)&pt.pt_pfd;
msg.msg_accrightslen = sizeof pt.pt_pfd;
if (sendmsg(sd, &msg, 0) < 0) {
free((char *)uwip);
uwerrno = UWE_ERRNO;
return(-1);
}
free((char *)uwip);
uwerrno = UWE_NONE;
return(wid);
}
static
char *
ltoa(l, buf, buflen)
long l;
char *buf;
int buflen;
{
register char *cp;
register unsigned long ul;
static char digits[] = "0123456789";
/*
* This routine replaces a call to sprintf() so that the library
* is independent of stdio.
*/
cp = buf+buflen;
*--cp = '\0';
ul = l;
if (cp > buf) {
do {
*--cp = digits[ul%10];
ul /= 10;
} while (cp > buf && ul != 0);
}
return(cp);
}
l 1
* will be used for the remainder of the session.
*
* If the server recognizes the P1_FN_ASKPCL command it will respond
* with the name of the most complex protocol it can support (currently
* '!'). If this is acceptable to the Macintosh, it will instruct the
* server to use this protocol. If the Macintosh cannot support this
* protocol it will respond with a P1_FN_CANPCL suggesting a less-complex
* lib/uw_gpos.c 600 11722 76400 2310 4750124266 6632 /*
* uw library - uw_gpos, uw_spos
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
uw_gpos(uwin, pp)
register UWIN uwin;
register struct uwpoint *pp;
{
/*
* Get the position of window "uwin" and store it in the point
* whose address is "pp".
*/
if (uwin != (UWIN)0) {
if (pp != (struct uwpoint *)0) {
*pp = uwin->uwi_pos;
if (uwin->uwi_ctlfd > 0) {
return(0);
} else {
uwerrno = uwin->uwi_uwerr = UWE_NOCTL;
return(-1);
}
} else {
uwerrno = uwin->uwi_uwerr = UWE_INVAL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
uw_spos(uwin, pp)
register UWIN uwin;
struct uwpoint *pp;
{
union uwoptval optval;
/*
* Set the position of window "uwin" to "pp".
*/
if (uwin != (UWIN)0) {
if (pp != (struct uwpoint *)0) {
uwin->uwi_pos = *pp;
optval.uwov_point.v = pp->uwp_v;
optval.uwov_point.h = pp->uwp_h;
return(uw_optcmd(uwin, UWOP_POS, UWOC_SET, &optval));
} else {
uwerrno = uwin->uwi_uwerr = UWE_INVAL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
there.
*/
/*
* Get the terminal configuration for this tty. For now we
* assume that "/dev/tty" is defined. Eventually we'll have to
* provide defaults in case it is not.
*/
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
(void)ioctl(fd, (int)TIOCGETP, (char *)&sg);
(void)ioctl(fd, (int)TIOCGETC,lib/uw_gtitle.c 600 11722 76400 2212 4750124267 7154 /*
* uw library - uw_gtitle, uw_stitle
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include "uwlib.h"
uw_gtitle(uwin, ttl)
register UWIN uwin;
uwtitle_t ttl;
{
/*
* Get the title of window "uwin" and put it in "ttl".
*/
if (uwin != (UWIN)0) {
(void)strncpy(ttl, uwin->uwi_title, sizeof(uwtitle_t));
if (uwin->uwi_ctlfd > 0) {
return(0);
} else {
uwerrno = uwin->uwi_uwerr = UWE_NOCTL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
uw_stitle(uwin, ttl)
register UWIN uwin;
uwtitle_t ttl;
{
union uwoptval optval;
/*
* Set the title of window "uwin" to "ttl".
*/
if (uwin != (UWIN)0) {
(void)strncpy(uwin->uwi_title, ttl, sizeof uwin->uwi_title);
uwin->uwi_title[sizeof uwin->uwi_title - 1] = '\0';
(void)strncpy(optval.uwov_string,ttl,sizeof optval.uwov_string);
optval.uwov_string[sizeof optval.uwov_string - 1] = '\0';
return(uw_optcmd(uwin, UWOP_TITLE, UWOC_SET, &optval));
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
there.
*/
/*
* Get the terminal configuration for this tty. For now we
* assume that "/dev/tty" is defined. Eventually we'll have to
* provide defaults in case it is not.
*/
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
(void)ioctl(fd, (int)TIOCGETP, (char *)&sg);
(void)ioctl(fd, (int)TIOCGETC,lib/uw_gtype.c 600 11722 76400 2236 4750124267 7022 /*
* uw library - uw_gtype, uw_stype
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
uw_gtype(uwin, tp)
register UWIN uwin;
register uwtype_t *tp;
{
/*
* Get the type of the window "uwin". The window type is stored
* in the variable whose address is passed in "tp".
*/
if (uwin != (UWIN)0) {
if (tp != (uwtype_t *)0) {
*tp = uwin->uwi_type;
if (uwin->uwi_ctlfd > 0) {
return(0);
} else {
uwerrno = uwin->uwi_uwerr = UWE_NOCTL;
return(-1);
}
} else {
uwerrno = uwin->uwi_uwerr = UWE_INVAL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
uw_stype(uwin, t)
register UWIN uwin;
int t;
{
union uwoptval optval;
/*
* Set the type of window "uwin" to "t".
*/
if (uwin != (UWIN)0) {
if (t < UW_NWTYPES) {
uwin->uwi_type = t;
optval.uwov_6bit = uwin->uwi_type;
return(uw_optcmd(uwin, UWOP_TYPE, UWOC_SET, &optval));
} else {
uwerrno = uwin->uwi_uwerr = UWE_INVAL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
uwerrno = UWE_INVAL;
return(-1);
}
}
there.
*/
/*
* Get the terminal configuration for this tty. For now we
* assume that "/dev/tty" is defined. Eventually we'll have to
* provide defaults in case it is not.
*/
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
(void)ioctl(fd, (int)TIOCGETP, (char *)&sg);
(void)ioctl(fd, (int)TIOCGETC,lib/uw_gvis.c 600 11722 76400 2105 4750124270 6627 /*
* uw library - uw_gvis, uw_svis
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
uw_gvis(uwin, vp)
register UWIN uwin;
register int *vp;
{
/*
* Get the visibility status of the window "uwin". "vp" is a
* pointer to the integer where the status is returned.
*/
if (uwin != (UWIN)0) {
if (vp != (int *)0) {
*vp = uwin->uwi_vis;
if (uwin->uwi_ctlfd > 0) {
return(0);
} else {
uwerrno = uwin->uwi_uwerr = UWE_NOCTL;
return(-1);
}
} else {
uwerrno = uwin->uwi_uwerr = UWE_INVAL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
uw_svis(uwin, v)
register UWIN uwin;
int v;
{
union uwoptval optval;
/*
* Make window "uwin" visible (v != 0) or invisible (v == 0).
*/
if (uwin != (UWIN)0) {
uwin->uwi_vis = (v != 0);
optval.uwov_1bit = uwin->uwi_vis;
return(uw_optcmd(uwin, UWOP_VIS, UWOC_SET, &optval));
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
werr = UWE_INVAL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
uwerrno = UWE_INVAL;
return(-1);
}
}
there.
*/
/*
* Get the terminal configuration for this tty. For now we
* assume that "/dev/tty" is defined. Eventually we'll have to
* provide defaults in case it is not.
*/
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
(void)ioctl(fd, (int)TIOCGETP, (char *)&sg);
(void)ioctl(fd, (int)TIOCGETC,lib/uw_gwsize.c 600 11722 76400 2336 4750124270 7175 /*
* uw library - uw_gwsize, uw_swsize
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
uw_gwsize(uwin, pp)
register UWIN uwin;
register struct uwpoint *pp;
{
/*
* Get the (pixel) size of window "uwin" and store it in the
* point whose address is "pp".
*/
if (uwin != (UWIN)0) {
if (pp != (struct uwpoint *)0) {
*pp = uwin->uwi_wsize;
if (uwin->uwi_ctlfd > 0) {
return(0);
} else {
uwerrno = uwin->uwi_uwerr = UWE_NOCTL;
return(-1);
}
} else {
uwerrno = uwin->uwi_uwerr = UWE_INVAL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
uw_swsize(uwin, pp)
register UWIN uwin;
struct uwpoint *pp;
{
union uwoptval optval;
/*
* Set the (pixel) size of window "uwin" to "pp".
*/
if (uwin != (UWIN)0) {
if (pp != (struct uwpoint *)0) {
uwin->uwi_wsize = *pp;
optval.uwov_point.v = pp->uwp_v;
optval.uwov_point.h = pp->uwp_h;
return(uw_optcmd(uwin, UWOP_WSIZE, UWOC_SET, &optval));
} else {
uwerrno = uwin->uwi_uwerr = UWE_INVAL;
return(-1);
}
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
et the terminal configuration for this tty. For now we
* assume that "/dev/tty" is defined. Eventually we'll have to
* provide defaults in case it is not.
*/
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
(void)ioctl(fd, (int)TIOCGETP, (char *)&sg);
(void)ioctl(fd, (int)TIOCGETC,lib/uw_kill.c 600 11722 76400 2475 4750124271 6625 /*
* uw library - uw_kill
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include "uwlib.h"
#ifndef htons
/* These should have been defined in
extern unsigned short htons(), ntohs();
extern unsigned long htonl(), ntohl();
#endif
uw_kill(uwin)
UWIN uwin;
{
register int len;
struct uwipc uwip;
extern int errno;
/*
* Kill the window "uwin". After putting out the contract,
* destroy the evidence by closing all existing connections
* to the window.
*/
if (uwin != (UWIN)0) {
if (uwin->uwi_ctlfd >= 0) {
len = sizeof uwip.uwip_killw +
(char *)&uwip.uwip_killw - (char *)&uwip;
uwip.uwip_len = htons(len);
uwip.uwip_cmd = htons(UWC_KILLW);
uwip.uwip_killw.uwkw_id = htonl(uwin->uwi_id);
if (write(uwin->uwi_ctlfd, (char *)&uwip, len) < 0) {
uwin->uwi_errno = errno;
uwerrno = uwin->uwi_uwerr = UWE_ERRNO;
} else
uwerrno = uwin->uwi_uwerr = UWE_NONE;
(void)uw_detach(uwin);
} else
uwerrno = uwin->uwi_uwerr = UWE_NOCTL;
if (uwin->uwi_uwerr == UWE_NONE)
return(0);
else
return(-1);
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
Eventually we'll have to
* provide defaults in case it is not.
*/
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
(void)ioctl(fd, (int)TIOCGETP, (char *)&sg);
(void)ioctl(fd, (int)TIOCGETC,lib/uw_netadj.c 600 11722 76400 10167 4750124272 7155 /*
* uw library - uw_netadj
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "openpty.h"
#include "uw_opt.h" /* I had hoped to avoid including this */
#include "uwlib.h"
static woptarg_t woa_vis[] = { WOA_UDATA(1), WOA_END };
static woptarg_t woa_type[] = { WOA_UDATA(6), WOA_END };
static woptarg_t woa_pos[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
static woptarg_t woa_title[] = { WOA_STRING(255), WOA_END };
static woptarg_t woa_size[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
static woptarg_t woa_tsize[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
static woptarg_t woa_fontsz[] = { WOA_UDATA(6), WOA_END };
static woptarg_t woa_clipb[] = { WOA_UDATA(1), WOA_END };
static woptarg_t woa_bell[] = { WOA_UDATA(2), WOA_END };
static woptarg_t woa_curs[] = { WOA_UDATA(1), WOA_END };
static woptarg_t woa_chgsz[] = { WOA_UDATA(1), WOA_END };
static woptarg_t *optargs[][WONUM_MAX+1] = {
/* window type 0 == adm31 */
{
0, woa_vis, woa_type, woa_pos, woa_title, woa_size, 0, 0,
woa_tsize, woa_fontsz, woa_clipb, woa_bell, woa_curs, woa_chgsz
},
/* window type 1 == vt52 */
{
0, woa_vis, woa_type, woa_pos, woa_title, woa_size, 0, 0,
woa_tsize, woa_fontsz, woa_clipb, woa_bell, woa_curs, woa_chgsz
},
/* window type 2 == ansi */
{
0, woa_vis, woa_type, woa_pos, woa_title, woa_size, 0, 0,
woa_tsize, woa_fontsz, woa_clipb, woa_bell, woa_curs, woa_chgsz
},
/* window type 3 = tek4010 */
{
0, woa_vis, woa_type, woa_pos, woa_title, woa_size, 0, 0,
},
/* window type 4 = file transfer */
{
0, woa_vis, woa_type, woa_pos, woa_title, woa_size, 0, 0,
},
/* window type 5 = printer */
{
0, woa_vis, woa_type, woa_pos, woa_title, woa_size, 0, 0,
},
/* window type 6 = plot */
{
0, woa_vis, woa_type, woa_pos, woa_title, woa_size, 0, 0,
},
};
#ifdef htons
uw_hton(wtype, optnum, data)
uwtype_t wtype;
uwopt_t optnum;
char *data;
{
}
uw_ntoh(wtype, optnum, data)
uwtype_t wtype;
uwopt_t optnum;
char *data;
{
}
#else
/* These should have been defined in
extern unsigned short htons(), ntohs();
extern unsigned long htonl(), ntohl();
uw_hton(wtype, optnum, data)
uwtype_t wtype;
uwopt_t optnum;
char *data;
{
static struct netadj na = {
(short (*)())htons, (long (*)())htonl, htons, htonl
};
if (data != (char *)0 && wtype < sizeof optargs / sizeof optargs[0] &&
optnum <= WONUM_MAX && optargs[wtype][optnum] != (woptarg_t *)0) {
netadj(optargs[wtype][optnum], data, &na);
}
}
uw_ntoh(wtype, optnum, data)
uwtype_t wtype;
uwopt_t optnum;
char *data;
{
static struct netadj na = {
(short (*)())ntohs, (long (*)())ntohl, ntohs, ntohl
};
if (data != (char *)0 && wtype < sizeof optargs / sizeof optargs[0] &&
optnum <= WONUM_MAX && optargs[wtype][optnum] != (woptarg_t *)0) {
netadj(optargs[wtype][optnum], data, &na);
}
}
static
netadj(woa, data, na)
register woptarg_t *woa;
char *data;
register struct netadj *na;
{
register char *cp;
register int cnt;
union {
struct {
char c1;
short s;
} cs;
struct {
char c2;
long l;
} cl;
} u;
/*
* Convert an option between host byte order and network byte order.
*/
if (data && na) {
for (cp=data; *woa != WOA_END; woa++) {
cnt = *woa & ~WOA_CMDMASK;
switch (*woa & WOA_CMDMASK) {
case WOA_CHARS(0):
case WOA_STRING(0):
cp += cnt;
break;
case WOA_UDATA(0):
if (cnt <= NBBY) {
cp++;
} else if (cnt <= sizeof(short)*NBBY) {
while ((int)cp & ((char *)&u.cs.s-&u.cs.c1-1))
cp++;
*(u_short *)cp =
(*na->na_ushort)(*(u_short *)cp);
cp += sizeof(short);
} else {
while ((int)cp & ((char *)&u.cl.l-&u.cl.c2-1))
cp++;
*(u_short *)cp =
(*na->na_ushort)(*(u_short *)cp);
cp += sizeof(long);
}
}
}
}
}
#endif
return(-1);
}
free((char *)uwip);
uwerrno = UWE_NONE;
return(wid);
}
static
char *
ltoa(l, buf, buflen)
long l;
char *buf;
int buflen;
{
register char *cp;
register unsigned long ul;
static char digits[] = "0123456789";
/*
* This routine replaces a call to sprintf() so that the library
* is independent of stdio.
*/
cp = buf+buflen;
*--cp = '\0';
ul = l;
if (cp > buf) {
lib/uw_new.c 600 11722 76400 13237 4750124273 6503 /*
* uw library - uw_new
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "openpty.h"
#include "uwlib.h"
extern char *malloc();
extern char *getenv();
#ifndef htons
/* These should have been defined in
extern unsigned short htons(), ntohs();
extern unsigned long htonl(), ntohl();
#endif
UWIN
uw_new(uwtype, sin)
uwtype_t uwtype;
struct sockaddr_in *sin;
{
register UWIN uwin;
register char *cp, c;
register int len;
register int ctlfd;
int rdsz;
auto int namelen;
auto struct sockaddr_in sa, datasin, ctlsin;
auto struct uwipc uwip;
extern int errno;
/*
* If our caller didn't supply an address for us to contact,
* look in the environment to find it.
*/
if (sin == (struct sockaddr_in *)0) {
if ((cp = getenv(INET_ENV)) == (char *)0) {
uwerrno = UWE_NXSERV;
return((UWIN)0);
}
sin = &sa;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = 0;
sa.sin_port = 0;
bzero(sa.sin_zero, sizeof sa.sin_zero);
for ( ; isxdigit(c = *cp); cp++) {
/* Pyramid compiler blows this, must use left shift */
/* sa.sin_addr.s_addr *= 16; */
sa.sin_addr.s_addr <<= 4;
if (isdigit(c))
sa.sin_addr.s_addr += c-'0';
else if (islower(c))
sa.sin_addr.s_addr += c-'a' + 10;
else
sa.sin_addr.s_addr += c-'A' + 10;
}
if (c == '.') {
for (cp++; isdigit(c = *cp); cp++)
sa.sin_port = sa.sin_port*10 + c-'0';
}
if (sa.sin_addr.s_addr == 0 || sa.sin_port == 0 ||
c != '\0') {
/* bad address */
uwerrno = UWE_INVAL;
return((UWIN)0);
}
sa.sin_addr.s_addr = htonl(sa.sin_addr.s_addr);
sa.sin_port = htons(sa.sin_port);
}
/*
* Allocate space for a new window structure.
*/
if ((uwin = (UWIN)malloc(sizeof(*uwin))) == (UWIN)0) {
uwerrno = UWE_NOMEM;
return((UWIN)0);
}
uwin->uwi_type = uwtype;
for (len=0; len < UW_NUMOPTS; len++) /* "len" is a convenient "int" */
uwin->uwi_options[len].uwi_optfn = (uwfnptr_t)0;
/*
* Create sockets for the data and control file descriptors.
*/
if ((uwin->uwi_datafd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
(uwin->uwi_ctlfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
if (uwin->uwi_datafd >= 0)
(void)close(uwin->uwi_datafd);
return((UWIN)0);
}
/*
* Bind these sockets to a local address. We figure out the
* local machine's host number and use it if possible; otherwise,
* we fall back to 127.0.0.1 (loopback device). After binding,
* we determine the port number for the control socket, since we
* must send that to the server. Connect to the server.
*/
datasin.sin_family = AF_INET;
datasin.sin_port = 0;
bzero(datasin.sin_zero, sizeof datasin.sin_zero);
getmyaddr(&datasin.sin_addr);
ctlsin.sin_family = AF_INET;
ctlsin.sin_port = 0;
bzero(ctlsin.sin_zero, sizeof ctlsin.sin_zero);
getmyaddr(&ctlsin.sin_addr);
if (bind(uwin->uwi_datafd, (struct sockaddr *)&datasin, sizeof datasin) < 0 ||
bind(uwin->uwi_ctlfd, (struct sockaddr *)&ctlsin, sizeof ctlsin) < 0 ||
listen(uwin->uwi_ctlfd, 1) < 0) {
uwerrno = UWE_ERRNO;
goto error;
}
namelen = sizeof ctlsin;
(void)getsockname(uwin->uwi_ctlfd, (char *)&ctlsin, &namelen);
if (connect(uwin->uwi_datafd, sin, sizeof(struct sockaddr_in)) < 0) {
uwerrno = UWE_ERRNO;
goto error;
}
/*
* Now we have enough information to build the new-window command
* and send it to the server. The initial command is sent to the
* data port. Next, we wait for a connection from the server to
* our data socket. Finally, we expect the server to send us a
* new window status message on the data fd.
*/
len = sizeof uwip.uwip_neww + (char *)&uwip.uwip_neww - (char *)&uwip;
uwip.uwip_len = htons(len);
uwip.uwip_cmd = htons(UWC_NEWW);
uwip.uwip_neww.uwnw_id = 0; /* let server choose this */
uwip.uwip_neww.uwnw_type = htons(uwtype);
uwip.uwip_neww.uwnw_ctlport = ctlsin.sin_port;/* byte order correct */
if (write(uwin->uwi_datafd, (char *)&uwip, len) < 0) {
uwerrno = UWE_ERRNO;
goto error;
}
namelen = sizeof ctlsin;
if ((ctlfd = accept(uwin->uwi_ctlfd, (struct sockaddr_in *)&ctlsin, &namelen)) < 0) {
uwerrno = UWE_ERRNO;
goto error;
}
(void)close(uwin->uwi_ctlfd);
uwin->uwi_ctlfd = ctlfd;
uw_optinit(ctlfd, uwin);
cp = (char *)&uwip.uwip_len;
rdsz = sizeof uwip.uwip_len;
while (rdsz > 0 && (len=read(uwin->uwi_datafd, cp, rdsz)) > 0) {
cp += len;
rdsz -= len;
}
if (len > 0) {
rdsz = htons(uwip.uwip_len) - sizeof uwip.uwip_len;
while (rdsz > 0 && (len=read(uwin->uwi_datafd, cp, rdsz)) > 0) {
cp += len;
rdsz -= len;
}
}
if (len <= 0) {
uwerrno = UWE_ERRNO;
goto error;
}
uwerrno = uwin->uwi_uwerr = ntohs(uwip.uwip_status.uwst_err);
errno = uwin->uwi_errno = ntohs(uwip.uwip_status.uwst_errno);
if (uwin->uwi_uwerr != UWE_NONE)
goto error;
uwin->uwi_id = ntohl(uwip.uwip_status.uwst_id);
return(uwin);
error:
(void)close(uwin->uwi_datafd);
(void)close(uwin->uwi_ctlfd);
free((char *)uwin);
return((UWIN)0);
}
static
getmyaddr(addr)
struct in_addr *addr;
{
register struct hostent *h;
char hostname[32];
static int once = 1;
static struct in_addr myaddr;
if (once) {
if (gethostname(hostname, sizeof hostname) < 0) {
(void)strncpy(hostname, "localhost", sizeof hostname-1);
hostname[sizeof hostname-1] = '\0';
}
if ((h = gethostbyname(hostname)) != (struct hostent *)0)
myaddr = *(struct in_addr *)h->h_addr;
else
myaddr.s_addr = htonl(0x7f000001L);
once = 0;
}
*addr = myaddr;
}
l suggest protocol 1 (which is universal) and
* the other side will issue a P1_FN_SETPCL command to establish its use.
*
* Host:
* If the host receives a P1_FN_ASKPCL it will respond with the most
* complex protocol it can support (using the P1_FN_CANPCL command).
* Negotiations will proceed as described above until one side
* establishes a newlib/uw_optcmd.c 600 11722 76400 3553 4750124274 7161 /*
* uw library - uw_optcmd
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include "uwlib.h"
#ifndef htons
/* These should have been defined in
extern unsigned short htons(), ntohs();
extern unsigned long htonl(), ntohl();
#endif
uw_optcmd(uwin, optnum, optcmd, optval)
UWIN uwin;
uwopt_t optnum;
uwoptcmd_t optcmd;
union uwoptval *optval;
{
register int len;
struct uwipc uwip;
extern int errno;
/*
* Send an option command string to the server (and eventually
* to the Macintosh).
*/
if (uwin != (UWIN)0) {
if (uwin->uwi_ctlfd >= 0) {
if (optnum < UW_NUMOPTS) {
len = sizeof uwip;
uwip.uwip_len = htons(len);
uwip.uwip_cmd = htons(UWC_OPTION);
uwip.uwip_option.uwop_id = htonl(uwin->uwi_id);
uwip.uwip_option.uwop_opt = htons(optnum);
uwip.uwip_option.uwop_cmd = htons(optcmd);
switch (optcmd) {
case UWOC_SET:
if (optval == (union uwoptval *)0) {
uwin->uwi_uwerr = UWE_INVAL;
break;
}
uwip.uwip_option.uwop_val = *optval;
uw_hton(uwin->uwi_type, optnum,
(char *)&uwip.uwip_option.uwop_val);
/* no break */
case UWOC_ASK:
case UWOC_DO:
case UWOC_DONT:
case UWOC_WILL:
case UWOC_WONT:
if (write(uwin->uwi_ctlfd, (char *)&uwip,
len) < 0) {
uwin->uwi_uwerr = UWE_ERRNO;
uwin->uwi_errno = errno;
} else
uwin->uwi_uwerr = UWE_NONE;
break;
default:
uwin->uwi_uwerr = UWE_INVAL;
break;
}
} else
uwin->uwi_uwerr = UWE_INVAL;
}
uwerrno = uwin->uwi_uwerr;
if (uwin->uwi_uwerr == UWE_NONE)
return(0);
else
return(-1);
} else {
uwerrno = UWE_INVAL;
return(-1);
}
}
(uwin->uwi_ctlfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
if (uwin->uwi_datafd >= 0)
(void)close(uwin->uwi_datafd);
return((UWIN)0);
}
/*
lib/uw_optfn.c 600 11722 76400 1525 4750124274 7016 /*
* uw library - uw_optfn
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
uwfnptr_t
uw_optfn(uwin, optnum, optfn)
UWIN uwin;
uwopt_t optnum;
uwfnptr_t optfn;
{
uwfnptr_t oldfn;
/*
* Establish an option-processing function (defined by the host).
* The specified function will be called whenever an option message
* is received from the server. The previous function is returned.
*/
oldfn = (uwfnptr_t)0;
if (uwin != (UWIN)0) {
if (optnum < UW_NUMOPTS) {
oldfn = uwin->uwi_options[optnum].uwi_optfn;
uwin->uwi_options[optnum].uwi_optfn = optfn;
uwin->uwi_uwerr = UWE_NONE;
} else
uwin->uwi_uwerr = UWE_INVAL;
}
uwerrno = uwin->uwi_uwerr;
return(oldfn);
}
.uwip_len = htons(len);
uwip.uwip_cmd = htons(UWC_OPTION);
uwip.uwip_option.uwop_id = htonl(uwin->uwi_id);
uwip.uwip_option.uwop_opt = htons(optnum);
uwip.lib/uw_options.c 600 11722 76400 15115 4750124276 7405 /*
* uw library - uw_options
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include
#include "uwlib.h"
#ifndef FD_SET
#define FD_SET(n,p) ((p)->fds_bits[0] |= (1 << (n)))
#define FD_CLR(n,p) ((p)->fds_bits[0] &= ~(1 << (n)))
#define FD_ISSET(n,p) ((p)->fds_bits[0] & (1 << (n)))
#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
#define FD_SETSIZE (NBBY*sizeof(long))
#endif
#ifndef sigmask
#define sigmask(m) (1 << ((m)-1))
#endif
#ifndef htons
/* These should have been defined in
extern unsigned short htons(), ntohs();
extern unsigned long htonl(), ntohl();
#endif
static UWIN *fdmap;
static int (*oldsigio)();
static struct fd_set fdmask;
static int nfds;
extern char *malloc();
uw_optinit(fd, uwin)
int fd;
UWIN uwin;
{
register int i, flags;
static int first = 1;
extern uw_optinput();
/*
* The first time through, allocate the file descriptor map and
* bitmask, and cause SIGIO traps to be handled by uw_optinput.
*/
if (first) {
first = 0;
nfds = getdtablesize();
fdmap = (UWIN *)malloc((unsigned)(sizeof(UWIN)*nfds));
if (fdmap != (UWIN *)0)
for (i = 0; i < nfds; i++)
fdmap[i] = (UWIN)0;
oldsigio = signal(SIGIO, uw_optinput);
FD_ZERO(&fdmask);
}
/*
* Add the new control fd to the map and mask. Set the owner
* to this process
*/
if (fd >= 0 && fd < nfds && uwin != (UWIN)0 && fdmap != (UWIN *)0) {
fdmap[fd] = uwin;
FD_SET(fd, &fdmask);
#ifdef SETOWN_BUG
(void)fcntl(fd, F_SETOWN, -getpid());
#else
(void)fcntl(fd, F_SETOWN, getpid());
#endif
if ((flags = fcntl(fd, F_GETFL, 0)) >= 0)
(void)fcntl(fd, F_SETFL, flags|FASYNC|FNDELAY);
uwin->uwi_ipclen = 0;
}
}
uw_optdone(fd)
{
register int flags;
/*
* Turn off asynchronous I/O notification and remove the
* map and mask information for "fd". We do not close the
* file descriptor, however -- the caller is expected to
* take care of that.
*/
if (fd >= 0 && fd < nfds && fdmap != (UWIN *)0) {
if ((flags = fcntl(fd, F_GETFL, 0)) >= 0)
(void)fcntl(fd, F_SETFL, flags&~FASYNC);
else
(void)fcntl(fd, F_SETFL, 0);
(void)fcntl(fd, F_SETFL, 0);
fdmap[fd] = (UWIN)0;
FD_CLR(fd, &fdmask);
}
}
static
uw_optinput(sig, code, scp)
int sig, code;
struct sigcontext *scp;
{
register int k, n, fd;
register UWIN uwin;
register struct uwoption *uwop;
register union uwoptval *uwov;
uwopt_t optnum;
uwoptcmd_t optcmd;
uwfnptr_t userfn;
int oldmask;
struct timeval timeo;
struct fd_set ready;
extern int errno;
/*
* This routine is called when input is waiting on a control
* file descriptor.
*/
oldmask = sigblock(sigmask(SIGALRM));
do {
ready = fdmask;
timeo.tv_sec = 0;
timeo.tv_usec = 0;
n = select(nfds, &ready, (struct fd_set *)0,
(struct fd_set *)0, &timeo);
if (n < 0 && errno == EBADF) {
/*
* One of the file descriptors that we asked for
* is no longer valid. This isn't supposed to
* happen; however, we try to handle it by testing
* each bit individually and eliminating the bad
* ones.
*/
for (fd=0; fd < nfds; fd++) {
if (FD_ISSET(fd, &fdmask)) {
do {
ready = fdmask;
timeo.tv_sec = 0;
timeo.tv_usec = 0;
k = select(nfds, &ready,
(struct fd_set *)0,
(struct fd_set *)0, &timeo);
if (k < 0 && errno == EBADF) {
fdmap[fd] = (UWIN)0;
FD_CLR(fd, &fdmask);
}
} while (n < 0 && errno == EINTR);
}
}
}
} while (n < 0 && errno == EINTR);
for (fd=0; n > 0 && fd < nfds; fd++) {
if (FD_ISSET(fd, &ready)) {
n--;
uwin = fdmap[fd];
while ((k = getmesg(fd, uwin)) > 0) {
uwin->uwi_ipclen = 0; /* for next time */
if (uwin->uwi_ipcbuf.uwip_cmd == UWC_OPTION) {
uwop = &uwin->uwi_ipcbuf.uwip_option;
uwov = &uwop->uwop_val;
optnum = ntohs(uwop->uwop_opt);
optcmd = ntohs(uwop->uwop_cmd);
if (optcmd == UWOC_SET)
uw_ntoh(uwin->uwi_type, optnum,
(char *)uwov);
if (optcmd == UWOC_SET) switch(optnum) {
case UWOP_VIS:
uwin->uwi_vis = !!uwov->uwov_6bit;
break;
case UWOP_TYPE:
if (uwov->uwov_6bit
break;
case UWOP_POS:
uwin->uwi_pos.uwp_v = uwov->uwov_point.v;
uwin->uwi_pos.uwp_h = uwov->uwov_point.h;
break;
case UWOP_TITLE:
(void)strncpy(uwin->uwi_title,
uwov->uwov_string,
sizeof uwin->uwi_title);
break;
case UWOP_WSIZE:
uwin->uwi_wsize.uwp_v = uwov->uwov_point.v;
uwin->uwi_wsize.uwp_h = uwov->uwov_point.h;
break;
}
if (optnum == UWOP_TYPE &&
optcmd == UWOC_SET &&
uwov->uwov_6bit < UW_NWTYPES)
uwin->uwi_type=uwov->uwov_6bit;
userfn = uwin->uwi_options[optnum].uwi_optfn;
if (userfn != (uwfnptr_t)0)
(*userfn)(uwin, optnum,
optcmd, uwov);
}
}
if (k < 0)
(void)uw_detach(uwin); /* I/O error or EOF */
}
}
(void)sigsetmask(oldmask);
/*
* Finally, if "oldsigio" is not SIG_DFL, call it.
*/
if (oldsigio != SIG_DFL)
(*oldsigio)(sig, code, scp);
}
static
getmesg(fd, uwin)
register int fd;
register UWIN uwin;
{
register int len;
register char *cp;
/*
* Read some more bytes from control socket "fd" into the input
* buffer. Return 1 if the message is now complete, -1 if an
* EOF was reached, or 0 otherwise. Before returning 1, the byte
* order of the common parameters (command, length) is changed
* from network to host order.
*/
cp = (char *)&uwin->uwi_ipcbuf + uwin->uwi_ipclen;
if (uwin->uwi_ipclen < sizeof(uwin->uwi_ipcbuf.uwip_len)) {
len = read(fd, cp, sizeof uwin->uwi_ipcbuf.uwip_len - uwin->uwi_ipclen);
if (len == 0 || (len < 0 && errno != EWOULDBLOCK))
return(-1);
if (len < 0)
return(0);
if ((uwin->uwi_ipclen +=len) < sizeof uwin->uwi_ipcbuf.uwip_len)
return(0);
uwin->uwi_ipcbuf.uwip_len = ntohs(uwin->uwi_ipcbuf.uwip_len);
if (uwin->uwi_ipcbuf.uwip_len==sizeof uwin->uwi_ipcbuf.uwip_len)
return(1);
cp += len;
}
if (uwin->uwi_ipcbuf.uwip_len > sizeof(struct uwipc))
uwin->uwi_ipcbuf.uwip_len = sizeof(struct uwipc);
len = read(fd, cp, uwin->uwi_ipcbuf.uwip_len - uwin->uwi_ipclen);
if (len == 0 || (len < 0 && errno != EWOULDBLOCK))
return(-1);
if ((uwin->uwi_ipclen += len) == uwin->uwi_ipcbuf.uwip_len) {
uwin->uwi_ipcbuf.uwip_cmd = ntohs(uwin->uwi_ipcbuf.uwip_cmd);
return(1);
} else
return(0);
}
((p)->fds_bits[0] = 0)
#define FD_SETSIZE (NBBY*sizeof(long))
#endif
#ifndef sigmask
#define sigmask(m) (1 << ((m)-1))
#endif
#ifndef htons
/* These should have been defined in
extern unsigned short htons(), ntohs();
extern unsigned long htonl(), ntohl();
#endif
static UWIN *fdmap;
static int (*oldsigio)();
static struct fd_set fdmask;
static int nfds;
extern char *malloc();
uw_optinlib/uw_perror.c 600 11722 76400 2205 4750124276 7177 /*
* uw library - uw_perror
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
char *uwerrlist[] = {
"no error",
"system call error",
"nonexistent window type",
"window ID duplicated (in use)",
"operation not implemented",
"non-existent server",
"unable to allocate required memory",
"invalid argument to function",
"no control file descriptor for window",
};
unsigned uwnerr = sizeof uwerrlist / sizeof uwerrlist[0];
int uwerrno;
/*ARGSUSED*/
void
uw_perror(mesg, uwerr, errno)
char *mesg;
uwerr_t uwerr;
int errno;
{
register char *errmsg;
/*
* Print a UW error message. We call write() directly to avoid
* making the UW library dependent upon stdio.
*/
if (uwerr == UWE_ERRNO) {
perror(mesg);
} else {
if (mesg != (char *)0) {
(void)write(2, mesg, strlen(mesg));
(void)write(2, ": ", 2);
}
if (uwerr >= uwnerr)
errmsg = "unknown UW error";
else
errmsg = uwerrlist[uwerr];
(void)write(2, errmsg, strlen(errmsg));
(void)write(2, "\n", 1);
}
}
gh, allocate the file descriptor map and
* bitmask, and cause SIGIO traps to be handled by uw_optinput.
*/
if (first) {
first = 0;
nfds = getdtablesize();
fdmap = (UWIN *)malloc((unsigned)(sizeof(UWIN)*nfds));
if (fdmap != (UWIN *)0)
for (i = 0; i < nfds; i++)
fdmap[i] = (UWIN)0;
oldsigio = signal(SIGIO, uw_optinput);
FD_ZERO(&fdmask);
}
/*
* Add tlib/uw_rsetopt.c 600 11722 76400 3750 4750124277 7375 /*
* uw library - uw_rsetopt
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "openpty.h"
#include "uwlib.h"
extern char *malloc();
extern char *getenv();
uw_rsetopt(uwid, optnum, optval)
uwid_t uwid;
uwopt_t optnum;
union uwoptval *optval;
{
register int sd;
register struct uwipc *uwip;
char *portal;
struct iovec iov;
struct msghdr msg;
struct sockaddr_un sa;
/*
* Set a window option on a remote window (that is, one for which
* we do not have a control fd).
*/
/*
* Create a UNIX-domain socket.
*/
if (!(portal=getenv("UW_UIPC"))) {
uwerrno = UWE_NXSERV;
return(-1);
}
if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
uwerrno = UWE_ERRNO;
return(-1);
}
sa.sun_family = AF_UNIX;
(void)strncpy(sa.sun_path, portal, sizeof sa.sun_path-1);
sa.sun_path[sizeof sa.sun_path-1] = '\0';
/*
* Construct the datagram we will send later.
*/
uwip = (struct uwipc *)malloc(sizeof(struct uwipc));
if (uwip == (struct uwipc *)0) {
uwerrno = UWE_NOMEM;
return(-1);
}
uwip->uwip_cmd = UWC_OPTION;
uwip->uwip_len = sizeof(struct uwipc);
uwip->uwip_option.uwop_id = uwid;
uwip->uwip_option.uwop_cmd = UWOC_SET;
uwip->uwip_option.uwop_opt = optnum;
uwip->uwip_option.uwop_val = *optval;
/*
* Pass the file descriptor to the window server.
*/
iov.iov_base = (char *)uwip;
iov.iov_len = uwip->uwip_len;
msg.msg_name = (caddr_t)&sa;
msg.msg_namelen = sizeof sa.sun_family + strlen(sa.sun_path);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_accrights = (caddr_t)0;
msg.msg_accrightslen = 0;
if (sendmsg(sd, &msg, 0) < 0) {
free((char *)uwip);
uwerrno = UWE_ERRNO;
return(-1);
}
free((char *)uwip);
uwerrno = UWE_NONE;
return(0);
}
hronous I/O notificationlib/uw_shell.c 600 11722 76400 1523 4750124277 7000 /*
* uw library - uw_shell
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include "uwlib.h"
char *uwshellname = "/bin/sh"; /* can be patched by caller if desired */
uwid_t
uw_shell(wtype, cmd)
uwtype_t wtype;
char *cmd;
{
register uwid_t uwid;
/*
* Create a new window (using uw_fork()) and execute the specified
* shell command in it. Returns the window ID of the new window
* (or -1 if the window creation failed) There is no way to
* determine if the executed command failed.
*/
if ((uwid = uw_fork(wtype, (int *)0)) == 0) {
(void)execl(uwshellname, uwshellname, "-c", cmd, (char *)0);
_exit(1); /* we'd better not reach this point */
/*NOTREACHED*/
} else
return(uwid);
}
*/
if (!(portal=getenv("UW_UIPC"))) {
uwerrno = UWE_NXSERV;
return(-1);
}
if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
uwerrno = UWE_ERRNO;
return(-1);
}
sa.lib/uw_ttype.c 600 11722 76400 2043 4750124300 7017 /*
* uw library - uw_ttype
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include "uwlib.h"
struct table {
char *tname;
uwtype_t wtype;
};
/* The following table must be sorted */
static struct table table[] = {
{ "aaa-24", UWT_ANSI },
{ "adm3", UWT_ADM31 },
{ "adm31", UWT_ADM31 },
{ "adm3a", UWT_ADM31 },
{ "ansi", UWT_ANSI },
{ "tek", UWT_TEK4010 },
{ "tek4010", UWT_TEK4010 },
{ "tek4012", UWT_TEK4010 },
{ "vt52", UWT_VT52 },
};
uwtype_t
uw_ttype(name)
char *name;
{
register struct table *t, *lo, *hi;
register int cmp;
/*
* Map a terminal name string to a UW window emulation type.
*/
lo = table;
hi = table + sizeof table / sizeof table[0] - 1;
while (lo <= hi) {
t = lo + (hi-lo) / 2;
cmp = strcmp(name, t->tname);
if (cmp == 0)
return(t->wtype);
if (cmp < 0)
hi = t-1;
else
lo = t+1;
}
return(UWT_ADM31); /* default if no match */
}
the window creation failed) There is no way to
* determine if the executed command failed.
*/
if ((uwid = uw_fork(wtype, (int *)0)) == 0) {
(void)execl(uwshellname, uwshellname, "-c", cmd, (char *)0);
_exit(1); /* we'd better not reach this point */
/*NOTREACHED*/
} else
return(uwid);
}
*/
if (!(portal=getenv("UW_UIPC"))) {
uwerrno = UWE_NXSERV;
return(-1);
}
if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
uwerrno = UWE_ERRNO;
return(-1);
}
sa.misc/ 700 11722 76400 0 4750124222 5075 misc/README 600 11722 76400 1352 4750124220 6043 This directory contains three items that may be of interest:
getopt.c The AT&T version of the getopt() library
routine (for command-line processing). This
version, to the best of my knowledge, was
placed into the public domain by AT&T.
macmouse.ml A package for use with Gosling's EMACS
which intreprets encoded mouse-down and
mouse-up events within windows to perform
various operations.
Author: Chris Kent ([email protected])
macmouse.el A similar macro package for GNU EMACS.
Author: Gregory Lauer ([email protected])
The two EMACS macro packages were developed for a previous version of
UW (version 2.10). Since I (John Bruner) am not an EMACS user, I do
not know how well they will work with UW v4.2.
char *)0);
_exit(1); /* we'd better not reach this point */
/*NOTREACHED*/
} else
return(uwid);
}
*/
if (!(portal=getenv("UW_UIPC"))) {
uwerrno = UWE_NXSERV;
return(-1);
}
if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
uwerrno = UWE_ERRNO;
return(-1);
}
sa.misc/getopt.c 600 11722 76400 2337 4750124221 6636 /*LINTLIBRARY*/
#define NULL 0
#define EOF (-1)
#define ERR(s, c) if(opterr){\
extern int strlen(), write();\
char errbuf[2];\
errbuf[0] = c; errbuf[1] = '\n';\
(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
(void) write(2, s, (unsigned)strlen(s));\
(void) write(2, errbuf, 2);}
extern int strcmp();
extern char *strchr();
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
int
getopt(argc, argv, opts)
int argc;
char **argv, *opts;
{
static int sp = 1;
register int c;
register char *cp;
if(sp == 1)
if(optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return(EOF);
else if(strcmp(argv[optind], "--") == NULL) {
optind++;
return(EOF);
}
optopt = c = argv[optind][sp];
if(c == ':' || (cp=strchr(opts, c)) == NULL) {
ERR(": illegal option -- ", c);
if(argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return('?');
}
if(*++cp == ':') {
if(argv[optind][sp+1] != '\0')
optarg = &argv[optind++][sp+1];
else if(++optind >= argc) {
ERR(": option requires an argument -- ", c);
sp = 1;
return('?');
} else
optarg = argv[optind++];
sp = 1;
} else {
if(argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
return(c);
}
uct uwipc));
if (uwip == (struct uwipc *)0) {
uwerrno = UWE_NOMEM;
return(-1);
}
uwip->uwip_cmd = UWC_OPTION;
uwip->uwip_len = sizeof(struct uwipc);
uwip->uwip_option.uwop_id = uwid;
uwip->uwip_option.uwop_cmd = UWOC_SET;
uwip->uwip_option.uwop_opt = optnum;
uwip->uwip_option.misc/macmouse.el 600 11722 76400 22075 4750124222 7345 ;;; macmouse.el (Version: 2.0)
;;; Copyright (C) Gregory S. Lauer (glauer@bbn), 1985.
;;; Please send suggestions and corrections to the above address.
;;;
;;; This file contains macmouse, a GNU Emacs mouse package for UW.
;;
;; GNU Emacs is distributed in the hope that it will be useful,
;; but without any warranty. No author or distributor
;; accepts responsibility to anyone for the consequences of using it
;; or for whether it serves any particular purpose or works at all,
;; unless he says so in writing.
;; Everyone is granted permission to copy, modify and redistribute
;; GNU Emacs, but only under the conditions described in the
;; document "GNU Emacs copying permission notice". An exact copy
;; of the document is supposed to have been given to you along with
;; GNU Emacs so that you can know how you may redistribute it all.
;; It should be in a file named COPYING. Among other things, the
;; copyright notice and this notice must be preserved on all copies.
;;; Original version for Gosling emacs by Chris Kent, Purdue University 1985.
;;; Modified by Gregory Lauer, BBN, Novemeber 1985.
;
;
;
; Macmouse provides the following features:
; Up or down mouse button in a window selects that window
;
; A scroll bar/thumbing area for each window with the following features:
; the mode lines are horizontal scroll bars
; (running from rightmost column to under leftmost column)
; the unused right window bar and the dividing lines between
; windows are vertical scroll bars
; (running from top of window THRU modeline
; for vertical scroll bars:
; click at line 1 does previous page
; click at last line does next page
; click anywhere else "thumbs" to the relative portion of the buffer.
; shift-click at line 1 scrolls one line down
; shift-click at last line scrolls one line up
; shift-click elsewhere moves line to top of window
; option-shift-click elsewhere moves line to bottom of window
; for horizontal scroll bars:
; click at column 1 does scroll right one window width
; click at last column does scroll left one window width
; click anywhere else moves to that "percent" of the buffer width
; shift-click at column 1 scrolls one column right
; shift-click at last column scrolls one column left
; shift-click elsewhere moves column to right of window
; option-shift-click elsewhere moves column to left of window
;
; There is also basic positioning and kill-buffer support:
; click in a buffer moves dot there and selects that buffer
; drag copies the dragged region to the kill buffer
; shift-drag deletes the dragged region to the kill buffer
;
; It is possible to use the scrolling and thumbing area to make the region
; larger than a single screen; just click, scroll, release. Make sure
; that the last scroll is just a down event; the up must be in the buffer.
; The last mouse position is remembered for each different buffer (not
; window), and thus you can start a drag in one buffer, select another,
; go back to the first buffer, etc.
;
; option-click yanks from the kill buffer
; option-shift-click similarly yanks from a named buffer.
;
(defconst mouse-max-x 95 "Maximum UW column returned on mouse click")
(defconst mouse-max-y 95 "Maximum UW row returned on mouse click")
(make-variable-buffer-local 'mouse-last-x) ; x of last event
(set-default 'mouse-last-x 0)
(make-variable-buffer-local 'mouse-last-y) ; y of last event
(set-default 'mouse-last-y 0)
(make-variable-buffer-local 'mouse-last-b) ; buttons at last event
(set-default 'mouse-last-b 0)
(make-variable-buffer-local 'mouse-last-dot) ; dot after last event
(set-default 'mouse-last-dot 0)
(make-variable-buffer-local 'scrolling-p)
(set-default 'scrolling-p nil)
(defun move-mac-cursor ()
(interactive)
(let (savest b x y up down lock shift option command)
(setq savest stack-trace-on-error)
(setq stack-trace-on-error nil)
; decode everything
(setq y (- (read-char) 32))
(setq x (- (read-char) 32))
(setq b (- (read-char) 32))
(setq command (< 0 (logand b 1))) ; command key
(setq shift (< 0 (logand b 2))) ; shift
(setq lock (< 0 (logand b 4))) ; caps-lock
(setq option (< 0 (logand b 8))) ; option
(setq down (< 0 (logand b 16))) ; mouse down
(setq up (< 0 (logand b 32))) ; mouse up
(condition-case ()
(progn
(select-window-containing-x-and-y x y) ; side-effect sets scrolling-p
(if scrolling-p
(mouse-scroll-region b x y)
(progn
(move-to-window-x-y x y) ; move cursor to mouse-dot always
(if down (setq mouse-last-dot (dot)))
(mouse-edit-action))))
(error (message "Click not in selectable window")
(sit-for 1)
(message "")))
(setq stack-trace-on-error savest)
(if down
(progn
(setq mouse-last-x x)
(setq mouse-last-y y)
(setq mouse-last-b b))
(progn
(setq mouse-last-x 0)
(setq mouse-last-y 0)
(setq mouse-last-b 0)))))
(defun mouse-edit-action ()
;marking and editing actions on buttons:
; if no movement, nothing.
; if movement, save mouse-last-dot,
; and edit.
; editing (on upstrokes):
; unmodified, copy to kill buffer.
; SHIFTed, delete (cut) to kill buffer.
;
; option-click yanks from kill buffer;
; shift-option-click from named buffer.
(let ((fun (get 'mouse-function b)))
(if fun (apply fun nil))))
; individual button bindings
; generally will only need up mouse button: mouse-last-dot
; is saved automatically on down mouse button
; only need to define functions for keys that get used
(put 'mouse-function 32 ; up
'(lambda ()
(if (and (not (mouse-click-p))
(not scrolling-p))
(copy-region-as-kill (dot) mouse-last-dot))))
(put 'mouse-function 34 ; up/shift
'(lambda ()
(if (and (not (mouse-click-p))
(not scrolling-p))
(kill-region (dot) mouse-last-dot))))
(put 'mouse-function 40 ; up/option
'(lambda ()
(if (mouse-click-p)
(progn
(yank)
(exchange-dot-and-mark)))))
(put 'mouse-function 42
'(lambda () ; up/option/shift
(if (mouse-click-p)
(insert-buffer (read-buffer "Insert contents of buffer: ")))))
(defun mouse-click-p ()
(= (dot) mouse-last-dot))
(defun set-window-boundaries ()
(let ((edges (window-edges)))
(setq xl (1+ (car edges)))
(setq yt (1+ (car (cdr edges))))
(let ((temp (car (cdr (cdr edges)))))
(setq xr (if (= (screen-width) temp) mouse-max-x temp)))
(let ((temp (car (cdr (cdr (cdr edges))))))
(setq yb (if (= (screen-height) temp) mouse-max-y temp )))))
(defun select-window-containing-x-and-y (x y)
(let ((starting-window (selected-window)))
(set-window-boundaries)
(while (not (point-in-window x y))
(other-window 1)
(if (eq (selected-window) starting-window)
(error nil)
(set-window-boundaries)))
(if (or (= x xr) (= y yb))
(setq scrolling-p t)
(setq scrolling-p nil))))
(defun point-in-window (x y)
(and (<= xl x)(<= x xr)(<= yt y)(<= y yb)))
(defun move-to-window-x-y (x y)
(move-to-window-line (- y yt))
(move-to-window-column (- x xl)))
(defun move-to-window-column (x)
(move-to-column (+ (max 0 (- (window-hscroll) 1)) x)))
(defun mouse-scroll-region (b x y)
(if down
(if shift
(do-lines b x y)
(do-pages b x y)))
(if (and up
(or (/= x mouse-last-x)
(/= y mouse-last-y)))
(if shift
(do-lines b x y)
(do-pages b x y))))
(defun do-lines (b x y) ; fine control over lines
(if (= x xr)
(cond ((= y yt)(scroll-down 1))
((= y yb)(scroll-up 1))
(t (if option
(scroll-down (- yb y 1))
(scroll-up (- y yt))))))
(if (and (= y yb) (/= x xr))
(cond ((<= x xl)(scroll-right 1))
((>= x (1- xr))(scroll-left 1))
(t (if option
(move-column-right x)
(move-column-left x))))))
(defun move-column-left (x) ;need to mess about a bit because
(scroll-left ;first scroll left of 1 just writes
(if (= (window-hscroll) 0) ;a column of $s in column 1
(- x xl)
(- x xl 1))))
(defun move-column-right (x)
(scroll-right (- xr x 2)))
(defun do-pages (b x y) ; large motions via pages and thumbing
(if (= x xr)
(cond ((= y yt)(scroll-down nil))
((= y yb)(scroll-up nil))
(t (goto-percent (/ (* (- y yt 1) 100)
(- yb yt 2))))))
(if (and (= y yb)(/= x xr))
(cond ((<= x xl)(scroll-right (- (window-width)
next-screen-context-lines)))
((>= x (1- xr))(scroll-left (- (window-width)
next-screen-context-lines)))
(t (goto-horizontal-percent (/ (* (- x xl 1) 100)
(- xr xl 2)))))))
(defun goto-percent (p)
(goto-char (/ (* (- (dot-max) (dot-min)) p) 100)))
(defun goto-horizontal-percent (p) ;try to put this percent of columns
(let ((window-offset (window-hscroll));in the center column of the window
delta) ;unless that would move the first or
(setq delta ;last column past the window edge
(- window-offset
(min (max 0 (- (/ (* (screen-width) p) 100)
(/ (- xr xl) 2)))
(- (screen-width) (- xr xl)))))
(scroll-right delta)))
(global-set-key "\em" 'move-mac-cursor)
oid (*p_exit)(); /* shut down (EXIT maintenance fn) */
void (*p_renew)(); /* renew (re-init) */
struct window *(*p_neww)(); /* create new window */
void (*p_killw)(); /* kill window */
void (*p_xmit)(); /* transmit to specified window */
void (*p_recv)(); /* receive from Macintosh */
void (*p_chkopt)(); /* check for pending option output */
void (*p_sendopt)(); /* send option string to Macintosh */
void (*p_askpcl)(); /* send an ASmisc/macmouse.ml 600 11722 76400 20326 4750124223 7353 ; $Header: /c/cak/lib/mlisp/RCS/macmouse.ml,v 1.5 85/11/05 14:01:44 cak Rel $
;
; Macintosh mouse routines for use with John Bruner's uw program.
; Chris Kent, Purdue University Fri Oct 25 1985
; Copyright 1985 by Christopher A. Kent. All rights reserved.
; Permission to copy is given provided that the copy is not
; sold and this copyright notice is included.
;
; Provides a scroll bar/thumbing area in the unused scroll bar with the
; following features:
; click at line 1 does previous page
; click at line 24 does next page
; click anywhere else "thumbs" to the relative portion of the buffer.
; shift-click at line 1 scrolls one line down
; shift-click at line 24 scrolls one line up
; shift-click elsewhere moves line to top of window
; option-shift-click elsewhere moves line to bottom of window
;
; There is also basic positioning and kill-buffer support:
; click in a buffer moves dot there
; drag copies the dragged region to the kill buffer (mark is left
; at the beginning of the region.)
; shift-drag deletes the dragged region to the kill buffer
; it is possible to use the scrolling and thumbing area to make the region
; larger than a single screen; just click, scroll, release. Make sure
; that the last scroll is just a down event; the up must be in the buffer.
;
; option-click yanks from the kill buffer, doesn't affect mark.
; option-shift-click similarly yanks from a named buffer.
;
(declare-global
#mouse-last-x ; x of last event
#mouse-last-y ; y of last event
#mouse-last-b ; buttons at last event
#mouse-last-dot ; dot after last event
#mouse-last-action ; whether last was scroll (1) or edit (2)
)
(defun
(move-mac-cursor savest b x y up down lock shift option command saveb
(setq savest stack-trace-on-error)
(setq stack-trace-on-error 0)
; decode everything
(setq y (- (get-tty-character) 32))
(setq x (- (get-tty-character) 32))
(setq b (- (get-tty-character) 32))
(setq saveb b)
(setq command (% b 2))(setq b (/ b 2)) ; command key
(setq shift (% b 2))(setq b (/ b 2)) ; shift
(setq lock (% b 2))(setq b (/ b 2)) ; caps-lock
(setq option (% b 2))(setq b (/ b 2)) ; option
(setq down (% b 2))(setq b (/ b 2)) ; mouse down
(setq up (% b 2))
(if (= x 81) ; right margin -- move-dot-to-x-y is wrong
(progn
(#mouse-scroll-region)
(setq #mouse-last-action 1))
(if (error-occurred
(if (= #mouse-last-action 2) ; not if just scrolled
(setq #mouse-last-dot (dot)))
(move-dot-to-x-y x y)
(backward-character)(forward-character)
(#mouse-edit-action)
(setq #mouse-last-action 2)
)
(progn
(#mouse-scroll-region b x y)
(setq #mouse-last-action 1))
))
(setq stack-trace-on-error savest)
(if (= down 1)
(progn
(setq #mouse-last-x x)
(setq #mouse-last-y y)
(setq #mouse-last-b saveb))
(progn
(setq #mouse-last-x 0)
(setq #mouse-last-y 0)
(setq #mouse-last-b 0)))
)
(#mouse-edit-action ; marking and editing actions on buttons:
; if no movement, nothing.
; if movement, put mark at #mouse-last-dot,
; leave dot here,and edit.
; editing (on upstrokes):
; unmodified, copy to kill buffer.
; SHIFTed, delete (cut) to kill buffer.
;
; option-click yanks from kill buffer;
; shift-option-click from named buffer.
(if (= saveb 16)
(#mouse-d))
(if (= saveb 17)
(#mouse-dc))
(if (= saveb 18)
(#mouse-ds))
(if (= saveb 19)
(#mouse-dsc))
(if (= saveb 20)
(#mouse-dl))
(if (= saveb 21)
(#mouse-dlc))
(if (= saveb 22)
(#mouse-dls))
(if (= saveb 23)
(#mouse-dlsc))
(if (= saveb 24)
(#mouse-do))
(if (= saveb 25)
(#mouse-doc))
(if (= saveb 26)
(#mouse-dos))
(if (= saveb 27)
(#mouse-dosc))
(if (= saveb 28)
(#mouse-dol))
(if (= saveb 29)
(#mouse-dolc))
(if (= saveb 30)
(#mouse-dols))
(if (= saveb 31)
(#mouse-dolsc))
(if (= saveb 32)
(#mouse-u))
(if (= saveb 33)
(#mouse-uc))
(if (= saveb 34)
(#mouse-us))
(if (= saveb 35)
(#mouse-usc))
(if (= saveb 36)
(#mouse-ul))
(if (= saveb 37)
(#mouse-ulc))
(if (= saveb 38)
(#mouse-uls))
(if (= saveb 39)
(#mouse-ulsc))
(if (= saveb 40)
(#mouse-uo))
(if (= saveb 41)
(#mouse-uoc))
(if (= saveb 42)
(#mouse-uos))
(if (= saveb 43)
(#mouse-uosc))
(if (= saveb 44)
(#mouse-uol))
(if (= saveb 45)
(#mouse-uolc))
(if (= saveb 46)
(#mouse-uols))
(if (= saveb 47)
(#mouse-uolsc))
)
; individual button bindings
(#mouse-u ; up
(if (! (#mouse-click-p))
(progn
(#mouse-set-region)
(Copy-region-to-kill-buffer)
))
)
(#mouse-uc ; up/command
)
(#mouse-us ; up/shift
(if (! (#mouse-click-p))
(progn
(#mouse-set-region)
(delete-to-killbuffer)
))
)
(#mouse-usc ; up/shift/command
)
(#mouse-ul ; up/lock
)
(#mouse-ulc ; up/lock/command
)
(#mouse-uls ; up/lock/shift
)
(#mouse-ulsc ; up/lock/shift/command
)
(#mouse-uo ; up/option
(if (#mouse-click-p)
(yank-from-killbuffer)
)
)
(#mouse-uoc ; up/option/command
)
(#mouse-uos ; up/option/shift
(if (#mouse-click-p) ; click
(yank-buffer (get-tty-buffer "Insert contents of buffer: "))
)
)
(#mouse-uosc ; up/option/shift
)
(#mouse-uol ; up/option/lock
)
(#mouse-uolc ; up/option/lock
)
(#mouse-uols ; up/option/lock/shift
)
(#mouse-uolsc ; up/option/lock/shift/command
)
(#mouse-d ; down
)
(#mouse-dc ; down/command
)
(#mouse-ds ; down/shift
)
(#mouse-dsc ; down/shift/command
)
(#mouse-dl ; down/lock
)
(#mouse-dlc ; down/lock/command
)
(#mouse-dls ; down/lock/shift
)
(#mouse-dlsc ; down/lock/shift/command
)
(#mouse-do ; down/option
)
(#mouse-doc ; down/option/command
)
(#mouse-dos ; down/option/shift
)
(#mouse-dosc ; down/option/shift
)
(#mouse-dol ; down/option/lock
)
(#mouse-dolc ; down/option/lock
)
(#mouse-dols ; down/option/lock/shift
)
(#mouse-dolsc ; down/option/lock/shift/command
)
(#mouse-set-region ; set the region to be from last dot to dot.
(set-mark)
(goto-character #mouse-last-dot)
(exchange-dot-and-mark)
)
(#mouse-click-p clickp
(if (= (dot) #mouse-last-dot)
(setq clickp 1)
(setq clickp 0)
))
(#mouse-scroll-region ; out of range actions:
; left margin -- hard to generate, ignored
; right margin -- simulate scroll bar
; line 1 -- previous page
; line 24/25 -- next page
; other lines -- thumbing
; top margin -- previous page
; bottom margin -- next page
;
; if shifted, deal with lines.
; line 1 scrolls one line down
; line 24/25 scrolls one line up
; else line to top; with option to bottom.
;
; if up stroke is in same place as down
; stroke, don't do anything, so clicks in
; the scroll region don't do the action
; twice.
(if (= down 1)
(if (= shift 1)
(do-lines)
(do-pages))
)
(if (& (= up 1)
(| (!= x #mouse-last-x) (!= y #mouse-last-y)))
(if (= shift 1)
(do-lines)
(do-pages)
)
)
(#mouse-set-region)
)
(do-pages ; large motions via pages and thumbing
(if (| (= y 0) (= y 1) (= y 24) (= y 25))
(progn
(if (| (= y 0) (= y 1))
(previous-page)
(Next-Page)
))
(if (= x 81)
(goto-percent (/ (* y 100) 25))
)
))
(do-lines ; fine control over lines
(if (= x 81)
(if (| (= y 1) (= y 24) (= y 25))
(if (| (= y 0) (= y 1))
(scroll-one-line-down)
(scroll-one-line-up)
)
(progn
(move-dot-to-x-y 1 y)
(if (= option 0)
(line-to-top-of-window)
(line-to-bottom-of-window))
)
)
)
)
(line-to-bottom-of-window nlines i
(line-to-top-of-window)
(setq i 0)
(setq nlines (- (window-height) 1))
(while (< i nlines)
(scroll-one-line-down)
(setq i (+ i 1))
)
)
(goto-percent
(goto-character (/ (* (buffer-size) (arg 1)) 100))
)
)
(bind-to-key "move-mac-cursor" "\em")
nore the maintenance function.
The client will time out after five seconds
and retry several times
(three in the present implementation);
if the server never responds
the client will ``give up'' and will
continue to use protocol 1 indefinitely.
.PP
When the client receives P1_MF_CANPCL from the seserver/ 700 11722 76400 0 4750124261 5453 server/Makefile_4.2 600 11722 76400 2263 4750124243 7570 #! /bin/make -f
#
# uw makefile (4.2BSD)
#
# INCDIR names the directory where the header files are located.
#
# OBJECTS names all of the object files required for the server.
#
INCDIR = ../h
OBJECTS = uw_clk.o uw_env.o uw_fd.o uw_ipc.o uw_main.o uw_opt.o \
uw_pcl.o uw_tty.o uw_utmp.o uw_win.o openpty.o
SOURCES = `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
DEFINES = `cat ../DEFINES`
CFLAGS = $(DEFINES) -I$(INCDIR) -O
LFLAGS =
uw: $(OBJECTS)
$(CC) $(LFLAGS) -o uw $(OBJECTS) $(LIBS)
lint:
lint -hbx -I$(INCDIR) $(DEFINES) $(SOURCES)
tags:
ctags $(SOURCES)
depend:
grep '^#include' $(SOURCES) | \
sed -e '/ -e 's/:[^"]*"\([^"]*\)".*/: ..\/h\/\1/' \
-e 's,^../[a-zA-Z0-9]*/\([^\.]*\)\.[cs],\1.o \1.L,' | \
awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
else { if (length(rec $$3) > 78) { print rec; rec = $$0; } \
else rec = rec " " $$3 } } \
END { print rec } ' > makedep
echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ex - Makefile < eddep
rm eddep makedep
clean:
rm *.o
# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
b x y up down lock shift option command saveb
(setq savest stack-trace-on-error)
(setq stack-trace-on-error 0)
; decode everything
(setq y (- (get-tty-character) 32))
(setq x (- (get-tty-character) 32))
(setq b (- (get-tty-character) 32))
(setq saveb b)
(setq command (% b 2))(setq b (/ b 2)) ; command key
(setq shift (% bserver/Makefile_4.3 600 11722 76400 2222 4750124244 7565 #! /bin/make -f
#
# uw makefile (4.3BSD)
#
# INCDIR names the directory where the header files are located.
#
# OBJECTS names all of the object files required for the server.
#
INCDIR = ../h
OBJECTS = uw_clk.o uw_env.o uw_fd.o uw_ipc.o uw_main.o uw_opt.o \
uw_pcl.o uw_tty.o uw_utmp.o uw_win.o openpty.o
SOURCES = `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
DEFINES = `cat ../DEFINES`
CFLAGS = $(DEFINES) -I$(INCDIR) -O
LFLAGS =
uw: $(OBJECTS)
$(CC) $(LFLAGS) -o uw $(OBJECTS) $(LIBS)
lint:
lint -hbx -I$(INCDIR) $(DEFINES) $(SOURCES)
tags:
ctags $(SOURCES)
depend:
$(CC) -M -I$(INCDIR) $(DEFINES) $(SOURCES) | \
sed -e ':loop' \
-e 's/\.\.\/[^ /]*\/\.\./../' \
-e 't loop' | \
awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
else rec = rec " " $$2 } } \
END { print rec } ' >> makedep
echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ex - Makefile < eddep
rm eddep makedep
clean:
rm *.o
# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
nk line) -- make depend uses it
b x y up down lock shift option command saveb
(setq savest stack-trace-on-error)
(setq stack-trace-on-error 0)
; decode everything
(setq y (- (get-tty-character) 32))
(setq x (- (get-tty-character) 32))
(setq b (- (get-tty-character) 32))
(setq saveb b)
(setq command (% b 2))(setq b (/ b 2)) ; command key
(setq shift (% bserver/openpty.c 600 11722 76400 7442 4750124245 7415 /*
* openpty - open a pseudo-terminal
*
* The first time that the routine is called, the device directory is
* searched and a list of all candidate pseudo-terminals is compiled.
* Candidates are defined to be those entries in "/dev" whose names
* (1) are the same length as PTY_PROTO and (2) start with the
* initial string PTY_PREFIX. Further, the master and slave sides
* must both exist.
*
* openpty() attempts to find an unused pseudo-terminal from the list
* of candidates. If one is found, the master and slave sides are
* opened and the file descriptors and names of these two devices are
* returned in a "ptydesc" structure. (The address of this structure
* is supplied by the caller. Zero is returned if openpty() was
* successful, -1 is returned if no pty could be found.
*/
#include
#include
#include
#include
#include "openpty.h"
#define DEV_DIR "/dev" /* directory where devices live */
#define PT_INDEX (sizeof DEV_DIR) /* location of 'p' in "pty" */
#define PTY_PROTO "ptyp0" /* prototype for pty names */
#define PTY_PREFIX "pty" /* prefix required for name of pty */
struct ptyinfo {
struct ptyinfo *pi_next;
char *pi_pty;
char *pi_tty;
};
static struct ptyinfo *ptylist;
extern char *malloc();
static
char *
devname(name)
char *name;
{
register char *fullname;
/*
* Construct the full name of a device in DEV_DIR. Returns
* NULL if it failed (because malloc() failed).
*/
fullname = malloc((unsigned)(sizeof DEV_DIR + 1 + strlen(name)));
if (fullname != NULL) {
(void)strcpy(fullname, DEV_DIR);
(void)strcat(fullname, "/");
(void)strcat(fullname, name);
}
return(fullname);
}
static
isapty(dp)
struct direct *dp;
{
static struct ptyinfo *pi;
/*
* We don't care about the gory details of the directory entry.
* Instead, what we really want is an array of pointers to
* device names (with DEV_DIR prepended). Therefore, we create
* this array ourselves and tell scandir() to ignore every
* directory entry.
*
* If malloc() fails, the current directory entry is ignored.
*/
if (pi == NULL) {
pi = (struct ptyinfo *)malloc((unsigned)sizeof *pi);
if (pi == NULL)
return(0);
}
if (strlen(dp->d_name) == sizeof PTY_PROTO - 1 &&
strncmp(dp->d_name, PTY_PREFIX, sizeof PTY_PREFIX - 1) == 0) {
pi->pi_pty = devname(dp->d_name);
if (pi->pi_pty == NULL)
return(0);
pi->pi_tty = malloc((unsigned)(strlen(pi->pi_pty) + 1));
if (pi->pi_tty == NULL) {
free(pi->pi_pty);
return(0);
}
(void)strcpy(pi->pi_tty, pi->pi_pty);
pi->pi_tty[PT_INDEX] = 't';
if (access(pi->pi_pty, 0) == 0 && access(pi->pi_tty, 0) == 0) {
pi->pi_next = ptylist;
ptylist = pi;
pi = NULL;
} else {
free(pi->pi_pty);
free(pi->pi_tty);
}
}
return(0);
}
openpty(pt)
struct ptydesc *pt;
{
register struct ptyinfo *pi;
static int fail;
auto struct direct **dirlist;
extern char *re_comp();
extern int alphasort();
/*
* If scandir() fails or no possible pty's are found, then "fail"
* is set non-zero. If "fail" is non-zero then the routine bombs
* out immediately. Otherwise, the list of candidates is examined
* starting with the entry following the last one chosen.
*/
if (fail)
return(-1);
if (!ptylist) { /* first time */
if (scandir(DEV_DIR, &dirlist, isapty, alphasort) < 0 ||
ptylist == NULL) {
fail = 1;
return(-1);
}
for (pi=ptylist; pi->pi_next; pi=pi->pi_next)
;
pi->pi_next = ptylist; /* make the list circular */
}
pi = ptylist;
do {
if ((pt->pt_pfd = open(pi->pi_pty, O_RDWR)) >= 0) {
if ((pt->pt_tfd = open(pi->pi_tty, O_RDWR)) >= 0) {
ptylist = pi->pi_next;
pt->pt_pname = pi->pi_pty;
pt->pt_tname = pi->pi_tty;
return(0);
} else
(void)close(pt->pt_pfd);
}
pi = pi->pi_next;
} while (pi != ptylist);
return(-1);
}
*/
#include
#include
#include
#include
#include "openpty.h"
#define DEV_DIR "/dev" /* directory where devices live */
#define PT_INDEX (sizeof DEV_DIR) /* location of 'p'server/uw_clk.c 600 11722 76400 3051 4750124245 7173 /*
* uw_clk - timer support for UW
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include "uw_param.h"
#include "uw_clk.h"
static struct timeout *pending;
static struct timeout *freelist;
int timer_rdy; /* nonzero when some timeout is ready to run */
clk_timeout(secs, fn, arg)
int secs;
void (*fn)();
toarg_t arg;
{
register struct timeout *to, **tol;
register time_t curtime;
extern time_t time();
to = freelist;
if (!to) {
if (!(to = (struct timeout *)malloc(sizeof *to)))
return(-1);
} else
freelist = to->to_next;
to->to_fn = fn;
to->to_arg = arg;
if (secs < 0)
secs = 0;
curtime = time((time_t *)0);
to->to_when = curtime + secs;
tol = &pending;
while (*tol && to->to_when > (*tol)->to_when)
tol = &(*tol)->to_next;
to->to_next = *tol;
*tol = to;
clk_service();
return(0);
}
clk_service()
{
register struct timeout *to;
register time_t curtime;
curtime = time((time_t *)0);
while ((to=pending) && to->to_when <= curtime) {
pending = to->to_next;
if (to->to_fn) {
(*to->to_fn)(to->to_arg);
to->to_next = freelist;
freelist = to;
}
}
timer_rdy = 0;
if (pending)
(void)alarm((unsigned)(pending->to_when - curtime));
}
void
clk_alarm()
{
/*
* A SIGALRM has been received.
*/
timer_rdy = 1;
}
clk_init()
{
timer_rdy = 0;
(void)signal(SIGALRM, clk_alarm);
}
(void)strcpy(fullname, DEV_DIR);
(void)strcat(fullname, "/");
(void)strcat(fullname, name);
}
return(fullname);
}
static
isapty(dp)
struct direct *dp;
{
static struct ptyinfo *pi;
/*
* We don't care about the gory details of the directory entry.
* Instead, what we really want is an array of pointers to
* device names (with DEV_DIR prepended). Therefore, we create
* this array ourselves and tell scandir() to ignore every
* directory entry.
*
server/uw_env.c 600 11722 76400 3166 4750124246 7222 /*
* uw_env - environment manipulation
*
* Copyright 1985,1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#define MAXENV 128 /* maximum number of arguments in environment */
static char *earray[MAXENV+1];
env_set(env)
char **env;
{
register char **ep1, **ep2, *cp;
char **ep3;
extern char **environ;
/*
* Merge the set of environment strings in "env" into the
* environment.
*/
/*
* The first time through, copy the environment from its
* original location to the array "earray". This makes it a
* little easier to change things.
*/
if (environ != earray) {
ep1=environ;
ep2=earray;
while(*ep1 && ep2 <= earray+MAXENV)
*ep2++ = *ep1++;
*ep2++ = (char *)0;
environ = earray;
}
/*
* If "env" is non-NULL, it points to a list of new items to
* be added to the environment. These replace existing items
* with the same name.
*/
if (env) {
for (ep1=env; *ep1; ep1++) {
for (ep2=environ; *ep2; ep2++)
if (!env_cmp(*ep1, *ep2))
break;
if (ep2 < earray+MAXENV) {
if (!*ep2)
ep2[1] = (char *)0;
*ep2 = *ep1;
}
}
}
/* Finally, use an insertion sort to put things in order. */
for (ep1=environ+1; cp = *ep1; ep1++) {
for(ep2=environ; ep2 < ep1; ep2++)
if (env_cmp(*ep1, *ep2) < 0)
break;
ep3 = ep2;
for(ep2=ep1; ep2 > ep3; ep2--)
ep2[0] = ep2[-1];
*ep2 = cp;
}
}
static
env_cmp(e1, e2)
register char *e1, *e2;
{
register d;
do {
if (d = *e1 - *e2++)
return(d);
} while (*e1 && *e1++ != '=');
return(0);
}
cat(fullname, name);
}
return(fullname);
}
static
isapty(dp)
struct direct *dp;
{
static struct ptyinfo *pi;
/*
* We don't care about the gory details of the directory entry.
* Instead, what we really want is an array of pointers to
* device names (with DEV_DIR prepended). Therefore, we create
* this array ourselves and tell scandir() to ignore every
* directory entry.
*
server/uw_fd.c 600 11722 76400 1547 4750124246 7024 /*
* uw_fd - file-descriptor/select data
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include "uw_param.h"
#include "uw_fd.h"
struct selmask selmask[2];
struct fdmap fdmap[FD_SETSIZE];
fildes_t nfds; /* number of file descriptors */
fd_init()
{
register fildes_t fd;
nfds = getdtablesize();
if (nfds > FD_SETSIZE)
nfds = FD_SETSIZE;
fdmap[0].f_type = FDT_MAC;
fdmap[1].f_type = FDT_MAC;
fdmap[2].f_type = FDT_DEBUG;
for (fd=3; fd < FD_SETSIZE; fd++) {
fdmap[fd].f_type = FDT_NONE;
(void)close(fd);
}
FD_ZERO(&selmask[0].sm_rd);
FD_ZERO(&selmask[0].sm_wt);
FD_ZERO(&selmask[0].sm_ex);
}
fd_exit()
{
register fildes_t fd;
for (fd=3; fd < nfds; fd++)
(void)close(fd);
}
non-NULL, it points to a list of new items to
* be added to the environment. These replace existing items
* with the same name.
*/
if (env) {
server/uw_main.c 600 11722 76400 21264 4750124247 7376 /*
* uw - UNIX windows program for the Macintosh (host end)
*
* Copyright 1985,1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "uw_param.h"
#include "uw_clk.h"
#include "uw_opt.h"
#include "uw_win.h"
#include "uw_fd.h"
#include "uw_pcl.h"
#include "uw_ipc.h"
#include "openpty.h"
int nflag; /* no startup file */
int sflag; /* "secure" (hee hee) -- no network requests */
int errflag; /* argument error */
char *rcfile; /* ".uwrc" file name */
extern void rc_kludge(); /* horrible hack (see rc_kludge()) */
main(argc, argv)
char **argv;
{
register int c;
register fildes_t fd;
extern int calloptscan;
extern int errno;
extern int optind;
extern char *optarg;
/*
* Make sure we don't accidentally try to run this inside itself.
*/
if (getenv(UIPC_ENV)) {
fprintf(stderr, "%s is already running\n", *argv);
exit(1);
}
/*
* Process command-line arguments.
*/
while ((c=getopt(argc, argv, "f:ns")) != EOF) {
switch (c) {
case 'f':
if (nflag) {
fprintf(stderr,
"Cannot specify both \"-f\" and \"-n\"\n");
nflag = 0;
}
rcfile = optarg;
break;
case 'n':
if (rcfile != (char *)0) {
fprintf(stderr,
"Cannot specify both \"-f\" and \"-n\"\n");
rcfile = (char *)0;
}
nflag = 1;
break;
case 's':
sflag = 1;
break;
case '?':
default:
errflag = 1;
break;
}
}
if (errflag) {
fprintf(stderr, "Usage: \"%s [-f file] [-n] [-s]\"\n", *argv);
exit(1);
}
/*
* Initialize the file descriptor table.
*/
fd_init();
FD_SET(0, &selmask[0].sm_rd);
/*
* If we can open the "/etc/utmp" for write, do so.
* Immediately afterwards, we lose any magic powers that
* might have allowed us to do this.
*/
#ifdef UTMP
fd = open("/etc/utmp", O_WRONLY);
(void)setgid(getgid());
(void)setuid(getuid());
if (fd >= 0)
fdmap[fd].f_type = FDT_OTHER;
utmp_init(fd);
#endif
/*
* Initialize the window structures.
*/
win_init();
/*
* Initialize timeouts.
*/
clk_init();
/*
* Create a UNIX-domain network address, and put its name into
* the environment so that descendents can contact us with new
* window requests. If we want to be "secure", we don't allow
* any UNIX-domain messages to come in.
*/
ipc_init(!sflag);
if (!sflag)
clk_timeout(5, rc_kludge, (toarg_t)0);
/*
* Ignore interrupts, quits, and terminal stops. Clean up and exit
* if a hangup or termination is received. Also catch changes in
* child status (so that we can wait for them). Set up the terminal
* modes.
*/
(void)signal(SIGHUP, done);
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGTERM, done);
(void)signal(SIGTSTP, SIG_IGN);
(void)signal(SIGCHLD, cwait);
tty_mode(1);
/*
* Tell the Macintosh to initialize.
*/
pcl_entry(0);
/*
* Create window 1 (to start things off) and wait for input.
* When input is available, process it.
*/
if (!nflag)
finduwrc();
while (1) {
CLK_CHECK();
if (calloptscan && protocol->p_chkopt) {
calloptscan = 0;
(*protocol->p_chkopt)(0);
}
selmask[1] = selmask[0];
if (select(nfds, &selmask[1].sm_rd, &selmask[1].sm_wt,
&selmask[1].sm_ex, (struct timeval *)0) < 0) {
if (errno == EINTR)
continue;
perror("select");
done(1); /* for now -- fix this! */
}
for (fd=0; fd < nfds; fd++) {
if (FD_ISSET(fd, &selmask[1].sm_rd)) {
switch (fdmap[fd].f_type) {
case FDT_MAC:
PCL_RECV(0, (char *)0, 0);
break;
case FDT_UDSOCK:
ipc_udrecv(fd);
break;
case FDT_ISSOCK:
ipc_isrecv(fd);
break;
case FDT_DATA:
PCL_XMIT(0, fdmap[fd].f_win);
break;
case FDT_CTL:
ipc_ctlrecv(0, fd, fdmap[fd].f_win);
break;
default:
/* "can't happen" */
FD_CLR(fd, &selmask[0].sm_rd);
break;
}
}
if (FD_ISSET(fd, &selmask[1].sm_wt)) {
/* "can't happen" */
FD_CLR(fd, &selmask[0].sm_wt);
break;
}
if (FD_ISSET(fd, &selmask[1].sm_ex)) {
/* "can't happen" */
FD_CLR(fd, &selmask[0].sm_ex);
break;
}
}
}
}
finduwrc()
{
register struct passwd *pw;
register char *homedir;
/*
* If the global variable "rcfile" is non-NULL, then it specifies
* the name of the startup file. Otherwise, the name of the startup
* file is "$HOME/.uwrc". If $HOME is undefined or null, the password
* file is consulted. The ".uwrc" file is an executable program or
* "/bin/sh" command file. (For "csh" (ugh) use "#! /bin/csh".)
*
* Returns 0 if the ".uwrc" file doesn't exist, 1 if it does. As
* a side-effect, this routine sets the global variable "rcfile"
* to the name of the ".uwrc" file.
*/
if (rcfile == (char *)0) {
if ((homedir=getenv("HOME")) == NULL || !*homedir) {
if ((pw = getpwuid(getuid())) != NULL)
homedir = pw->pw_dir;
else
return;
}
rcfile = malloc((unsigned)(strlen(homedir) + sizeof "/.uwrc"));
if (rcfile == (char *)0)
return;
(void)strcpy(rcfile, homedir);
(void)strcat(rcfile, "/.uwrc");
}
if (access(rcfile, F_OK) < 0)
rcfile = (char *)0;
}
runuwrc()
{
register int pid;
register fildes_t fd;
struct ptydesc pt;
/*
* We use a real fork (rather than a vfork()) because the parent
* doesn't wait for the child. The caller knows that the file
* exists; however, it cannot determine whether or not it is
* successfully executed.
*
* We acquire a pseudo-terminal for rather convoluted reasons.
* Programs such as "uwtool" expect to be able to inherit tty
* modes from their controlling terminal. By the time that we
* reach this point, we've already changed our controlling
* terminal to use cbreak mode with no special characters except
* XON/XOFF. Therefore, we obtain a pseudo-terminal and
* restore our original modes onto it. We double-fork (sigh,
* another miserable kludge) so that the server does not have
* to wait for the completion of the ".uwrc" file. (The child
* waits for the grandchild so that the master side of the pty
* remains open until the grandchild is finished.)
*/
if (openpty(&pt) < 0)
return;
while ((pid = fork()) < 0)
sleep(5);
if (pid > 0) {
(void)close(pt.pt_pfd);
(void)close(pt.pt_tfd);
} else {
/* child */
while ((pid = fork()) < 0)
sleep(5);
if (pid > 0) {
while (wait((int *)0) < 0 && errno == EINTR)
;
_exit(1);
/*NOTREACHED*/
} else {
/* grandchild */
(void)setgid(getgid());
(void)setuid(getuid());
(void)close(pt.pt_pfd);
if (pt.pt_tfd != 0)
(void)dup2(pt.pt_tfd, 0);
if (pt.pt_tfd != 1);
(void)dup2(pt.pt_tfd, 1);
if (pt.pt_tfd != 2)
(void)dup2(pt.pt_tfd, 2);
win_envinit(defwtype, (long)0);
(void)signal(SIGHUP, SIG_DFL);
(void)signal(SIGINT, SIG_DFL);
(void)signal(SIGQUIT, SIG_DFL);
(void)signal(SIGTERM, SIG_DFL);
(void)signal(SIGTSTP, SIG_IGN);
(void)signal(SIGCHLD, SIG_DFL);
(void)ioctl(open("/dev/tty",O_RDWR),
(int)TIOCNOTTY, (char *)0);
(void)open(pt.pt_tname, O_RDONLY);
for (fd=3; fd < nfds; fd++)
(void)close(fd);
tty_mode(0);
(void)execlp(rcfile, rcfile, (char *)0);
(void)execl("/bin/sh", "sh", rcfile, (char *)0);
_exit(1);
/*NOTREACHED*/
}
}
}
void
rc_kludge()
{
static int firsttime = 1;
/*
* A problem which occurs with ".uwrc" file handling is that
* the "rc" file is interpreted immediately after the server
* begins, i.e. before it and the Macintosh have (possibly)
* changed from the default protocol to an extended one.
*
* To get around this problem, if a ".uwrc" file exists, it
* is not executed immediately. Instead, it will be executed
* when this routine is called, either directly by pcl_newpcl()
* when the protocol changes, or after an initial timeout.
*
* It is most unfortunate that "pcl_newpcl" must call "upwards"
* into this source file.
*/
if (firsttime) {
firsttime = 0;
if (rcfile != (char *)0)
runuwrc();
else
(void)PCL_NEWW(0, WC_INTERNAL, defwtype, (nwin_t)1, 0L,
(fildes_t)-1, (fildes_t)-1);
}
}
void
done(s)
{
/*
* Clean up and exit. It is overkill to close all of the file
* descriptors, but it causes no harm.
*/
pcl_exit(0);
utmp_exit();
fd_exit();
ipc_exit();
tty_mode(0);
exit(s);
}
void
cwait()
{
register int pid;
union wait status;
struct rusage rusage;
/*
* Collect dead children. Restart any children that have stopped.
*/
while ((pid=wait3(&status, WNOHANG|WUNTRACED, &rusage)) > 0)
if (WIFSTOPPED(status))
(void)kill(pid, SIGCONT);
}
int sflag; /* "secure" (hee hee) -- no network requests */
int errflag; /* argument error */
char *rcfile; /* ".uwrc" file name */
extern void rc_kludge(); /* horrible hack (see rc_kludge()) */
main(argc, argv)
char **argv;
{
register int c;
register fildes_t fd;
extern int calloptscan;
extern int errno;
extern int oserver/uw_ipc.c 600 11722 76400 32176 4750124251 7224 /*
* uw IPC
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "uw_param.h"
#include "uw_err.h"
#include "uw_opt.h"
#include "uw_win.h"
#include "uw_fd.h"
#include "uw_pcl.h"
#include "uw_ipc.h"
#ifndef ntohs
/* declaring these as one-element arrays or as NULL pointers is a HACK */
extern unsigned long ntohl(), htonl();
extern unsigned short ntohs(), htons();
static struct netadj na_ntoh[1] = {
(short (*)())ntohs, (long (*)())ntohl, ntohs, ntohl
};
static struct netadj na_hton[1] = {
(short (*)())htons, (long (*)())htonl, htons, htonl
};
#else
static struct netadj *na_ntoh = NULL;
static struct netadj *na_hton = NULL;
#endif
static int have_udport;
static char uipc_port[] = "/tmp/uwXXXXXX";
static int inet_sd;
static struct ipcmsg {
int im_len;
struct uwipc im_msg;
} *inet_buf;
extern int errno;
ipc_init(use_uipc)
{
ipc_isinit();
if (use_uipc)
ipc_udinit();
}
/*
* UNIX-domain
*/
static
ipc_udinit()
{
register int len;
register char *cp;
register fildes_t sd;
auto struct sockaddr_un sa;
auto char *env[2];
extern char *mktemp();
len = strlen(UIPC_ENV) + sizeof uipc_port + 1;
if ((cp = malloc(len)) != NULL) {
(void)sprintf(cp, "%s=%s", UIPC_ENV, mktemp(uipc_port));
env[0] = cp;
env[1] = (char *)0;
env_set(env);
sa.sun_family = AF_UNIX;
(void)strncpy(sa.sun_path, uipc_port, sizeof sa.sun_path-1);
sa.sun_path[sizeof sa.sun_path-1] = '\0';
if ((sd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0 &&
bind(sd,&sa,sizeof sa.sun_family+strlen(sa.sun_path)) >= 0){
have_udport = 1;
(void)chmod(uipc_port, S_IREAD|S_IWRITE);
(void)fcntl(sd, F_SETFL, FNDELAY);
fdmap[sd].f_type = FDT_UDSOCK;
FD_SET(sd, &selmask[0].sm_rd);
}
}
}
ipc_exit()
{
if (have_udport)
(void)unlink(uipc_port);
}
ipc_udrecv(sd)
register fildes_t sd;
{
register struct window *w;
register int cnt;
struct msghdr msg;
auto int fd;
struct iovec iov;
struct stat st1, st2;
union {
struct uwipc uwip;
char data[1024];
} buf;
/*
* main() calls this routine when there is a message waiting on
* the UNIX-domain socket. The message's access rights are
* expected to contain the file descriptor for the "master" side
* of a pseudo-tty. The message contains the name of the pty.
* The sender is expected to start up a process on the slave side
* of the pty. This allows the host end to create windows which
* run something other than the shell.
*/
fd = -1;
iov.iov_base = (caddr_t)buf.data;
iov.iov_len = sizeof buf - 1;
msg.msg_name = (caddr_t)0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_accrights = (caddr_t)&fd;
msg.msg_accrightslen = sizeof fd;
if ((cnt=recvmsg(sd, &msg, 0)) < 0 || cnt != buf.uwip.uwip_len)
return;
switch (buf.uwip.uwip_cmd) {
case UWC_NEWT:
if (msg.msg_accrightslen > 0 && fd >= 0) {
/*
* We can't trust the process which connected to us,
* so we verify that it really passed us a pseudo-tty's
* file descriptor by checking the device name and its
* inode number. [Of course, if someone else wants to
* hand us a terminal session running under their
* uid....]
*/
if (cnt == sizeof buf)
cnt--;
buf.data[cnt] = '\0';
if (strncmp(buf.uwip.uwip_newt.uwnt_pty,
"/dev/pty", sizeof "/dev/pty"-1) ||
fstat(fd, &st1) < 0 ||
stat(buf.uwip.uwip_newt.uwnt_pty, &st2) < 0 ||
st1.st_dev != st2.st_dev ||
st1.st_ino != st2.st_ino) {
(void)close(fd);
return;
}
/*
* OK, we believe the sender. We allocate a window and
* tell the Macintosh to create that window on its end.
* If we have no free windows, then we close the file
* descriptor (which will terminate the slave process).
*/
w = PCL_NEWW(0, WC_INTERNAL,
buf.uwip.uwip_newt.uwnt_type,
(nwin_t)0, buf.uwip.uwip_newt.uwnt_id,
fd, (fildes_t)-1);
if (w != NULL) {
(void)strncpy(w->w_tty,
buf.uwip.uwip_newt.uwnt_pty,
sizeof w->w_tty-1);
w->w_tty[5] = 't'; /* switch to "/dev/ttyp?" */
utmp_add(w->w_tty);
} else
(void)close(fd);
}
break;
case UWC_OPTION:
w = win_search(buf.uwip.uwip_option.uwop_id,
protocol->p_maxwin);
if (w != NULL) {
opt_extopt((caddr_t)w, &w->w_optdefn,
(woptcmd_t)buf.uwip.uwip_option.uwop_cmd,
(woption_t)buf.uwip.uwip_option.uwop_opt,
(char *)&buf.uwip.uwip_option.uwop_val,
(struct netadj *)0);
}
break;
}
}
/*
* Internet domain
*/
static
ipc_isinit()
{
register fildes_t sd;
register char *cp;
struct hostent *h;
struct sockaddr_in sin;
auto int sinlen;
char hostname[32];
char *env[2];
/*
* Allocate enough buffers for each file descriptor to have one.
* This is overkill.
*/
inet_buf = (struct ipcmsg *)malloc(nfds * sizeof(struct ipcmsg));
if (inet_buf == NULL)
return;
/*
* Determine our host name and get an Internet stream socket.
* We really should specify the protocol here (rather than 0)
* but we "know" that it defaults to TCP.
*/
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return;
sin.sin_family = AF_INET;
sin.sin_port = 0;
bzero(sin.sin_zero, sizeof sin.sin_zero);
if (gethostname(hostname, sizeof hostname) < 0 || hostname[0] == '\0')
(void)strcpy(hostname, "localhost");
if ((h = gethostbyname(hostname)) != NULL)
bcopy(h->h_addr, (char *)&sin.sin_addr, h->h_length);
else
sin.sin_addr.s_addr = htonl(0x7f000001L); /* 128.0.0.1 (lo0) */
if (bind(sd, &sin, sizeof sin) < 0) {
/*
* Unable to bind to unspecified port -- try once more with
* loopback device. If we already were using the loopback
* device we just suffer the inefficiency of doing this twice.
*/
sin.sin_addr.s_addr = htonl(0x7f000001L);
if (bind(sd, &sin, sizeof sin) < 0) {
(void)close(sd);
return;
}
}
/*
* Listen for incoming connections
*/
if (listen(sd, NWINDOW) < 0) {
(void)close(sd);
return;
}
/*
* Determine our port number and put our address in the environment.
*/
sinlen = sizeof sin;
if (getsockname(sd, (char *)&sin, &sinlen) < 0) {
/* huh? Oh well, give up */
(void)close(sd);
return;
}
if ((cp = malloc(sizeof INET_ENV + 1 + 8 + 1 + 5)) == NULL) {
/* no memory, give up */
(void)close(sd);
return;
}
sprintf(cp, "%s=%08lx.%05u", INET_ENV,
ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port));
env[0] = cp;
env[1] = (char *)0;
env_set(env);
inet_sd = sd;
fdmap[sd].f_type = FDT_ISSOCK;
FD_SET(sd, &selmask[0].sm_rd);
}
ipc_isrecv(sd)
register fildes_t sd;
{
register fildes_t fd;
register struct uwipc *uwip;
register struct window *w;
register uwerr_t uwerr;
register int len;
struct sockaddr sin;
struct uwipc reply;
auto int sinlen;
/*
* This routine is called when one of two conditions occur. It is
* called when an outside process tries to establish a steam
* Internet connection.
*
* Later, as soon as data is available, this routine will be
* called again to handle the external message (which must be
* a "new window" command).
*/
if (sd == inet_sd) {
sinlen = sizeof sin;
if ((fd = accept(sd, &sin, &sinlen)) >= 0) {
(void)fcntl(fd, F_SETFL, FNDELAY);
fdmap[fd].f_type = FDT_ISSOCK;
fdmap[fd].f_win = (struct window *)0;
FD_SET(fd, &selmask[0].sm_rd);
inet_buf[fd].im_len = 0;
}
} else {
switch (ipc_getmsg(sd, inet_buf + sd)) {
case -1:
(void)close(sd);
fdmap[sd].f_type = FDT_NONE;
FD_CLR(sd, &selmask[0].sm_rd);
FD_CLR(sd, &selmask[0].sm_wt);
FD_CLR(sd, &selmask[0].sm_ex);
break;
case 1:
uwip = &inet_buf[sd].im_msg;
uwerr = UWE_NONE;
if ((uwip->uwip_len < sizeof(struct uwneww) +
((char *)&uwip->uwip_neww - (char *)uwip)) ||
uwip->uwip_cmd != UWC_NEWW) {
uwerr = UWE_NXTYPE;
} else {
fd = ipc_ctlopen(sd,
(unsigned)uwip->uwip_neww.uwnw_ctlport);
w = PCL_NEWW(0, WC_EXTERNAL,
ntohs(uwip->uwip_neww.uwnw_type),
(nwin_t)0, ntohl(uwip->uwip_neww.uwnw_id),
sd, fd);
if (w == (struct window *)0)
uwerr = UWE_NXTYPE; /* for now */
else
uwerr = UWE_NONE;
}
len = sizeof(struct uwstatus) +
((char *)&reply.uwip_status - (char *)&reply);
reply.uwip_len = htons(len);
reply.uwip_cmd = htons(UWC_STATUS);
reply.uwip_status.uwst_err = htons(uwerr);
reply.uwip_status.uwst_errno = htons(errno);
if (uwerr == UWE_NONE)
reply.uwip_status.uwst_id = htonl(w->w_id);
else
reply.uwip_status.uwst_id = 0;
(void)write(sd, (char *)&reply, len);
if (uwerr != UWE_NONE) {
(void)close(sd);
fdmap[sd].f_type = FDT_NONE;
FD_CLR(sd, &selmask[0].sm_rd);
FD_CLR(sd, &selmask[0].sm_wt);
FD_CLR(sd, &selmask[0].sm_ex);
}
inet_buf[sd].im_len = 0;
}
}
}
ipc_ctlopen(sd, port)
fildes_t sd;
unsigned port;
{
register int fd;
auto struct sockaddr_in sin;
auto int sinlen;
/*
* Create a control socket and connect it to the same host as
* "sd" on the specified port.
*/
sinlen = sizeof sin;
if (port == 0 ||
getpeername(sd, (struct sockaddr *)&sin, &sinlen) < 0 ||
(fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return(-1);
} else {
sin.sin_port = port;
(void)fcntl(fd, F_SETFL, FNDELAY);
if (connect(fd, &sin, sinlen) < 0 && errno != EINPROGRESS) {
(void)close(fd);
return(-1);
} else
return(fd);
}
}
void
ipc_optmsg(win, optcmd, optnum, data, datalen)
caddr_t win;
woptcmd_t optcmd;
woption_t optnum;
char *data;
unsigned datalen;
{
register struct window *w;
register int len;
struct uwipc uwip;
/*
* Propagate a window option message (WILL, WONT, SET) from the Mac
* to the remote process (external windows only).
*/
if ((w = (struct window *)win) != NULL && w->w_alloc &&
w->w_class == WC_EXTERNAL && w->w_ctlfd >= 0 &&
optnum <= WONUM_MAX && (optcmd == WOC_WILL || optcmd == WOC_WONT ||
(optcmd == WOC_SET && data != NULL))) {
len = datalen +
((char *)&uwip.uwip_option.uwop_val - (char *)&uwip);
uwip.uwip_len = htons(len);
uwip.uwip_cmd = htons(UWC_OPTION);
uwip.uwip_option.uwop_id = htonl(w->w_id);
uwip.uwip_option.uwop_opt = htons(optnum);
uwip.uwip_option.uwop_cmd = htons(optcmd);
if (optcmd == WOC_SET) {
bcopy(data, (char *)&uwip.uwip_option.uwop_val,
(int)datalen);
opt_netadj(w->w_optdefn.wod_optlst[optnum].wol_argdefn,
(char *)&uwip.uwip_option.uwop_val, na_hton);
}
(void)write(w->w_ctlfd, (char *)&uwip, len);
}
}
ipc_ctlrecv(mfd, sd, win)
fildes_t mfd;
register fildes_t sd;
register struct window *win;
{
register struct window *w;
register struct uwipc *uwip;
switch (ipc_getmsg(sd, inet_buf + sd)) {
case -1:
(void)close(sd);
fdmap[sd].f_type = FDT_NONE;
FD_CLR(sd, &selmask[0].sm_rd);
FD_CLR(sd, &selmask[0].sm_wt);
FD_CLR(sd, &selmask[0].sm_ex);
break;
case 1:
uwip = &inet_buf[sd].im_msg;
switch (uwip->uwip_cmd) {
case UWC_KILLW:
if ((uwip->uwip_len == sizeof(struct uwkillw) +
((char *)&uwip->uwip_killw - (char *)uwip))) {
w = win_search(ntohl(uwip->uwip_killw.uwkw_id),
protocol->p_maxwin);
if (w == win)
PCL_KILLW(mfd, w);
}
break;
case UWC_OPTION:
/* hope the message is long enough... sigh */
if (uwip->uwip_len >
((char *)&uwip->uwip_option.uwop_val - (char *)uwip)) {
w = win_search(ntohl(uwip->uwip_option.uwop_id),
protocol->p_maxwin);
if (w == win) {
opt_extopt((caddr_t)w, &w->w_optdefn,
(woptcmd_t)ntohs(uwip->uwip_option.uwop_cmd),
(woption_t)ntohs(uwip->uwip_option.uwop_opt),
(char *)&uwip->uwip_option.uwop_val,
na_ntoh);
}
}
break;
}
inet_buf[sd].im_len = 0;
}
}
ipc_getmsg(sd, im)
register fildes_t sd;
register struct ipcmsg *im;
{
register int len;
register char *cp;
/*
* Read some more bytes from socket "sd" into the message buffer
* contained in "im". Return 1 if the message is now complete,
* -1 if an EOF was reached, or 0 otherwise. Before returning 1,
* the byte order of the common parameters (command, length) is
* changed from network to host order.
*
* This routine expects the socket to use non-blocking I/O (which
* is enabled by ipc_isrecv() when the connection is accepted).
*/
cp = (char *)&im->im_msg + im->im_len;
if (im->im_len < sizeof(im->im_msg.uwip_len)) {
len = read(sd, cp, sizeof im->im_msg.uwip_len - im->im_len);
if (len == 0 || (len < 0 && errno != EWOULDBLOCK))
return(-1);
if ((im->im_len += len) < sizeof im->im_msg.uwip_len)
return(0);
im->im_msg.uwip_len = ntohs(im->im_msg.uwip_len);
if (im->im_msg.uwip_len == sizeof im->im_msg.uwip_len)
return(1);
cp += len;
}
if (im->im_msg.uwip_len > sizeof(struct ipcmsg))
im->im_msg.uwip_len = sizeof(struct ipcmsg);
len = read(sd, cp, im->im_msg.uwip_len - im->im_len);
if (len == 0)
return(-1);
if (len < 0)
return((errno==EWOULDBLOCK) ? 0 : -1);
if ((im->im_len += len) == im->im_msg.uwip_len) {
im->im_msg.uwip_cmd = ntohs(im->im_msg.uwip_cmd);
return(1);
} else
return(0);
}
d(getgid());
(void)setuid(getuid());
(void)close(pt.pt_pfd);
if (pt.pt_tfd != 0)
(void)dup2(pt.pt_tfd, 0);
if (pt.pt_tfd != 1);
(void)dup2(pt.pt_tfd, 1);
if (pt.pt_tfd != 2)
(void)dup2(pt.pt_tfd, 2);
win_envinit(defwtype, (long)0);
(void)signal(SIGHUP, SIG_DFL);
(void)signal(SIGINT, SIG_DFL);
(void)signal(SIGQUIT, SIG_DFL);
(void)signal(SIGTEserver/uw_opt.c 600 11722 76400 33717 4750124253 7257 /*
* uw_opt - window option handling for UW
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include "uw_param.h"
#include "uw_opt.h"
/*
* The following variable is a kludge for efficiency. It is set to
* a nonzero value when a bitmask is changed, indicating that opt_scan()
* should be called.
*/
int calloptscan; /* pending,do,dont awaits opt_scan */
/* option input state variables */
static caddr_t optwin; /* window */
static struct woptdefn *optwod; /* window option definition */
static woptcmd_t optcmd; /* option command */
static woption_t optnum; /* current option number */
static woptarg_t *optarg; /* current encoding */
static int optcnt; /* count in current encoding */
static char *optout; /* decoded option */
static char optbuf[512]; /* buffer for decoded option */
opt_new(wod, generic, unique)
register struct woptdefn *wod, *generic, *unique;
{
register int n, mask;
/*
* Set up the option definition structure pointed to by "wod" to
* correspond with the option definitions in "generic" (common to
* all window types) and "unique" (per-window).
*/
mask = (1<<(WONUM_GENERIC+1))-1;
if (unique) {
wod->wod_askrpt = unique->wod_askrpt & ~mask;
wod->wod_pending = unique->wod_pending & ~mask;
for (n=WONUM_GENERIC+1; n <= WONUM_MAX; n++)
wod->wod_optlst[n] = unique->wod_optlst[n];
} else {
wod->wod_askrpt = 0;
wod->wod_pending = 0;
for (n=WONUM_GENERIC+1; n <= WONUM_MAX; n++)
wod->wod_optlst[n].wol_argdefn = (woptarg_t *)0;
}
if (generic) {
wod->wod_askrpt |= generic->wod_askrpt & mask;
wod->wod_pending |= generic->wod_pending & mask;
for (n=1; n <= WONUM_GENERIC; n++)
wod->wod_optlst[n] = generic->wod_optlst[n];
} else {
for (n=1; n <= WONUM_GENERIC; n++)
wod->wod_optlst[n].wol_argdefn = (woptarg_t *)0;
}
wod->wod_do = wod->wod_askrpt;
wod->wod_dont = 0;
wod->wod_inquire = 0;
calloptscan = 1;
}
opt_renew(wod, report)
register struct woptdefn *wod;
int report;
{
/*
* Reset "wod_do" for all window options that we want the Macintosh
* to report to us. If "report" is nonzero, send the Mac the
* current values of these options.
*/
wod->wod_do = wod->wod_askrpt;
wod->wod_dont = 0;
if (report)
wod->wod_pending = wod->wod_askrpt;
calloptscan = 1;
}
opt_newtype(wod, generic, unique)
register struct woptdefn *wod, *generic, *unique;
{
register int n, bit;
register woptbmask_t oldask;
/*
* Change the window options to reflect a new window emulation type.
* The new emulation may not support all of the events that the old
* one did, and in any event they may not mean the same thing.
*/
oldask = wod->wod_askrpt;
opt_new(wod, generic, unique);
for (n=1, bit=2; n <= WONUM_GENERIC; n++,bit<<=1) {
if ((oldask&bit) && !(wod->wod_askrpt&bit))
wod->wod_dont |= bit;
if (!(oldask&bit) && (wod->wod_askrpt&bit))
wod->wod_do |= bit;
}
for ( ; n <= WONUM_MAX; n++, bit<<=1)
if (wod->wod_askrpt&bit)
wod->wod_do |= bit;
calloptscan = 1;
}
opt_setext(wod, fn)
register struct woptdefn *wod;
register void (*fn)();
{
register int n;
/*
* Set "wol_ext" to "fn" for each option that has a defined "wol_set".
*/
for (n=1; n <= WONUM_MAX; n++)
if (wod->wod_optlst[n].wol_set)
wod->wod_optlst[n].wol_ext = fn;
}
opt_scan(w, wod, fn, mfd, cmd)
caddr_t w;
register struct woptdefn *wod;
void (*fn)();
fildes_t mfd;
int cmd;
{
register struct woptlst *wol;
register char *cp;
register int n, bit, maxsize;
char buf[512];
/*
* Scan the entire list of options for pending ones. For each
* one, call "fn". "cmd" is the command that we are to pass as the
* first argument to "fn".
*
* Note that we must send data (wod_pending) before processing
* DO commands (wod_do); otherwise, the host and Mac may not
* agree upon the value of a window option. (The Mac might
* respond to the "do" command before it sees the new value.)
*/
cp = buf;
#ifdef notdef
for (n=1,bit=2,wol=wod->wod_optlst+1; n<=WONUM_MAX; n++,bit<<=1,wol++) {
#else
for (n=WONUM_MAX, bit=(1<
n > 0;
n--, bit >>= 1, wol--) {
#endif
if (wod->wod_pending&bit) {
wod->wod_pending &= ~bit;
if (wol->wol_argdefn) {
maxsize = 2 +
opt_size(wol->wol_argdefn);
if (cp > buf + sizeof buf - maxsize - 1) {
*cp++ = 0;
(*fn)(mfd, cmd, buf, cp-buf);
cp = buf;
}
if (WONUM_USELONG(n)) {
*cp++ = WOC_SET|WONUM_LPREFIX;
*cp++ = WONUM_LENCODE(n);
} else
*cp++ = WOC_SET|WONUM_SENCODE(n);
cp += opt_encode(cp, wol->wol_argdefn,
(*wol->wol_get)(w, n));
}
}
if (wod->wod_inquire&bit) {
wod->wod_inquire &= ~bit;
if (cp > buf + sizeof buf - 3) {
*cp++ = 0;
(*fn)(mfd, cmd, buf, cp-buf);
cp = buf;
}
if (wol->wol_argdefn) {
if (WONUM_USELONG(n)) {
*cp++ = WOC_INQUIRE|WONUM_LPREFIX;
*cp++ = WONUM_LENCODE(n);
} else
*cp++ = WOC_INQUIRE|WONUM_SENCODE(n);
}
}
if ((wod->wod_do|wod->wod_dont)&bit) {
if (cp > buf + sizeof buf - 3) {
*cp++ = 0;
(*fn)(mfd, cmd, buf, cp-buf);
cp = buf;
}
if (wod->wod_do&bit) {
wod->wod_do &= ~bit;
wod->wod_dont &= ~bit;
if (wol->wol_argdefn) {
if (WONUM_USELONG(n)) {
*cp++ = WOC_DO|WONUM_LPREFIX;
*cp++ = WONUM_LENCODE(n);
} else
*cp++ = WOC_DO|WONUM_SENCODE(n);
}
} else if (wod->wod_dont&bit) {
wod->wod_do &= ~bit;
wod->wod_dont &= ~bit;
if (wol->wol_argdefn) {
if (WONUM_USELONG(n)) {
*cp++ = WOC_DONT|WONUM_LPREFIX;
*cp++ = WONUM_LENCODE(n);
} else
*cp++=WOC_DONT|WONUM_SENCODE(n);
}
}
}
if (cp > buf) {
*cp++ = 0;
(*fn)(mfd, cmd, buf, cp-buf);
cp = buf;
}
}
}
opt_size(woa)
register woptarg_t *woa;
{
register int size, cnt;
/*
* Determine the maximum size of an option whose argument encoding
* is specified by "woa". This does NOT include additional encoding
* (e.g. for meta characters) at the protocol level.
*/
if (woa) {
for (size=0; *woa != WOA_END; woa++) {
cnt = *woa & ~WOA_CMDMASK;
switch (*woa & WOA_CMDMASK) {
case WOA_CHARS(0):
case WOA_STRING(0):
size += cnt;
break;
case WOA_UDATA(0):
size += (cnt + 5) / 6;
break;
}
}
} else
size = 0;
return(size);
}
opt_encode(buf, woa, data)
char *buf;
register woptarg_t *woa;
char *data;
{
register char *cp, *cq;
register int n, cnt;
register unsigned long ival;
union {
struct {
char c1;
short s;
} cs;
struct {
char c2;
long l;
} cl;
} u;
/*
* Encode "data" according to the option argument specifier "woa"
* into the buffer "buf". Return the number of bytes of "buf"
* actually used. The caller has already verified that "buf" is
* large enough.
*/
if (!data)
return(0);
for (cp=buf,cq=data; *woa != WOA_END; woa++) {
cnt = *woa & ~WOA_CMDMASK;
switch (*woa & WOA_CMDMASK) {
case WOA_CHARS(0):
for (n=0; n < cnt; n++)
*cp++ = *cq++;
break;
case WOA_STRING(0):
for (n=0; n < cnt-1 && *cq; n++)
*cp++ = *cq++;
if (n < cnt)
cq += cnt-n;
*cp++ = '\0';
break;
case WOA_UDATA(0):
if (cnt <= NBBY) {
ival = (unsigned char)*cq++;
} else if (cnt <= sizeof(short)*NBBY) {
while ((int)cq & ((char *)&u.cs.s-&u.cs.c1-1))
cq++;
ival = *(unsigned short *)cq;
cq += sizeof(short);
} else {
while ((int)cq & ((char *)&u.cl.l-&u.cl.c2-1))
cq++;
ival = *(unsigned long *)cq;
cq += sizeof(long);
}
if (cnt != sizeof(long)*NBBY)
ival &= (1<
*cp++ = (ival & 077) | 0100;
break;
}
}
return(cp-buf);
}
opt_istart(w, wod)
caddr_t w;
struct woptdefn *wod;
{
/*
* Start collecting input for a window option specification.
*/
optwin = w;
optwod = wod;
optnum = 0;
}
opt_input(c)
char c;
{
register int cnt, bit;
register struct woptdefn *wod;
register struct woptlst *wol;
register unsigned long ival;
union {
struct {
char c1;
short s;
} cs;
struct {
char c2;
long l;
} cl;
} u;
/*
* Add the received character "c" to the current option specification.
* If it is complete, take the appropriate action. If option 0
* (the endmarker) is received, return 0 (to notify the caller that
* we are done). Otherwise, return 1 -- more option data remains
* to be processed.
*
* This code isn't as readable as it should be; there are far too
* many return statements floating around. Sorry about that.
*/
if (optwin) {
wod = optwod;
if (optnum == 0 || optnum == WONUM_MAX+1) {
/* start (or continue) decoding a new option */
if (optnum == 0) {
/* start new option (or decode endmarker) */
if (c & WONUM_MASK) {
/* new option */
optcmd = c & WOC_MASK;
if (WOC_BADCMD(optcmd)) {
opt_iflush();
return(0);
}
if (c == WONUM_LPREFIX) {
optnum = WONUM_MAX+1;
return(1);
} else
optnum = WONUM_SDECODE(c);
} else {
/* end of options */
opt_iflush();
return(0);
}
} else {
/* read second byte of long option number */
optnum = WONUM_LDECODE(c);
if (optnum > WONUM_MAX) {
opt_iflush();
return(0);
}
}
/*
* This point is reached when the option number has
* been completely decoded. If the command is not
* WOC_SET, then it has no arguments and we can
* process it immediately.
*/
wol = &wod->wod_optlst[optnum];
bit = 1<
optout = optbuf;
optcnt = 0;
optarg = wol->wol_argdefn;
if (!optarg) {
opt_iflush();
return(0);
}
} else {
if (wol->wol_ext &&
(optcmd == WOC_WILL || optcmd == WOC_WONT))
(*wol->wol_ext)(optwin, optcmd,
optnum, (char *)0, 0);
switch (optcmd) {
case WOC_INQUIRE:
wod->wod_pending |= bit;
calloptscan = 1;
break;
case WOC_DO:
case WOC_DONT:
break;
case WOC_WILL:
wod->wod_askrpt |= bit;
wod->wod_do &= ~bit;
break;
case WOC_WONT:
wod->wod_askrpt &= ~bit;
wod->wod_dont &= ~bit;
break;
}
optnum = 0;
}
return(1);
} else {
/* continue processing argument to option */
wol = &wod->wod_optlst[optnum];
bit = 1<
switch (*optarg & WOA_CMDMASK) {
case WOA_CHARS(0):
*optout++ = c;
optcnt++;
break;
case WOA_STRING(0):
*optout++ = c;
optcnt++;
if (!c) {
optout += cnt - optcnt;
optcnt = cnt;
} else if (optcnt == cnt-1) {
*optout++ = '\0';
optcnt = cnt;
}
break;
case WOA_UDATA(0):
if (optcnt == 0) {
if (cnt <= NBBY) {
*optout = 0;
} else if (cnt <= sizeof(short)*NBBY) {
while ((int)optout & ((char *)&u.cs.s-&u.cs.c1-1))
optout++;
*(short *)optout = 0;
} else {
while ((int)optout & ((char *)&u.cl.l-&u.cl.c2-1))
optout++;
*(long *)optout = 0;
}
}
ival = (c & 077) << optcnt;
if (cnt != NBBY*sizeof(long))
ival &= (1<
if (cnt <= NBBY) {
*(unsigned char *)optout |= (unsigned char)ival;
if (optcnt >= cnt)
optout++;
} else if (cnt <= sizeof(short)*NBBY) {
*(unsigned short *)optout |= (unsigned short)ival;
if (optcnt >= cnt)
optout += sizeof(short);
} else {
*(unsigned long *)optout |= ival;
if (optcnt >= cnt)
optout += sizeof(long);
}
break;
}
if (optcnt >= cnt) {
optcnt = 0;
if (*++optarg == WOA_END) {
wod->wod_pending &= ~bit;
(*wol->wol_set)(optwin, optnum, optbuf);
if (wol->wol_ext) {
(*wol->wol_ext)(optwin, WOC_SET,
optnum, optbuf,
optout-optbuf);
}
optnum = 0;
}
}
return(1);
}
/*NOTREACHED*/
}
return(0);
}
opt_iflush()
{
optwin = (caddr_t)0;
}
opt_extopt(w, wod, cmd, num, data, na)
caddr_t w;
register struct woptdefn *wod;
woptcmd_t cmd;
woption_t num;
char *data;
struct netadj *na;
{
register struct woptlst *wol;
if (w != NULL && wod != NULL && num <= WONUM_MAX) {
wol = wod->wod_optlst + num;
if (wol->wol_argdefn) {
switch (cmd) {
case WOC_SET:
if (data && wol->wol_set) {
if (na) {
opt_netadj(wol->wol_argdefn,
data, na);
}
/*
* Set the new value and notify the Mac.
* Because of a race condition (the Mac
* might concurrently be sending us its
* value for this option), we ask the
* Mac to send back the value after it
* is set.
*/
(*wol->wol_set)(w, num, data);
WOPT_SET(wod->wod_pending, num);
WOPT_SET(wod->wod_inquire, num);
calloptscan = 1;
}
break;
case WOC_INQUIRE:
WOPT_SET(wod->wod_inquire, num);
calloptscan = 1;
break;
case WOC_DO:
WOPT_SET(wod->wod_do, num);
WOPT_SET(wod->wod_askrpt, num);
calloptscan = 1;
break;
case WOC_DONT:
WOPT_SET(wod->wod_dont, num);
WOPT_CLR(wod->wod_askrpt, num);
calloptscan = 1;
break;
}
}
}
}
opt_netadj(woa, data, na)
register woptarg_t *woa;
char *data;
register struct netadj *na;
{
register char *cp;
register int cnt;
union {
struct {
char c1;
short s;
} cs;
struct {
char c2;
long l;
} cl;
} u;
/*
* Convert an option (in internal format) from host byte order
* to network byte order. If the two are the same then this is
* a NOP.
*/
if (data && na) {
for (cp=data; *woa != WOA_END; woa++) {
cnt = *woa & ~WOA_CMDMASK;
switch (*woa & WOA_CMDMASK) {
case WOA_CHARS(0):
case WOA_STRING(0):
cp += cnt;
break;
case WOA_UDATA(0):
if (cnt <= NBBY) {
cp++;
} else if (cnt <= sizeof(short)*NBBY) {
while ((int)cp & ((char *)&u.cs.s-&u.cs.c1-1))
cp++;
*(u_short *)cp =
(*na->na_ushort)(*(u_short *)cp);
cp += sizeof(short);
} else {
while ((int)cp & ((char *)&u.cl.l-&u.cl.c2-1))
cp++;
*(u_short *)cp =
(*na->na_ushort)(*(u_short *)cp);
cp += sizeof(long);
}
}
}
}
}
nclude additional encoding
* (e.g. for meta chaserver/uw_pcl.c 600 11722 76400 52460 4750124256 7232 /*
* uw_pcl - protocol handling for UW
*
* Copyright 1985,1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include "uw_param.h"
#include "uw_clk.h"
#include "uw_opt.h"
#include "uw_win.h"
#include "uw_pcl.h"
#include "openpty.h"
#define XON 0021 /* ASCII XON */
#define XOFF 0023 /* ASCII XOFF */
#define RUB 0177 /* ASCII RUBout */
#define META 0200 /* "meta" bit for whatever it's worth */
/*
* Protocol negotiation is performed by a finite state machine (implemented
* in pcl_haggle()). The states are defined as the enumerated type
* "pnstate_t". The inputs have type "pnreq_t".
*/
typedef enum {
PNST_NOP, /* no protocol negotiation */
PNST_AWAIT, /* timing out an ASKPCL */
PNST_CWAIT, /* timing out a CANPCL */
PNST_OK, /* negotiations completed */
PNST_FAIL /* negotiation failed */
} pnstate_t;
typedef unsigned short pnreq_t; /* finite state machine requests */
#define PNRQ_PCL 0000377 /* protocol mask */
#define PNRQ_CMD 0177400 /* command mask: */
#define PNRQ_NONE (pnreq_t)(0<<8) /* no request */
#define PNRQ_START (pnreq_t)(1<<8) /* start negotiation */
#define PNRQ_AWAIT (pnreq_t)(2<<8) /* timeout waiting for ASKPCL */
#define PNRQ_ASK (pnreq_t)(3<<8) /* process received ASKPCL */
#define PNRQ_CAN (pnreq_t)(4<<8) /* process received CANPCL */
#define PNRQ_SET (pnreq_t)(5<<8) /* process received SETPCL */
#define PNRQ_CWAIT (pnreq_t)(6<<8) /* timeout waiting for CANPCL */
#define PNRQ_INIT (pnreq_t)(7<<8) /* initialize everything */
static int p1_ctlch[] = { -1, P1_IAC, XON, XOFF, -1, -1, -1, -1 };
extern void p1_entry(), p1_renew(), p2_renew();
extern struct window *p1_neww(), *p2_neww();
extern void p1_killw(), p1_xmit(), p1_recv();
extern void p1_askpcl(), p1_canpcl(), p1_setpcl();
extern void p2_recv(), p2_chkopt(), p2_sendopt();
static struct protocol pcl_table[] = {
{
' ',
P1_NWINDOW,
p1_ctlch, sizeof p1_ctlch / sizeof p1_ctlch[0],
p1_entry, NULL, p1_renew,
p1_neww, p1_killw,
p1_xmit, p1_recv, NULL, NULL,
p1_askpcl, p1_canpcl, p1_setpcl
},
{
'!',
P2_NWINDOW,
p1_ctlch, sizeof p1_ctlch / sizeof p1_ctlch[0],
p1_entry, NULL, p2_renew,
p2_neww, p1_killw,
p1_xmit, p2_recv, p2_chkopt, p2_sendopt,
p1_askpcl, p1_canpcl, p1_setpcl
},
};
struct protocol *protocol = pcl_table;
/*
* Two "current" windows are defined: the current input window (for
* input from the Macintosh) and the current output window (for output
* to the Macintosh).
*/
static struct {
struct window *in;
struct window *out;
} curwin;
pcl_entry(mfd)
register fildes_t mfd;
{
/*
* This routine is called to start up protocol handling. We always
* start with protocol 1 (the original UW protocol).
*/
protocol = pcl_table;
pcl_haggle(mfd, PNRQ_INIT);
if (protocol->p_entry)
(*protocol->p_entry)(mfd);
}
pcl_exit(mfd)
register fildes_t mfd;
{
/*
* This routine is called when we shut down (just before the server
* exits).
*/
if (protocol->p_exit)
(*protocol->p_exit)(mfd);
protocol = pcl_table;
}
static
pcl_newpcl(newproto)
struct protocol *newproto;
{
extern void rc_kludge();
/*
* Switch to new protocol "newproto". Right now we can get away
* with just changing the value of "protocol". Eventually we will
* probably want to call protocol-dependent functions to shut down
* the old protocol and start up the new one.
*/
protocol = newproto;
/*
* This is a horrible kludge. See rc_kludge() in "main.c" for
* further details.
*/
rc_kludge();
}
static
void
pcl_tohaggle(arg)
register toarg_t arg;
{
/*
* This is a kludge to get around the single-argument restriction
* on clk_timeout. We split the argument "arg" into two 16-bit
* pieces and invoke pcl_haggle.
*/
pcl_haggle((fildes_t)((arg>>16)&0177777), (pnreq_t)(arg&0177777));
}
static
pcl_haggle(mfd, req)
fildes_t mfd;
register pnreq_t req;
{
register struct protocol *p, *q;
register char pname;
register int request;
static pnstate_t pnstate;
static int waitcnt;
/*
* This routine implements the finite-state machine that handles
* protocol negotiation. This routine is called by routines which
* recognize incoming protocol commands and at 5 second intervals
* when negotiations are in progress. The current protocol is
* described by the variable "protocol".
*/
if (req == PNRQ_INIT) {
waitcnt = 0;
pnstate = PNST_NOP;
req = PNRQ_NONE;
}
if (!(p = protocol) || !p->p_askpcl || !p->p_canpcl || !p->p_setpcl) {
req = PNRQ_NONE;
} else {
pname = req & PNRQ_PCL;
request = req & PNRQ_CMD;
switch (request) {
case PNRQ_START: /* start protocol negotiation */
/*
* The Macintosh is responsible for starting protocol
* negotiation (if it wants something other than the
* standard protocol). This code is present for
* purposes of exposition only.
*/
(*p->p_askpcl)(mfd);
req = PNRQ_AWAIT | pname;
waitcnt = 0;
pnstate = PNST_AWAIT;
break;
case PNRQ_AWAIT: /* timeout an ASKPCL */
/*
* This state also is not reached on the host.
*/
if (pnstate == PNST_AWAIT) {
if (++waitcnt > 3) {
pnstate = PNST_FAIL;
req = PNRQ_NONE;
} else
(*p->p_askpcl)(mfd);
} else
req = PNRQ_NONE;
break;
case PNRQ_ASK: /* handle received ASKPCL */
q = pcl_table+sizeof pcl_table/sizeof pcl_table[0] - 1;
(*p->p_canpcl)(mfd, q->p_name);
pnstate = PNST_CWAIT;
req = PNRQ_CWAIT | q->p_name;
waitcnt = 0;
break;
case PNRQ_CAN: /* handle received CANPCL */
for (q=pcl_table+sizeof pcl_table/sizeof pcl_table[0]-1;
q > pcl_table && q->p_name > pname;
q--)
;
if (q->p_name == pname || q == pcl_table) {
(*p->p_setpcl)(mfd, q->p_name);
pcl_newpcl(q);
pnstate = PNST_OK;
req = PNRQ_NONE;
} else {
(*p->p_canpcl)(mfd, q->p_name);
pnstate = PNST_CWAIT;
req = PNRQ_CWAIT | q->p_name;
waitcnt = 0;
}
break;
case PNRQ_CWAIT: /* timeout a CANPCL */
if (pnstate == PNST_CWAIT) {
if (++waitcnt > 3) {
pnstate = PNST_FAIL;
req = PNRQ_NONE;
} else
(*p->p_canpcl)(mfd, pname);
} else
req = PNRQ_NONE;
break;
case PNRQ_SET: /* handle a received SETPCL */
for (q=pcl_table+sizeof pcl_table/sizeof pcl_table[0]-1;
q > pcl_table && q->p_name != pname;
q--)
;
if (q->p_name == pname) {
pcl_newpcl(q);
pnstate = PNST_OK;
req = PNRQ_NONE;
} else {
/*
* We are in trouble now -- the Mac has
* instructed us to switch to a protocol
* that we can't support. We switch back
* to protocol 1 and hope that our message
* to the Mac (telling it to switch to
* protocol 1) will be interpreted correctly.
*/
pnstate = PNST_FAIL;
req = PNRQ_NONE;
(*p->p_setpcl)(mfd, ' ');
if (p != pcl_table)
pcl_newpcl(pcl_table);
}
break;
}
if (req != PNRQ_NONE)
(void)clk_timeout(5*CLK_HZ,
pcl_tohaggle, (toarg_t)(((long)mfd<<16)|req));
}
}
static
void
p1_entry(mfd)
fildes_t mfd;
{
static char cmdbuf[2] = { P1_IAC };
cmdbuf[1] = P1_DIR_HTOM|P1_FN_MAINT|P1_MF_ENTRY;
(void)write(mfd, cmdbuf, sizeof cmdbuf);
}
static
struct window *
p1_neww(mfd, wclass, wtype, wnum, wid, datafd, ctlfd)
fildes_t mfd;
wclass_t wclass;
wtype_t wtype;
nwin_t wnum;
long wid;
fildes_t datafd;
fildes_t ctlfd;
{
register struct window *w;
static char cmdbuf[2] = { P1_IAC, 0 };
/*
* Create a new window for the host. This routine is not called when
* the Macintosh creates a window.
*/
w = win_neww(wclass, wtype, wnum, protocol->p_maxwin, wid,
datafd, ctlfd, (struct woptdefn *)0);
if (w) {
cmdbuf[1] = P1_DIR_HTOM|P1_FN_NEWW|WIN_NUM(w);
(void)write(mfd, cmdbuf, sizeof cmdbuf);
}
return(w);
}
static
void
p1_killw(mfd, w)
register struct window *w;
{
static char cmdbuf[] = { P1_IAC, P1_DIR_HTOM|P1_FN_KILLW };
/*
* Kill window "w" and tell the Macintosh to do the same.
*/
if (w && w->w_alloc) {
if (curwin.in == w)
curwin.in = (struct window *)0;
if (curwin.out == w)
curwin.out = (struct window *)0;
cmdbuf[1] = P1_DIR_HTOM|P1_FN_KILLW|WIN_NUM(w);
(void)write(mfd, cmdbuf, sizeof cmdbuf);
win_killw(w);
}
}
static
void
p1_xmit(mfd, w)
fildes_t mfd;
register struct window *w;
{
register char *cp, *cq;
register int i, len;
char ibuf[32], obuf[32];
static char refresh;
static char cmdbuf[] = { P1_IAC, 0 };
extern int errno;
/*
* Transmit data to the Macintosh (via file descriptor "mfd)
* on behalf of window "w". Be sure to convert any embedded
* control characters and meta characters.
*
* Note that the input/output buffers should NOT be very large.
* It is undesirable to perform large reads and effectively
* "lock out" all other file descriptors. The chosen size
* should preserve a reasonable amount of efficiency.
*
* The UW protocol only requires an OSELW command when the
* output window changes. We issue this command more often
* to "refresh" the Mac's idea of what the output window is.
* This helps (slightly) to overcome spurious output redirects
* caused by a noisy line.
*/
if (w && w->w_alloc) {
if (curwin.out != w || ++refresh == 0) {
refresh = 0;
curwin.out = w;
cmdbuf[1] = P1_DIR_HTOM|P1_FN_OSELW|WIN_NUM(w);
(void)write(mfd, cmdbuf, sizeof cmdbuf);
}
cq = obuf;
if ((len = read(w->w_datafd, ibuf, sizeof ibuf)) < 0 &&
errno != EWOULDBLOCK)
(*protocol->p_killw)(mfd, w);
for (cp=ibuf; cp < ibuf+len; cp++) {
if (*cp&META) {
if (cq > obuf) {
(void)write(mfd, obuf, cq-obuf);
cq = obuf;
}
cmdbuf[1] = P1_DIR_HTOM|P1_FN_META;
(void)write(mfd, cmdbuf, sizeof cmdbuf);
*cp &= ~META;
}
i = -1;
if (*cp == RUB || *cp < ' ') {
i = protocol->p_szctlch - 1;
while (i >= 0 && protocol->p_ctlch[i] != *cp)
i--;
}
if (i >= 0) {
if (cq > obuf) {
(void)write(mfd, obuf, cq-obuf);
cq = obuf;
}
cmdbuf[1] = P1_DIR_HTOM|P1_FN_CTLCH|i;
(void)write(mfd, cmdbuf, sizeof cmdbuf);
} else {
*cq++ = *cp;
if (cq >= obuf+sizeof obuf) {
(void)write(mfd, obuf, cq-obuf);
cq = obuf;
}
}
}
if (cq > obuf)
(void)write(mfd, obuf, cq-obuf);
} else
(void)read(w->w_datafd, ibuf, sizeof ibuf);
}
static
void
p1_recv(mfd, cbuf, clen)
fildes_t mfd;
char *cbuf;
int clen;
{
register int len;
register char *buf, *cp, *cq;
register struct window *w;
nwin_t wnum;
auto int nready;
char ibuf[512], obuf[512];
static int seen_iac, seen_meta;
static pnreq_t pnrq_cmd;
static char cmdbuf[2] = { P1_IAC };
/*
* The received bytestream is examined. Non-command bytes are
* written to the file descriptor corresponding to the current
* "input" window (relative to the Macintosh -- the window the
* user types input to).
*
* If "clen" is nonzero, then the contents of the buffer "cbuf"
* are processed before any input is read.
*/
if (ioctl(mfd, (int)FIONREAD, (char *)&nready) < 0) {
perror("FIONREAD");
return;
}
nready += clen;
for (cq = obuf; nready > 0; nready -= len) {
if (clen > 0) {
len = clen;
buf = cbuf;
clen = 0;
} else {
if (nready > sizeof ibuf)
len = read(mfd, ibuf, sizeof ibuf);
else
len = read(mfd, ibuf, nready);
if (len <= 0) {
perror("read");
return;
}
buf = ibuf;
}
for (cp=buf; cp < buf+len; cp++) {
if (pnrq_cmd) {
pcl_haggle(mfd, pnrq_cmd|*cp);
pnrq_cmd = 0;
/* pcl_haggle may have changed the protocol */
if (protocol != pcl_table) {
if (protocol->p_recv)
(*protocol->p_recv)(mfd,
cp+1, buf+len-cp-1);
return;
}
} else if (seen_iac) {
if ((*cp&P1_DIR) == P1_DIR_MTOH) {
if (cq > obuf) {
(void)write(curwin.in->w_datafd,
obuf, cq-obuf);
cq = obuf;
}
switch (*cp & P1_FN) {
case P1_FN_NEWW:
wnum = *cp & P1_WINDOW;
if (!wnum)
break;
w = WIN_PTR(wnum);
if (w->w_alloc)
break;
if (!win_neww(WC_INTERNAL,
defwtype, wnum,
protocol->p_maxwin, 0L,
(fildes_t)-1, (fildes_t)-1,
(struct woptdefn *)0)) {
cmdbuf[1] = P1_DIR_HTOM|
P1_FN_KILLW|wnum;
(void)write(mfd, cmdbuf,
sizeof cmdbuf);
}
break;
case P1_FN_KILLW:
wnum = *cp & P1_WINDOW;
if (!wnum)
break;
win_killw(WIN_PTR(wnum));
break;
case P1_FN_ISELW:
wnum = *cp & P1_WINDOW;
if (!wnum)
break;
w = WIN_PTR(wnum);
if (w->w_alloc)
curwin.in = w;
else
curwin.in = NULL;
break;
case P1_FN_META:
seen_meta = 1;
break;
case P1_FN_CTLCH:
*cq = protocol->p_ctlch[*cp&P1_CC];
if (seen_meta) {
seen_meta = 0;
*cq |= META;
}
if (curwin.in)
cq++;
break;
case P1_FN_MAINT:
switch (*cp & P1_MF) {
case P1_MF_ENTRY:
(*protocol->p_renew)(mfd);
break;
case P1_MF_ASKPCL:
pcl_haggle(mfd,PNRQ_ASK);
break;
case P1_MF_CANPCL:
pnrq_cmd = PNRQ_CAN;
break;
case P1_MF_SETPCL:
pnrq_cmd = PNRQ_SET;
break;
case P1_MF_EXIT:
done(0);
break;
}
break;
}
}
seen_iac = 0;
} else if (*cp == P1_IAC)
seen_iac++;
else {
if (seen_meta) {
seen_meta = 0;
*cq = *cp | META;
} else
*cq = *cp;
if (curwin.in) {
if (++cq >= obuf+sizeof obuf) {
(void)write(curwin.in->w_datafd,
obuf, cq-obuf);
cq = obuf;
}
}
}
}
}
if (cq > obuf)
(void)write(curwin.in->w_datafd, obuf, cq-obuf);
}
static
void
p1_askpcl(mfd)
fildes_t mfd;
{
static char cmdbuf[2] = { P1_IAC,P1_DIR_HTOM|P1_FN_MAINT|P1_MF_ASKPCL };
(void)write(mfd, cmdbuf, sizeof cmdbuf);
}
static
void
p1_canpcl(mfd, pname)
fildes_t mfd;
char pname;
{
static char cmdbuf[3] = { P1_IAC,P1_DIR_HTOM|P1_FN_MAINT|P1_MF_CANPCL };
cmdbuf[2] = pname;
(void)write(mfd, cmdbuf, sizeof cmdbuf);
}
static
void
p1_setpcl(mfd, pname)
fildes_t mfd;
char pname;
{
static char cmdbuf[3] = { P1_IAC,P1_DIR_HTOM|P1_FN_MAINT|P1_MF_SETPCL };
cmdbuf[2] = pname;
(void)write(mfd, cmdbuf, sizeof cmdbuf);
}
static
void
p1_renew(mfd)
fildes_t mfd;
{
register struct window *w;
static char cmdbuf[2] = { P1_IAC };
/*
* Re-init (re-NEW) an existing connection. Send a NEWW command
* for each existing window. This function is invoked when the
* Macintosh sends an ENTRY maintenance command.
*/
for (w=window; w < window+protocol->p_maxwin; w++) {
if (w->w_alloc) {
win_renew(w, 0);
cmdbuf[1] = P1_DIR_HTOM|P1_FN_NEWW|WIN_NUM(w);
(void)write(mfd, cmdbuf, sizeof cmdbuf);
}
}
}
static
void
p2_renew(mfd)
fildes_t mfd;
{
register struct window *w;
static char cmdbuf[3] = { P2_IAC };
/*
* Re-init (re-NEW) an existing connection. Send a NEWW command
* for each existing window. This function is invoked when the
* Macintosh sends an ENTRY maintenance command.
*/
for (w=window; w < window+protocol->p_maxwin; w++) {
if (w->w_alloc) {
win_renew(w, 1);
cmdbuf[1] = P2_DIR_HTOM|P2_FN_NEWW|WIN_NUM(w);
cmdbuf[2] = w->w_type + ' ';
(void)write(mfd, cmdbuf, sizeof cmdbuf);
}
}
}
static
struct window *
p2_neww(mfd, wclass, wtype, wnum, wid, datafd, ctlfd)
fildes_t mfd;
wclass_t wclass;
wtype_t wtype;
nwin_t wnum;
long wid;
fildes_t datafd;
fildes_t ctlfd;
{
register struct window *w;
static char cmdbuf[3] = { P2_IAC };
/*
* Create a new window as requested by the host. This routine is not
* called when the Macintosh creates a window.
*/
w = win_neww(wclass, wtype, wnum, protocol->p_maxwin, wid,
datafd, ctlfd, (struct woptdefn *)0);
if (w) {
cmdbuf[1] = P2_DIR_HTOM|P2_FN_NEWW|WIN_NUM(w);
cmdbuf[2] = ' ' + wtype;
(void)write(mfd, cmdbuf, sizeof cmdbuf);
}
return(w);
}
static
void
p2_chkopt(mfd)
fildes_t mfd;
{
register struct window *w;
nwin_t maxwin;
/*
* Ideally, this routine would call a routine in the window
* module (perhaps win_chkopt()), passing the maximum window
* number as one argument. The "for" loop would be in that
* routine. However, I'm not willing to accept the overhead
* for that conceptual nicety.
*/
maxwin = protocol->p_maxwin;
for (w=window; w < window+maxwin; w++)
if (w->w_alloc)
opt_scan((caddr_t)w, &w->w_optdefn, p2_sendopt, mfd,
P2_FN_WOPT|WIN_NUM(w));
}
static
void
p2_sendopt(mfd, fn, buf, len)
fildes_t mfd;
int fn;
register char *buf;
register int len;
{
register char *cp;
register int i;
char outbuf[512];
/*
* Encode and transmit the option string contained in "buf". The
* initial command (which will be P2_FN_WOPT|WIN_NUM(w)) is
* contained in "fn".
*
* The caller is responsible for handing us a correctly-formed
* option string. This routine merely performs the protocol encoding
* which is required for control and meta characters.
*/
curwin.out = NULL;
outbuf[0] = P2_IAC;
outbuf[1] = fn|P2_DIR_HTOM;
for (cp=outbuf+2; len > 0; buf++,len--) {
if (cp > outbuf+sizeof outbuf - 4) {
(void)write(mfd, outbuf, cp-outbuf);
cp = outbuf;
}
if (*buf & META) {
*cp++ = P2_IAC;
*cp++ = P2_DIR_HTOM|P2_FN_META;
*buf &= ~META;
}
i = -1;
if (*buf == RUB || *buf < ' ') {
i = protocol->p_szctlch - 1;
while (i >= 0 && protocol->p_ctlch[i] != *buf)
i--;
}
if (i >= 0) {
*cp++ = P2_IAC;
*cp++ = P2_DIR_HTOM|P2_FN_CTLCH|(i&7);
} else
*cp++ = *buf;
}
if (cp > outbuf)
(void)write(mfd, outbuf, cp-outbuf);
}
static
void
p2_recv(mfd, cbuf, clen)
fildes_t mfd;
char *cbuf;
int clen;
{
register int len;
register char *buf, *cp, *cq;
register struct window *w;
register char c;
nwin_t wnum;
auto int nready;
char ibuf[512], obuf[512];
static int seen_iac, seen_meta, is_option;
static pnreq_t pnrq_cmd;
static nwin_t neww;
static char cmdbuf[2] = { P2_IAC };
/*
* The received bytestream is examined. Non-command bytes are
* written to the file descriptor corresponding to the current
* "input" window (relative to the Macintosh -- the window the
* user types input to).
*
* If "clen" is nonzero, then the contents of the buffer "cbuf"
* are processed before any input is read.
*/
if (ioctl(mfd, (int)FIONREAD, (char *)&nready) < 0) {
perror("FIONREAD");
return;
}
nready += clen;
for (cq = obuf; nready > 0; nready -= len) {
if (clen > 0) {
len = clen;
buf = cbuf;
clen = 0;
} else {
if (nready > sizeof ibuf)
len = read(mfd, ibuf, sizeof ibuf);
else
len = read(mfd, ibuf, nready);
if (len <= 0) {
perror("read");
return;
}
buf = ibuf;
}
for (cp=buf; cp < buf+len; cp++) {
if (pnrq_cmd) {
pcl_haggle(mfd, pnrq_cmd|*cp);
pnrq_cmd = 0;
/* pcl_haggle may have changed the protocol */
if (protocol != pcl_table) {
if (protocol->p_recv)
(*protocol->p_recv)(mfd,
cp+1, buf+len-cp-1);
return;
}
} else if (neww) {
w = WIN_PTR(neww);
if (!w->w_alloc &&
!win_neww(WC_INTERNAL, (wtype_t)(*cp-' '),
neww, protocol->p_maxwin, 0L,
(fildes_t)-1, (fildes_t)-1,
(struct woptdefn *)0)) {
cmdbuf[1] = P2_DIR_HTOM|
P2_FN_KILLW|neww;
(void)write(mfd, cmdbuf,
sizeof cmdbuf);
}
neww = 0;
} else if (seen_iac) {
if ((*cp&P2_DIR) == P2_DIR_MTOH) {
c = *cp & P2_FN;
if (is_option &&
c!=P2_FN_META && c!=P2_FN_CTLCH) {
opt_iflush();
is_option = 0;
}
if (cq > obuf) {
(void)write(curwin.in->w_datafd,
obuf, cq-obuf);
cq = obuf;
}
switch (*cp & P2_FN) {
case P2_FN_NEWW:
neww = *cp & P2_WINDOW;
break;
case P2_FN_WOPT:
wnum = *cp & P2_WINDOW;
if (!wnum)
break;
w = WIN_PTR(wnum);
if (!w->w_alloc) {
curwin.in = NULL;
break;
}
is_option = 1;
opt_istart((caddr_t)w, &w->w_optdefn);
break;
case P2_FN_KILLW:
wnum = *cp & P2_WINDOW;
if (!wnum)
break;
win_killw(WIN_PTR(wnum));
break;
case P2_FN_ISELW:
wnum = *cp & P2_WINDOW;
if (!wnum)
break;
w = WIN_PTR(wnum);
if (w->w_alloc)
curwin.in = w;
else
curwin.in = NULL;
break;
case P2_FN_META:
seen_meta = 1;
if ((*cp&P2_CC) == 0)
break;
/* no break */
case P2_FN_CTLCH:
c=protocol->p_ctlch[*cp&P2_CC];
if (seen_meta) {
seen_meta = 0;
c |= META;
}
if (is_option)
is_option=opt_input(c);
else
if (curwin.in)
*cq++ = c;
break;
case P2_FN_MAINT:
switch (*cp & P2_MF) {
case P2_MF_ENTRY:
(*protocol->p_setpcl)(mfd, protocol->p_name);
(*protocol->p_renew)(mfd);
break;
case P2_MF_ASKPCL:
pcl_haggle(mfd,PNRQ_ASK);
break;
case P2_MF_CANPCL:
pnrq_cmd = PNRQ_CAN;
break;
case P2_MF_SETPCL:
pnrq_cmd = PNRQ_SET;
break;
case P2_MF_EXIT:
done(0);
break;
}
break;
}
}
seen_iac = 0;
} else if (*cp == P2_IAC)
seen_iac++;
else {
if (seen_meta) {
c = *cp | META;
seen_meta = 0;
} else
c = *cp;
if (is_option)
is_option = opt_input(c);
else
if (curwin.in)
*cq++ = c;
if (cq >= obuf+sizeof obuf) {
(void)write(curwin.in->w_datafd,
obuf, cq-obuf);
cq = obuf;
}
}
}
}
if (cq > obuf)
(void)write(curwin.in->w_datafd, obuf, cq-obuf);
}
= *cp;
if (curwin.in) {
if (++cq >= obuf+sizeof obuf) {
(void)write(curwin.in->w_datafd,
obuf, cq-obuf);
cq = obuf;
}
}
}
}
}
if (cq > obuf)
(void)write(curwiserver/uw_tty.c 600 11722 76400 21064 4750124257 7271 /*
* uw_tty - terminal support for UW
*
* Copyright 1985,1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include "uw_param.h"
#include "uw_win.h"
#include "uw_opt.h"
#define XON 021 /* ASCII XON (ASR-33 paper-tape reader on) */
#define XOFF 023 /* ASCII XOFF (ASR-33 paper-tape reader off) */
static char *envinfo[][3] = {
{
"TERM=adm31",
"TERMCAP=adm31:cr=^M:do=^J:nl=^J:al=\\EE:am:le=^H:bs:ce=\\ET:cm=\\E=%+ %+ :cl=^Z:cd=\\EY:co#80:dc=\\EW:dl=\\ER:ei=\\Er:ho=^^:im=\\Eq:li#24:mi:nd=^L:up=^K:MT:km:so=\\EG1:se=\\EG0:",
(char *)0
},
{
"TERM=vt52",
(char *)0
},
{
"TERM=ansi",
(char *)0
},
{
"TERM=tek4010",
(char *)0
}
};
/* private (emulation-specific) data */
struct tty {
struct {
unsigned short h,v;
} t_size;
unsigned t_fontsz;
unsigned t_clipb;
unsigned t_bell;
unsigned t_curs;
unsigned t_chgsz;
};
#define WOTTY_SIZE 8 /* terminal size in (row, col) */
#define WOTTY_FONTSZ 9 /* font size index (0=7pt, 1=9pt) */
#define WOTTY_CLIPB 10 /* 0=clipboard, 1=encode mouse clicks */
#define WOTTY_BELL 11 /* bell: bit 0=visible, bit 1=audible */
#define WOTTY_CURSOR 12 /* cursor type: 0=block, 1=underscore */
#define WOTTY_CHGSZ 13 /* change actual size (not view size) */
static woptarg_t size_xdr[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
static woptarg_t fontsz_xdr[] = { WOA_UDATA(6), WOA_END };
static woptarg_t clipb_xdr[] = { WOA_UDATA(1), WOA_END };
static woptarg_t bell_xdr[] = { WOA_UDATA(2), WOA_END };
static woptarg_t curs_xdr[] = { WOA_UDATA(1), WOA_END };
static woptarg_t chgsz_xdr[] = { WOA_UDATA(1), WOA_END };
/* TIOCSWINSZ is in 4.3BSD, TIOCSSIZE is in Sun UNIX */
#if defined(TIOCSWINSZ) || defined(TIOCSSIZE)
#define RPTWINSZ (1<
#define RPTWINSZ 0
#endif
#define TTY_WOPT { \
0, 0, 0, 0, \
RPTWINSZ|(1<
{ NULL, NULL, NULL }, \
{ NULL, NULL, NULL }, \
{ NULL, NULL, NULL }, \
{ NULL, NULL, NULL }, \
{ NULL, NULL, NULL }, \
{ NULL, NULL, NULL }, \
{ NULL, NULL, NULL }, \
{ NULL, NULL, NULL }, \
{ size_xdr, tty_getopt, tty_setopt }, \
{ fontsz_xdr, tty_getopt, tty_setopt }, \
{ clipb_xdr, tty_getopt, tty_setopt }, \
{ bell_xdr, tty_getopt, tty_setopt }, \
{ curs_xdr, tty_getopt, tty_setopt }, \
{ chgsz_xdr, tty_getopt, tty_setopt } \
} \
}
extern int tty_start();
extern void tty_stop(), tty_setopt(), tty_setext();
extern char *tty_getopt();
struct emulation adm31_emul = { TTY_WOPT, tty_start, tty_stop, tty_setext };
struct emulation vt52_emul = { TTY_WOPT, tty_start, tty_stop, tty_setext };
struct emulation ansi_emul = { TTY_WOPT, tty_start, tty_stop, tty_setext };
struct emulation tek_emul = { { 0, 0, 0, 0, 0 }, tty_start, tty_stop };
tty_mode(f)
int f;
{
static struct sgttyb ostty, nstty;
static struct tchars otchars, ntchars;
static struct ltchars oltchars, nltchars;
static int olmode, nlmode;
static int operm;
static saved;
static int inout = FREAD|FWRITE;
struct stat st;
/*
* This routine either saves the current terminal modes and then
* sets up the terminal line or resets the terminal modes (depending
* upon the value of "f"). The terminal line is used in "cbreak"
* mode with all special characters except XON/XOFF disabled. The
* hated (by me) LDECCTQ mode is required for the Macintosh to
* handle flow control properly.
*/
if (f == 1) {
if (fstat(0, &st) == 0)
operm = st.st_mode & 06777;
else
operm = -1;
if (ioctl(0, (int)TIOCGETP, (char *)&ostty) < 0) {
perror("ioctl((int)TIOCGETP)");
done(1);
}
if (ioctl(0, (int)TIOCGETC, (char *)&otchars) < 0) {
perror("ioctl((int)TIOCGETC)");
done(1);
}
if (ioctl(0, (int)TIOCGLTC, (char *)&oltchars) < 0) {
perror("ioctl((int)TIOCGLTC)");
done(1);
}
if (ioctl(0, (int)TIOCLGET, (char *)&olmode) < 0) {
perror("ioctl((int)TIOCLGET)");
done(1);
}
nstty = ostty;
nstty.sg_erase = nstty.sg_kill = -1;
nstty.sg_flags |= CBREAK;
nstty.sg_flags &= ~(RAW|CRMOD|ECHO|LCASE|XTABS|ALLDELAY);
ntchars.t_intrc = ntchars.t_quitc = -1;
ntchars.t_eofc = ntchars.t_brkc = -1;
ntchars.t_startc = XON;
ntchars.t_stopc = XOFF;
nltchars.t_suspc = nltchars.t_dsuspc = -1;
nltchars.t_rprntc = nltchars.t_flushc = -1;
nltchars.t_werasc = nltchars.t_lnextc = -1;
nlmode = olmode | LDECCTQ;
if (operm != -1 && fchmod(0, S_IREAD|S_IWRITE) < 0)
operm = -1;
if (ioctl(0, (int)TIOCSETN, (char *)&nstty) < 0) {
perror("ioctl((int)TIOCSETN)");
done(1);
}
if (ioctl(0, (int)TIOCSETC, (char *)&ntchars) < 0) {
perror("ioctl((int)TIOCSETC");
done(1);
}
if (ioctl(0, (int)TIOCSLTC, (char *)&nltchars) < 0) {
perror("ioctl((int)TIOCSLTC");
done(1);
}
if (ioctl(0, (int)TIOCLSET, (char *)&nlmode) < 0) {
perror("ioctl((int)TIOCLSET)");
done(1);
}
saved = 1;
} else if (saved) {
(void)ioctl(0, (int)TIOCFLUSH, (char *)&inout);
(void)ioctl(0, (int)TIOCSETP, (char *)&ostty);
(void)ioctl(0, (int)TIOCSETC, (char *)&otchars);
(void)ioctl(0, (int)TIOCSLTC, (char *)&oltchars);
(void)ioctl(0, (int)TIOCLSET, (char *)&olmode);
if (operm != -1)
(void)fchmod(0, operm);
}
}
static
tty_start(w)
register struct window *w;
{
register struct tty *t;
extern char *malloc();
/*
* Start up a terminal emulation. Establish reasonable defaults
* for the terminal-specific window options.
*/
if (w->w_type != WT_TEK4010) {
if ((w->w_private = malloc(sizeof(struct tty))) != NULL) {
t = (struct tty *)w->w_private;
t->t_size.h = 80;
t->t_size.v = 24;
t->t_fontsz = 0;
t->t_clipb = 0;
t->t_bell = 3;
t->t_curs = 0;
t->t_chgsz = 0;
return(1);
} else
return(0);
} else {
w->w_private = (char *)0;
return(1);
}
}
static
void
tty_stop(w)
register struct window *w;
{
/*
* Shut down (stop) a terminal emulation.
*/
free(w->w_private);
w->w_private = (char *)0;
}
static
void
tty_setext(wod)
register struct woptdefn *wod;
{
/*
* This routine makes adjustments to the window option definitions
* for external windows. Basically, we turn off reporting for
* WOTTY_SIZE. (If the external process wants to handle this, it
* can turn it back on.)
*/
WOPT_CLR(wod->wod_do, WOTTY_SIZE);
WOPT_CLR(wod->wod_askrpt, WOTTY_SIZE);
}
tty_envinit(wtype)
register wtype_t wtype;
{
/*
* Set up environment variables corresponding to the window type
* "wtype".
*/
env_set(envinfo[wtype]);
}
static
char *
tty_getopt(win, num)
caddr_t win;
woption_t num;
{
register struct tty *t;
static union optvalue ov;
struct window *w;
if ((w=(struct window *)win) != NULL && w->w_alloc &&
(t=(struct tty *)w->w_private) != NULL) {
switch (num) {
case WOTTY_SIZE:
ov.ov_point.h = t->t_size.h;
ov.ov_point.v = t->t_size.v;
break;
case WOTTY_FONTSZ:
ov.ov_udata6 = t->t_fontsz;
break;
case WOTTY_CLIPB:
ov.ov_udata1 = t->t_clipb;
break;
case WOTTY_BELL:
ov.ov_udata2 = t->t_bell;
break;
case WOTTY_CURSOR:
ov.ov_udata1 = t->t_curs;
break;
case WOTTY_CHGSZ:
ov.ov_udata1 = t->t_chgsz;
break;
}
}
return((char *)&ov);
}
static
void
tty_setopt(win, num, value)
caddr_t win;
woption_t num;
char *value;
{
register struct tty *t;
register union optvalue *ovp;
register struct window *w;
if ((w=(struct window *)win) != NULL && w->w_alloc &&
(t=(struct tty *)w->w_private) != NULL &&
(ovp = (union optvalue *)value) != NULL) {
switch (num) {
case WOTTY_SIZE:
t->t_size.h = ovp->ov_point.h;
t->t_size.v = ovp->ov_point.v;
#ifdef TIOCSWINSZ
if (w->w_class == WC_INTERNAL) {
/* set window size on pty (4.3BSD) */
struct winsize ws;
ws.ws_row = t->t_size.v;
ws.ws_col = t->t_size.h;
ws.ws_xpixel = w->w_size.h;
ws.ws_ypixel = w->w_size.v;
(void)ioctl(w->w_datafd, (int)TIOCSWINSZ,
(char *)&ws);
}
#else
#ifdef TIOCSSIZE
if (w->w_class == WC_INTERNAL) {
/* set window size on pty (Sun) */
struct ttysize ts;
ts.ts_lines = t->t_size.v;
ts.ts_cols = t->t_size.h;
(void)ioctl(w->w_datafd, (int)TIOCSSIZE,
(char *)&ts);
}
#endif
#endif
break;
case WOTTY_FONTSZ:
t->t_fontsz = ovp->ov_udata6;
break;
case WOTTY_CLIPB:
t->t_clipb = ovp->ov_udata1;
break;
case WOTTY_BELL:
t->t_bell = ovp->ov_udata2;
break;
case WOTTY_CURSOR:
t->t_curs = ovp->ov_udata1;
break;
case WOTTY_CHGSZ:
t->t_chgsz = ovp->ov_udata1;
break;
}
}
}
of cmdbuf);
}
}
}
static
void
p2_renew(mfd)
fildes_t mfd;
{
register struct window *w;
static char cmdbuf[3] = { P2_IAC };
/*
* Re-init (re-NEW) an existing connection. Send a NEWW command
* for each existing window. This function is invoked when the
* Macintosh sends an ENTRY maintenance command.
*/
for (w=window; w < window+protocol->p_maxwin; w++) {
if (w->w_alloc) {
win_renew(w, 1);
cmdbuf[1] = P2_DIR_HTOM|P2_FN_NEWW|WIN_NUM(server/uw_utmp.c 600 11722 76400 7455 4750124261 7421 /*
* uw_utmp - /etc/utmp handling
*
* Copyright 1985,1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#ifdef UTMP
#include
#include
#include
#include
#include
#include
#include
#include
#include "uw_param.h"
struct utinfo {
struct utinfo *ui_next;
struct utinfo *ui_chain;
char *ui_line;
int ui_slot;
int ui_inuse;
};
static struct utinfo *hash[31];
static struct utinfo *head;
static char *myname;
static fildes_t utmpfd;
extern time_t time();
utmp_init(fd)
fildes_t fd;
{
register char *cp, *cq;
register struct utinfo *ui;
register int hashidx, slot;
struct passwd *pw;
FILE *fp;
char line[256];
if ((utmpfd = fd) >= 0 && (fp = fopen("/etc/ttys", "r")) == NULL) {
(void)close(utmpfd);
utmpfd = -1;
}
if (utmpfd >= 0) {
slot = 0;
while (fgets(line, sizeof line, fp) != NULL) {
#ifdef V7TTYS
if (!line[0] || !line[1]) { /* malformed line */
slot++;
continue;
}
cp = line+2; /* skip flag and speed index */
#else
for (cp=line; *cp && isspace(*cp); cp++)
;
if (*cp == '#')
continue;
#endif
slot++;
if ((ui=(struct utinfo *)malloc(sizeof *ui)) != NULL) {
for (cq=cp; *cq && !isspace(*cq); cq++)
;
if ((ui->ui_line=malloc(cq-cp+1)) != NULL) {
(void)strncpy(ui->ui_line, cp, cq-cp);
ui->ui_line[cq-cp] = '\0';
} else {
free((char *)ui);
ui = (struct utinfo *)0;
}
}
if (ui != NULL) {
ui->ui_slot = slot;
ui->ui_inuse = 0;
ui->ui_chain = head;
head = ui;
hashidx = utmp_hash(ui->ui_line);
ui->ui_next = hash[hashidx];
hash[hashidx] = ui;
}
}
(void)fclose(fp);
}
if ((pw = getpwuid(getuid())) != NULL &&
(myname=malloc(1+strlen(pw->pw_name))) != NULL)
(void)strcpy(myname, pw->pw_name);
}
static
struct utinfo *
utmp_find(tty)
char *tty;
{
register char *cp;
register struct utinfo *ui;
if ((cp = rindex(tty, '/')) != NULL)
cp++;
else
cp = tty;
ui = hash[utmp_hash(cp)];
while (ui != NULL && strcmp(ui->ui_line, cp) != 0)
ui = ui->ui_next;
return(ui);
}
utmp_add(tty)
char *tty;
{
register struct utinfo *ui;
struct utmp ut;
if ((ui = utmp_find(tty)) != NULL) {
(void)strncpy(ut.ut_line, ui->ui_line, sizeof ut.ut_line);
(void)strncpy(ut.ut_name, myname, sizeof ut.ut_name);
(void)strncpy(ut.ut_host, "", sizeof ut.ut_host);
ut.ut_time = (long)time((time_t)0);
ui->ui_inuse = 1;
utmp_write(ui->ui_slot, &ut);
}
}
utmp_rm(tty)
char *tty;
{
register struct utinfo *ui;
struct utmp ut;
if ((ui = utmp_find(tty)) != NULL) {
(void)strncpy(ut.ut_line, ui->ui_line, sizeof ut.ut_line);
(void)strncpy(ut.ut_name, "", sizeof ut.ut_name);
(void)strncpy(ut.ut_host, "", sizeof ut.ut_host);
ut.ut_time = (long)time((time_t)0);
ui->ui_inuse = 0;
utmp_write(ui->ui_slot, &ut);
}
}
utmp_exit()
{
register struct utinfo *ui;
struct utmp ut;
for (ui=head; ui; ui=ui->ui_chain) {
if (ui->ui_inuse) {
(void)strncpy(ut.ut_line,ui->ui_line,sizeof ut.ut_line);
(void)strncpy(ut.ut_name, "", sizeof ut.ut_name);
(void)strncpy(ut.ut_host, "", sizeof ut.ut_host);
ut.ut_time = (long)time((time_t)0);
ui->ui_inuse = 0;
utmp_write(ui->ui_slot, &ut);
}
}
}
utmp_write(slot, ut)
register int slot;
struct utmp *ut;
{
extern off_t lseek();
if (utmpfd >= 0 &&
lseek(utmpfd, slot*sizeof(*ut), L_SET) == (off_t)(slot*sizeof(*ut)))
(void)write(utmpfd, (char *)ut, sizeof *ut);
}
static
utmp_hash(s)
register char *s;
{
register short h;
for (h=0; *s; s++)
h = (h << ((*s)&7)) | (h >> (sizeof h - ((*s)&7))) + *s;
return(h % sizeof hash / sizeof hash[0]);
}
#else
utmp_add(tty)
char *tty;
{
}
utmp_rm(tty)
char *tty;
{
}
utmp_exit()
{
}
#endif
f *ui)) != NULL) {
for (cq=cp; *cq && !isspace(*cq); cq++)
;
if ((ui->ui_line=malloc(cq-cp+1)) != NULL) {
(void)strncpy(ui->ui_line, cp, cq-cp);
ui->ui_line[cq-cp] = '\0';
} else {
server/uw_win.c 600 11722 76400 25024 4750124262 7242 /*
* uw_win - window handling for UW
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include "openpty.h"
#include "uw_param.h"
#include "uw_opt.h"
#include "uw_win.h"
#include "uw_fd.h"
/*
* "defwtype" specifies the default window type. This type is used when
* more specific information is not available.
*/
wtype_t defwtype = WT_ADM31;
/*
* "window" is declared in "uw_win.h" Here we define it.
*/
struct window window[NWINDOW]; /* window data structures */
/*
* "emulation" describes window emulation-specific data. "generic_emul"
* describes emulations which do not require special server attention
* (e.g. file transfer, all of whose real work is done by a separate process).
*/
extern struct emulation adm31_emul, vt52_emul, ansi_emul, tek_emul;
static struct emulation generic_emul;
static struct emulation *emulation[WT_MAXTYPE+1] = {
&adm31_emul,
&vt52_emul,
&ansi_emul,
&tek_emul,
&generic_emul,
&generic_emul,
&generic_emul,
};
extern char *win_getopt();
extern void win_setopt();
static woptarg_t woa_vis[] = { WOA_UDATA(1), WOA_END };
static woptarg_t woa_type[] = { WOA_UDATA(6), WOA_END };
static woptarg_t woa_pos[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
static woptarg_t woa_title[] = { WOA_STRING(255), WOA_END };
static woptarg_t woa_size[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
static struct woptdefn genwinopt = {
(1<
/* WOG_END */ { NULL, NULL, NULL },
/* WOG_VIS */ { woa_vis, win_getopt, win_setopt },
/* WOG_TYPE */ { woa_type, win_getopt, win_setopt },
/* WOG_POS */ { woa_pos, win_getopt, win_setopt },
/* WOG_TITLE */ { woa_title, win_getopt, win_setopt },
/* WOG_SIZE */ { woa_size, win_getopt, win_setopt },
/* WOG_6 */ { NULL, NULL, NULL },
/* WOG_7 */ { NULL, NULL, NULL }
}
};
/*
* This is a violation of the level structure, but it is expedient.
*/
extern void ipc_optmsg();
win_init()
{
register struct window *w;
/*
* Initialize. Mark all windows unallocated.
*/
for (w=window; w < window+NWINDOW; w++)
w->w_alloc = 0;
}
long
win_mkid()
{
static unsigned short i = 0;
static long pid = -1;
if (pid == -1)
pid = getpid();
return((pid << (NBBY*(sizeof(long)/sizeof(short)))) | i++);
}
struct window *
win_search(wid, maxwin)
long wid;
nwin_t maxwin;
{
register struct window *w;
for (w=window; w < window+maxwin; w++)
if (w->w_alloc && w->w_id == wid)
return(w);
return((struct window *)0);
}
struct window *
win_neww(wclass, wtype, wnum, maxwin, wid, datafd, ctlfd, options)
wclass_t wclass;
wtype_t wtype;
nwin_t wnum;
nwin_t maxwin;
long wid;
fildes_t datafd;
fildes_t ctlfd;
struct woptdefn *options;
{
fildes_t fd;
int pid;
struct window *w;
char *tty, *shell;
auto struct ptydesc pt;
extern char *getenv();
/*
* Create a new window. "wclass" specifies the window wclass.
* If "wnum" is negative, choose a window number; otherwise,
* "wnum" is the window number. "datafd" and "ctlfd" are the
* data and control file descriptors to be associated with
* this window. If "datafd" is negative and "wclass" is
* WC_INTERNAL, allocate a pseudo-terminal.
*
* If "options" is non-NULL it specifies the address of an
* option definition structure; otherwise, a new one is constructed
* from the generic and emulation-specific prototype structures.
*
* If "wid" is nonzero it is a proposed window ID. It must be
* unique (not in use). If "wid" is zero, a new ID is assigned.
*
* The window type "wtype" will always be a terminal emulation
* if the wclass is WC_INTERNAL.
*
* Internal-class windows are visible by default, while external
* ones are initially invisible.
*
* Return the address of the window structure or NULL if
* none could be created.
*/
tty = (char *)0;
if (wtype > WT_MAXTYPE)
return((struct window *)0);
if (wid == 0) {
while (win_search(wid=win_mkid(), maxwin) != NULL)
;
} else if (win_search(wid, maxwin) != NULL)
return((struct window *)0);
if (datafd < 0 && wclass == WC_INTERNAL) {
if (!openpty(&pt)) {
datafd = pt.pt_pfd;
tty = pt.pt_tname;
while ((pid = fork()) < 0)
sleep(5);
if (!pid) {
win_envinit(wtype, wid);
(void)signal(SIGHUP, SIG_DFL);
(void)signal(SIGINT, SIG_DFL);
(void)signal(SIGQUIT, SIG_DFL);
(void)signal(SIGTERM, SIG_DFL);
(void)signal(SIGTSTP, SIG_IGN);
(void)signal(SIGCHLD, SIG_DFL);
(void)ioctl(open("/dev/tty",O_RDWR),
(int)TIOCNOTTY, (char *)0);
(void)close(open(pt.pt_tname, O_RDONLY));
(void)setuid(getuid());
if (!(shell = getenv("SHELL")))
shell = "/bin/sh";
if (pt.pt_tfd != 0)
(void)dup2(pt.pt_tfd, 0);
if (pt.pt_tfd != 1);
(void)dup2(pt.pt_tfd, 1);
if (pt.pt_tfd != 2)
(void)dup2(pt.pt_tfd, 2);
for (fd=3; fd < nfds; fd++)
(void)close(fd);
tty_mode(0); /* HACK! */
execl(shell, shell, (char *)0);
_exit(1);
} else {
utmp_add(tty);
(void)close(pt.pt_tfd);
}
}
}
if (datafd >= 0) {
if (wnum > 0) {
w = WIN_PTR(wnum);
if (w->w_alloc)
w = (struct window *)0;
} else {
for (w=window; w < window+maxwin && w->w_alloc; w++)
;
if (w >= window+maxwin)
w = (struct window *)0;
}
} else
w = (struct window *)0;
if (w) {
w->w_alloc = 1;
w->w_id = wid;
w->w_class = wclass;
w->w_type = wtype;
w->w_visible = (w->w_class == WC_INTERNAL);
w->w_position.h = w->w_position.v = 0;
w->w_size.h = w->w_size.v = 0;
w->w_title[0] = '\0';
if (emulation[wtype]->we_start &&
!(*emulation[wtype]->we_start)(w)) {
if (options)
w->w_optdefn = *options;
else
opt_new(&w->w_optdefn, &genwinopt,
(struct woptdefn *)0);
} else {
if (options)
w->w_optdefn = *options;
else
opt_new(&w->w_optdefn, &genwinopt,
&emulation[wtype]->we_optdefn);
}
w->w_datafd = datafd;
(void)fcntl(datafd, F_SETFL, FNDELAY);
FD_SET(datafd, &selmask[0].sm_rd);
fdmap[datafd].f_type = FDT_DATA;
fdmap[datafd].f_win = w;
if (w->w_class == WC_INTERNAL) {
if (tty)
(void)strncpy(w->w_tty, tty, sizeof w->w_tty);
} else {
w->w_ctlfd = ctlfd;
if (ctlfd >= 0) {
(void)fcntl(ctlfd, F_SETFL, FNDELAY);
FD_SET(ctlfd, &selmask[0].sm_rd);
fdmap[ctlfd].f_type = FDT_CTL;
fdmap[ctlfd].f_win = w;
if (emulation[wtype]->we_setext)
(*emulation[wtype]->we_setext)(&w->w_optdefn);
opt_setext(&w->w_optdefn, ipc_optmsg);
}
}
}
return(w);
}
win_killw(w)
register struct window *w;
{
/*
* Kill the window "w". This is pretty simple; we just close
* the data and control file descriptors and mark the structure
* inactive.
*/
if (w && w->w_alloc) {
if (w->w_datafd >= 0) {
if (w->w_class == WC_INTERNAL)
utmp_rm(w->w_tty);
FD_CLR(w->w_datafd, &selmask[0].sm_rd);
FD_CLR(w->w_datafd, &selmask[0].sm_wt);
FD_CLR(w->w_datafd, &selmask[0].sm_ex);
fdmap[w->w_datafd].f_type = FDT_NONE;
(void)close(w->w_datafd);
}
if (w->w_class == WC_EXTERNAL && w->w_ctlfd >= 0) {
FD_CLR(w->w_ctlfd, &selmask[0].sm_rd);
FD_CLR(w->w_ctlfd, &selmask[0].sm_wt);
FD_CLR(w->w_ctlfd, &selmask[0].sm_ex);
fdmap[w->w_ctlfd].f_type = FDT_NONE;
(void)close(w->w_ctlfd);
}
w->w_alloc = 0;
}
}
win_renew(w, report)
struct window *w;
int report;
{
/*
* Reinitialize (re-NEW) the window "w". Report the state of the
* window to the Mac if "report" is nonzero.
*/
opt_renew(&w->w_optdefn, report);
}
win_newtype(w, wtype)
register struct window *w;
register wtype_t wtype;
{
/*
* Change the window emulation type to "wtype".
*/
if (wtype <= WT_MAXTYPE && wtype != w->w_type) {
if (emulation[w->w_type]->we_stop)
(*emulation[w->w_type]->we_stop)(w);
w->w_type = wtype;
if (emulation[wtype]->we_start &&
!(*emulation[wtype]->we_start)(w)) {
opt_newtype(&w->w_optdefn, &genwinopt,
(struct woptdefn *)0);
} else {
opt_newtype(&w->w_optdefn, &genwinopt,
&emulation[wtype]->we_optdefn);
}
if (w->w_class == WC_EXTERNAL && w->w_ctlfd >= 0) {
if (emulation[wtype]->we_setext)
(*emulation[wtype]->we_setext)(&w->w_optdefn);
opt_setext(&w->w_optdefn, ipc_optmsg);
}
}
}
win_envinit(wtype, wid)
register wtype_t wtype;
long wid;
{
register char *widstr;
auto char *env[2];
/*
* Set up the environment according to the new window type and
* window ID.
*
* A 64-bit integer will fit in 20 digits. If a "long" is wider
* than this, then this code will have to be adjusted.
*/
if (wtype <= WT_TEK4010)
tty_envinit(wtype);
if ((widstr = malloc(sizeof "UW_ID=" + 20)) != NULL) {
sprintf(widstr, "UW_ID=%ld", wid);
env[0] = widstr;
env[1] = (char *)0;
env_set(env);
}
}
static
char *
win_getopt(win, num)
caddr_t win;
woption_t num;
{
register struct window *w;
static union optvalue ov;
/*
* Get the value of window option "num". It is arguably wrong to
* always return the address of "ov" (even if the window isn't
* allocated or an unknown option type was requested); however,
* we're already in trouble and there is no good way to recover
* at this point.
*/
if ((w = (struct window *)win) != NULL && w->w_alloc) {
switch (num) {
case WOG_VIS:
ov.ov_udata1 = w->w_visible;
break;
case WOG_TYPE:
ov.ov_udata6 = w->w_type;
break;
case WOG_POS:
ov.ov_point.h = w->w_position.h;
ov.ov_point.v = w->w_position.v;
break;
case WOG_TITLE:
(void)strncpy(ov.ov_string, w->w_title,
sizeof ov.ov_string);
ov.ov_string[sizeof ov.ov_string-1] = '\0';
break;
case WOG_SIZE:
ov.ov_point.h = w->w_size.h;
ov.ov_point.v = w->w_size.v;
break;
}
}
return((char *)&ov);
}
static
void
win_setopt(win, num, value)
caddr_t win;
woption_t num;
char *value;
{
register struct window *w;
register union optvalue *ov;
/*
* Set window option "num" to "value"
*/
if ((w = (struct window *)win) != NULL && w->w_alloc &&
(ov = (union optvalue *)value) != NULL) {
switch (num) {
case WOG_VIS:
w->w_visible = ov->ov_udata1;
break;
case WOG_TYPE:
win_newtype(w, (wtype_t)ov->ov_udata6);
break;
case WOG_POS:
w->w_position.h = ov->ov_point.h;
w->w_position.v = ov->ov_point.v;
break;
case WOG_TITLE:
(void)strncpy(w->w_title, ov->ov_string,
sizeof w->w_title);
w->w_title[sizeof w->w_title-1] = '\0';
break;
case WOG_SIZE:
w->w_size.h = ov->ov_point.h;
w->w_size.v = ov->ov_point.v;
break;
}
}
}
ignal(SIGTERM, SIG_DFL);
(void)signal(SIGTSTP, SIG_IGN);
(void)signal(SIGCHLD, SIG_DFL);
(void)ioctl(open("/dev/tty",O_RDWR),
(int)TIOCNOTTY, (char *)0);
(void)close(open(pt.pt_tname, O_RDONLY));
(void)setuid(getuid());
if (!(shell = getenv("SHELL")))
shell = "/bin/sh";
if (pt.pt_tfd != 0)
(void)dup2(pt.pt_tfd, 0);
if (pt.pt_tfd != 1);
(void)dup2(pt.pt_tfd, 1);
if (pt.pt_tfd != 2)
(void)dup2(pt.pt_tfd, 2);
for (fd=3; fd utility/ 700 11722 76400 0 4750124220 5643 utility/Makefile_4.2 600 11722 76400 3545 4750124213 7766 #! /bin/make -f
#
# uw utility makefile (4.2BSD)
#
# INCDIR should be set to the directory containing header files.
#
# LIBUW should be set to the name of the library file (or, if it is
# installed in a system directory, "-luw").
#
# Note: in order for "uwterm" to work on remote machines it is
# necessary for it to be installed in a directly where "rsh"
# will find it. The #defined symbol UWTERM in the source can
# be set to the desired absolute pathname, if necessary.
#
INCDIR = ../h
LIBUW = ../lib/libuw.a
UWTOOL_OBJS = uwtool.o
UWTITLE_OBJS = uwtitle.o
UWTERM_OBJS = uwterm.o
UWPLOT_OBJS = uwplot.o
OBJECTS = $(UWTOOL_OBJS) $(UWTITLE_OBJS) $(UWTERM_OBJS) $(UWPLOT_OBJS)
SOURCES = `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
DEFINES = `cat ../DEFINES`
CFLAGS = -O -I$(INCDIR) $(DEFINES)
LFLAGS =
all: uwtool uwtitle uwterm uwplot
uwtool: $(UWTOOL_OBJS)
$(CC) -o $@ $(LFLAGS) $(UWTOOL_OBJS) $(LIBUW)
uwtitle: $(UWTITLE_OBJS)
$(CC) -o $@ $(LFLAGS) $(UWTITLE_OBJS) $(LIBUW)
uwterm: $(UWTERM_OBJS)
$(CC) -o $@ $(LFLAGS) $(UWTERM_OBJS) $(LIBUW)
uwplot: $(UWPLOT_OBJS)
$(CC) -o $@ $(LFLAGS) $(UWPLOT_OBJS) $(LIBUW)
lint:
for src in $(SOURCES); \
do echo $$src:; lint -hubx -I$(INCDIR) $(DEFINES) $$src; done
tags:
ctags $(SOURCES)
depend:
grep '^#include' $(SOURCES) | \
sed -e '/ -e 's/:[^"]*"\([^"]*\)".*/: ..\/h\/\1/' \
-e 's,^../[a-zA-Z0-9]*/\([^\.]*\)\.[cs],\1.o \1.L,' | \
awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
else { if (length(rec $$3) > 78) { print rec; rec = $$0; } \
else rec = rec " " $$3 } } \
END { print rec } ' > makedep
echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ex - Makefile < eddep
rm eddep makedep
clean:
-rm -f *.o
# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
w->w_type = wtype;
if (emulation[wtype]->we_start &&
!(*emulation[wtype]->we_start)(w)) {
opt_newtype(&w->w_optdefn, &genwinopt,
(struutility/Makefile_4.3 600 11722 76400 3504 4750124214 7763 #! /bin/make -f
#
# uw utility makefile (4.3BSD)
#
# INCDIR should be set to the directory containing header files.
#
# LIBUW should be set to the name of the library file (or, if it is
# installed in a system directory, "-luw").
#
# Note: in order for "uwterm" to work on remote machines it is
# necessary for it to be installed in a directly where "rsh"
# will find it. The #defined symbol UWTERM in the source can
# be set to the desired absolute pathname, if necessary.
#
INCDIR = ../h
LIBUW = ../lib/libuw.a
UWTOOL_OBJS = uwtool.o
UWTITLE_OBJS = uwtitle.o
UWTERM_OBJS = uwterm.o
UWPLOT_OBJS = uwplot.o
OBJECTS = $(UWTOOL_OBJS) $(UWTITLE_OBJS) $(UWTERM_OBJS) $(UWPLOT_OBJS)
SOURCES = `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
DEFINES = `cat ../DEFINES`
CFLAGS = -O -I$(INCDIR) $(DEFINES)
LFLAGS =
all: uwtool uwtitle uwterm uwplot
uwtool: $(UWTOOL_OBJS)
$(CC) -o $@ $(LFLAGS) $(UWTOOL_OBJS) $(LIBUW)
uwtitle: $(UWTITLE_OBJS)
$(CC) -o $@ $(LFLAGS) $(UWTITLE_OBJS) $(LIBUW)
uwterm: $(UWTERM_OBJS)
$(CC) -o $@ $(LFLAGS) $(UWTERM_OBJS) $(LIBUW)
uwplot: $(UWPLOT_OBJS)
$(CC) -o $@ $(LFLAGS) $(UWPLOT_OBJS) $(LIBUW)
lint:
for src in $(SOURCES); \
do echo $$src:; lint -hubx -I$(INCDIR) $(DEFINES) $$src; done
tags:
ctags $(SOURCES)
depend:
$(CC) -M -I$(INCDIR) $(DEFINES) $(SOURCES) | \
sed -e ':loop' \
-e 's/\.\.\/[^ /]*\/\.\./../' \
-e 't loop' | \
awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
else rec = rec " " $$2 } } \
END { print rec } ' >> makedep
echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
echo '$$r makedep' >>eddep
echo 'w' >>eddep
cp Makefile Makefile.bak
ex - Makefile < eddep
rm eddep makedep
clean:
-rm -f *.o
# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
nk line) -- make depend uses it
w->w_type = wtype;
if (emulation[wtype]->we_start &&
!(*emulation[wtype]->we_start)(w)) {
opt_newtype(&w->w_optdefn, &genwinopt,
(struutility/uwplot.c 600 11722 76400 5372 4750124214 7442 /*
* uwplot
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include
#include "uwlib.h"
char *argv0;
UWIN uwin;
main(argc, argv)
char **argv;
{
register int c, len;
register char *cp;
register char *title;
register struct sockaddr_in *sin;
auto struct sockaddr_in sa;
auto char buf[4096];
extern char *optarg;
extern int errno;
extern onintr();
/*
* Options which are recognized directly are:
*
* -ninet connect to server at address "inet"
* -ttitle label window with "title" (default is argv[0])
*/
argv0 = argv[0];
sin = (struct sockaddr_in *)0;
title = argv0;
while ((c = getopt(argc, argv, "n:t:")) != EOF) {
switch (c) {
case 'n':
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = 0;
sa.sin_port = 0;
bzero(sa.sin_zero, sizeof sa.sin_zero);
for (cp=optarg; isxdigit(c = *cp); cp++) {
/* Pyramid compiler botch */
/* sa.sin_addr.s_addr *= 16; */
sa.sin_addr.s_addr <<= 4;
if (isdigit(c))
sa.sin_addr.s_addr += c - '0';
else if (islower(c))
sa.sin_addr.s_addr += c-'a' + 10;
else
sa.sin_addr.s_addr += c-'A' + 10;
}
if (c == '.')
for (cp++; isdigit(c = *cp); cp++)
sa.sin_port = sa.sin_port*10 + c-'0';
if (sa.sin_addr.s_addr == 0 || sa.sin_port == 0) {
fprintf(stderr,
"%s: bad Internet address: %s\n",
argv0, optarg);
return(1);
}
sa.sin_addr.s_addr = htonl(sa.sin_addr.s_addr);
sa.sin_port = htons(sa.sin_port);
sin = &sa;
break;
case 't':
title = optarg;
break;
}
}
/*
* Catch hangup, interrupt, quit, and termination signals. Kill
* the window if one of these is received.
*/
(void)signal(SIGHUP, onintr);
(void)signal(SIGINT, onintr);
(void)signal(SIGQUIT, onintr);
(void)signal(SIGTERM, onintr);
/*
* Create a new plot window, title it, and make it visible.
*/
if ((uwin = uw_new(UWT_PLOT, sin)) == (UWIN)0) {
uw_perror(argv[0], uwerrno, errno);
return(1);
}
(void)uw_stitle(uwin, title);
(void)uw_svis(uwin, 1);
/*
* Copy the standard input to the plot window.
*/
while ((len = read(0, buf, sizeof buf)) > 0 ||
(len < 0 && errno == EINTR)) {
if (len > 0)
(void)write(UW_DATAFD(uwin), buf, len);
}
/*
* This is something of a hack. We don't expect to be able to
* read anything from the window. The read will hang until the
* window is killed.
*/
while ((len = read(UW_DATAFD(uwin), buf, sizeof buf)) > 0 ||
len < 0 && errno == EINTR)
;
return(0);
}
onintr()
{
uw_kill(uwin);
exit(0);
}
id);
env[0] = widstr;
env[1] = (char *)0;
env_set(env);
}
}
static
char *
win_getopt(win, num)
caddr_t win;
woption_t num;
{
register struct window *w;
static union optvalue ov;
/*
* Get the value of window option "num". It is arguably wrong to
utility/uwterm.c 600 11722 76400 37030 4750124216 7451 /*
* uwterm
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "openpty.h"
#include "uwlib.h"
#ifndef UWTERM
#define UWTERM "uwterm"
#endif
#define CTL(c) ((c)&037)
#ifndef FD_SET
/* 4.2 retrofit: better definitions for these are in 4.3BSD's
#define FD_SET(n,p) ((p)->fds_bits[0] |= (1 << (n)))
#define FD_CLR(n,p) ((p)->fds_bits[0] &= ~(1 << (n)))
#define FD_ISSET(n,p) ((p)->fds_bits[0] & (1 << (n)))
#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
#define FD_SETSIZE (NBBY*sizeof(long))
#endif
extern int optind;
extern char *optarg;
extern char *getenv();
extern char *malloc();
extern deadkid();
extern int errno;
#ifndef htons
/* These should have been defined in
extern unsigned short htons(), ntohs();
extern unsigned long htonl(), ntohl();
#endif
char *argv0;
main(argc, argv)
int argc;
char **argv;
{
register char *cp;
register int c;
int wflag;
uwtype_t wtype;
char *term, *title, *server, *login;
struct sockaddr_in sa, *sin;
char hostname[32];
/*
* If called with no arguments, create a new window using the
* current shell according to the SHELL environment variable
* (or "/bin/sh" if that doesn't exist).
*
* Options which are recognized directly are:
*
* -ninet connect to server at address "inet"
* -wtype create window with emulation "type"
* -ttitle label window with "title"
* -llogin use login name "login" on remote machine
*
* If no explicit title is specified, the command name is used.
*/
argv0 = argv[0];
sin = (struct sockaddr_in *)0;
server = (char *)0;
login = (char *)0;
title = (char *)0;
wflag = 0;
term = (char *)0;
while ((c = getopt(argc, argv, "l:n:t:w:")) != EOF) {
switch (c) {
case 'l':
if (optarg[0] == '\0') {
fprintf(stderr,
"%s: \"-l\" requires user name\n", argv0);
} else
login = optarg;
break;
case 'n':
server = optarg;
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = 0;
sa.sin_port = 0;
bzero(sa.sin_zero, sizeof sa.sin_zero);
for (cp=optarg; isxdigit(c = *cp); cp++) {
/* Pyramid compiler botch */
/* sa.sin_addr.s_addr *= 16; */
sa.sin_addr.s_addr <<= 4;
if (isdigit(c))
sa.sin_addr.s_addr += c - '0';
else if (islower(c))
sa.sin_addr.s_addr += c-'a' + 10;
else
sa.sin_addr.s_addr += c-'A' + 10;
}
if (c == '.')
for (cp++; isdigit(c = *cp); cp++)
sa.sin_port = sa.sin_port*10 + c-'0';
if (sa.sin_addr.s_addr == 0 || sa.sin_port == 0) {
fprintf(stderr,
"%s: bad Internet address: %s\n",
argv0, optarg);
return(1);
}
sa.sin_addr.s_addr = htonl(sa.sin_addr.s_addr);
sa.sin_port = htons(sa.sin_port);
sin = &sa;
break;
case 'w':
wflag++;
term = optarg;
wtype = uw_ttype(optarg);
break;
case 't':
title = optarg;
break;
}
}
gethostname(hostname, sizeof hostname);
if (title == (char *)0) {
/*
* If there was no "-t" argument, then "title" will still
* be NULL. In this case we use the host name.
*/
if (optind == argc)
title = hostname;
else
title = argv[optind];
}
if (!term) {
/*
* If there was no "-w" argument, fetch the window
* type from the environment. If that fails, use
* a default.
*/
if ((term=getenv("TERM")) != (char *)0)
wtype = uw_ttype(term);
else
wtype = UWT_ADM31;
}
if (optind == argc-1) {
/*
* The remaining argument is the host name. Fork an "rsh"
* to execute this on the remote machine.
*/
return(doremote(argv[optind], server, title, term, login));
} else if (optind == argc) {
/*
* There are no other arguments. Set up the connection
* to this machine.
*/
return(dolocal(sin, title, wtype, term));
} else {
fprintf(stderr,
"Usage: \"%s [-ttitle] [-wtype] [-naddr] [-llogin] host\"\n",
argv0);
return(1);
}
}
doremote(host, server, title, term, login)
char *host;
char *server;
char *title;
char *term;
char *login;
{
register int fd, i, pid;
register char *cp;
char *av[16];
/*
* Invoke a remote "uwterm" via "rsh".
*/
i = 0;
av[i++] = "rsh";
av[i++] = host;
av[i++] = "-n";
if (login != NULL) {
av[i++] = "-l";
av[i++] = login;
}
av[i++] = UWTERM;
if (server == (char *)0) {
if ((server = getenv("UW_INET")) == (char *)0) {
fprintf(stderr,"%s: Can't find window server\n",argv0);
return(1);
}
}
if ((cp = malloc(3+strlen(server))) == (char *)0) {
fprintf(stderr, "%s: out of memory\n", argv0);
return(1);
}
(void)strcat(strcpy(cp, "-n"), server);
av[i++] = cp;
if (title != (char *)0) {
if ((cp = malloc(3+strlen(title))) == (char *)0) {
fprintf(stderr, "%s: out of memory\n", argv0);
return(1);
}
(void)strcat(strcpy(cp, "-t"), title);
av[i++] = cp;
}
if (term != (char *)0) {
if ((cp = malloc(3+strlen(term))) == (char *)0) {
fprintf(stderr, "%s: out of memory\n", argv0);
return(1);
}
(void)strcat(strcpy(cp, "-w"), term);
av[i++] = cp;
}
av[i] = (char *)0;
for (fd=getdtablesize()-1; fd > 2; fd--)
(void)fcntl(fd, F_SETFD, 1);
(void)execvp(av[0], av);
(void)execv("/usr/ucb/rsh", av); /* last-ditch try */
perror(av[0]);
return(1);
}
dolocal(sin, title, wtype, term)
struct sockaddr_in *sin;
char *title;
uwtype_t wtype;
char *term;
{
register UWIN uwin;
register int fd;
register int s;
struct ptydesc pt;
/*
* Create and initialize a pseudo-terminal.
*/
if (openpty(&pt) < 0) {
fprintf(stderr, "No pseudo-terminals are available\n");
return(1);
}
ttyinit(pt.pt_tfd);
/*
* Make fd's 0 and 1 be "/dev/null". We'd like to force a known
* definition for fd 2 at this point, but we may need it for
* uw_perror() if uw_new() fails.
*/
if ((fd = open("/dev/null", O_RDWR)) >= 0) { /* should be zero */
if (fd != 0 && pt.pt_tfd != 0 && pt.pt_pfd != 0)
dup2(fd, 0);
if (fd != 1 && pt.pt_tfd != 1 && pt.pt_pfd != 1)
dup2(fd, 1);
if (fd > 2)
(void)close(fd);
}
/*
* Create and title the window. Make it visible.
*/
if ((uwin = uw_new(wtype, sin)) == (UWIN)0) {
uw_perror(argv0, uwerrno, errno);
return(1);
}
(void)uw_stitle(uwin, title);
(void)uw_svis(uwin, 1);
/*
* We no longer have use for fd 2, so make it "/dev/null" (the
* same as fd 0.
*/
(void)dup2(0, 2);
/*
* Adjust the environment to contain the correct values of TERM,
* UW_ID, and UW_INET. These will be inherited by the child
* we will create next.
*/
adjenv(term, sin, UW_ID(uwin));
/*
* Create a process to execute the command connected to the pty.
*/
runcmd(pt.pt_tfd, pt.pt_tname);
/*
* Ignore signals that might cause us trouble. We do NOT ignore
* SIGTSTP so that the user can move us from the foreground into
* the background if desired.
*/
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGCHLD, deadkid);
#if defined(TIOCSWINSZ) || defined(TIOCSSIZE)
/*
* Install an option handling routine to catch window size
* changes from the Mac and make the appropriate changes to
* the pseudo-terminal.
*/
setresize(uwin, pt.pt_pfd);
#endif
/*
* Close the slave side of the pty. Copy data between the pty
* and the window. The return value from copy() is the exit
* status.
*/
(void)close(pt.pt_tfd);
s = copy(pt.pt_pfd, UW_DATAFD(uwin));
uw_kill(uwin);
return(s);
}
ttyinit(ptyfd)
register int ptyfd;
{
register int ttyfd;
struct sgttyb sg;
struct tchars tc;
struct ltchars ltc;
int ldisc;
int lmode;
/*
* Initialize the modes of the terminal whose file descriptor
* is "ptyfd" to the same modes as the current terminal. If there
* isn't a "current terminal" handy, then use hardcoded defaults.
*/
for (ttyfd=0; ttyfd < 3 && ioctl(ttyfd, TIOCGETD, &ldisc) < 0; ttyfd++)
;
if (ttyfd < 3) {
(void)ioctl(ttyfd, TIOCGETP, &sg);
(void)ioctl(ttyfd, TIOCGETC, &tc);
(void)ioctl(ttyfd, TIOCGLTC, <c);
(void)ioctl(ttyfd, TIOCLGET, &lmode);
} else {
ldisc = NTTYDISC;
sg.sg_ispeed = sg.sg_ospeed = 13; /* doesn't really matter */
sg.sg_erase = 0177; /* ugh */
sg.sg_kill = CTL('u'); /* ugh */
sg.sg_flags = ECHO|CRMOD|ANYP;
tc.t_intrc = CTL('c'); /* yuck, should be 0177 */
tc.t_quitc = CTL('\\');
tc.t_startc = CTL('q');
tc.t_stopc = CTL('s');
tc.t_eofc = CTL('d');
tc.t_brkc = -1;
ltc.t_suspc = CTL('z');
ltc.t_dsuspc = CTL('y');
ltc.t_rprntc = CTL('r');
ltc.t_flushc = CTL('o');
ltc.t_werasc = CTL('w');
ltc.t_lnextc = CTL('v');
lmode = LCRTBS|LCRTERA|LCRTKIL|LCTLECH;
}
(void)ioctl(ptyfd, TIOCSETD, &ldisc);
(void)ioctl(ptyfd, TIOCSETP, &sg);
(void)ioctl(ptyfd, TIOCSETC, &tc);
(void)ioctl(ptyfd, TIOCSLTC, <c);
(void)ioctl(ptyfd, TIOCLSET, &lmode);
}
adjenv(term, sin, wid)
char *term;
struct sockaddr_in *sin;
uwid_t wid;
{
char *env[4];
static char ttype[sizeof "TERM=" + 16];
static char inet[sizeof INET_ENV + 16];
static char idstr[sizeof "UW_ID=" + 20];
/*
* Redefine the environment variable UW_ID. Redefine UW_INET
* if "sin" is non-NULL. Redefine TERM.
*/
(void)sprintf(ttype, "TERM=%.15s", term);
env[0] = ttype;
(void)sprintf(idstr, "UW_ID=%ld", wid);
env[1] = idstr;
if (sin != NULL) {
(void)sprintf(inet, "%s=%08lx.%d", INET_ENV,
ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port));
env[2] = inet;
env[3] = (char *)0;
} else
env[2] = (char *)0;
env_set(env);
}
runcmd(fd, tname)
int fd;
char *tname;
{
register int pid;
register char *shell;
/*
* Figure out the name of the user's shell. If unknown,
* use a default.
*/
if ((shell = getenv("SHELL")) == (char *)0)
shell = "/bin/sh";
/*
* Fork a new process and attach "fd" to fd's 0, 1, and 2 of
* that new process. Disassociate the current controlling
* terminal and attach the new one (whose name is "tname").
*/
while ((pid = fork()) < 0)
sleep(5);
if (pid == 0) {
if (fd != 0)
dup2(fd, 0);
if (fd != 1)
dup2(fd, 1);
if (fd != 2)
dup2(fd, 2);
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
(void)ioctl(fd, TIOCNOTTY, (char *)0);
(void)close(fd);
} else
setpgrp(0, 0);
(void)open(tname, O_RDWR);
for (fd=getdtablesize()-1; fd > 2; fd--)
(void)fcntl(fd, F_SETFD, 1);
execlp(shell, "-", (char *)0);
execl(shell, "-", (char *)0);
_exit(1);
}
}
copy(fd1, fd2)
int fd1, fd2;
{
struct fdinfo {
int fi_fd; /* associated file descriptor */
int fi_size; /* amount of data in buffer */
char *fi_ptr; /* pointer to data in fi_buf */
char fi_buf[1024];
};
register struct fdinfo *fi, *fo;
register int n, nfds, len;
struct fdinfo fdinfo[2];
struct fd_set rdmask[2], wtmask[2], exmask[2];
struct timeval tv;
/*
* Copy data between file descriptors fd1 and fd2. Return when an
* EOF is read or an I/O error (other than an interrupted system
* call or non-blocking I/O message) is encountered.
*/
FD_ZERO(&rdmask[1]);
FD_ZERO(&wtmask[1]);
FD_ZERO(&exmask[1]);
fdinfo[0].fi_fd = fd1;
fdinfo[0].fi_size = 0;
fdinfo[1].fi_fd = fd2;
fdinfo[1].fi_size = 0;
FD_SET(fd1, &rdmask[1]);
FD_SET(fd2, &rdmask[1]);
(void)fcntl(fd1, F_SETFL, FNDELAY);
(void)fcntl(fd2, F_SETFL, FNDELAY);
nfds = ((fd1 > fd2) ? fd1 : fd2) + 1;
while (1) {
rdmask[0] = rdmask[1];
wtmask[0] = wtmask[1];
exmask[0] = exmask[1];
errno = 0;
if (fdinfo[0].fi_size != 0 || fdinfo[1].fi_size != 0) {
/*
* Select does not work correctly for writes on
* some machines, so we must fake it. If a write
* is pending, we time out after 1/50 second and
* pretend that select told us that writes could
* now be performed. The code below will do the
* correct thing if the write would still block.
*/
tv.tv_sec = 0;
tv.tv_usec = 1000000 / 50;
n = select(nfds, rdmask, wtmask, exmask, &tv);
wtmask[0] = wtmask[1];
} else
n = select(nfds, rdmask, wtmask, exmask, (struct timeval *)0);
if (n < 0 && errno == EINTR) {
continue;
} else if (n <= 0) {
perror("select");
return(1);
}
for (fi=fdinfo; fi < fdinfo+2; fi++) {
fo = fdinfo + !(fi - fdinfo);
if (FD_ISSET(fi->fi_fd, rdmask)) {
/* data available for reading */
len = read(fi->fi_fd, fi->fi_buf,
sizeof fi->fi_buf);
if (len > 0) {
fi->fi_size = len;
fi->fi_ptr = fi->fi_buf;
FD_CLR(fi->fi_fd, &rdmask[1]);
FD_SET(fo->fi_fd, &wtmask[1]);
FD_SET(fo->fi_fd, &wtmask[0]);
} else if (len == 0) {
/* EOF, exit */
return(0);
} else if (errno != EWOULDBLOCK &&
errno != EINTR) {
/* error, exit */
return(1);
}
}
if (FD_ISSET(fo->fi_fd, wtmask)) {
/* data ready for writing */
errno = 0;
len = write(fo->fi_fd, fi->fi_ptr, fi->fi_size);
if (len > 0) {
fi->fi_ptr += len;
fi->fi_size -= len;
if (fi->fi_size == 0) {
FD_SET(fi->fi_fd, &rdmask[1]);
FD_CLR(fo->fi_fd, &wtmask[1]);
}
} else if (errno != EWOULDBLOCK &&
errno != EINTR) {
/* error, exit */
return(1);
}
}
}
}
}
deadkid()
{
register int pid;
/*
* Collect dead children. Don't bother with their exit status
* or resource usage.
*/
while ((pid = wait3((union wait *)0, WNOHANG, (struct rusage *)0)) > 0)
;
}
#if defined(TIOCSWINSZ) || defined(TIOCSSIZE)
static int ptyfd;
#ifdef TIOCSWINSZ
static struct winsize winsz;
void
doresize(uwin, optnum, optcmd, uwoptval)
UWIN uwin;
uwopt_t optnum;
uwoptcmd_t optcmd;
union uwoptval *uwoptval;
{
uwtype_t wtype;
/*
* 4.3BSD-style window resizing
*/
if (uw_gtype(uwin, &wtype) < 0)
wtype = UWT_ADM31; /* probably wrong to do this here */
if (optcmd == UWOC_SET) {
switch (optnum) {
case UWOP_WSIZE:
winsz.ws_ypixel = uwoptval->uwov_point.v;
winsz.ws_xpixel = uwoptval->uwov_point.h;
break;
case UWOP_TSIZE:
if (wtype <= UWT_ANSI) {
winsz.ws_row = uwoptval->uwov_point.v;
winsz.ws_col = uwoptval->uwov_point.h;
}
break;
}
if (wtype <= UWT_ANSI &&
(optnum == UWOP_WSIZE || optnum == UWOP_TSIZE))
(void)ioctl(ptyfd, TIOCSWINSZ, &winsz);
}
}
setresize(uwin, fd)
UWIN uwin;
int fd;
{
struct uwpoint pt;
uwtype_t wtype;
/*
* Set up the option-handling routine "doresize".
*/
ptyfd = fd;
uw_optfn(uwin, UWOP_TSIZE, doresize);
uw_optfn(uwin, UWOP_WSIZE, doresize);
winsz.ws_row = 24; /* default to standard terminal size */
winsz.ws_col = 80;
if (uw_gwsize(uwin, &pt) == 0) {
winsz.ws_ypixel = pt.uwp_v;
winsz.ws_xpixel = pt.uwp_h;
} else {
/* make up something plausible */
winsz.ws_ypixel = 8 * winsz.ws_row;
winsz.ws_xpixel = 8 * winsz.ws_col;
}
if (uw_gtype(uwin, &wtype) == 0 && wtype <= UWT_ANSI)
(void)uw_optcmd(uwin, UWOP_TSIZE, UWOC_DO, (union uwoptval *)0);
}
#else
#ifdef TIOCSSIZE
void
doresize(uwin, optnum, optcmd, uwoptval)
UWIN uwin;
uwopt_t optnum;
uwoptcmd_t optcmd;
union uwoptval *uwoptval;
{
struct ttysize ts;
uwtype_t wtype;
/*
* Sun-style window resizing
*/
if (uw_gtype(uwin, &wtype) < 0)
wtype = UWT_ADM31; /* probably wrong to do this here */
if (wtype <= UWT_ANSI && optnum == UWOP_TSIZE && optcmd == UWOC_SET) {
ts.ts_lines = uwoptval->uwov_point.v;
ts.ts_cols = uwoptval->uwov_point.h;
(void)ioctl(ptyfd, TIOCSSIZE, &ts);
}
}
setresize(uwin, fd)
UWIN uwin;
int fd;
{
uwtype_t wtype;
/*
* Set up the option-handling routine "doresize".
*/
ptyfd = fd;
uw_optfn(uwin, UWOP_TSIZE, doresize);
if (uw_gtype(uwin, &wtype) == 0 && wtype <= UWT_ANSI)
(void)uw_optcmd(uwin, UWOP_TSIZE, UWOC_DO, (union uwoptval *)0);
}
#endif
#endif
#endif
FD(uwin));
uw_kill(uwin);
return(s);
}
ttyinit(ptyfd)
register int ptyfd;
{
register int ttyfd;
struct sgttyb sg;
struct tchars tc;
struct ltchars ltc;
int ldisc;
int lmode;
/*
* Initialize the modes of the terminal whose file descriptor
* is "ptyfd" to the same modes as the current terminal. If there
* isn't a "current terminal" handy, then use hardcoded defaults.
*/
for (ttyfd=0; ttyfd < 3 && ioctl(ttyfd, TIOCGETD, &ldisc) < 0; ttyfd++)
;
if (ttyfd < 3) {
utility/uwtitle.c 600 11722 76400 3504 4750124217 7603 /*
* uwtitle
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include "uwlib.h"
extern char *optarg;
extern int optind;
extern int errno;
extern char *getenv();
extern long atol();
main(argc, argv)
int argc;
char **argv;
{
register int c;
register char *cp, *cq, **av;
register uwid_t uwid;
char *argv0;
char *cqlimit;
union uwoptval uwoptval;
/*
* If called with no arguments, print a syntax message. Otherwise,
* set the title of the current window to argv[1..argc-1]. The
* window ID is obtained from the environment or the "-i" argument.
*/
argv0 = argv[0];
uwid = 0;
while ((c = getopt(argc, argv, "i:")) != EOF) {
switch (c) {
case 'i':
if ((uwid = atol(optarg)) == 0) {
fprintf(stderr,
"%s: malformed \"-i\" argument\n", argv0);
return(1);
}
break;
}
}
if (optind >= argc) {
fprintf(stderr, "Syntax: \"%s [-iID] title ...\"\n", *argv);
return(1);
}
if (uwid == 0) {
if ((cp = getenv("UW_ID")) == NULL) {
fprintf(stderr,
"%s: can't determine window ID\n", argv0);
return(1);
}
if ((uwid = (uwid_t)atol(cp)) == 0) {
fprintf(stderr,
"%s: garbaged window ID in environment: %s",
argv0, cp);
return(1);
}
}
/*
* Copy the argv list into "uwoptval" and change the title.
*/
av = argv + optind - 1;
cq = uwoptval.uwov_string;
cqlimit = uwoptval.uwov_string + sizeof uwoptval.uwov_string;
while ((cp = *++av) != NULL && cq < cqlimit) {
while (cq < cqlimit && (*cq++ = *cp++) != '\0')
;
cq[-1] = ' ';
}
cq[-1] = '\0';
if (uw_rsetopt(uwid, UWOP_TITLE, &uwoptval) < 0) {
uw_perror("uw_rsetopt", uwerrno, errno);
return(1);
} else
return(0);
}
tch (c) {
case 'i':
if ((uwid = atol(optarg)) == 0) {
fprintf(stderr,
"%s: malformed \"-i\" argument\n", argv0);
return(1);
}
break;
}
}
if (optind >= argc) utility/uwtool.c 600 11722 76400 4766 4750124220 7444 /*
* uwtool
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include "uwlib.h"
main(argc, argv)
int argc;
char **argv;
{
register uwid_t uwid;
register char *fname, *term;
register int c;
register uwtype_t wtype;
char *argv0;
char *av[2];
int vflag;
int wflag;
char *title;
union uwoptval uwoptval;
extern int errno;
extern int optind;
extern char *optarg;
extern char *getenv();
/*
* If called with no arguments, create a new window using the
* current shell according to the SHELL environment variable
* (or "/bin/sh" if that doesn't exist). If called with
* arguments, argv[optind] through argv[argc-1] are the arguments
* to the command.
*
* Options which are recognized directly are:
*
* -v (verbose) print new window ID on stdout
* -wtype create window with emulation "type"
* -ttitle label window with "title"
*
* If no explicit title is specified, the command name is used.
*/
argv0 = argv[0];
wflag = 0;
vflag = 0;
title = (char *)0;
while ((c = getopt(argc, argv, "vw:t:")) != EOF) {
switch (c) {
case 'v':
vflag++;
break;
case 'w':
wflag++;
wtype = uw_ttype(optarg);
break;
case 't':
title = optarg;
break;
}
}
if (optind < argc) {
/*
* Adjust the "argv" pointer according to the number of
* arguments we've processed.
*/
argv += optind;
fname = *argv;
} else {
/*
* No (non-option) arguments -- use SHELL
*/
if ((fname = getenv("SHELL")) == (char *)0)
fname = "/bin/sh";
av[0] = fname;
av[1] = (char *)0;
argv = av;
}
if (title == (char *)0) {
/*
* If there was no "-t" argument, then "title" will still
* be NULL. In this case we use the command name as
* the title.
*/
title = fname;
}
if (!wflag) {
/*
* If there was no "-w" argument, fetch the window
* type from the environment. If that fails, use
* a default.
*/
if ((term=getenv("TERM")) != (char *)0)
wtype = uw_ttype(term);
else
wtype = UWT_ADM31;
}
if ((uwid = uw_cmd(wtype, fname, argv)) > 0) {
(void)strncpy(uwoptval.uwov_string, title,
sizeof uwoptval.uwov_string);
(void)uw_rsetopt(uwid, UWOP_TITLE, &uwoptval);
if (vflag)
printf("%d\n", uwid);
return(0);
} else {
if (uwerrno != UWE_NXSERV)
uw_perror(fname, uwerrno, errno);
else
uw_perror(argv0, uwerrno, errno);
return(1);
}
}
INTR) {
ething plausible */
winsz.ws_ypixel = 8 * winsz.ws_row;
winsz.ws_xpixel = 8 * winsz.ws_col;
}
if (uw_gtype(uwin, &wtype) == 0 && wtype <= UWT_ANSI)
(void)uw_optcmd(uwin, UWOP_TSIZE, UWOC_DO, (union uwoptval *)0);
}
#else
#ifdef TIOCSSIZE
void
doresize(uwin, optnum, optcmd, uwoptval)
UWIN uwin;
uwopt_t optnum;
uwoptcmd_t optcmd;
union uwoptval *uwoptval;
{
struct ttysize ts;
uwtype_t wtype;
/*
* Sun-style window resizing
*/
if (uw_gtype(uwin, &wtype) < 0)
wtype = UWT_ADM31; /* probably wrong to do this here */
if (wtype <= UWT_ANSI && optnum == UWOP_TSIZE && optcmd == UWOC_SET) {
ts.ts_lines = uwoptval->uwov_point.v;
ts.ts_cols = uwoptval->uwov_point.h;
(void)ioctl(ptyfd, TIOCSSIZE, &ts);
}
}
setresize(uwin, fd)
UWIN uwin;
int fd;
{
uwtype_t wtype;
/*
* Set up the option-handling routine "doresize".
*/
ptyfd = fd;
uw_optfn(uwin, UWOP_TSIZE, doresize);
if (uw_gtype(uwin, &wtype) == 0 && wtype <= UWT_ANSI)
(void)uw_optcmd(uwin, UWOP_TSIZE, UWOC_DO, (union uwoptval *)0);
}
#endif
#endif
#endif
FD(uwin));
uw_kill(uwin);
return(s);
}
ttyinit(ptyfd)
register int ptyfd;
{
register int ttyfd;
struct sgttyb sg;
struct tchars tc;
struct ltchars ltc;
int ldisc;
int lmode;
/*
* Initialize the modes of the terminal whose file descriptor
* is "ptyfd" to the same modes as the current terminal. If there
* isn't a "current terminal" handy, then use hardcoded defaults.
*/
for (ttyfd=0; ttyfd < 3 && ioctl(ttyfd, TIOCGETD, &ldisc) < 0; ttyfd++)
;
if (ttyfd < 3) {
utility/uwtitle.c 600 11722 76400 3504 4750124217 7603 /*
* uwtitle
*
* Copyright 1986 by John D. Bruner. All rights reserved. Permission to
* copy this program is given provided that the copy is not sold and that
* this copyright notice is included.
*/
#include
#include
#include "uwlib.h"
extern char *optarg;
extern int optind;
extern int errno;
extern char *getenv();
extern long atol();
main(argc, argv)
int argc;
char **argv;
{
register int c;
register char *cp, *cq, **av;
register uwid_t uwid;
char *argv0;
char *cqlimit;
union uwoptval uwoptval;
/*
* If called with no arguments, print a syntax message. Otherwise,
* set the title of the current window to argv[1..argc-1]. The
* window ID is obtained from the environment or the "-i" argument.
*/
argv0 = argv[0];
uwid = 0;
while ((c = getopt(argc, argv, "i:")) != EOF) {
switch (c) {
case 'i':
if ((uwid = atol(optarg)) == 0) {
fprintf(stderr,
"%s: malformed \"-i\" argument\n", argv0);
return(1);
}
break;
}
}
if (optind >= argc)
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/