home *** CD-ROM | disk | FTP | other *** search
- Subject: v19i010: A command-line editor (for BSD), Part01/04
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: ka@june.cs.washington.edu (Kenneth Almquist)
- Posting-number: Volume 19, Issue 10
- Archive-name: atty/part01
-
- Atty is an alternative to tty(4).
- Atty provides a set of EMACS-like editing commands which allow
- you to move around the input line and make corrections where ever you want.
- Atty allows you to bring lines that you previously typed into the input
- buffer so that you can resend them, possible after modifying them. Atty
- also handles line wrapping and does a better job than tty of keeping input
- and output from getting intermingled. Not to mention its abbreviation
- feature... Try it, you'll like it!
-
- Atty runs entirely in user mode and requires no special privileges to run
- or install. It's a hack, but it works. I developed the code under Ultrix,
- a 4.2 BSD derivative. It has also been tested on a couple of other 4.2 BSD
- derivatives. The code does not run under System V, and would not be easy
- to port.
-
- # This is part 1 of atty. To unpack, feed it into the shell (not csh).
- # The atty distribution consists of four pieces. After you unpack everyting,
- # read the file README.
-
- echo extracting README
- cat > README <<\EOF
- Welcome to ATTY
-
- Atty is an alternative to tty(4). To correct a mistake using tty(4), you
- must erase all the characters between the mistake and the end of the line.
- In contrast, atty provides a set of EMACS-like editing commands which allow
- you to move around the input line and make corrections where ever you want.
- Atty allows you to bring lines that you previously typed into the input
- buffer so that you can resend them, possible after modifying them. Atty
- also handles line wrapping and does a better job than tty of keeping input
- and output from getting intermingled. Not to mention its abbreviation
- feature... Try it, you'll like it!
-
- Atty runs entirely in user mode and requires no special privileges to run
- or install. It's a hack, but it works. I developed the code under Ultrix,
- a 4.2 BSD derivative. It has also been tested on a couple of other 4.2 BSD
- derivatives. The code does not run under System V, and would not be easy
- to port.
-
-
- INSTALLATION
-
- To compile atty, just type "make". Three programs should be created:
-
- atty - the atty program
- kbind - program to generate key binding files
- fmatch - file name matching program
-
- These should be installed in a bin directory somewhere. Three additional
- files are generated:
-
- atty.bindc - default binding file
- dftbind.c - name of default binding file
- atty.1 - atty manual page
-
- Atty.bindc is the default key binding file, which is created from the
- file atty.bind. The latter two files include the absolution path name
- of atty.bindc. The makefile will create these files correctly if you
- just leave atty.bindc in the source directory. If you install atty.bindc
- somewhere else, you will have to edit these files.
-
- The makefile used cc. The Berkeley header files are incompatible with
- ANSI C, so if you compile with gcc or some other ANSI compiler, you will
- get incorrect code. You can use an ANSI compatable version of the header
- files, or you can use the -traditional flag of gcc.
-
- Having compiled atty, you are now ready to run it. However, you may want
- to change some the bindings first. The end of the "Getting Started"
- section of the atty manual page provides a tutorial introduction to
- doing this; if you really want to know what's going on read the kbind
- manual page. Some users will probably want set up their bindings to act
- like vi rather than emacs. The file vi.bind illustrates how to set up
- separate insert and command modes, like vi has. However, I have not
- implemented the vi commands, and you can't have a real vi emulation
- without them.
-
-
- Copyright (c) 1989 by Kenneth Almquist
- EOF
- if test `wc -c < README` -ne 2593
- then echo 'README is the wrong size'
- fi
- echo extracting LICENSE
- cat > LICENSE <<\EOF
- ATTY GENERAL PUBLIC LICENSE
-
- Copyright 1989 by Kenneth Almquist.
- Everyone is permitted to copy and distribute verbatim copies of this
- license, but changing it is not allowed. You can also use this wording
- to make the terms for other programs. This license agreement uses
- wording taken from the GNU Emacs General Public License, which is
- copyright 1985, 1987, 1988 by Richard M. Stallman. Richard M. Stallman
- is not responsible for the contents of this license.
-
-
- Atty is copyrighted. To encourage maximum use of this software, I,
- Kenneth Almquist, hereby grant all recipients of atty the right to
- reproduce and modify atty under the terms specified in this license.
-
-
- COPYING POLICIES
-
- 1. You may copy and distribute verbatim copies of atty source code
- as you receive it, in any medium, provided that you conspicuously and
- appropriately publish on each copy a valid copyright notice "Copyright
- 1989 by Kenneth Almquist." (or with whatever year is appropriate); keep
- intact the notices on all files that refer to this License Agreement
- and to the absence of any warranty; and give any other recipients of
- the atty program a copy of this License Agreement along with the program.
- You may charge a distribution fee for the physical act of transferring
- a copy.
-
- 2. You may modify your copy or copies of atty source code or
- any portion of it, and copy and distribute such modifications under
- the terms of Paragraph 1 above, provided that you also do the following:
-
- a) cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change; and
-
- b) cause the whole of any work that you distribute or publish,
- that in whole or in part contains or is a derivative of atty
- or any part thereof, to be licensed at no charge to all third
- parties on terms identical to those contained in this License
- Agreement (except that you may choose to grant more extensive
- warranty protection to some or all third parties, at your option).
-
- c) You may charge a distribution fee for the physical act of
- transferring a copy, and you may at your option offer warranty
- protection in exchange for a fee.
-
- Mere aggregation of another unrelated program with this program (or its
- derivative) on a volume of a storage or distribution medium does not bring
- the other program under the scope of these terms.
-
- 3. You may copy and distribute atty (or a portion or derivative of it,
- under Paragraph 2) in object code or executable form under the terms of
- Paragraphs 1 and 2 above provided that you also do one of the following:
-
- a) accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- b) accompany it with a written offer, valid for at least three
- years, to give any third party free (except for a nominal
- shipping charge) a complete machine-readable copy of the
- corresponding source code, to be distributed under the terms of
- Paragraphs 1 and 2 above; or,
-
- c) accompany it with the information you received as to where the
- corresponding source code may be obtained. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form alone.)
-
- For an executable file, complete source code means all the source code for
- all modules it contains; but, as a special exception, it need not include
- source code for modules which are standard libraries that accompany the
- operating system on which the executable file runs.
-
- 4. The atty distribution contains two files, regex.h and regex.c,
- which are copyrighted by the Free Software Foundation, Inc. These files
- are not covered by this license agreement, and may only be used or copied
- in accordance with the license agreements that appear at the top of those
- files. The compilation process for the atty program links it with regex.c.
- Therefore binary versions of the atty program are covered by both this
- license and the license appearing at the top of regex.c.
-
- 5. You may not copy, sublicense, distribute or transfer atty except as
- expressly provided under this License Agreement. Any attempt otherwise
- to copy, sublicense, distribute or transfer atty is void and your rights
- to use atty under this License agreement shall be automatically terminated.
- However, parties who have received computer software programs from you
- with this License Agreement will not have their licenses terminated so
- long as such parties remain in full compliance.
-
-
- NO WARRANTY
-
- Because atty is licensed free of charge, I provide absolutely no
- warranty, to the extent permitted by applicable state law. Except
- when otherwise stated in writing, Kenneth Almquist and/or other
- parties provide atty "as is" without warranty of any kind, either
- expressed or implied, including, but not limited to, the implied
- warranties of merchantability and fitness for a particular purpose.
- The entire risk as to the quality and performance of the program is
- with you. Should the atty program prove defective, you assume the cost
- of all necessary servicing, repair or correction.
-
- In no event unless required by applicable law will Kenneth Almquist
- and/or any other party who may modify and redistribute atty as permitted
- above, be liable to you for damages, including any lost profits, lost
- monies, or other special, incidental or consequential damages arising
- out of the use or inability to use (including but not limited to loss
- of data or data being rendered inaccurate or losses sustained by third
- parties or a failure of the program to operate with programs provided
- by other parties) the program, even if you have been advised of the
- possibility of such damages, or for any claim by any other party.
- EOF
- if test `wc -c < LICENSE` -ne 5831
- then echo 'LICENSE is the wrong size'
- fi
- echo extracting atty.1.mk
- cat > atty.1.mk <<\EOF
- echo '.TH ATTY 1'
- echo ".ds d `pwd`/atty.bind"
- cat <<\!
- .SH NAME
- atty \- alternative tty driver
- .SH SYNOPSYS
- .B atty
- .B -ls
- .B -c
- .I command
- [
- .I bindings-file
- ]
- .SH COPYRIGHT
- .if n Copyright (C) 1989 by Kenneth Almquist.
- .if t Copyright \(co 1989 by Kenneth Almquist.
- .SH DESCRIPTION
- .I Atty
- is an alternative to
- .IR tty (4).
- It puts the terminal in
- .I cbreak
- mode to suppress the line editing normally done by
- .IR tty (4)
- .PP
- Most of the standard
- .IR tty (4)
- features (except for the ones relating to input line editing) are supported.
- Skip to the the section titled
- .I "Getting Started"
- if you just want an introduction to
- .IR atty .
- .PP
- When
- .I atty
- starts up, it runs the shell specified by the environment variable
- SHELL. It sets the environment variable ATTY to inform programs that
- they are running under \fIatty\fR.
- If the
- .B -l
- option is given, the shell is made a login shell (by prepending a minus
- sign to arg zero).
- Normally suspending the shell will cause
- .I atty
- to suspend itself. The
- .B -s
- option causes
- .I atty
- to restart a suspended shell instead.
- The
- .B -c
- option causes the shell to run the specified command before reading commands
- from the standard input. This only works with
- .IR ash (1).
- (I use it to make the prompt of my top level shell different from the
- default ``@\ '' \fIwithout\fR passing PS1 as an environment variable,
- which would change the prompt for subshells as well as the top level shell.)
- .PP
- The optional
- .I bindings-file
- controls the key bindings used by the editor (see
- .IR kbind (1)).
- If
- .I bindings-file
- is omitted,
- .I atty
- use the file "$HOME/.bindc" as the bindings file if it exists;
- otherwise it uses the system default binding file ``\*dc''.
- .PP
- Several escape sequences are handled specially by
- .IR atty .
- ``ESC ] P''
- introduces a prompt. The remainder of the line consists of a sequence
- of digits giving the program ID, a semicolon, and the text of the
- prompt.
- ``ESC ] D newline'' deletes the current prompt (if any).
- These two escape sequences can be used by shells (such as
- .IR ash (1))
- that know about
- .IR atty .
- ``ESC ] I'' inserts text in the input buffer. The remainder of the
- line contains the text to be inserted. This is used by the
- .B -c
- option of
- .IR fmatch (1).
- .PP
- Clearing the ODDP bit in the sgtty structure (``stty -odd'') turns off
- the special input editing features of
- .I atty
- and causes the normal
- .IR tty (4)
- input editing to be done.
- .PP
- When the prompt is set (via ``ESC ] P''),
- .I atty
- assumes that it can run the
- .IR fmatch (1)
- program by inputing a command line preceded by an FS character (octal 34).
- .sp 2
- .B "Getting Started"
- .PP
- This section gives an overview of the editiing features of
- .I atty
- when the default binding file is used. For detailed descriptions of the
- commands, see
- .IR kbind (1).
- .PP
- Each command can be given a numeric prefix argument. One way to do this
- is to type ESC followed by the number. Another is to type ^U.
- ^U multiplies the preceding prefix argument by 4 if one is given,
- so a single ^U sets the prefix argument to 4, ^U ^U sets the prefix
- argument to 16, and so on. Typically, the prefix argument specifies the
- number of times that a command is to be repeated. Most commands will do
- something sensible with a negative argument.
- .PP
- Printing characters are bound to the
- .I self-insert
- command, so to enter then you just type them.
- Control characters are used for commands, but you can enter them by
- preceding them with ^V.
- .PP
- Several commands correspond to functions normally provided by
- .IR tty (4).
- DEL (^?) sends an interrupt signal, FS (^\e) sends a quit signal, and
- ^Z sends a stop signal. The first two of these normally flush
- .IR atty 's
- input buffer. ^D generate an end of file when typed on an empty line.
- (Otherwise it deletes the following character.) These keys are the ones
- that you are most likely to want to re-bind; see below.
- .PP
- There are several commands for moving around on a line. ^F moves forward
- one character and ^B moves backward one character. ESC f and ESC b move
- forward and backword by words rather than characters. ESC a and ESC e
- move to the beginning and the end of the line, respectively.
- .PP
- The commands that delete text generally save the deleted text in the
- .IR "kill buffer" .
- You can then get the text back by typing ^Y. This feature is often
- used to move text around. Also, if you delete text by accident, you
- can get it back by typing ^Y.
- .PP
- The most important deletion command is BACKSPACE, which deletes the
- preceding character. It only saves the deleted text to the kill buffer
- if you gave an explicit prefix argument. ^D is similar to BACKSPACE,
- but deletes forwards rather than backwards. (As a special case, ^D
- generates an end of file when typed on an empty line.) There are also
- commands for deleting words: ESC BACKSPACE deletes the preceding word and
- ESC d deletes the following word. Finally, ^W deletes everything between
- the cursor and a location in the line known as the
- .IR mark .
- You can set the location of the mark by typing ^@.
- .PP
- One final text modification command worth mentioning is ^T, which transposes
- the two preceding characters.
- .PP
- .I Atty
- mantains a history of lines typed. ^P moves to the preceding history line
- and ^N moves to the next history line. Both ^P and ^N skip blank lines.
- ^R does a reverse search through the history file for a specified regular
- expression (which you type in, followed by a carriage return). When
- you go to a line, it is loaded into the input buffer where you can then
- edit it. (Editing it does not affect the contents of the actual history
- file.)
- .PP
- When you type carriage return to send a line,
- .I atty
- moves to the end of the history file. You can also send a line using
- ^J (NEWLINE); in this case
- .I atty
- will advance to the next line of the history file rather than moving to
- the end. ^J is useful for resending a series of lines.
- ESC . inserts the last word of the last history line. This
- is useful for entering sequences like:
- .in +1i
- .nf
- mkdir directory
- cd directory
- .fi
- .in -1i
- Finally, ``ESC ,'' inserts the last line of output.
- .sp 2
- .B "Changing Bindings"
- .PP
- If you want to change a few bindings, the best thing to do is to copy
- the system binding file \*d to the file .bind in your home directory,
- and then edit it. As an example, suppose you are a closet VMS fanatic
- and want to make CONTROL-C be your interrupt character. You will find
- that two of the lines in the .bind file read
- .sp
- .nf
- b ^C upcase-char
- and
- b \e177 tty-intr
- .fi
- .sp
- The first line binds ^C to upcase-char, a function that converts a
- character to upper case. The second line binds DELETE (written here
- as \e177; it could also have been written as ^?) to tty-intr. You
- want CONTROL C to do what DELETE does in the standard binding file,
- so change the ``upcase-char'' to ``tty-intr''. Now both CONTROL C
- and DELETE will generate an interrupt, which is perfectly legal. In
- practice you probably want to make DELETE delete the preceding character,
- which you can do by binding it to delete-backward-char. The resulting
- lines look like:
- .sp
- .nf
- b ^C tty-intr
- and
- b \e177 delete-backward-char
- .fi
- .PP
- After you have set up the .bind file to your satisfaction, type
- .sp
- kbind .bind
- .sp
- This will create a file named .bindc which
- .I atty
- will read instead of the default binding file.
- \fIIf you omit this step, atty will ignore the \fR.bind\fI file and will
- continue to use the default binding file.\fR Atty doesn't look for a
- \&.bind file, only a .bindc file.
- .SH AUTHORS
- Kenneth Almquist
- .SH FILES
- \*dc\h'0.5i'default binding file
- .SH "SEE ALSO"
- .ta 2i
- \fIkbind\fR(1)
- .SH BUGS
- Atty could be more intelligent about updating the screen in some cases.
- (The slowest terminals on the systems it was developed on were 9600 baud.)
- .PP
- The program does not create a /etc/utmp entry for the pseudo-terminal that
- it uses. This confuses
- .IR talk (1).
- .PP
- Changing the line discipline will cause problems. There are also a number
- of race conditions. This program really needs more operating system support.
- (Stream pipes would help, but an acknowledgement should really be sent back
- when data is read to allow prompts and input lines to be associated correctly.)
- !
- EOF
- if test `wc -c < atty.1.mk` -ne 8197
- then echo 'atty.1.mk is the wrong size'
- fi
- echo extracting atty.bind
- cat > atty.bind <<\EOF
- # This is the default key binding file for atty.
-
- mode 0
-
- default self-insert
- b ^@ set-mark
- b ^A beginning-of-line
- b ^B backward-char
- b ^C upcase-char
- #b ^D delete-char
- b ^D eof-or-delete-char
- b ^E end-of-line
- b ^F forward-char
- b ^G undefined
- b ^H delete-backward-char
- b \t self-insert
- b ^J newline-and-insert
- b ^K kill-line
- b ^L undefined
- b \r newline
- b ^N next-history
- b ^O undefined
- b ^P previous-history
- b ^Q quoted-insert
- b ^R re-search-backward
- b ^S re-search-forward
- b ^T gosling-transpose-chars
- b ^U universal-argument
- b ^V quoted-insert
- b ^W kill-region
- b ^X kill-input
- b ^Y yank
- b ^Z tty-susp
- b \034 tty-quit
- b \035 undefined
- b \036 undefined
- #b \037 end-of-file
- b \177 tty-intr
-
- b \e^H backward-kill-word
- b \e\s set-mark
- b \e< beginning-of-history
- b \e> end-of-history
- b \e- negative-argument
- b \e0 digit-argument
- b \e1 digit-argument
- b \e2 digit-argument
- b \e3 digit-argument
- b \e4 digit-argument
- b \e5 digit-argument
- b \e6 digit-argument
- b \e7 digit-argument
- b \e8 digit-argument
- b \e9 digit-argument
- b \eb backward-word
- b \eB backward-word
- b \ed kill-word
- b \eD kill-word
- b \ef forward-word
- b \eF forward-word
- b \eh backward-kill-word
- b \eH backward-kill-word
- #b \em insert "/usr/spool/mail/ka"
- b \et transpose-words
- b \eT transpose-words
- b \eu upcase-word
- b \eU upcase-region
- b \ew copy-region-as-kill
- b \eW copy-region-as-kill
- b \ex exchange-point-and-mark
- b \eX exchange-point-and-mark
- b \e\e file-complete
- b \e= list-file-completions
- b \e, last-output-line
- b \e. get-history-word
- b \e\177 backward-kill-word
-
- # arrow keys
- b \e[C forward-char
- b \e[D backward-char
- b \e[A previous-history
- b \e[B next-history
-
- syntax word "a-zA-Z0-9$%"
- syntax filename "^ \t\n&();<>|"
- syntax abbrev "^ \t\n&();<>|/"
-
- #abbrev "~" "$HOME"
- EOF
- if test `wc -c < atty.bind` -ne 1737
- then echo 'atty.bind is the wrong size'
- fi
- echo extracting atty.h
- cat > atty.h <<\EOF
- /*
- * Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
- * This file is part of atty, which is distributed under the terms specified
- * by the Atty General Public License. See the file named LICENSE.
- */
-
- struct tty { /* structure containing terminal modes */
- int ldisc; /* line discipline */
- struct sgttyb sgtty; /* stty modes */
- int lmode; /* local mode */
- struct tchars tchars; /* special characters */
- struct ltchars ltchars; /* more special characters */
- /* window size omitted */
- };
- EOF
- if test `wc -c < atty.h` -ne 542
- then echo 'atty.h is the wrong size'
- fi
- echo extracting atty.c
- cat > atty.c <<\EOF
- /*
- * Atty - tty(4) replacement.
- *
- * Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
- * This file is part of atty, which is distributed under the terms specified
- * by the Atty General Public License. See the file named LICENSE.
- */
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <signal.h>
- #include <sgtty.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <setjmp.h>
- #include <sys/wait.h>
- #include <sys/resource.h>
- #include "atty.h"
- #include "attyed.h"
-
-
- #ifndef __STDC__
- #define const
- #define volatile
- #endif
-
-
- #define ECHO_NL 1 /* echo input line terminated by a newline */
- #define ECHO_EOF 2 /* echo input line terminated by EOF */
- #define ECHO_SIG 3 /* echo interrupt character */
-
-
- struct indata {
- struct indata *next; /* next structure on queue */
- short nchars; /* number of characters */
- short nwrt; /* number of characters already written */
- char data[4]; /* characters; should be "char data[nchars]" */
- };
-
-
- struct tty origtty; /* original tty modes */
- struct tty realtty; /* tty modes of real tty */
- struct tty ptymodes; /* modes of pty */
- int realfcntl; /* flags for real tty file descriptor */
- int ptyfd; /* file descriptor of pty */
- char ptydevice[12]; /* pty device */
- int childpid; /* pid of child process */
- jmp_buf sigjmp; /* where to jump on signal */
- volatile int canjump; /* set if should do longjmp on signal */
- volatile int gotsigchild; /* child is dead */
- volatile int gotsigwinch; /* window size has changed */
- volatile int childstatus; /* status of child */
- struct indata *inputq; /* queue of data to be sent to pty */
- struct indata *inqlast; /* last entry in inputq */
- struct mode ttymode; /* tty characters for editor */
- int remoteon; /* true if TIOCREMOTE mdoe is on */
- int needclearin; /* true if we must clear the tty input */
- int echoflag; /* set if output echoed */
- char sigchar; /* signal character to be echoed */
- int noedit; /* true if not using input editor */
- int logall; /* save all output data in the trace file */
- int loginshell; /* true if should start up login shell */
- int nosuspend; /* don't permit atty to be suspended */
- char *shellcmd; /* prompt to be used by shell */
- short ospeed; /* output speed, for termcap */
- int gottty; /* true if we have read the tty modes */
-
- const struct ltchars real_ltchars = { -1, -1, -1, -1, -1, -1 };
-
- /* C library routines */
- #ifdef __STDC__
- int ioctl(int, int, char *);
- int isatty(int);
- int getpid(void);
- char *getenv(char *);
- #else
- int ioctl();
- int isatty();
- int getpid();
- char *getenv();
- #endif
-
-
- #ifdef __STDC__
- int openpty(void);
- void spawnshell(void);
- void runtty(void);
- void ttyoutc(int);
- void outreal(char *, int);
- void writereal(void);
- void senddata(char *, int);
- void writepty(void);
- int stripecho(int, char *, int);
- void flushptyin(void);
- void onchild();
- void onwinch();
- void indata(char *, int);
- void newttymodes();
- void fillttymode(void);
- void sendsig(int);
- void flushoutput(void);
- void fatal(char *);
- void done(int);
- void cleanup(void);
- int getttymodes(int, struct tty *);
- int setttymodes(int, struct tty *);
- int copyttysize(void);
- #else
- int openpty();
- void spawnshell();
- void runtty();
- void ttyoutc();
- void outreal();
- void writereal();
- void senddata();
- void writepty();
- int stripecho();
- void flushptyin();
- void onchild();
- void onwinch();
- void indata();
- void newttymodes();
- void fillttymode();
- void sendsig();
- void flushoutput();
- void fatal();
- void done();
- void cleanup();
- int getttymodes();
- int setttymodes();
- int copyttysize();
- #endif
-
- #define scopy(s1, s2) strcpy(s2, s1) /*TEMPORARY*/
-
-
- main(argc, argv)
- char **argv;
- {
- int one = 1;
- int i;
- char **ap;
- char *p;
-
- if (! isatty(2) || ! isatty(0)) {
- fputs("Atty can only be run from a terminal\n", stderr);
- exit(2);
- }
- ap = argv;
- if (argc > 0) {
- ap++;
- for (;;) {
- if ((p = *ap) == NULL || *p++ != '-')
- break;
- ap++;
- if (p[0] == '-' && p[1] == '\0') /* "--" */
- break;
- while (*p) {
- switch (*p++) {
- case 'l':
- loginshell++;
- break;
- case 's':
- nosuspend++;
- break;
- case 'c':
- if (*p == '\0' && (p = *ap++) == NULL) {
- fputs("atty: no arg for -c option\n");
- exit(2);
- }
- shellcmd = p;
- p = "";
- break;
- default:
- fprintf(stderr, "atty: Illegal option -%c\n", p[-1]);
- exit(2);
- }
- }
- }
- }
- signal(SIGCHLD, onchild);
- ptyfd = openpty();
- if (getttymodes(2, &origtty) < 0)
- fatal("getttymodes");
- realfcntl = fcntl(2, F_GETFL, 0);
- gottty = 1;
- ospeed = origtty.sgtty.sg_ospeed;
- edinit(*ap);
- ptymodes = origtty;
- ptymodes.ldisc = NTTYDISC; /* we must have literal next char */
- ptymodes.sgtty.sg_flags |= EVENP|ODDP; /* no parity checking */
- realtty = origtty;
- realtty.tchars.t_intrc = -1;
- realtty.tchars.t_quitc = -1;
- realtty.ltchars = real_ltchars;
- realtty.sgtty.sg_flags |= CBREAK;
- realtty.sgtty.sg_flags &=~ (CRMOD|ECHO|LCASE);
- if ((realtty.sgtty.sg_flags & TBDELAY) == XTABS)
- realtty.sgtty.sg_flags &=~ TBDELAY;
- if (setttymodes(2, &realtty) < 0) {
- perror("setttymodes");
- exit(2);
- }
- /* copyttysize(); */
- realfcntl |= FNDELAY;
- fcntl(2, F_SETFL, realfcntl);
- i = fcntl(ptyfd, F_GETFL, 0);
- i |= FNDELAY;
- fcntl(ptyfd, F_SETFL, i);
- #ifdef REMOTE
- if (ioctl(ptyfd, TIOCREMOTE, (char *)&one) < 0)
- fatal("TIOCREMOTE");
- remoteon = 1;
- #endif
- if (ioctl(ptyfd, TIOCPKT, (char *)&one) < 0)
- fatal("TIOCPKT");
- if (setttymodes(ptyfd, &ptymodes) < 0)
- fatal("set pty modes");
- fillttymode();
- copyttysize();
- if ((childpid = fork()) == -1) {
- fatal("fork");
- }
- if (childpid == 0)
- spawnshell();
- else {
- signal(SIGTTOU, SIG_IGN);
- signal(SIGWINCH, onwinch);
- runtty();
- }
- /*NOTREACHED*/
- }
-
-
- /*
- * Search for an unused pty. It returns a file descriptor for the master
- * and leaves the name of the slave in the global variable ptydevice.
- * This code starts at the beginning; a more efficient version might start
- * at a randomly chosen point in the middle.
- */
-
- int
- openpty() {
- char c;
- int i;
- int fd;
-
- scopy("/dev/ptyXX", ptydevice);
- for (c = 'p'; c <= 's'; c++) {
- for (i = 0 ; i < 16 ; i++) {
- ptydevice[8] = c;
- ptydevice[9] = "0123456789abcdef"[i];
- fd = open(ptydevice, 2);
- if (fd >= 0) {
- ptydevice[5] = 't'; /* change "pty" to "tty" */
- return fd; /* success */
- }
- if (errno == ENOENT)
- goto failure;
- }
- }
- failure:
- fprintf(stderr, "Out of pty's\n");
- exit(2);
- }
-
-
- /*
- * This routine exec's the shell.
- */
-
- void
- spawnshell() {
- int fd;
- int mypid = getpid();
- char *shell;
- char **env;
- char **ep;
- extern char **environ;
- char arg0[16];
- char *p;
- char *basename;
- char *argv[4];
-
- if ((shell = getenv("SHELL")) == NULL)
- shell = "/bin/sh";
- for (ep = environ ; *ep ; ep++);
- if ((env = (char **)malloc((char *)(ep + 2) - (char *)environ)) == NULL)
- fatal("Malloc failed");
- for (ep = env ; *environ ; environ++) {
- if (strncmp(*environ, "ATTY=", 5) != 0)
- *ep++ = *environ;
- }
- *ep++ = "ATTY=";
- *ep = NULL;
- close(0);
- close(1);
- close(ptyfd);
- fd = open("/dev/tty", O_RDWR);
- if (fd >= 0) {
- ioctl(fd, TIOCNOTTY, (char *)0);
- close(fd);
- }
- setpgrp(mypid, 0);
- if (open(ptydevice, O_RDWR) != 0) {
- perror(ptydevice);
- exit(2);
- }
- setpgrp(mypid, mypid);
- close(2);
- dup(0); /* file descriptor 1 = dup of 0 */
- dup(0); /* file descriptor 2 = dup of 0 */
- if (ioctl(2, TIOCSPGRP, (char *)&mypid) < 0)
- printf("TIOCSPGRP failed, errno=%d\n", errno);
- basename = shell;
- for (p = shell ; *p ; p++) {
- if (*p == '/')
- basename = p + 1;
- }
- if (loginshell) {
- arg0[0] = '-';
- for (p = arg0 + 1 ; p < arg0 + 15 && *basename ; *p++ = *basename++);
- *p = '\0';
- basename = arg0;
- }
- argv[0] = basename;
- argv[1] = NULL;
- if (shellcmd) {
- argv[1] = "-sc";
- argv[2] = shellcmd;
- argv[3] = NULL;
- }
- execve(shell, argv, env);
- perror(shell);
- exit(2);
- }
-
-
- #define OUTRSIZE 512
-
- char outrbuf[OUTRSIZE];
- char *outrp = outrbuf;
- char *outrnext = outrbuf;
- int outrsize;
-
-
- /*
- * This routine contains the main loop which is run after initialization.
- */
-
- void
- runtty() {
- volatile int ptybit = 1 << ptyfd;
- volatile int realbit = 1 << 2;
- volatile int nfds = ptyfd + 1;
- volatile int inbits, outbits, exceptbits;
- volatile int sel;
- int i, j;
- char buf[260];
-
- if (setjmp(sigjmp))
- goto gotsig;
- for (;;) {
- inbits = realbit;
- outbits = 0;
- if (outrsize == 0)
- inbits |= ptybit;
- else
- outbits = realbit;
- if (inputq != NULL)
- outbits |= ptybit;
- exceptbits = 0;
- canjump = 1;
- if (gotsigchild || gotsigwinch)
- goto gotsig;
- sel = select(nfds, &inbits, &outbits, &exceptbits, (struct timeval *)NULL);
- canjump = 0;
- if (0) { /* if interrupted by signal */
- gotsig:
- if (gotsigchild) {
- gotsigchild = 0;
- i = childstatus;
- if ((i & 0xFF) == 0177
- && (i >> 8 == SIGTSTP || i >> 8 == SIGSTOP)) {
- if (! nosuspend) {
- setttymodes(2, &origtty);
- fcntl(2, F_SETFL, realfcntl &~ FNDELAY);
- kill(getpid(), SIGTSTP);
- setttymodes(2, &realtty);
- fcntl(2, F_SETFL, realfcntl);
- }
- killpg(childpid, SIGCONT);
- } else {
- if ((i & 0xFF) == 0)
- i >>= 8;
- else
- i = i & 0xFF | 0x80;
- done(i);
- }
- }
- if (gotsigwinch) {
- gotsigwinch = 0;
- newscrnwidth(copyttysize());
- }
- } else if (sel < 0) {
- if (errno != EINTR)
- fatal("select");
- } else {
- if (inbits & realbit) {
- if ((i = read(2, buf, sizeof buf)) < 0)
- fatal("tty read");
- if (i == 0)
- fatal("tty eof");
- indata(buf, i);
- }
- if (inbits & ptybit) {
- if ((i = read(ptyfd, buf, sizeof buf)) < 0) {
- /*
- * Probably the problem is that the child
- * process has terminated, which causes the
- * ptc device to return EIO.
- */
- if (gotsigchild)
- goto gotsig;
- if (errno == EIO) {
- sleep(1);
- errno = EIO;
- if (gotsigchild)
- goto gotsig;
- }
- fatal("pty read");
- }
- if (i == 0)
- fatal("pty eof");
- #ifndef TIOCPKT_IOCTL
- newttymodes();
- #endif
- if (buf[0] == TIOCPKT_DATA) {
- j = 0;
- if (echoflag) {
- j = stripecho(echoflag, buf + 1, i - 1);
- echoflag = 0;
- }
- j++;
- #ifdef notdef
- if (logall)
- fwrite(buf + 1, i - 1, 1, trace);
- #endif
- outchars(buf + j, i - j);
- writereal();
- if (noedit == 0)
- refresh();
- } else {
- #ifdef TIOCPKT_IOCTL
- if (buf[0] & TIOCPKT_IOCTL)
- newttymodes();
- #endif
- if (buf[0] & TIOCPKT_FLUSHREAD) {
- clearinput();
- }
- }
- }
- if (outbits & realbit) {
- writereal();
- }
- if (outbits & ptybit) {
- writepty();
- }
- }
- }
- }
-
-
- /*
- * Output a character to the real tty device.
- */
-
- void
- ttyoutc(c)
- char c;
- {
- outreal(&c, 1);
- }
-
-
- /*
- * Output a block of characters to the real tty device.
- */
-
- void
- outreal(p, size)
- char *p;
- {
- int n = &outrbuf[OUTRSIZE] - outrnext;
-
- if (size + outrsize > OUTRSIZE)
- fatal("output overflow");
- if (n > size)
- n = size;
- bcopy(p, outrnext, n);
- outrnext += n;
- if (outrnext == &outrbuf[OUTRSIZE])
- outrnext = outrbuf;
- if (n < size) {
- p += n;
- n = size - n;
- bcopy(p, outrnext, n);
- outrnext += n;
- }
- outrsize += size;
- }
-
-
- /*
- * Write as much data as possible to the real tty, until we block.
- */
-
- void
- writereal() {
- int i;
- int n;
-
- while (outrsize > 0) {
- n = &outrbuf[OUTRSIZE] - outrp;
- if (n > outrsize)
- n = outrsize;
- if ((i = write(2, outrp, n)) < 0) {
- if (errno == EWOULDBLOCK)
- break;
- else
- fatal("tty write");
- }
- outrsize -= i;
- outrp += i;
- if (outrp == &outrbuf[OUTRSIZE])
- outrp = outrbuf;
- }
- }
-
-
- /*
- * Send data to the pty.
- */
-
- #define INDATAHDR ((char *)((struct indata *)0)->data - (char *)0)
-
- void
- senddata(p, size)
- char *p;
- {
- struct indata *ip;
-
- if ((ip = (struct indata *)malloc(INDATAHDR + size)) == NULL)
- fatal("malloc pty data");
- ip->nchars = size;
- ip->nwrt = 0;
- bcopy(p, ip->data, size);
- ip->next = NULL;
- if (inputq == NULL)
- inputq = ip;
- else
- inqlast->next = ip;
- inqlast = ip;
- }
-
-
-
- /*
- * Like writereal, but for pty.
- */
-
- void
- writepty() {
- #ifdef REMOTE
- int i;
- struct indata *ip;
- int one = 1;
-
- if ((ip = inputq) == NULL)
- return;
- if (! remoteon) {
- if (ioctl(ptyfd, TIOCREMOTE, (char *)&one) < 0)
- fatal("TIOCREMOTE");
- remoteon = 1;
- }
- if ((i = write(ptyfd, ip->data, ip->nchars)) < 0) {
- if (errno != EWOULDBLOCK)
- fatal("pty write");
- return;
- } else if (i != ip->nchars) {
- fatal("partial pty write");
- }
- inputq = ip->next;
- free((char *)ip);
- #else
- int i;
- struct indata *ip;
- char buf[512];
- int buflen;
- char c;
- char *p;
- int echotype;
-
- if ((ip = inputq) == NULL)
- return;
- if (noedit) {
- i = write(ptyfd, ip->data + ip->nwrt, ip->nchars - ip->nwrt);
- if (i < 0)
- fatal("pty write");
- if ((ip->nwrt += i) >= ip->nchars) {
- inputq = ip->next;
- free((char *)ip);
- }
- } else {
- newttymodes(); /* just in case */
- p = buf;
- for (i = ip->nwrt ; i < ip->nchars ; i++) {
- c = ip->data[i];
- if (c == ptymodes.sgtty.sg_erase
- || c == ptymodes.sgtty.sg_kill
- || c == ptymodes.tchars.t_intrc
- || c == ptymodes.tchars.t_quitc
- || c == ptymodes.tchars.t_startc
- || c == ptymodes.tchars.t_stopc
- || c == ptymodes.tchars.t_eofc
- || c == ptymodes.tchars.t_brkc
- || c == ptymodes.ltchars.t_suspc
- || c == ptymodes.ltchars.t_dsuspc
- || c == ptymodes.ltchars.t_rprntc
- || c == ptymodes.ltchars.t_flushc
- || c == ptymodes.ltchars.t_werasc
- || c == ptymodes.ltchars.t_lnextc)
- *p++ = ptymodes.ltchars.t_lnextc;
- *p++ = c;
- }
- echotype = ECHO_NL;
- if (p == buf || p[-1] != '\n') {
- *p++ = ptymodes.tchars.t_eofc;
- echotype = ECHO_EOF;
- }
- buflen = p - buf;
- i = write(ptyfd, buf, buflen);
- if (i < 0) {
- if (errno != EWOULDBLOCK)
- fatal("pty write");
- } else if (i < buflen) {
- for (p = buf ; p < buf + buflen ; p++) {
- if (*p == ptymodes.ltchars.t_lnextc)
- p++;
- ip->nwrt++;
- }
- } else {
- inputq = ip->next;
- free((char *)ip);
- }
- if (ptymodes.sgtty.sg_flags & ECHO) {
- echoflag = echotype;
- }
- }
- #endif
- }
-
-
-
- /*
- * Locate the end of the echoed characters.
- */
-
- int
- stripecho(type, p, n)
- char *p;
- {
- register char *q;
-
- q = p;
- if (type == ECHO_NL) {
- do {
- if (--n < 0)
- return 0;
- } while (*q++ != '\n');
- } else if (type == ECHO_EOF) {
- do {
- if (--n <= 0)
- return 0;
- } while (*q++ != '\b' || *q != '\b');
- q++;
- } else {
- if (n < 2 || p[0] != '^' || p[1] != (sigchar ^ 0100))
- return 0;
- q += 2;
- }
- return q - p;
- }
-
-
-
- /*
- * Clear pty input queue. The input queue is the one we write to.
- */
-
- void
- flushptyin() {
- struct indata *ip;
-
- while (inputq != NULL) {
- ip = inputq;
- inputq = ip->next;
- free((char *)ip);
- }
- /* ioctl(ptyfd, TIOCFLUSH, (char *)&mode); */
- }
-
-
- /*
- * Signal handler invoked when a child dies or is stopped.
- */
-
- void
- onchild() {
- int pid;
- int status;
- int e = errno;
-
- if ((pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0)) == childpid) {
- childstatus = status;
- gotsigchild = 1;
- if (canjump)
- longjmp(sigjmp, 1);
- }
- errno = e;
- }
-
-
- /*
- * Signal handler called when the terminal changes size.
- */
-
- void
- onwinch() {
- gotsigwinch = 1;
- if (canjump)
- longjmp(sigjmp, 1);
- }
-
-
- /*
- * Called to process data received from the real tty.
- */
-
- void
- indata(p, n)
- char *p;
- {
- if (noedit) {
- senddata(p, n);
- #ifdef REMOTE
- if (ptymodes.sgtty.sg_flags & ECHO) {
- outchars(p, n);
- writereal();
- }
- #endif
- } else {
- while (--n >= 0)
- inchar(*p++);
- refresh();
- if (needclearin) {
- clearinput();
- needclearin = 0;
- }
- if (outrsize)
- writereal();
- }
- }
-
-
- clearinput() {
- edflush();
- flushptyin();
- }
-
-
- /*
- * Send a signal to the user process.
- */
-
- void
- sendsig(signo) {
- #ifdef REMOTE
- int pgrp;
- int zero = 0;
-
- if (ioctl(ptyfd, TIOCFLUSH, (char *)&zero) < 0)
- fatal("TIOCFLUSH");
- needclearin++;
- if (ioctl(ptyfd, TIOCGPGRP, (char *)&pgrp) < 0)
- fatal("TIOCGPRGP");
- killpg(pgrp, signo);
- #else
- char c;
-
- switch (signo) {
- case SIGINT: c = ttymode.intr; break;
- case SIGQUIT: c = ttymode.quit; break;
- case SIGTSTP: c = ttymode.susp; break;
- default: fatal("sendsig arg");
- }
- if ((ptymodes.lmode & LNOFLSH) == 0 && signo != SIGTSTP)
- flushoutput();
- echoflag = ECHO_SIG;
- sigchar = c;
- if (write(ptyfd, &sigchar, 1) != 1)
- fatal("sendsig write");
- #endif
- }
-
-
- void
- flushoutput() {
- int two = 2;
-
- outrp = outrnext = outrbuf;
- outrsize = 0;
- ioctl(2, TIOCFLUSH, (char *)&two);
- }
-
-
- puttty(c)
- char c;
- {
- write(2, &c, 1);
- }
-
-
- puttstr(s)
- char *s;
- {
- write(2, s, strlen(s));
- }
-
-
- /*
- * Called when the tty modes of the pty are changed by the user.
- */
-
- #define SGCOPY (ALLDELAY|RAW) /* bits to copy from pty to real tty */
-
- void
- newttymodes() {
- char startc, stopc;
- int changereal;
- int flags;
-
- if (getttymodes(ptyfd, &ptymodes) < 0)
- fatal("get pty modes");
- noedit = 0;
- #ifdef notdef
- if (ptymodes.sgtty.sg_flags & (RAW|CBREAK))
- #else
- if ((ptymodes.sgtty.sg_flags & (RAW|CBREAK|ODDP)) != ODDP)
- #endif
- noedit = 1;
- changereal = 0;
- startc = ptymodes.tchars.t_startc;
- stopc = ptymodes.tchars.t_stopc;
- #ifdef notdef
- if (ptymodes.sgtty.sg_flags & RAW)
- startc = stopc = -1;
- #endif
- if (realtty.tchars.t_startc != startc
- || realtty.tchars.t_stopc != stopc) {
- realtty.tchars.t_startc = startc;
- realtty.tchars.t_stopc = stopc;
- changereal = 1;
- }
- flags = ptymodes.sgtty.sg_flags & SGCOPY;
- if ((flags & TBDELAY) == XTABS)
- flags &=~ TBDELAY;
- if ((realtty.sgtty.sg_flags & SGCOPY) != flags) {
- realtty.sgtty.sg_flags &=~ SGCOPY;
- realtty.sgtty.sg_flags |= flags;
- changereal = 1;
- }
- if ((realtty.lmode & LDECCTQ) != (ptymodes.lmode & DECCTQ)) {
- realtty.lmode &=~ LDECCTQ;
- if (ptymodes.lmode & DECCTQ)
- realtty.lmode |= LDECCTQ;
- changereal = 1;
- }
- if (changereal) {
- if (setttymodes(2, &realtty) < 0)
- fatal("change real");
- }
- if (ttymode.intr != ptymodes.tchars.t_intrc
- || ttymode.quit != ptymodes.tchars.t_quitc
- || ttymode.erase!= ptymodes.sgtty.sg_erase
- || ttymode.kill != ptymodes.sgtty.sg_kill
- || ttymode.eof != ptymodes.tchars.t_eofc
- || ttymode.susp != ptymodes.ltchars.t_suspc
- || ttymode.echo != (ptymodes.sgtty.sg_flags & ECHO)) {
- fillttymode();
- newttychars();
- }
- }
-
-
- void
- fillttymode() {
- ttymode.intr = ptymodes.tchars.t_intrc;
- ttymode.quit = ptymodes.tchars.t_quitc;
- ttymode.erase= ptymodes.sgtty.sg_erase;
- ttymode.kill = ptymodes.sgtty.sg_kill;
- ttymode.eof = ptymodes.tchars.t_eofc;
- ttymode.susp = ptymodes.ltchars.t_suspc;
- ttymode.echo = ptymodes.sgtty.sg_flags & ECHO;
- }
-
-
- /*
- * A unexpected error occurred.
- */
-
- void
- fatal(msg)
- char *msg;
- {
- int e = errno;
-
- cleanup();
- errno = e;
- perror(msg);
- fflush(stderr);
- abort();
- }
-
-
- /*
- * Called if initialization fails.
- */
-
- void
- badinit(msg)
- char *msg;
- {
- cleanup();
- fputs(msg, stderr);
- putc('\n', stderr);
- exit(2);
- }
-
-
- /*
- * Exit the program, resetting the terminal modes first. Status is the
- * exit status.
- */
-
- void
- done(status) {
- cleanup();
- exit(status);
- }
-
-
- void
- cleanup() {
- if (gottty) {
- setttymodes(2, &origtty);
- realfcntl &=~ FNDELAY;
- fcntl(2, F_SETFL, realfcntl);
- }
- }
-
-
-
- int
- getttymodes(fd, tty)
- int fd;
- struct tty *tty;
- {
- if (ioctl(fd, TIOCGETD, (char *)&tty->ldisc) < 0
- || ioctl(fd, TIOCGETP, (char *)&tty->sgtty) < 0
- || ioctl(fd, TIOCGETC, (char *)&tty->tchars) < 0
- || ioctl(fd, TIOCLGET, (char *)&tty->lmode) < 0
- || ioctl(fd, TIOCGLTC, (char *)&tty->ltchars) < 0)
- return -1;
- return 0;
- }
-
-
-
- int
- setttymodes(fd, tty)
- int fd;
- struct tty *tty;
- {
- if (ioctl(fd, TIOCSETD, (char *)&tty->ldisc) < 0
- || ioctl(fd, TIOCSETP, (char *)&tty->sgtty) < 0
- || ioctl(fd, TIOCSETC, (char *)&tty->tchars) < 0
- || ioctl(fd, TIOCLSET, (char *)&tty->lmode) < 0
- || ioctl(fd, TIOCSLTC, (char *)&tty->ltchars) < 0)
- return -1;
- return 0;
- }
-
-
-
- /*
- * Copy the size of the tty from the real device to the pty.
- * Returns the number of columns.
- */
-
- int
- copyttysize() {
- #ifdef TIOCGWINSZ
- struct winsize size;
-
- if (ioctl(2, TIOCGWINSZ, (char *)&size) >= 0)
- ioctl(ptyfd, TIOCSWINSZ, (char *)&size);
- return size.ws_col;
- #else
- return 0;
- #endif
- }
- EOF
- if test `wc -c < atty.c` -ne 22147
- then echo 'atty.c is the wrong size'
- fi
- echo extracting attyed.h
- cat > attyed.h <<\EOF
- /*
- * Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
- * This file is part of atty, which is distributed under the terms specified
- * by the Atty General Public License. See the file named LICENSE.
- *
- * This file defines the interface between the editor and the rest of
- * atty. First come things defined in atty and exported to the editor.
- */
-
- #define MAXLLEN 254 /* maximum line length (excluding newline) */
- #define COLUMNS 132 /* maximum screen width we expect */
-
-
- struct mode {
- int intr; /* interrupt character */
- int quit; /* quit character */
- int erase; /* erase character */
- int kill; /* kill character */
- int eof; /* eof character */
- int susp; /* suspend character */
- int echo; /* set if echo turned on */
- };
-
-
- extern struct mode ttymode; /* various info about the tty */
- extern short ospeed; /* output speed (as returned by gtty) */
- extern int promptset; /* true if prompt specified by the user */
- extern char prompt[COLUMNS]; /* the prompt, if any */
- extern int column; /* column for writing output to (see below) */
- extern char outline[COLUMNS]; /* current output line */
- extern char lastoutline[COLUMNS]; /* last complete line of output */
- extern int lastoutlinelen; /* lenght of lastoutline */
-
-
- #ifdef __STDC__
- void ttyoutc(int); /* write a character to the tty */
- void outreal(char *, int); /* write a block of characters to the tty */
- void senddata(char *, int); /* send a line to the process */
- void badinit(char *); /* edinit failed; print message and exit */
- #else
- void ttyoutc();
- void outreal();
- void senddata();
- void badinit();
- #endif
-
-
-
- /*
- * Now routines provide by the editor.
- */
-
- #ifdef __STDC__
- void edinit(char *); /* initialize the editor */
- void newttychars(void); /* called when ttymode changes */
- void newscrnwidth(int); /* called when the screen width changes */
- void inchar(int); /* called to input a character */
- void edflush(void); /* discard any input */
- void refresh(void); /* turn display on and update it */
- void dispoff(int); /* turn display off */
- void freezedisp(int); /* freeze the editor display */
- void insertchars(char *, int); /* insert characters into input buffer */
- #else
- void edinit();
- void newttychars();
- void newscrnwidth();
- void inchar();
- void edflush();
- void refresh();
- void dispoff();
- void freezedisp();
- void insertchars();
- #endif
- EOF
- if test `wc -c < attyed.h` -ne 2378
- then echo 'attyed.h is the wrong size'
- fi
- echo extracting bind.h
- cat > bind.h <<\EOF
- /*
- * Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
- * This file is part of atty, which is distributed under the terms specified
- * by the Atty General Public License. See the file named LICENSE.
- */
-
- #define BINDMAGIC 300 /* magic number at start of .bindc file */
-
- #define C_FUNC 0 /* start of functions */
- #define C_PFXTBL 1 /* prefix table */
- #define C_INSERT 2 /* insert string */
- #define C_UNDEF 3 /* not defined */
-
- #define NSYNTAX 3 /* number of syntax classes */
- EOF
- if test `wc -c < bind.h` -ne 495
- then echo 'bind.h is the wrong size'
- fi
- echo extracting bindc.5
- cat > bindc.5 <<\EOF
- .TH BINDC 5
- .SH NAME
- bindc \- compiled bindings file
- .SH COPYRIGHT
- .if n Copyright (C) 1989 by Kenneth Almquist.
- .if t Copyright \(co 1989 by Kenneth Almquist.
- .SH DESCRIPTION
- The manual page describes the format of the compiled binding files
- produced by
- .IR kbind (1)
- and used by
- .IR atty (1).
- The format assumes eight bit characters. Short integers are stored in
- two bytes, with the low order byte first.
- .PP
- The overall format of the file is:
-
- .in +1i
- .nf
- Magic number (300) (2 bytes)
- Version number of the bindc format (1 byte)
- Number of keymaps (1 bytes)
- Size of string area (2 bytes)
- Size of abbreviations (2 bytes)
- Keymap
- ...
- Word syntax bitmap (16 bytes)
- File name syntax bitmap (16 bytes)
- Abbrev syntax bitmap (16 bytes)
- String area
- Abbreviations area
- .fi
- .in -1i
- .PP
- A keymap consists of two 128 byte arrays, which are indexed by the
- input character. The first array specifies the type of operation
- to be performed when that key is typed. C_FUNC specifies that a
- function is to be performed. The number of the function is given
- by the second array. C_PFXTBL specifies that the next key is to
- be interpreted using the keymap whose number is given by the
- second array. (This is used to implement multicharacter commands.) \
- C_INSERT causes a string in the string area to be inserted. The
- number of the string appears in the second array. C_UNDEF indicates
- that this character is undefined.
- .PP
- The string table consists of a series of strings laid end to end.
- Each string is preceded by a single byte giving the length of the
- string. The length byte is used instead of a nul terminator to allow
- nul characters to be included in strings. The abbreviations area
- contains pairs of strings laid end to end. Each string is preceded by
- a byte giving the length of the string. The first string in each pair
- is the name of an abbreviation; the second is the string that the
- abbreviation expands to.
- .SH AUTHORS
- Kenneth Almquist
- .SH "SEE ALSO"
- .IR kbind (1),
- .IR atty (1).
- EOF
- if test `wc -c < bindc.5` -ne 1987
- then echo 'bindc.5 is the wrong size'
- fi
- echo extracting ed.h
- cat > ed.h <<\EOF
- /*
- * Stuff shared between ed.c and update.c.
- *
- * Copyright (C) 1989 by Kenneth Almquist. All rights reserved.
- * This file is part of atty, which is distributed under the terms specified
- * by the Atty General Public License. See the file named LICENSE.
- */
-
- extern char curline[MAXLLEN+1]; /* line being edited */
- extern char *point; /* cursor location within line */
- extern char *endcurline; /* end of current line */
- extern int needbeep; /* set to request beep */
- extern char editprompt; /* prompt for recursive edit */
-
-
- #ifdef __STDC__
- void gettermcap(void);
- void movetoend(void);
- #else
- void gettermcap();
- void movetoend();
- #endif
- EOF
- if test `wc -c < ed.h` -ne 644
- then echo 'ed.h is the wrong size'
- fi
- echo Archive 1 unpacked
- exit
-