mse/src/docmd1.c

1474 lines
26 KiB
C
Raw Normal View History

2022-02-08 14:11:56 -05:00
/*
** docmd1.c
**
** main command processor. routines for individual commands
**
** This file is part of mse, under GPLv3.
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "se.h"
#include "changetty.h"
#include "edit.h"
#include "extern.h"
#include "docmd1.h"
#include "docmd2.h"
#include "main.h"
#include "misc.h"
#include "scratch.h"
#include "screen.h"
#include "term.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 (char lin[], int i, int glob, int *status)
{
char file[MAXLINE], sub[MAXPAT];
char *expanded;
char kname;
int gflag, line3, pflag, flag, fflag, junk, allbut, tflag;
*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;
se_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 (se_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, MAXPAT, &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, MAXLINE) == OK)
{
expanded = expand_env (file);
memset (Savfil, EOS, MAXLINE);
strncpy (Savfil, expanded, MAXLINE-1);
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, MAXLINE) == OK)
{
expanded = expand_env (file);
memset (Savfil, EOS, MAXLINE);
strncpy (Savfil, expanded, MAXLINE-1);
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, MAXLINE) == 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, MAXLINE) == 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 */
void dohelp (char lin[], int *i, int *status)
{
char filename[MAXLINE];
char swt_filename[MAXLINE];
static char helpdir[] = HELP_DIR; /* help scripts */
int j;
FILE *fp;
memset (filename, EOS, MAXLINE);
SKIPBL (lin, *i);
if (lin[*i] == NEWLINE)
{
snprintf (filename, MAXLINE-1, "%s/elp", helpdir);
}
else
{
/* build filename from text after "h" */
snprintf (filename, MAXLINE-1, "%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
{
/* status is OK */
display_message (fp); /* display the help script */
fclose (fp);
}
}
/* doopt --- interpret option command */
int doopt (char lin[], int *i)
{
int temp, line, stat;
char tempstr[4];
int ret;
(*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;
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 */
}
}
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]);
memset (Tabstr, EOS, MAXLINE);
if (ret == OK)
{
strncpy (Tabstr, &lin[*i], MAXLINE-1);
}
else
{ /* defaults were set */
strncpy (Tabstr, "+4", MAXLINE-1);
}
}
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 '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
{
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 (char kname)
{
int line;
int ret;
LINEDESC *k;
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 (int from, int to)
{
if (from <= 0)
{
Errcode = EORANGE;
return (ERR);
}
adjust_window (from, to);
Curln = to;
return (OK);
}
/* doread --- read "file" after "line" */
int doread (int line, char *file, int tflag)
{
int count, len, i;
int ret;
FILE *fd;
char lin1[MAXLINE], lin2[MAXLINE];
LINEDESC *ptr;
file = expand_env (file); /* expand $HOME, etc. */
if (Savfil[0] == EOS)
{
memset (Savfil, EOS, MAXLINE);
strncpy (Savfil, file, MAXLINE-1);
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;
Curln = line;
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 (char lin[])
{
char lang[8];
int i;
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;
memset (Tabstr, EOS, MAXLINE);
strncpy (Tabstr, "+4", MAXLINE-1);
break;
case 2:
Warncol = 72;
memset (Tabstr, EOS, MAXLINE);
strncpy (Tabstr, "17+8", MAXLINE-1);
Compress = YES; /* except this one */
break;
case 3:
Warncol = 74;
memset (Tabstr, EOS, MAXLINE);
strncpy (Tabstr, "+8", MAXLINE-1);
break;
case 4:
Warncol = 72;
memset (Tabstr, EOS, MAXLINE);
strncpy (Tabstr, "7+3", MAXLINE-1);
break;
}
settab (Tabstr);
mesg (Invert_case == YES ? "CASE" : "", CASE_MSG);
mesg (Compress == YES ? "XTABS" : "", COMPRESS_MSG);
return (OK);
}
/* dotlit --- transliterate characters */
int dotlit (char sub[], int allbut)
{
char new[MAXLINE];
char kname;
int collap, x, i, j, line, lastsub, status;
int ret;
LINEDESC *inx;
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 = se_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 */
se_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 (int dflg, int *status)
{
LINEDESC *l1, *l2, *k1, *k2;
int oldcnt;
*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;
blkmove (Limbo - Buf, MAXBUF - 1, Line2);
svins (Line2, Limcnt);
oldcnt = Limcnt;
Limcnt = 0;
Limbo = NOMORE;
Lastln += oldcnt;
if (dflg == NO)
se_delete (Line1, Line2, status);
Curln += oldcnt;
if (First_affected > Line1)
First_affected = Line1;
}
return (*status);
}
/* dowrit --- write "from" through "to" into file */
int dowrit (int from, int to, char *file, int aflag, int fflag, int tflag)
{
FILE *fd;
int line, ret, i, j;
char tabs[MAXLINE];
LINEDESC *k;
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 (char *file)
{
int i, j, k; /* indices */
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 (char *file, char *mode)
{
char buf[MAXLINE];
FILE *fp;
memset (buf, EOS, MAXLINE);
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':
snprintf (buf, MAXLINE-1, "crypt %s < %s", Key, file);
fp = popen (buf, "r");
return (fp); /* caller checks for NULL or not */
break;
case 'w':
snprintf (buf, MAXLINE-1, "crypt %s > %s", Key, file);
fp = popen (buf, "w");
return (fp); /* caller checks for NULL or not */
break;
case 'a':
snprintf (buf, MAXLINE-1, "crypt %s >> %s", Key, file);
fp = popen (buf, "w");
return (fp); /* caller checks for NULL or not */
break;
default:
return (NULL);
}
}
void crypt_close (FILE *fp)
{
pclose (fp);
}
/* getkey -- get an encryption key from the user */
void getkey (void)
{
clrscreen (); /* does NOT wipe out Screen_image */
tflush ();
ttynormal ();
do
{
memset (Key, EOS, KEYSIZE);
strncpy (Key, getpass ("Enter encryption key: "), KEYSIZE-1);
if (strcmp (Key, getpass ("Again: ")) != 0)
{
Key[0] = EOS;
fprintf (stderr, "didn't work. try again.\n");
}
/* else
all ok */
} while (Key[0] == EOS);
ttyedit ();
restore_screen ();
}