v08i001: Georgia Tech 'se' Screen Editor
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Tue Jan 27 07:15:12 AEST 1987
Submitted by: emoryu1!arnold (Arnold D. Robbins)
Mod.sources: Volume 8, Issue 1
Archive-name: se/Part01
Here is the second release of the Georgia Tech Screen Editor, 'se'.
There were enough changes that a whole new posting is warranted.
Major Changes:
All Georgia Tech specific stuff removed.
It understands window size changes on 4.3BSD and ATT Unix PC/3B1
Support for the shared library on the ATT Unix PC/3B1
Considerable source code reorganization in certain files.
Enjoy,
Arnold Robbins
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# README
# ascii.h
# constdefs.h
# docmd1.c
# docmd2.c
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(6131 characters)'
if test -f 'README'
then
echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
#
# $Header: README,v 1.3 86/07/17 17:52:23 arnold Exp $
#
# $Log: README,v $
# Revision 1.3 86/07/17 17:52:23 arnold
# Fixed some spelling mistakes.
#
# Revision 1.2 86/07/17 17:19:06 arnold
# Removed GT specific stuff, added discussion of window sensitivities.
#
# Revision 1.1 86/05/06 13:34:09 osadr
# Initial revision
#
#
#
README:
This directory contains the source files for the Unix version of the Georgia
Tech Screen Editor "Se". It has three subdirectories which contain things
that se needs. Here is a rundown of the various files.
Files containing documentation are:
README -- this file.
se.m4 -- nroff manual page for se (has to be munged to create se.1).
scriptse.1 -- nroff manual page for scriptse.
The header files are:
ascii.h -- definition of ASCII mnemonics and control characters.
extern.h -- external data definitions for the screen editor.
se.h -- global #define's for the screen editor.
constdefs.h -- global constants, also used by files in subdirectories.
The C source files are:
main.c -- main program and declaration of globals, initialization.
edit.c -- main command loop to get and execute commands, file handling.
docmd1.c -- command decoder and functions for most commands.
docmd2.c -- functions for the rest of the commands.
misc.c -- miscellanious functions.
scratch.c -- scratch file manipulating functions.
screen.c -- routines to keep track of the screen contents.
term.c -- routines for changing the terminal.
The subdirectories are:
libchangetty -- routines to change the terminal driver back and forth.
pat -- pattern matching routines.
se_h -- contains help scripts for all commands in se.
Miscellanious files:
where -- shell file to determine System V (R 1 or 2), 4.1, or 4.2 BSD.
m4munge -- manipulate output of where for m4 for se man page
makefile -- the makefile for make(1).
print2 -- inode used by make for printing only changed stuff.
scriptse.c -- quick and dirty C program to make scripts for se.
scriptse.1 -- manual page for same.
Executable files:
se -- executable version of the screen editor.
scriptse -- the executable version of the script maker.
Conditional Compilation flags:
The flag HARD_TERMS, if added to the CFLAGS macro in the makefile,
will remove the terminal-independent code which uses termlib, and put back
the original, terminal-types-hardwired-into-the-program code. The only
reason to do this is if se has to run on a system without the termlib package.
Using termlib, se is considerably smaller, as well as more flexible.
The flag OLD_SCRATCH, if added to the CFLAGS macro in the makefile,
will cause se to use the original, linked-list method for keeping track of
lines in the buffer. This method is faster for rearranging lines, but
considerably slower for simply looking up lines. Currently, se uses the
method given in Software Tools in Pascal, which keeps the lines in order in
an array. It is slower at rearranging, but as fast as possible for finding
lines in the buffer. This version also takes less data and code space.
The flag OLD_GLOB, if added to the CFLAGS macro in the makefile,
will keep se from special casing commands whose effect is to reverse the
order of the lines in the buffer. The special casing code can save an
*incredible* amount of time for this pathological case, so it is best to leave
things alone. This only applies to the Software Tools in Pascal style
line handling.
The flag LOG_USAGE, if added to the CFLAGS macro in the makefile,
will cause se to write usage "statistics" to a log file, consisting of the
login name and time and date when an individual used se. The logfile path
name in the log() routine in edit.c should be changed to use a system
accounting file somewhere. It currently creates a file in /usr/tmp.
The 'where' command creates a file called 'flags', which the makefile
cats inside ``s. These define and/or undefine the flags USG for System V,
S5R2 if for Release 2, BSD for 4.1 and 4.2, and BSD4_2 for 4.2 specific code.
Miscellanious:
Code which is dependent on the Berkeley job control stuff is also
conditionally compiled in, so that on systems without it, it won't get in
the way.
Code has been added which should allow se to come up under USG Unix
5.0 (System V). If S5R2 is defined, se will use the terminfo package.
Otherwise, it assumes Release 1, and that the BSD termlib package has
been ported and is available.
There is code in term.c to test if se is running on a system with
windows or not. It currently understands the windows on an ATT Unix PC (or 3B1)
and the windowing ioctl's in BRL Unix, which should be identical to those
in 4.3 BSD.
Comments:
It is a big piece of software. But, if you 1) read both Software Tools
and Software Tools in Pascal (the chapters on editing and pattern matching, if
you don't want to read all of the books), and 2) take your time, you should be
able to understand, and eventually make changes to it, as necessary.
Authors:
Se started out as the version of 'ed' that came with the book 'Software
Tools', by Kernighan and Plauger, which was written in Ratfor. On the Pr1me
computers at the School of Information and Computer Science at Georgia Tech,
Dan Forsyth, Perry Flinn, and Alan Akin added all the enhancements suggested
in the exercises in the book, and some more of their own. Jack Waugh made
extensive modifications to turn it into a screen editor; further work was done
by Dan Forsyth. All of this was in an improved Georgia Tech version of Ratfor.
Later, Dan Forsyth, then (and now) at Medical Systems Development
Corporation, converted the Ratfor version into C, for Berkeley Unix (4.1 BSD).
At Georgia Tech, Arnold Robbins took the C version and added many new features
and improvements, the most important of which was termcap support and System V
support. The existing help screens were edited and completed at that time, as
well. This was completed in early 1985.
Arnold Robbins is now at ...!gatech!emory!arnold, and will make every
reasonable attempt to answer any questions anyone may have about it, but in
no way promises to support or enhance 'se'.
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'ascii.h'" '(1389 characters)'
if test -f 'ascii.h'
then
echo shar: will not over-write existing file "'ascii.h'"
else
cat << \SHAR_EOF > 'ascii.h'
/*
* $Header: ascii.h,v 1.1 86/05/06 13:35:19 osadr Exp $
*/
/*
* $Log: ascii.h,v $
* Revision 1.1 86/05/06 13:35:19 osadr
* Initial revision
*
*
*/
/*
** ascii.h
**
** definitions of ASCII mnemonics and synonyms.
*/
#ifndef _ASCII_H
#define _ASCII_H
#define NUL '\0'
#define SOH '\001'
#define STX '\002'
#define ETX '\003'
#define EOT '\004'
#define ENQ '\005'
#define ACK '\006'
#define BEL '\007'
#define BS '\010'
#define HT '\011'
#define LF '\012'
#define VT '\013'
#define FF '\014'
#define CR '\015'
#define SO '\016'
#define SI '\017'
#define DLE '\020'
#define DC1 '\021'
#define DC2 '\022'
#define DC3 '\023'
#define DC4 '\024'
#define NAK '\025'
#define SYN '\026'
#define ETB '\027'
#define CAN '\030'
#define EM '\031'
#define SUB '\032'
#define ESC '\033'
#define FS '\034'
#define GS '\035'
#define RS '\036'
#define US '\037'
#define SP '\040'
#define DEL '\177'
#define CTRL_A SOH
#define CTRL_B STX
#define CTRL_C ETX
#define CTRL_D EOT
#define CTRL_E ENQ
#define CTRL_F ACK
#define CTRL_G BEL
#define CTRL_H BS
#define CTRL_I HT
#define CTRL_J LF
#define CTRL_K VT
#define CTRL_L FF
#define CTRL_M CR
#define CTRL_N SO
#define CTRL_O SI
#define CTRL_P DLE
#define CTRL_Q DC1
#define CTRL_R DC2
#define CTRL_S DC3
#define CTRL_T DC4
#define CTRL_U NAK
#define CTRL_V SYN
#define CTRL_W ETB
#define CTRL_X CAN
#define CTRL_Y EM
#define CTRL_Z SUB
#endif
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'constdefs.h'" '(325 characters)'
if test -f 'constdefs.h'
then
echo shar: will not over-write existing file "'constdefs.h'"
else
cat << \SHAR_EOF > 'constdefs.h'
/*
* $Header: constdefs.h,v 1.1 86/05/06 13:35:37 osadr Exp $
*/
/*
* $Log: constdefs.h,v $
* Revision 1.1 86/05/06 13:35:37 osadr
* Initial revision
*
*
*/
/*
** constdefs.h
**
** Standard macro definitions for se screen editor
*/
#define EOS '\0'
#define ERR (-3)
#define OK (-2)
#define NO 0
#define YES 1
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'docmd1.c'" '(27523 characters)'
if test -f 'docmd1.c'
then
echo shar: will not over-write existing file "'docmd1.c'"
else
cat << \SHAR_EOF > 'docmd1.c'
#ifndef lint
static char RCSid[] = "$Header: docmd1.c,v 1.3 86/07/17 17:19:37 arnold Exp $";
#endif
/*
* $Log: docmd1.c,v $
* Revision 1.3 86/07/17 17:19:37 arnold
* Some general code cleaning up.
*
* Revision 1.2 86/07/11 15:10:20 osadr
* Removed Georgia Tech specific items.
*
* Revision 1.1 86/05/06 13:36:44 osadr
* Initial revision
*
*
*/
/*
** docmd1.c
**
** main command processor. routines for individual commands
*/
#include "se.h"
#include "extern.h"
/* static data definitions -- variables only needed in this file */
static char Tlpat[MAXPAT] = ""; /* saved character list for y/t command */
static char Tabstr[MAXLINE] = ""; /* string representation of tab stops */
static char Ddir = FORWARD; /* delete direction */
static int Compress; /* compress/expand tabs on read/write */
/* docmd --- handle all commands except globals */
int docmd (lin, i, glob, status)
char lin[];
int i, glob, *status;
{
char file[MAXLINE], sub[MAXPAT];
char kname;
int gflag, line3, pflag, flag, fflag, junk, allbut, tflag;
int append (), ckchar (), ckp (), ckupd (), copy ();
int delete (), domark (), doopt (), doprnt (), doread ();
int doshell ();
int dotlit (), doundo (), dowrit (), getfn (), getkn ();
int getone (), getrange (), getrhs (), getstr (), inject ();
int join (), makset (), move (), nextln (), optpat ();
int prevln (), substr (), draw_box ();
char *expand_env ();
*status = ERR;
if (intrpt ()) /* catch a pending interrupt */
return (*status);
switch (lin[i]) {
case APPENDCOM:
case UCAPPENDCOM:
if (lin[i + 1] == '\n' || lin[i + 1] == ':')
{
defalt (Curln, Curln);
if (lin[i + 1] == '\n')
{
/* avoid updating with inline insertion */
adjust_window (Line1, Line2);
updscreen ();
}
*status = append (Line2, &lin[i + 1]);
}
break;
case PRINTCUR:
if (lin[i + 1] == '\n')
{
defalt (Curln, Curln);
saynum (Line2);
*status = OK;
}
break;
case OVERLAYCOM:
case UCOVERLAYCOM:
defalt (Curln, Curln);
if (lin[i + 1] == '\n')
overlay (status);
break;
case CHANGE:
case UCCHANGE:
defalt (Curln, Curln);
if (Line1 <= 0)
Errcode = EORANGE;
else if (lin[i + 1] == '\n' || lin[i + 1] == ':')
{
if (lin[i + 1] == '\n')
{
/* avoid updating with inline insertion */
adjust_window (Line2, Line2);
updscreen ();
}
First_affected = min (First_affected, Line1);
if (lin[i + 1] == '\n')
warn_deleted (Line1, Line2);
*status = append (Line2, &lin[i + 1]);
if (*status != ERR)
{
line3 = Curln;
delete (Line1, Line2, status);
Curln = line3 - (Line2 - Line1 + 1);
/* adjust for deleted lines */
}
}
break;
case DELCOM:
case UCDELCOM:
if (ckp (lin, i + 1, &pflag, status) == OK)
{
defalt (Curln, Curln);
if (delete (Line1, Line2, status) == OK
&& Ddir == FORWARD
&& nextln (Curln) != 0)
Curln = nextln (Curln);
}
break;
case INSERT:
case UCINSERT:
defalt (Curln, Curln);
if (Line1 <= 0)
Errcode = EORANGE;
else if (lin[i + 1] == '\n' || lin[i + 1] == ':')
{
if (lin[i + 1] == '\n')
{
/* avoid updating with inline insertion */
adjust_window (Line1, Line2);
updscreen ();
}
*status = append (prevln (Line2), &lin[i + 1]);
}
break;
case MOVECOM:
case UCMOVECOM:
i++;
if (getone (lin, &i, &line3, status) == EOF)
*status = ERR;
if (*status == OK && ckp (lin, i, &pflag, status) == OK)
{
defalt (Curln, Curln);
*status = move (line3);
}
break;
case COPYCOM:
case UCCOPYCOM:
i++;
if (getone (lin, &i, &line3, status) == EOF)
*status = ERR;
if (*status == OK && ckp (lin, i, &pflag, status) == OK)
{
defalt (Curln, Curln);
*status = copy (line3);
}
break;
case SUBSTITUTE:
case UCSUBSTITUTE:
i++;
if (lin[i] == '\n')
{
/* turn "s\n" into "s//%/\n" */
lin[i+0] = '/';
lin[i+1] = '/';
lin[i+2] = '%';
lin[i+3] = '/';
lin[i+4] = '\n';
lin[i+5] = EOS;
Peekc = SKIP_RIGHT;
}
else
{
/* try to handle "s/stuff\n" */
int j, missing_delim;
missing_delim = YES;
for (j = i + 1; lin[j] != '\n'; j++)
if (lin[j] == ESCAPE && lin[j+1] == lin[i])
j++; /* skip esc, loop continues */
else if (lin[j] == lin[i])
{
missing_delim = NO;
break; /* for */
}
if (missing_delim)
{
for (; lin[j] != EOS; j++)
;
j--; /* j now at newline */
lin[j] = lin[i]; /* delim */
lin[++j] = '\n';
lin[++j] = EOS;
Peekc = SKIP_RIGHT;
/* rest of routines will continue to fix up */
}
}
if (optpat (lin, &i) == OK
&& getrhs (lin, &i, sub, &gflag) == OK
&& ckp (lin, i + 1, &pflag, status) == OK)
{
defalt (Curln, Curln);
*status = subst (sub, gflag, glob);
}
break;
case TLITCOM:
case UCTLITCOM:
i++;
if (lin[i] == '\n')
{
/* turn "y\n" into "y//%/\n" */
lin[i+0] = '/';
lin[i+1] = '/';
lin[i+2] = '%';
lin[i+3] = '/';
lin[i+4] = '\n';
lin[i+5] = EOS;
Peekc = SKIP_RIGHT;
}
else
{
/* try to handle "y/stuff\n" */
int j, missing_delim;
missing_delim = YES;
for (j = i + 1; lin[j] != '\n'; j++)
if (lin[j] == ESCAPE && lin[j+1] == lin[i])
j++; /* skip esc, loop continues */
else if (lin[j] == lin[i])
{
missing_delim = NO;
break; /* for */
}
if (missing_delim)
{
for (; lin[j] != EOS; j++)
;
j--; /* j now at newline */
lin[j] = lin[i]; /* delim */
lin[++j] = '\n';
lin[++j] = EOS;
Peekc = SKIP_RIGHT;
/* rest of routines will continue to fix up */
}
}
if (getrange (lin, &i, Tlpat, MAXPAT, &allbut) == OK
&& makset (lin, &i, sub, MAXPAT) == OK
&& ckp (lin, i + 1, &pflag, status) == OK)
{
defalt (Curln, Curln);
*status = dotlit (sub, allbut);
}
break;
case JOINCOM:
case UCJOINCOM:
i++;
if (getstr (lin, &i, sub, MAXPAT) == OK
&& ckp (lin, i + 1, &pflag, status) == OK)
{
defalt (prevln (Curln), Curln);
*status = join (sub);
}
break;
case UNDOCOM:
case UCUNDOCOM:
i++;
defalt (Curln, Curln);
if (ckchar (UCDELCOM, DELCOM, lin, &i, &flag, status) == OK
&& ckp (lin, i, &pflag, status) == OK)
*status = doundo (flag, status);
break;
case ENTER:
case UCENTER:
i++;
if (Nlines != 0)
Errcode = EBADLNR;
else if (ckupd (lin, &i, ENTER, status) == OK
&& ckchar ('x', 'X', lin, &i, &tflag, status) == OK)
if (getfn (lin, i - 1, file) == OK)
{
strcpy (Savfil, expand_env (file));
mesg (Savfil, FILE_MSG);
clrbuf ();
mkbuf ();
dfltsopt (file);
*status = doread (0, file, tflag);
First_affected = 0;
Curln = min (1, Lastln);
Buffer_changed = NO;
}
else
*status = ERR;
break;
case PRINTFIL:
case UCPRINTFIL:
if (Nlines != 0)
Errcode = EBADLNR;
else if (getfn (lin, i, file) == OK)
{
strcpy (Savfil, expand_env (file));
mesg (Savfil, FILE_MSG);
*status = OK;
}
break;
case READCOM:
case UCREADCOM:
i++;
if (ckchar ('x', 'X', lin, &i, &tflag, status) == OK)
if (getfn (lin, i - 1, file) == OK)
{
defalt (Curln, Curln);
*status = doread (Line2, file, tflag);
}
break;
case WRITECOM:
case UCWRITECOM:
i++;
flag = NO;
fflag = NO;
junk = ckchar ('>', '+', lin, &i, &flag, &junk);
if (flag == NO)
junk = ckchar ('!', '!', lin, &i, &fflag, &junk);
junk = ckchar ('x', 'X', lin, &i, &tflag, &junk);
if (getfn (lin, i - 1, file) == OK)
{
defalt (1, Lastln);
*status = dowrit (Line1, Line2, file, flag, fflag, tflag);
}
break;
case PRINT:
case UCPRINT:
if (lin[i + 1] == '\n')
{
defalt (1, Topln);
*status = doprnt (Line1, Line2);
}
break;
case PAGECOM:
defalt (1, min (Lastln, Botrow - Toprow + Topln));
if (Line1 <= 0)
Errcode = EORANGE;
else if (lin[i + 1] == '\n')
{
Topln = Line2;
Curln = Line2;
First_affected = Line2;
*status = OK;
}
break;
case NAMECOM:
case UCNAMECOM:
i++;
if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR
&& lin[i] == '\n')
uniquely_name (kname, status);
break;
case MARKCOM:
case UCMARKCOM:
i++;
if (getkn (lin, &i, &kname, DEFAULTNAME) != ERR
&& lin[i] == '\n')
{
defalt (Curln, Curln);
*status = domark (kname);
}
break;
case '\n':
line3 = nextln (Curln);
defalt (line3, line3);
*status = doprnt (Line2, Line2);
break;
case LOCATECMD:
case UCLOCATECMD:
if (lin[i+1] == '\n')
{
char *sysname ();
remark (sysname ());
*status = OK;
}
break;
case OPTCOM:
case UCOPTCOM:
if (Nlines == 0)
*status = doopt (lin, &i);
else
Errcode = EBADLNR;
break;
case QUIT:
case UCQUIT:
i++;
if (Nlines != 0)
Errcode = EBADLNR;
else if (ckupd (lin, &i, QUIT, status) == OK)
if (lin[i] == '\n')
*status = EOF;
else
*status = ERR;
break;
case HELP:
case UCHELP:
i++;
if (Nlines == 0)
dohelp (lin, &i, status);
else
Errcode = EBADLNR;
break;
case MISCCOM: /* miscellanious features */
case UCMISCCOM:
i++;
switch (lin[i]) {
case 'b': /* draw box */
case 'B':
defalt (Curln, Curln);
i++;
*status = draw_box (lin, &i);
break;
default:
Errcode = EWHATZAT;
break;
}
break;
case SHELLCOM:
i++;
defalt (Curln, Curln);
*status = doshell (lin, &i);
break;
default:
Errcode = EWHATZAT; /* command not recognized */
break;
}
if (*status == OK)
Probation = NO;
return (*status);
}
/* dohelp --- display documentation about editor */
dohelp (lin, i, status)
char lin[];
int *i, *status;
{
char filename[MAXLINE];
char swt_filename[MAXLINE];
static char helpdir[] = "/usr/local/lib/se_h"; /* help scripts */
int j;
FILE *fp, *fopen ();
SKIPBL (lin, *i);
if (lin[*i] == NEWLINE)
sprintf (filename, "%s/elp", helpdir);
else
{
/* build filename from text after "h" */
sprintf (filename, "%s/%s", helpdir, &lin[*i]);
j = strlen (filename);
filename[j-1] = EOS; /* lop off newline */
}
/* map to lower case */
for (j = 0; filename[j] != EOS; j++)
if (isupper (filename[j]))
filename[j] = tolower (filename[j]);
*status = OK;
if ((fp = fopen (filename, "r")) == NULL)
{
*status = ERR;
Errcode = ENOHELP;
}
else
{
#ifdef u3b2
/* 3B2 seems to have problems with stdio and malloc... */
char buf[BUFSIZ];
setbuf (fp, buf);
#endif
/* status is OK */
display_message (fp); /* display the help script */
fclose (fp);
}
}
/* doopt --- interpret option command */
int doopt (lin, i)
char lin[];
int *i;
{
int temp, line, stat;
char tempstr[4];
int ret;
int dosopt ();
int ctoi ();
(*i)++;
ret = ERR;
switch (lin[*i]) {
case 'g': /* substitutes in a global can(not) fail */
case 'G':
if (lin[*i + 1] == '\n')
{
ret = OK;
Globals = ! Globals; /* toggle */
if (Globals == YES)
remark ("failed global substitutes continue");
else
remark ("failed global substitutes stop");
}
break;
case 'h':
case 'H': /* do/don't use hardware insert/delete */
if (lin[*i + 1] == '\n')
{
ret = OK;
No_hardware = ! No_hardware;
if (No_hardware == YES)
remark ("no line insert/delete");
else
remark ("line insert/delete");
}
break;
case 'k': /* tell user if buffer saved or not */
case 'K':
if (lin[*i + 1] == '\n')
{
ret = OK;
if (Buffer_changed == YES)
remark ("not saved");
else
remark ("saved");
}
break;
case 'z': /* suspend the editor process */
case 'Z':
if (lin[*i + 1] == '\n')
{
ret = OK;
#ifdef BSD
if (Catching_stops)
{
if (Buffer_changed == YES)
fprintf (stderr, "WARNING: buffer not saved\r\n");
kill (getpid(), SIGTSTP);
/* stop_hdlr() will do all the work for us */
}
#else
remark ("process suspension not available");
#endif
}
break;
case 't': /* set or display tab stops for expanding tabs */
case 'T':
++(*i);
if (lin[*i] == '\n')
{
remark (Tabstr);
ret = OK;
}
else
{
ret = settab (&lin[*i]);
if (ret == OK)
strcpy (Tabstr, &lin[*i]);
else /* defaults were set */
strcpy (Tabstr, "+4");
}
break;
case 'w': /* set or display warning column */
case 'W':
++(*i);
if (lin[*i] == '\n')
ret = OK;
else
{
temp = ctoi (lin, i);
if (lin[*i] == '\n')
if (temp > 0 && temp < MAXLINE - 3)
{
ret = OK;
Warncol = temp;
}
else
Errcode = ENONSENSE;
}
if (ret == OK)
saynum (Warncol);
break;
case '-': /* fix window in place on screen, or erase it */
++(*i);
if (getnum (lin, i, &line, &stat) == EOF)
{
mesg ("", HELP_MSG);
if (Toprow > 0)
{
Topln = max (1, Topln - Toprow);
Toprow = 0;
First_affected = Topln;
}
ret = OK;
}
else if (stat != ERR && lin[*i] == '\n')
if (Toprow + (line - Topln + 1) < Cmdrow)
{
Toprow += line - Topln + 1;
Topln = line + 1;
for (temp = 0; temp < Ncols; temp++)
load ('-', Toprow - 1, temp);
if (Topln > Lastln)
adjust_window (1, Lastln);
if (Curln < Topln)
Curln = min (Topln, Lastln);
ret = OK;
}
else
Errcode = EORANGE;
break;
case 'a': /* toggle absolute line numbering */
case 'A':
if (lin[*i + 1] == '\n')
{
Absnos = ! Absnos;
ret = OK;
}
break;
case 'c': /* toggle case option */
case 'C':
if (lin[*i + 1] == '\n')
{
ret = OK;
Invert_case = ! Invert_case;
if (Rel_a == 'A')
{
Rel_a = 'a';
Rel_z = 'z';
}
else
{
Rel_a = 'A';
Rel_z = 'Z';
}
}
mesg (Invert_case ? "CASE" : "", CASE_MSG);
break;
case 'd': /* set or display placement of "." after a delete */
case 'D':
if (lin[*i + 1] == '\n')
{
if (Ddir == FORWARD)
remark (">");
else
remark ("<");
ret = OK;
}
else if (lin[*i + 2] != '\n')
Errcode = EODLSSGTR;
else if (lin[*i + 1] == '>')
{
ret = OK;
Ddir = FORWARD;
}
else if (lin[*i + 1] == '<')
{
ret = OK;
Ddir = BACKWARD;
}
else
Errcode = EODLSSGTR;
break;
case 'v': /* set or display overlay column */
case 'V':
++(*i);
if (lin[*i] == '\n')
{
if (Overlay_col == 0)
remark ("$");
else
saynum (Overlay_col);
ret = OK;
}
else
{
if (lin[*i] == '$' && lin[*i + 1] == '\n')
{
Overlay_col = 0;
ret = OK;
}
else
{
temp = ctoi (lin, i);
if (lin[*i] == '\n')
{
Overlay_col = temp;
ret = OK;
}
else
Errcode = ENONSENSE;
}
}
break;
case 'u': /* set or display character for unprintable chars */
case 'U':
if (lin[*i + 1] == '\n')
{
ret = OK;
tempstr[0] = tempstr[2] = '"';
tempstr[1] = Unprintable;
tempstr[3] = EOS;
remark (tempstr);
}
else if (lin[*i + 2] == '\n')
{
if (lin[*i + 1] < ' ' || lin[*i + 1] >= DEL)
Errcode = ENONSENSE;
else
{
ret = OK;
if (Unprintable != lin[*i + 1])
{
Unprintable = lin[*i + 1];
First_affected = Topln;
}
}
}
break;
case 'l': /* set or display line number display option */
case 'L':
if (lin[*i+1] == '\n')
{
Nchoise = EOS;
ret = OK;
}
else if (lin[*i + 2] == '\n' &&
(lin[*i + 1] == CURLINE || lin[*i + 1] == LASTLINE
|| lin[*i + 1] == TOPLINE))
{
Nchoise = lin[*i + 1];
ret = OK;
}
else if (lin[*i + 1] == 'm' || lin[*i + 1] == 'M')
{
/* set or display the left margin */
(*i)++;
if (lin[*i + 1] == '\n')
{
saynum (Firstcol + 1);
ret = OK;
}
else
{
(*i)++;
temp = ctoi (lin, i);
if (lin[*i] == '\n')
if (temp > 0 && temp < MAXLINE)
{
First_affected = Topln;
Firstcol = temp - 1;
ret = OK;
}
else
Errcode = ENONSENSE;
}
}
break;
case 'f': /* fortran (ugh, yick, gross) options */
case 'F':
if (lin[*i + 1] == '\n')
ret = dosopt ("f");
break;
case 's': /* set source options */
case 'S':
ret = dosopt (&lin[*i + 1]);
break;
case 'i': /* set or display indent option */
case 'I':
++(*i);
if (lin[*i] == '\n')
ret = OK;
else if ((lin[*i] == 'a' || lin[*i] == 'A') && lin[*i + 1] == '\n')
{
Indent = 0;
ret = OK;
}
else
{
temp = ctoi (lin, i);
if (lin[*i] == '\n')
if (temp > 0 && temp < MAXLINE - 3)
{
ret = OK;
Indent = temp;
}
else
Errcode = ENONSENSE;
}
if (ret == OK)
if (Indent > 0)
saynum (Indent);
else
remark ("auto");
break;
case 'm': /* toggle mail notification */
case 'M':
if (lin[*i + 1] == '\n')
{
Notify = ! Notify; /* toggle notification */
remark (Notify ? "notify on" : "notify off");
ret = OK;
}
break;
case 'x':
case 'X': /* toggle tab compression */
if (lin[*i + 1] == '\n')
{
ret = OK;
Compress = ! Compress;
mesg (Compress ? "XTABS" : "", COMPRESS_MSG);
}
break;
case 'y': /* encrypt files */
case 'Y':
if (lin[*i + 1] == '\n')
{
crypt_toggle:
ret = OK;
Crypting = ! Crypting;
if (Crypting )
do {
getkey ();
if (Key[0] == EOS)
remark ("Empty keys are not allowed.\n");
} while (Key[0] == EOS);
else
Key[0] = EOS;
}
else
{
register int j;
ret = OK;
(*i)++; /* *i was the 'y' */
while (isspace (lin[*i]) && lin[*i] != '\n')
(*i)++;
if (lin[*i] != '\n' && lin[*i] != EOS)
{
for (j = 0; lin[*i] != '\n' && lin[*i] != EOS;
j++, (*i)++)
Key[j] = lin[*i];
Key[j] = EOS;
Crypting = YES;
}
else
goto crypt_toggle;
}
mesg (Crypting ? "ENCRYPT" : "", CRYPT_MSG);
break;
default:
Errcode = EOWHAT;
}
return (ret);
}
/* domark --- name lines line1 through line2 as kname */
int domark (kname)
char kname;
{
int line;
int ret;
register LINEDESC *k;
LINEDESC *getind ();
if (Line1 <= 0)
{
Errcode = EORANGE;
ret = ERR;
}
else
{
k = getind (Line1);
for (line = Line1; line <= Line2; line++)
{
if (intrpt())
return (ERR);
k -> Markname = kname;
k = NEXTLINE(k);
}
ret = OK;
}
return (ret);
}
/* doprnt --- set curln, locate window */
int doprnt (from, to)
int from, to;
{
if (from <= 0)
{
Errcode = EORANGE;
return (ERR);
}
adjust_window (from, to);
Curln = to;
return (OK);
}
/* doread --- read "file" after "line" */
int doread (line, file, tflag)
int line;
char *file;
int tflag;
{
register int count, len, i;
int ret;
int strlen ();
FILE *fd;
FILE *fopen (), *crypt_open ();
char lin1[MAXLINE], lin2[MAXLINE];
char *fgets ();
register LINEDESC *ptr;
LINEDESC *sp_inject ();
LINEDESC *getind ();
char *expand_env ();
file = expand_env (file); /* expand $HOME, etc. */
if (Savfil[0] == EOS)
{
strcpy (Savfil, file);
mesg (Savfil, FILE_MSG);
}
if (Crypting)
fd = crypt_open (file, "r");
else
fd = fopen (file, "r");
if (fd == NULL)
{
ret = ERR;
Errcode = ECANTREAD;
}
else
{
First_affected = min (First_affected, line + 1);
ptr = getind (line);
ret = OK;
#ifndef OLD_SCRATCH
Curln = line;
#endif
remark ("reading");
for (count = 0; fgets (lin1, MAXLINE, fd) != NULL; count++)
{
if (intrpt ())
{
ret = ERR;
break;
}
if (Compress == NO && tflag == NO)
ptr = sp_inject (lin1, strlen (lin1), ptr);
else
{
len = 0;
for (i = 0; lin1[i] != EOS && len < MAXLINE - 1; i++)
if (lin1[i] != '\t')
lin2[len++] = lin1[i];
else
do
lin2[len++] = ' ';
while (len % 8 != 0
&& len < MAXLINE - 1);
lin2[len] = EOS;
if (len >= MAXLINE)
{
ret = ERR;
Errcode = ETRUNC;
}
ptr = sp_inject (lin2, len, ptr);
}
if (ptr == NOMORE)
{
ret = ERR;
break;
}
}
if (Crypting)
crypt_close (fd);
else
fclose (fd);
saynum (count);
Curln = line + count;
svins (line, count);
}
return (ret);
}
/* dosopt --- set source language-related options */
int dosopt (lin)
char lin[];
{
char lang[8];
int i;
int strbsr ();
static struct {
char *txt;
int val;
} ltxt[] = {
"", 1,
"as", 2,
"c", 3,
"d", 1,
"data", 1,
"f", 4,
"h", 3,
"n", 1,
"nr", 1,
"nroff",1,
"p", 3,
"r", 3,
"s", 2,
};
i = 0;
getwrd (lin, &i, lang, 8);
strmap (lang, 'a');
i = strbsr ((char *)ltxt, sizeof (ltxt), sizeof (ltxt[0]), lang);
if (i == EOF)
{
Errcode = ENOLANG;
return (ERR);
}
/*
* these are all the same under Unix, so factor
* them out of the switch.
*/
Rel_a = 'A';
Rel_z = 'Z';
Invert_case = NO;
Compress = NO;
switch (ltxt[i].val) {
case 1:
Warncol = 74;
strcpy (Tabstr, "+4");
break;
case 2:
Warncol = 72;
strcpy (Tabstr, "17+8");
Compress = YES; /* except this one */
break;
case 3:
Warncol = 74;
strcpy (Tabstr, "+8");
break;
case 4:
Warncol = 72;
strcpy (Tabstr, "7+3");
break;
}
settab (Tabstr);
mesg (Invert_case == YES ? "CASE" : "", CASE_MSG);
mesg (Compress == YES ? "XTABS" : "", COMPRESS_MSG);
return (OK);
}
/* dotlit --- transliterate characters */
int dotlit (sub, allbut)
char sub[];
int allbut;
{
char new[MAXLINE];
char kname;
int collap, x, i, j, line, lastsub, status;
int ret;
LINEDESC *inx;
LINEDESC *gettxt (), *getind ();
ret = ERR;
if (Line1 <= 0)
{
Errcode = EORANGE;
return (ret);
}
if (First_affected > Line1)
First_affected = Line1;
lastsub = strlen (sub) - 1;
if ((strlen (Tlpat) - 1) > lastsub || allbut == YES)
collap = YES;
else
collap = NO;
for (line = Line1; line <= Line2; line++)
{
if (intrpt ()) /* check for interrupts */
return (ERR);
inx = gettxt (line); /* get text of line into txt, return index */
j = 0;
for (i = 0; Txt[i] != EOS && Txt[i] != '\n'; i++)
{
x = xindex (Tlpat, Txt[i], allbut, lastsub);
if (collap == YES && x >= lastsub && lastsub >= 0) /* collapse */
{
new[j] = sub[lastsub];
j++;
for (i++; Txt[i] != EOS && Txt[i] != '\n'; i++)
{
x = xindex (Tlpat, Txt[i], allbut, lastsub);
if (x < lastsub)
break;
}
}
if (Txt[i] == EOS || Txt[i] == '\n')
break;
if (x >= 0 && lastsub >= 0) /* transliterate */
{
new[j] = sub[x];
j++;
}
else if (x < 0) /* copy */
{
new[j] = Txt[i];
j++;
}
/* else
delete */
}
if (Txt[i] == '\n') /* add a newline, if necessary */
{
new[j] = '\n';
j++;
}
new[j] = EOS; /* add the EOS */
kname = inx -> Markname; /* save the markname */
delete (line, line, &status);
ret = inject (new);
if (ret == ERR)
break;
inx = getind (Curln);
inx -> Markname = kname; /* set markname */
ret = OK;
Buffer_changed = YES;
}
return (ret);
}
/* doundo --- restore last set of lines deleted */
int doundo (dflg, status)
int dflg;
int *status;
{
LINEDESC *l1, *l2, *k1, *k2;
LINEDESC *getind ();
int oldcnt;
int nextln (), prevln ();
*status = ERR;
if (dflg == NO && Line1 <= 0)
Errcode = EORANGE;
else if (Limbo == NOMORE)
Errcode = ENOLIMBO;
else if (Line1 > Line2)
Errcode = EBACKWARD;
else if (Line2 > Lastln)
Errcode = ELINE2;
else
{
*status = OK;
Curln = Line2;
#ifdef OLD_SCRATCH
k1 = getind (Line2);
k2 = getind (nextln (Line2));
l1 = Limbo;
l2 = l1 -> Prevline;
relink (k1, l1, l2, k2);
relink (l2, k2, k1, l1);
#else
blkmove (Limbo - Buf, MAXBUF - 1, Line2);
#endif
svins (Line2, Limcnt);
oldcnt = Limcnt;
Limcnt = 0;
Limbo = NOMORE;
Lastln += oldcnt;
if (dflg == NO)
delete (Line1, Line2, status);
Curln += oldcnt;
if (First_affected > Line1)
First_affected = Line1;
}
return (*status);
}
/* dowrit --- write "from" through "to" into file */
int dowrit (from, to, file, aflag, fflag, tflag)
int from, to, aflag, fflag, tflag;
char *file;
{
FILE *fd;
FILE *fopen (), *crypt_open ();
register int line, ret, i, j;
int strcmp (), access ();
char tabs[MAXLINE];
register LINEDESC *k;
LINEDESC *getind ();
char *expand_env ();
ret = ERR;
if (from <= 0)
Errcode = EORANGE;
else
{
file = expand_env (file); /* expand $HOME, etc. */
if (aflag == YES)
{
if (Crypting)
fd = crypt_open (file, "a");
else
fd = fopen (file, "a");
}
else if (strcmp (file, Savfil) == 0 || fflag == YES
|| Probation == WRITECOM || access (file, 0) == -1)
{
if (Crypting)
fd = crypt_open (file, "w");
else
fd = fopen (file, "w");
}
else
{
Errcode = EFEXISTS;
Probation = WRITECOM;
return (ret);
}
if (fd == NULL)
Errcode = ECANTWRITE;
else
{
ret = OK;
remark ("writing");
k = getind (from);
for (line = from; line <= to; line++)
{
if (intrpt ())
return (ERR);
gtxt (k);
if (Compress == NO && tflag == NO)
fputs (Txt, fd);
else
{
for (i = 0; Txt[i] == ' '; i++)
;
for (j = 0; j < i / 8; j++)
tabs[j] = '\t';
tabs[j] = EOS;
fputs (tabs, fd);
fputs (&Txt[j * 8], fd);
}
k = NEXTLINE(k);
}
if (Crypting)
crypt_close (fd);
else
fclose (fd);
sync (); /* just in case the system crashes */
saynum (line - from);
if (from == 1 && line - 1 == Lastln)
Buffer_changed = NO;
}
}
return (ret);
}
/* expand_env --- expand environment variables in file names */
char *expand_env (file)
register char *file;
{
register int i, j, k; /* indices */
char *getenv ();
char var[MAXLINE]; /* variable name */
char *val; /* value of environment variable */
static char buf[MAXLINE * 2]; /* expanded file name, static to not go away */
i = j = k = 0;
while (file[i] != EOS)
{
if (file[i] == ESCAPE)
{
if (file[i+1] == '$')
{
buf[j++] = file[++i]; /* the actual $ */
i++; /* for next time around the loop */
}
else
buf[j++] = file[i++]; /* the \ */
}
else if (file[i] != '$') /* normal char */
buf[j++] = file[i++];
else /* environment var */
{
i++; /* skip $ */
k = 0;
while (file[i] != '/' && file[i] != EOS)
var[k++] = file[i++]; /* get var name */
var[k] = EOS;
if ((val = getenv (var)) != NULL)
for (k = 0; val[k] != EOS; k++)
buf[j++] = val[k];
/* copy val into file name */
else if (file[i] == '/')
i++; /* var not in enviroment; strip */
/* extra slash */
}
}
buf[j] = EOS;
return (buf);
}
/* crypt_open -- run files through crypt */
FILE *crypt_open (file, mode)
char *file, *mode;
{
char buf[MAXLINE];
FILE *fp, *popen ();
if (! Crypting)
return (NULL);
while (Key[0] == EOS)
{
getkey ();
if (Key[0] == EOS)
fprintf (stderr, "The key must be non-empty!\r\n");
}
switch (mode[0]) {
case 'r':
sprintf (buf, "crypt %s < %s", Key, file);
fp = popen (buf, "r");
return (fp); /* caller checks for NULL or not */
break;
case 'w':
sprintf (buf, "crypt %s > %s", Key, file);
fp = popen (buf, "w");
return (fp); /* caller checks for NULL or not */
break;
case 'a':
sprintf (buf, "crypt %s >> %s", Key, file);
fp = popen (buf, "w");
return (fp); /* caller checks for NULL or not */
break;
default:
return (NULL);
}
}
crypt_close (fp)
FILE *fp;
{
pclose (fp);
}
/* getkey -- get an encryption key from the user */
#define repeat do
#define until(cond) while(!(cond))
getkey ()
{
char *getpass (); /* get input w/out echoing on screen */
clrscreen (); /* does NOT wipe out Screen_image */
tflush ();
ttynormal ();
repeat
{
strcpy (Key, getpass ("Enter encryption key: "));
if (strcmp (Key, getpass ("Again: ")) != 0)
{
Key[0] = EOS;
fprintf (stderr, "didn't work. try again.\n");
}
/* else
all ok */
} until (Key[0] != EOS);
ttyedit ();
restore_screen ();
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'docmd2.c'" '(18109 characters)'
if test -f 'docmd2.c'
then
echo shar: will not over-write existing file "'docmd2.c'"
else
cat << \SHAR_EOF > 'docmd2.c'
#ifndef lint
static char RCSid[] = "$Header: docmd2.c,v 1.3 86/07/17 17:20:29 arnold Exp $";
#endif
/*
* $Log: docmd2.c,v $
* Revision 1.3 86/07/17 17:20:29 arnold
* Some general code cleaning up.
*
* Revision 1.2 86/07/11 15:11:04 osadr
* Removed Georgia Tech specific code.
*
* Revision 1.1 86/05/06 13:36:57 osadr
* Initial revision
*
*
*/
/*
** docmd2.c
**
** routines to actually execute commands
*/
#include "se.h"
#include "extern.h"
/* append --- append lines after "line" */
append (line, str)
int line;
char str[];
{
char lin[MAXLINE];
char term;
int ret;
int len, i, dpos, dotseen;
int inject ();
Curln = line;
if (str[0] == ':') /* text to be added is in the command line */
ret = inject (&str[1]);
else
{
Cmdrow = Toprow + (Curln - Topln) + 1; /* 1 below Curln */
lin[0] = EOS;
if (Indent > 0 || line <= 0)
len = max (0, Indent - 1);
else /* do auto indent */
{
LINEDESC *k, *gettxt ();
k = gettxt (line);
for (len = 0; Txt[len] == ' '; len++)
;
}
dpos = len; /* position for terminating '.' */
for (ret = NOSTATUS; ret == NOSTATUS; )
{
if (! hwinsdel()) /* do it the old, slow way */
{
if (Cmdrow > Botrow)
{
Cmdrow = Toprow + 1;
cprow (Botrow, Toprow);
adjust_window (Curln, Curln);
if (First_affected > Topln)
First_affected = Topln;
}
clrrow (Cmdrow);
if (Cmdrow < Botrow)
clrrow (Cmdrow + 1);
}
else /* try to be smart about it */
{
if (Cmdrow > Botrow)
{
Cmdrow--;
dellines (Toprow, 1);
inslines (Cmdrow, 1);
Topln++;
}
else
{
dellines (Botrow, 1);
inslines (Cmdrow, 1);
}
}
prompt ("apd>");
do
getcmd (lin, Firstcol, &len, &term);
while (term == CURSOR_UP || term == CURSOR_DOWN
|| term == CURSOR_SAME);
dotseen = 0;
if (lin[0] == '.' && lin[1] == '\n' && lin[2] == EOS)
dotseen = 1;
for (i = 0; i < dpos && lin[i] == ' '; i++)
;
if (i == dpos && lin[dpos] == '.' && lin[dpos + 1] == '\n'
&& lin[dpos+2] == EOS)
dotseen = 1;
if (dotseen)
{
if (hwinsdel())
{
dellines (Cmdrow, 1);
inslines (Botrow, 1);
}
ret = OK;
}
else if (inject (lin) == ERR)
ret = ERR;
else /* inject occured */
prompt (""); /* erase prompt */
Cmdrow++;
if (term != FUNNY)
{
if (Indent > 0)
len = Indent - 1;
else /* do auto indent */
for (len = 0; lin[len] == ' '; len++)
;
dpos = len;
lin[0] = EOS;
}
}
Cmdrow = Botrow + 1;
if (hwinsdel()) /* since we take control */
{ /* of the screen, we're sure */
Sctop = Topln; /* it's still OK */
for (i = 0; i < Sclen; i++)
Scline[i] = Sctop + i <= Lastln ? i : -1;
}
}
if (Curln == 0 && Lastln > 0) /* for 0a or 1i followed by "." */
Curln = 1;
if (First_affected > line)
First_affected = line;
tflush ();
return (ret);
}
/* copy --- copy line1 through line2 after line3 */
int copy (line3)
int line3;
{
register int i;
int ret;
register LINEDESC *ptr3, *after3, *k;
LINEDESC *getind ();
ret = ERR;
#ifdef OLD_SCRATCH
ptr3 = getind (line3);
after3 = ptr3 -> Nextline;
#endif
if (Line1 <= 0)
Errcode = EORANGE;
else
{
ret = OK;
Curln = line3;
k = getind (Line1);
for (i = Line1; i <= Line2; i++)
{
gtxt (k);
if (inject (Txt) == ERR || intrpt ())
{
ret = ERR;
break;
}
#ifdef OLD_SCRATCH
if (k == ptr3) /* make sure we don't copy stuff */
k = after3; /* that's already been copied */
else
k = k -> Nextline;
#else
if (Line1 < line3)
k++;
else
k += 2;
/*
* inject calls blkmove, which will shift the
* lines down one in the array, so we add two
* instead of one to get to the next line.
*/
#endif
}
First_affected = min (First_affected, line3 + 1);
}
return (ret);
}
/* delete --- delete lines from through to */
int delete (from, to, status)
int from, to, *status;
{
int nextln (), prevln ();
LINEDESC *k1, *k2, *j1, *j2, *l1;
LINEDESC *getind ();
if (from <= 0) /* can't delete line 0 */
{
*status = ERR;
Errcode = EORANGE;
}
else
{
if (First_affected > from)
First_affected = from;
#ifdef OLD_SCRATCH
k1 = getind (prevln (from));
j1 = k1 -> Nextline;
j2 = getind (to);
k2 = j2 -> Nextline;
relink (k1, k2, k1, k2); /* close chain around deletion */
#else
blkmove (from, to, MAXBUF - 1); /* stick at end of buffer */
#endif
Lastln -= to - from + 1; /* adjust number of last line */
Curln = prevln (from);
#ifdef OLD_SCRATCH
if (Limbo != NOMORE) /* discard lines in limbo */
{
l1 = Limbo -> Prevline;
Limbo -> Prevline = Free;
Free = l1;
}
#endif
Lost_lines += Limcnt;
Limcnt = to - from + 1; /* number of lines "deleted" */
#ifdef OLD_SCRATCH
Limbo = j1; /* put what we just deleted in limbo */
relink (j2, j1, j2, j1); /* close the ring */
#else
/* point at first deleted */
Limbo = &Buf[MAXBUF - (to - from + 1)];
#endif
*status = OK;
svdel (from, to - from + 1);
Buffer_changed = YES;
}
return (*status);
}
/* join --- join a group of lines into a single line */
int join (sub)
char sub[];
{
char new[MAXLINE];
register int l, line, sublen;
int ret;
int inject (), delete (), prevln (), strlen ();
register LINEDESC *k;
LINEDESC *getind ();
ret = OK;
if (Line1 <= 0)
{
Errcode = EORANGE;
return (ERR);
}
sublen = strlen (sub) + 1; /* length of separator & EOS */
line = Line1;
k = getind (line);
gtxt (k);
move_ (Txt, new, (int) k -> Lineleng); /* move in first chunk */
l = k -> Lineleng;
for (line++; line <= Line2; line++)
{
if (intrpt ())
return (ERR);
if (new[l - 2] == '\n') /* zap the NEWLINE */
l--;
k = NEXTLINE(k); /* get the next line */
gtxt (k);
if (l + sublen - 1 + k -> Lineleng - 1 > MAXLINE) /* won't fit */
{
Errcode = E2LONG;
return (ERR);
}
move_ (sub, &new[l - 1], sublen); /* insert separator string */
l += sublen - 1;
move_ (Txt, &new[l - 1], (int) k -> Lineleng); /* move next line */
l += k -> Lineleng - 1;
}
Curln = Line2; /* all this will replace line1 through line2 */
ret = inject (new); /* inject the new line */
if (ret == OK)
ret = delete (Line1, Line2, &ret); /* delete old lines */
Curln++;
if (First_affected > Curln)
First_affected = Curln;
return (ret);
}
/* move --- move line1 through line2 after line3 */
int move (line3)
int line3;
{
int nextln (), prevln ();
LINEDESC *k0, *k1, *k2, *k3, *k4, *k5;
LINEDESC *getind ();
if (Line1 <= 0)
{
Errcode = EORANGE;
return (ERR);
}
if (Line1 <= line3 && line3 <= Line2)
{
Errcode = EINSIDEOUT;
return (ERR);
}
#ifdef OLD_SCRATCH
k0 = getind (prevln (Line1));
k1 = k0 -> Nextline;
k2 = getind (Line2);
k3 = k2 -> Nextline;
relink (k0, k3, k0, k3);
#else
blkmove (Line1, Line2, line3);
#endif
if (line3 > Line1)
{
Curln = line3;
#ifdef OLD_SCRATCH
line3 -= Line2 - Line1 + 1;
#endif
}
else
Curln = line3 + (Line2 - Line1 + 1);
#ifdef OLD_SCRATCH
k4 = getind (line3);
k5 = k4 -> Nextline;
relink (k4, k1, k2, k5);
relink (k2, k5, k4, k1);
#endif
Buffer_changed = YES;
First_affected = min (First_affected, min (Line1, line3));
return (OK);
}
/* overlay --- let user edit lines directly */
overlay (status)
int *status;
{
char savtxt[MAXLINE], term, kname;
static char empty[] = "\n";
int lng, vcol, lcurln, scurln;
int inject (), nextln (), prevln (), strcmp ();
LINEDESC *indx;
LINEDESC *getind (), *gettxt ();
*status = OK;
if (Line1 == 0)
{
Curln = 0;
*status = inject (empty);
if (*status == ERR)
return;
First_affected = 1;
Line1 = 1;
Line2++;
}
for (lcurln = Line1; lcurln <= Line2; lcurln++)
{
Curln = lcurln;
vcol = Overlay_col - 1;
do {
adjust_window (Curln, Curln);
updscreen ();
Cmdrow = Curln - Topln + Toprow;
indx = gettxt (Curln);
lng = indx -> Lineleng;
if (Txt[lng - 2] == '\n') /* clobber newline */
lng--;
if (vcol < 0)
vcol = lng - 1;
while (lng - 1 < vcol)
{
Txt[lng - 1] = ' ';
lng++;
}
Txt[lng - 1] = '\n';
Txt[lng] = EOS;
move_ (Txt, savtxt, lng + 1); /* make a copy of the line */
getcmd (Txt, Firstcol, &vcol, &term);
if (term == FUNNY)
{
if (First_affected > Curln)
First_affected = Curln;
Cmdrow = Botrow + 1;
return;
}
if (strcmp (Txt, savtxt) != 0) /* was line changed? */
{
kname = indx -> Markname;
delete (Curln, Curln, status);
scurln = Curln;
if (*status == OK)
*status = inject (Txt);
if (*status == ERR)
{
Cmdrow = Botrow + 1;
return;
}
indx = getind (nextln (scurln));
indx -> Markname = kname;
}
else
{ /* in case end-of-line is moved */
if (First_affected > Curln)
First_affected = Curln;
}
switch (term) {
case CURSOR_UP:
if (Curln > 1)
Curln--;
else
Curln = Lastln;
break;
case CURSOR_DOWN:
if (Curln < Lastln)
Curln++;
else
Curln = min (1, Lastln);
break;
case CURSOR_SAME:
vcol = 0;
break;
}
} while (term == CURSOR_UP ||
term == CURSOR_DOWN ||
term == CURSOR_SAME);
}
Cmdrow = Botrow + 1;
return;
}
/* subst --- substitute "sub" for occurrences of pattern */
int subst (sub, gflag, glob)
char sub[];
int gflag, glob;
{
char new[MAXLINE], kname;
register int line, m, k, lastm;
int j, junk, status, subbed, ret;
int tagbeg[10], tagend[10];
int amatch (), addset (), inject ();
register LINEDESC *inx;
LINEDESC *gettxt (), *getind ();
if (Globals && glob)
ret = OK;
else
ret = ERR;
if (Line1 <= 0)
{
Errcode = EORANGE;
return (ERR);
}
/* the following code has been removed for your protection
index() occasionally grabs newlines out of the character class
counter in a pattern. for example [0-9] doesn't work due to this
if (index (Pat, '\n') != -1) # never delete NEWLINE
{
Errcode = EBADPAT;
return (ERR);
}
*/
for (line = Line1; line <= Line2; line++)
{
if (intrpt ())
break;
j = 0;
subbed = NO;
inx = gettxt (line);
lastm = -1;
for (k = 0; Txt[k] != EOS; )
{
for (m = 1; m <= 9; m++)
{
tagbeg[m] = -1;
tagend[m] = -1;
}
if (gflag == YES || subbed == NO)
m = amatch (Txt, k, Pat, &tagbeg[1], &tagend[1]);
else
m = -1;
if (m > -1 && lastm != m) /* replace matched text */
{
subbed = YES;
tagbeg[0] = k;
tagend[0] = m;
catsub (Txt, tagbeg, tagend, sub, new, &j, MAXLINE);
lastm = m;
}
if (m == -1 || m == k) /* no match or null match */
{
junk = addset (Txt[k], new, &j, MAXLINE);
k++;
}
else
k = m; /* skip matched text */
}
if (subbed == YES)
{
if (addset (EOS, new, &j, MAXLINE) == NO)
{
ret = ERR;
Errcode = E2LONG;
break;
}
kname = inx -> Markname;
delete (line, line, &status); /* remembers dot */
ret = inject (new);
if (First_affected > Curln)
First_affected = Curln;
if (ret == ERR)
break;
inx = getind (Curln);
inx -> Markname = kname;
ret = OK;
Buffer_changed = YES;
}
else /* subbed == NO */
Errcode = ENOMATCH;
}
return (ret);
}
/* uniquely_name --- mark-name line; make sure no other line has same name */
uniquely_name (kname, status)
char kname;
int *status;
{
register int line;
register LINEDESC *k;
defalt (Curln, Curln);
if (Line1 <= 0)
{
*status = ERR;
Errcode = EORANGE;
return;
}
*status = OK;
line = 0;
k = Line0;
do {
line++;
k = NEXTLINE(k);
if (line == Line2)
k -> Markname = kname;
else if (k -> Markname == kname)
k -> Markname = DEFAULTNAME;
} while (line < Lastln);
return;
}
/* draw_box --- draw or erase a box at coordinates in command line */
int draw_box (lin, i)
char lin[];
int *i;
{
register int left, right, col, len;
int junk;
int ctoi (), strcmp (), inject (), delete ();
register LINEDESC *k;
LINEDESC *getind (), *gettxt ();
char text[MAXLINE];
char kname, ch;
left = ctoi (lin, i);
if (left <= 0 || left > MAXLINE)
{
Errcode = EBADCOL;
return (ERR);
}
if (lin[*i] == ',')
{
(*i)++;
SKIPBL (lin, *i);
right = ctoi (lin, i);
if (right <= 0 || right >= MAXLINE || left > right)
{
Errcode = EBADCOL;
return (ERR);
}
}
else
right = left;
SKIPBL (lin, *i);
if (lin[*i] == '\n')
ch = ' ';
else
ch = lin[(*i)++];
if (lin[*i] != '\n')
{
Errcode = EEGARB;
return (ERR);
}
if (Line1 <= 0)
{
Errcode = EORANGE;
return (ERR);
}
for (Curln = Line1; Curln <= Line2; Curln++)
{
k = gettxt (Curln);
len = k -> Lineleng;
move_ (Txt, text, len);
if (text[len - 2] == '\n')
col = len - 1;
else
col = len;
while (col <= right)
{
text[col - 1] = ' ';
col++;
}
text[col - 1] = '\n';
text[col] = EOS;
if (Curln == Line1 || Curln == Line2)
for (col = left; col <= right; col++)
text[col - 1] = ch;
else
{
text[left - 1] = ch;
text[right - 1] = ch;
}
if (strcmp (text, Txt) != 0)
{
kname = k -> Markname;
if (delete (Curln, Curln, &junk) == ERR
|| inject (text) == ERR)
return (ERR);
k = getind (Curln);
k -> Markname = kname;
Buffer_changed = YES;
}
}
Curln = Line1; /* move to top of box */
if (First_affected > Curln)
First_affected = Curln;
adjust_window (Curln, Curln);
updscreen ();
return (OK);
}
/* dfltsopt --- set the 's' option to the extension on the file name */
dfltsopt (name)
char name[];
{
int i;
int strlen (), dosopt ();
for (i = strlen (name) - 1; i >= 0; i--)
if (name[i] == '.')
{
dosopt (&name[i + 1]);
break;
}
if (i < 0)
dosopt ("");
}
/* doshell --- escape to the Shell to run one or more Unix commands */
/*
** emulate vi: if running just a shell, redraw the screen as
** soon as the shell exits. if running a program, let the user
** redraw the screen when he/she is ready.
**
** also emulate USG Unix 5.0 ed: a ! as the first character is
** replaced by the previous shell command; an unescaped % is replaced
** by the saved file name. The expanded command is echoed.
*/
#ifdef BSD
#define DEFAULT_PATH "/bin/csh"
#define DEF_SHELL "csh"
#else
#define DEFAULT_PATH "/bin/sh"
#define DEF_SHELL "sh"
#endif
int doshell (lin, pi)
char lin[];
int *pi;
{
int forkstatus, childstatus;
int (*save_quit)(), (*save_int)();
int int_hdlr ();
int (*signal())();
int i, auto_redraw;
char *path, *name, *p, *getenv ();
char new_command[MAXLINE];
int j, k;
static char sav_com[MAXLINE] = "";
int expanded = NO;
if (Nlines == 0) /* use normal 'ed' behavior */
{
tflush (); /* flush out the terminal output */
position_cursor (Nrows - 1, 0); /* bottom left corner */
if ((p = getenv ("SHELL")) == NULL || strcmp (p, DEFAULT_PATH) == 0)
{
path = DEFAULT_PATH;
name = DEF_SHELL; /* default */
}
#ifdef BSD
/* on Berkeley systems, check the other shell */
else if (strcmp (p, "/bin/sh") == 0)
{
path = "/bin/sh";
name = "sh";
}
#endif
else
{
if (p[0] == '/') /* full pathname there */
{
/* work backwards to find just name */
path = p;
i = strlen (p);
while (p[i] != '/')
i--;
i++; /* skip '/' */
name = &p[i];
}
else
{
char buf[MAXLINE];
sprintf (buf, "unknown shell, using %s",
DEF_SHELL);
remark (buf);
path = DEFAULT_PATH;
name = DEF_SHELL;
}
}
auto_redraw = (lin[*pi] == '\n') ? YES : NO;
/* build command, checking for leading !, and % anywhere */
if (lin[*pi] == '!')
{
if (sav_com[0] != EOS)
{
for (j = 0; sav_com[j] != EOS; j++)
new_command[j] = sav_com[j];
if (new_command[j-1] == '\n')
j--;
(*pi)++;
expanded = YES;
}
else
{
Errcode = ENOCMD;
return (ERR);
}
}
else
j = 0;
for (i = *pi; lin[i] != EOS; i++)
{
if (lin[i] == ESCAPE)
{
if (lin[i+1] != '%')
{
new_command[j++] = ESCAPE;
new_command[j++] = lin[++i];
}
else
new_command[j++] = lin[++i];
}
else if (lin[i] == '%')
{
for (k = 0; Savfil[k] != EOS; k++)
new_command[j++] = Savfil[k];
expanded = YES;
}
else
new_command[j++] = lin[i];
}
if (new_command[j-1] == '\n')
j--;
new_command[j] = EOS;
strcpy (sav_com, new_command); /* save it */
ttynormal ();
#ifndef HARD_TERMS
t_exit ();
#endif
write (1, "\n\n", 2); /* clear out a line */
forkstatus = fork();
if (forkstatus == -1) /* the fork failed */
{
ttyedit ();
#ifndef HARD_TERMS
t_init ();
#endif
Errcode = ECANTFORK;
return ERR;
}
if (forkstatus == 0) /* we're in the child process */
{
signal (SIGINT, SIG_DFL);
signal (SIGQUIT, SIG_DFL);
#ifdef BSD
if (strcmp (name, "sh") != 0) /* not /bin/sh */
signal (SIGTSTP, SIG_DFL);
else
signal (SIGTSTP, SIG_IGN);
#endif
if (auto_redraw) /* no params; run a shell */
{
execl (path, name, 0);
_exit (RETERR); /* exec failed, notify parent */
}
else
{
if (expanded) /* echo it */
printf ("%s\n", new_command);
execl (path, name, "-c", new_command, 0);
_exit (RETERR);
}
}
/* we're in the parent process here */
save_int = signal (SIGINT, SIG_IGN); /* ignore interrupts */
save_quit = signal (SIGQUIT, SIG_IGN);
while (wait (&childstatus) != forkstatus)
;
save_int = signal (SIGINT, save_int); /* catch interupts */
save_quit = signal (SIGQUIT, save_quit);
write (1, "\n\n", 2); /* clear out some message space */
Currow = Nrows - 1;
Curcol = 0;
if ((childstatus >> 8) != 0)
{
ttyedit ();
#ifndef HARD_TERMS
t_init ();
#endif
Errcode = ENOSHELL;
return ERR;
}
/* a la vi: */
if (! auto_redraw)
{
int c;
printf ("type return to continue: ");
while ((c = getchar()) != '\n' && c != EOF)
;
}
ttyedit ();
#ifndef HARD_TERMS
t_init ();
#endif
restore_screen ();
return OK;
}
else
remark ("Not implemented yet");
return OK;
}
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0
More information about the Mod.sources
mailing list