pkg://joe-2.9.6-2.src.rpm:223169/joe-2.9.6.tgz
info downloads
joe-2.9.6/ 0040755 0032337 0023564 00000000000 07267604100 011703 5 ustar xgrac student joe-2.9.6/b.c 0100600 0032337 0023564 00000127423 07265144131 012267 0 ustar xgrac student /*
Editor engine
Copyright
(C) 1992 Joseph H. Allen
This file is part of JOE (Joe's Own Editor)
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef __MSDOS__
#include <pwd.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "config.h"
#include "blocks.h"
#include "undo.h"
#include "vs.h"
#include "va.h"
#include "utils.h"
#include "path.h"
#include "w.h"
#include "tty.h"
#include "scrn.h"
#include "main.h"
#include "bw.h"
#include "uerror.h"
#include "b.h"
char stdbuf[stdsiz];
extern int errno;
int error;
int force = 0;
VFILE *vmem;
char *msgs[] = {
"Error writing file",
"Error opening file",
"Error seeking file",
"Error reading file",
"New File"
};
/* Get size of gap (amount of free space) */
#define GGAPSZ(hdr) ((hdr)->ehole-(hdr)->hole)
/* Get number of characters in gap buffer */
#define GSIZE(hdr) (SEGSIZ-GGAPSZ(hdr))
/* Set position of gap */
static void gstgap (H *hdr, char *ptr, int ofst) {
if (ofst > hdr->hole)
mfwrd (ptr + hdr->hole, ptr + hdr->ehole, ofst - hdr->hole),
vchanged (ptr);
else if (ofst < hdr->hole)
mbkwd (ptr + hdr->ehole - (hdr->hole - ofst), ptr + ofst,
hdr->hole - ofst), vchanged (ptr);
hdr->ehole = ofst + hdr->ehole - hdr->hole;
hdr->hole = ofst;
}
/* Insert a block */
static void ginsm (H *hdr, char *ptr, int ofst, char *blk, int size) {
if (ofst != hdr->hole)
gstgap (hdr, ptr, ofst);
mcpy (ptr + hdr->hole, blk, size);
hdr->hole += size;
vchanged (ptr);
}
/* Read block */
static void grmem (H *hdr, char *ptr, int ofst, char *blk, int size) {
if (ofst < hdr->hole)
if (size > hdr->hole - ofst)
mcpy (blk, ptr + ofst, hdr->hole - ofst),
mcpy (blk + hdr->hole - ofst,
ptr + hdr->ehole,
size - (hdr->hole - ofst));
else
mcpy (blk, ptr + ofst, size);
else
mcpy (blk, ptr + ofst + hdr->ehole - hdr->hole, size);
}
/* Header allocation */
static H nhdrs = { {&nhdrs, &nhdrs} };
static H ohdrs = { {&ohdrs, &ohdrs} };
static H *halloc (void) {
H *h;
if (qempty (H, link, &ohdrs))
{
h = (H *) alitem (&nhdrs, sizeof (H));
h->seg = my_valloc (vmem, (long) SEGSIZ);
}
else
h = deque (H, link, ohdrs.link.next);
h->hole = 0;
h->ehole = SEGSIZ;
h->nlines = 0;
izque (H, link, h);
return h;
}
static void hfree (H *h) {
enquef (H, link, &ohdrs, h);
}
static void hfreechn (H *h) {
splicef (H, link, &ohdrs, h);
}
/* Pointer allocation */
static P frptrs = { {&frptrs, &frptrs} };
static P *palloc (void) {
return alitem (&frptrs, sizeof (P));
}
static void pfree (P *p) {
enquef (P, link, &frptrs, p);
}
/* Doubly linked list of buffers and free buffer structures */
static B bufs = { {&bufs, &bufs} };
static B frebufs = { {&frebufs, &frebufs} };
B *bnext (void) {
B *b;
do
{
b = bufs.link.prev;
deque (B, link, &bufs);
enqueb (B, link, b, &bufs);
}
while (b->internal);
return b;
}
B *bprev (void) {
B *b;
do
{
b = bufs.link.next;
deque (B, link, &bufs);
enquef (B, link, b, &bufs);
}
while (b->internal);
return b;
}
/* Make a buffer out of a chain */
static B *bmkchn (H *chn, B *prop, long amnt, long nlines) {
B *b = alitem (&frebufs, sizeof (B));
b->undo = undomk (b);
if (prop)
b->o = prop->o;
else
b->o = pdefault;
mset (b->marks, 0, sizeof (b->marks));
b->rdonly = 0;
b->orphan = 0;
b->oldcur = 0;
b->oldtop = 0;
b->backup = 1;
b->internal = 1;
b->changed = 0;
b->count = 1;
b->name = 0;
b->er = -3;
b->bof = palloc ();
izque (P, link, b->bof);
b->bof->end = 0;
b->bof->b = b;
b->bof->owner = 0;
b->bof->hdr = chn;
b->bof->ptr = vlock (vmem, b->bof->hdr->seg);
b->bof->ofst = 0;
b->bof->byte = 0;
b->bof->line = 0;
b->bof->col = 0;
b->bof->xcol = 0;
b->bof->valcol = 1;
b->eof = pdup (b->bof);
b->eof->end = 1;
vunlock (b->eof->ptr);
b->eof->hdr = chn->link.prev;
b->eof->ptr = vlock (vmem, b->eof->hdr->seg);
b->eof->ofst = GSIZE (b->eof->hdr);
b->eof->byte = amnt;
b->eof->line = nlines;
b->eof->valcol = 0;
enquef (B, link, &bufs, b);
pcoalesce (b->bof);
pcoalesce (b->eof);
return b;
}
/* Create an empty buffer */
B *bmk (B *prop) {
return bmkchn (halloc (), prop, 0L, 0L);
}
/* Eliminate a buffer */
extern B *errbuf;
void brm (B *b) {
if (b && !--b->count)
{
if (b->changed)
abrerr (b->name);
if (b == errbuf)
errbuf = 0;
if (b->undo)
undorm (b->undo);
hfreechn (b->eof->hdr);
while (!qempty (P, link, b->bof))
prm (b->bof->link.next);
prm (b->bof);
if (b->name)
free (b->name);
demote (B, link, &frebufs, b);
}
}
P *poffline (P *p) {
if (p->ptr)
{
vunlock (p->ptr);
p->ptr = 0;
}
return p;
}
P *ponline (P *p) {
if (!p->ptr)
p->ptr = vlock (vmem, p->hdr->seg);
return p;
}
B *boffline (B *b) {
P *p = b->bof;
do
poffline (p);
while ((p = p->link.next) != b->bof);
return b;
}
B *bonline (B *b) {
P *p = b->bof;
do
ponline (p);
while ((p = p->link.next) != b->bof);
return b;
}
P *pdup (P *p) {
P *n = palloc ();
n->end = 0;
n->ptr = 0;
n->owner = 0;
enquef (P, link, p, n);
return pset (n, p);
}
P *pdupown (P *p, P **o) {
P *n = palloc ();
n->end = 0;
n->ptr = 0;
n->owner = o;
enquef (P, link, p, n);
pset (n, p);
if (*o)
prm (*o);
*o = n;
return n;
}
void prm (P *p) {
if (!p)
return;
if (p->owner)
*p->owner = 0;
if (p->ptr)
vunlock (p->ptr);
pfree (deque (P, link, p));
}
P *pset (P *n, P *p) {
if (n != p)
{
n->b = p->b;
n->ofst = p->ofst;
n->hdr = p->hdr;
if (n->ptr)
vunlock (n->ptr);
if (p->ptr)
{
n->ptr = p->ptr;
vupcount (n->ptr);
}
else
n->ptr = vlock (vmem, n->hdr->seg);
n->byte = p->byte;
n->line = p->line;
n->col = p->col;
n->valcol = p->valcol;
}
return n;
}
P *p_goto_bof (P *p) {
return pset (p, p->b->bof);
}
P *p_goto_eof (P *p) {
return pset (p, p->b->eof);
}
int pisbof (P *p) {
return p->hdr == p->b->bof->hdr && !p->ofst;
}
int piseof (P *p) {
return p->ofst == GSIZE (p->hdr);
}
int piseol (P *p) {
int c;
if (piseof (p))
return 1;
c = brc (p);
if (c == '\n')
return 1;
if (p->b->o.crlf)
if (c == '\r')
{
P *q = pdup (p);
pfwrd (q, 1L);
if (pgetc (q) == '\n')
{
prm (q);
return 1;
}
else
prm (q);
}
return 0;
}
int pisbol (P *p) {
char c;
if (pisbof (p))
return 1;
c = prgetc (p);
pgetc (p);
return c == '\n';
}
int pisbow (P *p) {
P *q = pdup (p);
int c = brc (p);
int d = prgetc (q);
prm (q);
if (isalnum_ (c) && !isalnum_ (d))
return 1;
else
return 0;
}
int piseow (P *p) {
P *q = pdup (p);
int d = brc (q);
int c = prgetc (q);
prm (q);
if (isalnum_ (c) && !isalnum_ (d))
return 1;
else
return 0;
}
int pisblank (P *p) {
P *q = pdup (p);
p_goto_bol (q);
while (isblank (brc (q))) {
pgetc (q);
}
if (piseol (q)) {
prm (q);
return 1;
} else {
prm (q);
return 0;
}
}
long pisindent (P *p) {
P *q = pdup (p);
long col;
p_goto_bol (q);
while (isblank (brc (q)))
pgetc (q);
col = q->col;
prm (q);
return col;
}
int pnext (P *p) {
if (p->hdr == p->b->eof->hdr)
{
p->ofst = GSIZE (p->hdr);
return 0;
}
p->hdr = p->hdr->link.next;
p->ofst = 0;
vunlock (p->ptr);
p->ptr = vlock (vmem, p->hdr->seg);
return 1;
}
int pprev (P *p) {
if (p->hdr == p->b->bof->hdr)
{
p->ofst = 0;
return 0;
}
p->hdr = p->hdr->link.prev;
p->ofst = GSIZE (p->hdr);
vunlock (p->ptr);
p->ptr = vlock (vmem, p->hdr->seg);
return 1;
}
int pgetc (P *p) {
unsigned char c;
if (p->ofst == GSIZE (p->hdr))
return MAXINT;
if (p->ofst >= p->hdr->hole)
c = p->ptr[p->ofst + p->hdr->ehole - p->hdr->hole];
else
c = p->ptr[p->ofst];
if (++p->ofst == GSIZE (p->hdr))
pnext (p);
++p->byte;
if (c == '\n') {
++(p->line);
p->col = 0;
p->valcol = 1;
} else if (p->b->o.crlf && c == '\r') {
if (brc (p) == '\n')
return pgetc (p);
else
++p->col;
} else {
if (c == '\t')
p->col += (p->b->o.tab) - (p->col) % (p->b->o.tab);
else
++(p->col);
}
return c;
}
P *pfwrd (P *p, long n) {
if (!n)
return p;
p->valcol = 0;
do
{
if (p->ofst == GSIZE (p->hdr))
do
{
if (!p->ofst)
p->byte += GSIZE (p->hdr), n -=
GSIZE (p->hdr), p->line +=
p->hdr->nlines;
if (!pnext (p))
return 0;
}
while (n > GSIZE (p->hdr));
if (p->ofst >= p->hdr->hole)
{
if (p->
ptr[p->ofst + p->hdr->ehole - p->hdr->hole] ==
'\n')
++p->line;
}
else if (p->ptr[p->ofst] == '\n')
++p->line;
++p->byte;
++p->ofst;
}
while (--n);
if (p->ofst == GSIZE (p->hdr))
pnext (p);
return p;
}
int prgetc1 (P *p) {
unsigned char c;
if (!p->ofst)
if (!pprev (p))
return MAXINT;
--p->ofst;
if (p->ofst >= p->hdr->hole)
c = p->ptr[p->ofst + p->hdr->ehole - p->hdr->hole];
else
c = p->ptr[p->ofst];
--p->byte;
if (c == '\n')
--p->line, p->valcol = 0;
else
{
if (c == '\t')
p->valcol = 0;
--p->col;
}
return c;
}
int prgetc (P *p) {
int c = prgetc1 (p);
if (p->b->o.crlf && c == '\n')
{
c = prgetc1 (p);
if (c == '\r')
return '\n';
if (c != MAXINT)
pgetc (p);
c = '\n';
}
return c;
}
P *pbkwd (P *p, long n) {
if (!n)
return p;
p->valcol = 0;
do
{
if (!p->ofst)
do
{
if (p->ofst)
p->byte -= p->ofst, n -=
p->ofst, p->line -=
p->hdr->nlines;
if (!pprev (p))
return 0;
}
while (n > GSIZE (p->hdr));
--p->ofst;
--p->byte;
if (p->ofst >= p->hdr->hole)
{
if (p->
ptr[p->ofst + p->hdr->ehole - p->hdr->hole] ==
'\n')
--p->line;
}
else if (p->ptr[p->ofst] == '\n')
--p->line;
}
while (--n);
return p;
}
P *pgoto (P *p, long loc) {
if (loc > p->byte)
pfwrd (p, loc - p->byte);
else if (loc < p->byte)
pbkwd (p, p->byte - loc);
return p;
}
P *pfcol (P *p) {
H *hdr = p->hdr;
int ofst = p->ofst;
p_goto_bol (p);
while (p->ofst != ofst || p->hdr != hdr)
pgetc (p);
return p;
}
P *p_goto_bol (P *p) {
if (pprevl (p))
pgetc (p);
p->col = 0;
p->valcol = 1;
return p;
}
P *p_goto_eol (P *p) {
if (p->b->o.crlf)
while (!piseol (p))
pgetc (p);
else
while (p->ofst != GSIZE (p->hdr))
{
unsigned char c;
if (p->ofst >= p->hdr->hole)
c =
p->ptr[p->ofst + p->hdr->ehole -
p->hdr->hole];
else
c = p->ptr[p->ofst];
if (c == '\n')
break;
else
{
++p->byte;
++p->ofst;
if (c == '\t')
p->col +=
p->b->o.tab -
p->col % p->b->o.tab;
else
++p->col;
if (p->ofst == GSIZE (p->hdr))
pnext (p);
}
}
return p;
}
P *pnextl (P *p) {
char c;
do
{
if (p->ofst == GSIZE (p->hdr))
do
{
p->byte += GSIZE (p->hdr) - p->ofst;
if (!pnext (p))
return 0;
}
while (!p->hdr->nlines);
if (p->ofst >= p->hdr->hole)
c = p->ptr[p->ofst + p->hdr->ehole - p->hdr->hole];
else
c = p->ptr[p->ofst];
++p->byte;
++p->ofst;
}
while (c != '\n');
++p->line;
p->col = 0;
p->valcol = 1;
if (p->ofst == GSIZE (p->hdr))
pnext (p);
return p;
}
P *pprevl (P *p) {
char c;
p->valcol = 0;
do
{
if (!p->ofst)
do
{
p->byte -= p->ofst;
if (!pprev (p))
return 0;
}
while (!p->hdr->nlines);
--p->ofst;
--p->byte;
if (p->ofst >= p->hdr->hole)
c = p->ptr[p->ofst + p->hdr->ehole - p->hdr->hole];
else
c = p->ptr[p->ofst];
}
while (c != '\n');
--p->line;
if (p->b->o.crlf && c == '\n')
{
int k = prgetc1 (p);
if (k != '\r' && k != MAXINT)
pgetc (p);
}
return p;
}
P *pline (P *p, long line) {
if (line > p->b->eof->line)
{
pset (p, p->b->eof);
return p;
}
if (line < labs (p->line - line))
pset (p, p->b->bof);
if (labs (p->b->eof->line - line) < labs (p->line - line))
pset (p, p->b->eof);
if (p->line == line)
{
p_goto_bol (p);
return p;
}
while (line > p->line)
pnextl (p);
if (line < p->line)
{
while (line < p->line)
pprevl (p);
p_goto_bol (p);
}
return p;
}
P *pcol (P *p, long goalcol) {
p_goto_bol (p);
do
{
unsigned char c;
int wid;
if (p->ofst == GSIZE (p->hdr))
break;
if (p->ofst >= p->hdr->hole)
c = p->ptr[p->ofst + p->hdr->ehole - p->hdr->hole];
else
c = p->ptr[p->ofst];
if (c == '\n')
break;
if (p->b->o.crlf && c == '\r' && piseol (p))
break;
if (c == '\t')
wid = p->b->o.tab - p->col % p->b->o.tab;
else
wid = 1;
if (p->col + wid > goalcol)
break;
if (++p->ofst == GSIZE (p->hdr))
pnext (p);
++p->byte;
p->col += wid;
}
while (p->col != goalcol);
return p;
}
P *pcolwse (P *p, long goalcol) {
int c;
pcol (p, goalcol);
do
c = prgetc (p);
while (c == ' ' || c == '\t');
if (c != MAXINT)
pgetc (p);
return p;
}
P *pcoli (P *p, long goalcol) {
p_goto_bol (p);
while (p->col < goalcol)
{
unsigned char c;
if (p->ofst == GSIZE (p->hdr))
break;
if (p->ofst >= p->hdr->hole)
c = p->ptr[p->ofst + p->hdr->ehole - p->hdr->hole];
else
c = p->ptr[p->ofst];
if (c == '\n')
break;
#ifdef __MSDOS
if (c == '\r' && piseol (p))
break;
#endif
else if (c == '\t')
p->col += p->b->o.tab - p->col % p->b->o.tab;
else
++p->col;
if (++p->ofst == GSIZE (p->hdr))
pnext (p);
++p->byte;
}
return p;
}
void pfill (P *p, long to, int usetabs) {
piscol (p);
if (usetabs)
while (p->col < to)
if (p->col + p->b->o.tab - p->col % p->b->o.tab <= to)
binsc (p, '\t'), pgetc (p);
else
binsc (p, ' '), pgetc (p);
else
while (p->col < to)
binsc (p, ' '), pgetc (p);
}
void pbackws (P *p) {
int c;
P *q = pdup (p);
do
c = prgetc (q);
while (c == ' ' || c == '\t');
if (c != MAXINT)
pgetc (q);
bdel (q, p);
prm (q);
}
static char frgetc (P *p) {
if (!p->ofst)
pprev (p);
--p->ofst;
if (p->ofst >= p->hdr->hole)
return p->ptr[p->ofst + p->hdr->ehole - p->hdr->hole];
else
return p->ptr[p->ofst];
}
static void ffwrd (P *p, int n) {
while (n > GSIZE (p->hdr) - p->ofst)
{
n -= GSIZE (p->hdr) - p->ofst;
if (!pnext (p))
return;
}
if ((p->ofst += n) == GSIZE (p->hdr))
pnext (p);
}
static P *ffind (P *p, unsigned char *s, int len) {
long amnt = p->b->eof->byte - p->byte;
int x;
unsigned char table[256], c;
if (len > amnt)
return 0;
if (!len)
return p;
p->valcol = 0;
mset (table, 255, 256);
for (x = 0; x != len - 1; ++x)
table[s[x]] = x;
ffwrd (p, len);
amnt -= len;
x = len;
do
if ((c = frgetc (p)) != s[--x])
{
if (table[c] == 255)
ffwrd (p, len + 1), amnt -= x + 1;
else if (x <= table[c])
ffwrd (p, len - x + 1), --amnt;
else
ffwrd (p, len - table[c]), amnt -=
x - table[c];
if (amnt < 0)
return 0;
else
x = len;
}
while (x);
return p;
}
static P *fifind (P *p, unsigned char *s, int len) {
long amnt = p->b->eof->byte - p->byte;
int x;
unsigned char table[256], c;
if (len > amnt)
return 0;
if (!len)
return p;
p->valcol = 0;
mset (table, 255, 256);
for (x = 0; x != len - 1; ++x)
table[s[x]] = x;
ffwrd (p, len);
amnt -= len;
x = len;
do
if ((c = toupper (frgetc (p))) != s[--x])
{
if (table[c] == 255)
ffwrd (p, len + 1), amnt -= x + 1;
else if (x <= table[c])
ffwrd (p, len - x + 1), --amnt;
else
ffwrd (p, len - table[c]), amnt -=
x - table[c];
if (amnt < 0)
return 0;
else
x = len;
}
while (x);
return p;
}
static P *getto (P *p, P *q) {
while (p->hdr != q->hdr || p->ofst != q->ofst)
{
if (p->ofst >= p->hdr->hole)
{
if (p->
ptr[p->ofst + p->hdr->ehole - p->hdr->hole] ==
'\n')
++p->line;
}
else if (p->ptr[p->ofst] == '\n')
++p->line;
++p->byte;
++p->ofst;
if (p->ofst == GSIZE (p->hdr))
pnext (p);
while (!p->ofst && p->hdr != q->hdr)
{
p->byte += GSIZE (p->hdr), p->line +=
p->hdr->nlines;
pnext (p);
}
}
return p;
}
P *pfind (P *p, char *s, int len) {
P *q = pdup (p);
if (ffind (q, s, len))
{
getto (p, q);
prm (q);
return p;
}
else
{
prm (q);
return 0;
}
}
P *pifind (P *p, char *s, int len) {
P *q = pdup (p);
if (fifind (q, s, len))
{
getto (p, q);
prm (q);
return p;
}
else
{
prm (q);
return 0;
}
}
static void fbkwd (P *p, int n) {
while (n > p->ofst)
{
n -= p->ofst;
if (!pprev (p))
return;
}
if (p->ofst >= n)
p->ofst -= n;
else
p->ofst = 0;
}
static int fpgetc (P *p) {
char c;
if (p->ofst == GSIZE (p->hdr))
return MAXINT;
if (p->ofst >= p->hdr->hole)
c = p->ptr[p->ofst + p->hdr->ehole - p->hdr->hole];
else
c = p->ptr[p->ofst];
if (++p->ofst == GSIZE (p->hdr))
pnext (p);
return c;
}
static P *frfind (P *p, unsigned char *s, int len) {
long amnt = p->byte;
int x;
unsigned char table[256], c;
if (len > p->b->eof->byte - p->byte)
{
x = len - (p->b->eof->byte - p->byte);
if (amnt < x)
return 0;
amnt -= x;
fbkwd (p, x);
}
if (!len)
return p;
p->valcol = 0;
mset (table, 255, 256);
for (x = len; --x; table[s[x]] = len - x - 1);
x = 0;
do
if ((c = fpgetc (p)) != s[x++])
{
if (table[c] == 255)
fbkwd (p, len + 1), amnt -= len - x + 1;
else if (len - table[c] <= x)
fbkwd (p, x + 1), --amnt;
else
fbkwd (p, len - table[c]), amnt -=
len - table[c] - x;
if (amnt < 0)
return 0;
else
x = 0;
}
while (x != len);
fbkwd (p, len);
return p;
}
static P *frifind (P *p, unsigned char *s, int len) {
long amnt = p->byte;
int x;
unsigned char table[256], c;
if (len > p->b->eof->byte - p->byte)
{
x = len - (p->b->eof->byte - p->byte);
if (amnt < x)
return 0;
amnt -= x;
fbkwd (p, x);
}
if (!len)
return p;
p->valcol = 0;
mset (table, 255, 256);
for (x = len; --x; table[s[x]] = len - x - 1);
x = 0;
do
if ((c = toupper (fpgetc (p))) != s[x++])
{
if (table[c] == 255)
fbkwd (p, len + 1), amnt -= len - x + 1;
else if (len - table[c] <= x)
fbkwd (p, x + 1), --amnt;
else
fbkwd (p, len - table[c]), amnt -=
len - table[c] - x;
if (amnt < 0)
return 0;
else
x = 0;
}
while (x != len);
fbkwd (p, len);
return p;
}
static P *rgetto (P *p, P *q) {
while (p->hdr != q->hdr || p->ofst != q->ofst)
{
if (!p->ofst)
do
{
if (p->ofst)
p->byte -= p->ofst, p->line -=
p->hdr->nlines;
pprev (p);
}
while (p->hdr != q->hdr);
--p->ofst;
--p->byte;
if (p->ofst >= p->hdr->hole)
{
if (p->
ptr[p->ofst + p->hdr->ehole - p->hdr->hole] ==
'\n')
--p->line;
}
else if (p->ptr[p->ofst] == '\n')
--p->line;
}
return p;
}
P *prfind (P *p, char *s, int len) {
P *q = pdup (p);
if (frfind (q, s, len))
{
rgetto (p, q);
prm (q);
return p;
}
else
{
prm (q);
return 0;
}
}
P *prifind (P *p, char *s, int len) {
P *q = pdup (p);
if (frifind (q, s, len))
{
rgetto (p, q);
prm (q);
return p;
}
else
{
prm (q);
return 0;
}
}
B *bcpy (P *from,P *to) {
H anchor, *l;
char *ptr;
P *q;
if (from->byte >= to->byte)
return bmk (from->b);
q = pdup (from);
izque (H, link, &anchor);
if (q->hdr == to->hdr)
{
l = halloc ();
ptr = vlock (vmem, l->seg);
if (q->ofst != q->hdr->hole)
gstgap (q->hdr, q->ptr, q->ofst);
l->nlines = mcnt (q->ptr + q->hdr->ehole, '\n', l->hole =
to->ofst - q->ofst);
mcpy (ptr, q->ptr + q->hdr->ehole, l->hole);
vchanged (ptr);
vunlock (ptr);
enqueb (H, link, &anchor, l);
}
else
{
l = halloc ();
ptr = vlock (vmem, l->seg);
if (q->ofst != q->hdr->hole)
gstgap (q->hdr, q->ptr, q->ofst);
l->nlines = mcnt (q->ptr + q->hdr->ehole, '\n', l->hole =
SEGSIZ - q->hdr->ehole);
mcpy (ptr, q->ptr + q->hdr->ehole, l->hole);
vchanged (ptr);
vunlock (ptr);
enqueb (H, link, &anchor, l);
pnext (q);
while (q->hdr != to->hdr)
{
l = halloc ();
ptr = vlock (vmem, l->seg);
l->nlines = q->hdr->nlines;
mcpy (ptr, q->ptr, q->hdr->hole);
mcpy (ptr + q->hdr->hole, q->ptr + q->hdr->ehole,
SEGSIZ - q->hdr->ehole);
l->hole = GSIZE (q->hdr);
vchanged (ptr);
vunlock (ptr);
enqueb (H, link, &anchor, l);
pnext (q);
}
if (to->ofst)
{
l = halloc ();
ptr = vlock (vmem, l->seg);
if (to->ofst != to->hdr->hole)
gstgap (to->hdr, to->ptr, to->ofst);
l->nlines = mcnt (to->ptr, '\n', to->ofst);
mcpy (ptr, to->ptr, l->hole = to->ofst);
vchanged (ptr);
vunlock (ptr);
enqueb (H, link, &anchor, l);
}
}
l = anchor.link.next;
deque (H, link, &anchor);
prm (q);
return bmkchn (l, from->b, to->byte - from->byte,
to->line - from->line);
}
/* Coalesce small blocks into a single larger one */
void pcoalesce (P *p) {
if (p->hdr != p->b->eof->hdr &&
GSIZE (p->hdr) + GSIZE (p->hdr->link.next) <= SEGSIZ - SEGSIZ / 4)
{
H *hdr = p->hdr->link.next;
char *ptr = vlock (vmem, hdr->seg);
int osize = GSIZE (p->hdr);
int size = GSIZE (hdr);
P *q;
gstgap (hdr, ptr, size);
ginsm (p->hdr, p->ptr, GSIZE (p->hdr), ptr, size);
p->hdr->nlines += hdr->nlines;
vunlock (ptr);
hfree (deque (H, link, hdr));
for (q = p->link.next; q != p; q = q->link.next)
if (q->hdr == hdr)
{
q->hdr = p->hdr;
if (q->ptr)
{
vunlock (q->ptr);
q->ptr =
vlock (vmem,
q->hdr->seg);
}
q->ofst += osize;
}
}
if (p->hdr != p->b->bof->hdr &&
GSIZE (p->hdr) + GSIZE (p->hdr->link.prev) <= SEGSIZ - SEGSIZ / 4)
{
H *hdr = p->hdr->link.prev;
char *ptr = vlock (vmem, hdr->seg);
int size = GSIZE (hdr);
P *q;
gstgap (hdr, ptr, size);
ginsm (p->hdr, p->ptr, 0, ptr, size);
p->hdr->nlines += hdr->nlines;
vunlock (ptr);
hfree (deque (H, link, hdr));
p->ofst += size;
for (q = p->link.next; q != p; q = q->link.next)
if (q->hdr == hdr)
{
q->hdr = p->hdr;
if (q->ptr)
vunlock (q->ptr);
q->ptr = vlock (vmem, q->hdr->seg);
}
else if (q->hdr == p->hdr)
q->ofst += size;
}
}
/* Delete the text between two pointers from a buffer and return it in a new
* buffer.
*
* This routine calls these functions:
* gstgap - to position gaps
* halloc - to allocate new header/segment pairs
* vlock - virtual memory routines
* vunlock
* vchanged
* vupcount
* mcpy - to copy deleted text
* mcnt - to count NLs
* snip - queue routines
* enqueb
* splicef
* scrdel - to tell screen update to scroll when NLs are deleted
* bmkchn - to make a buffer out of a chain
*/
/* This is only to be used for bdel() */
static B *bcut (P *from, P *to) {
H *h, /* The deleted text */
*i;
char *ptr;
P *p;
long nlines; /* No. EOLs to delete */
long amnt; /* No. bytes to delete */
int toamnt; /* Amount to delete from segment in 'to' */
int bofmove = 0; /* Set if bof got deleted */
if (!(amnt = to->byte - from->byte))
return 0; /* ...nothing to delete */
nlines = to->line - from->line;
if (from->hdr == to->hdr)
{ /* Delete is within a single segment */
/* Move gap to deletion point */
if (from->ofst != from->hdr->hole)
gstgap (from->hdr, from->ptr, from->ofst);
/* Store the deleted text */
h = halloc ();
ptr = vlock (vmem, h->seg);
mcpy (ptr, from->ptr + from->hdr->ehole, (int) amnt);
h->hole = amnt;
h->nlines = nlines;
vchanged (ptr);
vunlock (ptr);
/* Delete */
from->hdr->ehole += amnt;
from->hdr->nlines -= nlines;
toamnt = amnt;
}
else
{ /* Delete crosses segments */
H *a;
if (toamnt = to->ofst)
{
/* Delete beginning of to */
/* Move gap to deletion point */
/* To could be deleted if it's at the end of the file */
if (to->ofst != to->hdr->hole)
gstgap (to->hdr, to->ptr, to->ofst);
/* Save deleted text */
i = halloc ();
ptr = vlock (vmem, i->seg);
mcpy (ptr, to->ptr, to->hdr->hole);
i->hole = to->hdr->hole;
i->nlines = mcnt (to->ptr, '\n', to->hdr->hole);
vchanged (ptr);
vunlock (ptr);
/* Delete */
to->hdr->nlines -= i->nlines;
to->hdr->hole = 0;
}
else
i = 0;
/* Delete end of from */
if (!from->ofst)
{
/* ..unless from needs to be deleted too */
a = from->hdr->link.prev, h = 0;
if (a == from->b->eof->hdr)
bofmove = 1;
}
else
{
a = from->hdr;
/* Move gap to deletion point */
if (from->ofst != from->hdr->hole)
gstgap (from->hdr, from->ptr, from->ofst);
/* Save deleted text */
h = halloc ();
ptr = vlock (vmem, h->seg);
mcpy (ptr, from->ptr + from->hdr->ehole,
SEGSIZ - from->hdr->ehole);
h->hole = SEGSIZ - from->hdr->ehole;
h->nlines = mcnt (ptr, '\n', h->hole);
vchanged (ptr);
vunlock (ptr);
/* Delete */
from->hdr->nlines -= h->nlines;
from->hdr->ehole = SEGSIZ;
}
/* Make from point to header/segment of to */
from->hdr = to->hdr;
vunlock (from->ptr);
from->ptr = to->ptr;
vupcount (to->ptr);
from->ofst = 0;
/* Delete headers/segments between a and to->hdr (if there are any) */
if (a->link.next != to->hdr)
if (!h)
{
h =
snip (H, link, a->link.next,
to->hdr->link.prev);
if (i)
enqueb (H, link, h, i);
}
else
{
splicef (H, link, h,
snip (H, link, a->link.next,
to->hdr->link.prev));
if (i)
enqueb (H, link, h, i);
}
else if (!h)
h = i;
else if (i)
enqueb (H, link, h, i);
}
/* If to is empty, then it must have been at the end of the file. If
the file did not become empty, delete to */
if (!GSIZE (to->hdr) && from->byte)
{
H *ph = from->hdr->link.prev;
hfree (deque (H, link, from->hdr));
vunlock (from->ptr);
from->hdr = ph;
from->ptr = vlock (vmem, from->hdr->seg);
from->ofst = GSIZE (ph);
vunlock (from->b->eof->ptr);
from->b->eof->ptr = from->ptr;
vupcount (from->ptr);
from->b->eof->hdr = from->hdr;
from->b->eof->ofst = from->ofst;
}
/* The deletion is now done */
/* Scroll if necessary */
if (bofmove)
pset (from->b->bof, from);
if (nlines && !pisbol (from))
{
scrdel (from->b, from->line, nlines, 1);
/* too many arguments so I remove last one
delerr (from->b->name, from->line, nlines, 0);
*/
delerr (from->b->name, from->line, nlines);
}
else
{
scrdel (from->b, from->line, nlines, 0);
/* too many arguments so I remove last one
delerr (from->b->name, from->line, nlines, 1);
*/
delerr (from->b->name, from->line, nlines);
}
/* Fix pointers */
for (p = from->link.next; p != from; p = p->link.next)
if (p->line == from->line && p->byte > from->byte)
p->valcol = 0;
for (p = from->link.next; p != from; p = p->link.next)
if (p->byte >= from->byte)
if (p->byte <= from->byte + amnt) {
if (p->ptr) {
pset (p, from);
} else {
poffline (pset (p, from));
}
} else {
if (p->hdr == to->hdr)
p->ofst -= toamnt;
p->byte -= amnt;
p->line -= nlines;
}
pcoalesce (from);
/* Make buffer out of deleted text and return it */
return bmkchn (h, from->b, amnt, nlines);
}
void bdel (P *from, P *to) {
if (to->byte - from->byte)
{
B *b = bcut (from, to);
if (from->b->undo)
undodel (from->b->undo, from->byte, b);
else
brm (b);
from->b->changed = 1;
}
}
/* Split a block at p's ofst */
/* p is placed in the new block such that it points to the same text but with
* p->ofst==0
*/
static void bsplit (P *p) {
if (p->ofst)
{
H *hdr;
char *ptr;
P *pp;
hdr = halloc ();
ptr = vlock (vmem, hdr->seg);
if (p->ofst != p->hdr->hole)
gstgap (p->hdr, p->ptr, p->ofst);
mcpy (ptr, p->ptr + p->hdr->ehole, SEGSIZ - p->hdr->ehole);
hdr->hole = SEGSIZ - p->hdr->ehole;
hdr->nlines = mcnt (ptr, '\n', hdr->hole);
p->hdr->nlines -= hdr->nlines;
vchanged (ptr);
p->hdr->ehole = SEGSIZ;
enquef (H, link, p->hdr, hdr);
vunlock (p->ptr);
for (pp = p->link.next; pp != p; pp = pp->link.next)
if (pp->hdr == p->hdr && pp->ofst >= p->ofst)
{
pp->hdr = hdr;
if (pp->ptr)
{
vunlock (pp->ptr);
pp->ptr = ptr;
vupcount (ptr);
}
pp->ofst -= p->ofst;
}
p->ptr = ptr;
p->hdr = hdr;
p->ofst = 0;
}
}
/* Make a chain out of a block of memory */
/* The block must not be empty */
static H *bldchn (char *blk, int size, long *nlines) {
H anchor, *l;
*nlines = 0;
izque (H, link, &anchor);
do
{
char *ptr;
int amnt;
ptr = vlock (vmem, (l = halloc ())->seg);
if (size > SEGSIZ)
amnt = SEGSIZ;
else
amnt = size;
mcpy (ptr, blk, amnt);
l->hole = amnt;
l->ehole = SEGSIZ;
(*nlines) += (l->nlines = mcnt (ptr, '\n', amnt));
vchanged (ptr);
vunlock (ptr);
enqueb (H, link, &anchor, l);
blk += amnt;
size -= amnt;
}
while (size);
l = anchor.link.next;
deque (H, link, &anchor);
return l;
}
/* Insert a chain into a buffer */
/* This does not update pointers */
static void inschn (P *p, H *a) {
if (!p->b->eof->byte)
{ /* P's buffer is empty: replace the empty segment in p with a */
hfree (p->hdr);
p->hdr = a;
vunlock (p->ptr);
p->ptr = vlock (vmem, a->seg);
pset (p->b->bof, p);
p->b->eof->hdr = a->link.prev;
vunlock (p->b->eof->ptr);
p->b->eof->ptr = vlock (vmem, p->b->eof->hdr->seg);
p->b->eof->ofst = GSIZE (p->b->eof->hdr);
}
else if (piseof (p))
{ /* We're at the end of the file: append a to the file */
p->b->eof->hdr = a->link.prev;
spliceb (H, link, p->b->bof->hdr, a);
vunlock (p->b->eof->ptr);
p->b->eof->ptr = vlock (vmem, p->b->eof->hdr->seg);
p->b->eof->ofst = GSIZE (p->b->eof->hdr);
p->hdr = a;
vunlock (p->ptr);
p->ptr = vlock (vmem, p->hdr->seg);
p->ofst = 0;
}
else if (pisbof (p))
{ /* We're at the beginning of the file: insert chain and set bof pointer */
p->hdr = spliceb (H, link, p->hdr, a);
vunlock (p->ptr);
p->ptr = vlock (vmem, a->seg);
pset (p->b->bof, p);
}
else
{ /* We're in the middle of the file: split and insert */
bsplit (p);
p->hdr = spliceb (H, link, p->hdr, a);
vunlock (p->ptr);
p->ptr = vlock (vmem, a->seg);
}
}
static void fixupins (P *p, long amnt, long nlines, H *hdr, int hdramnt) {
P *pp;
if (nlines && !pisbol (p))
scrins (p->b, p->line, nlines, 1);
else
scrins (p->b, p->line, nlines, 0);
/* too few arguments so I added one but because I don't know is last
argument so first try is 0 :)
inserr (p->b->name, p->line, nlines);
*/
inserr (p->b->name, p->line, nlines, 0);
for (pp = p->link.next; pp != p; pp = pp->link.next)
if (pp->line == p->line &&
(pp->byte > p->byte || pp->end && pp->byte == p->byte))
pp->valcol = 0;
for (pp = p->link.next; pp != p; pp = pp->link.next)
if (pp->byte == p->byte && !pp->end)
if (pp->ptr)
pset (pp, p);
else
poffline (pset (pp, p));
else if (pp->byte > p->byte || pp->end && pp->byte == p->byte)
{
pp->byte += amnt;
pp->line += nlines;
if (pp->hdr == hdr)
pp->ofst += hdramnt;
}
if (p->b->undo)
undoins (p->b->undo, p, amnt);
p->b->changed = 1;
}
/* Insert a buffer at pointer position */
/* The buffer goes away */
P *binsb (P *p, B *b) {
if (b->eof->byte)
{
P *q = pdup (p);
inschn (q, b->bof->hdr);
b->eof->hdr = halloc ();
fixupins (q, b->eof->byte, b->eof->line, NULL, 0);
pcoalesce (q);
prm (q);
}
brm (b);
return p;
}
P *binsm (P *p, char *blk, int amnt) {
long nlines;
H *h = 0;
int hdramnt;
P *q;
if (!amnt)
return p;
q = pdup (p);
if (amnt <= GGAPSZ (q->hdr))
{
h = q->hdr;
hdramnt = amnt;
ginsm (q->hdr, q->ptr, q->ofst, blk, amnt);
q->hdr->nlines += (nlines = mcnt (blk, '\n', amnt));
}
else if (!q->ofst && q->hdr != q->b->bof->hdr
&& amnt <= GGAPSZ (q->hdr->link.prev))
{
pprev (q);
ginsm (q->hdr, q->ptr, q->ofst, blk, amnt);
q->hdr->nlines += (nlines = mcnt (blk, '\n', amnt));
}
else
{
H *a = bldchn (blk, amnt, &nlines);
inschn (q, a);
}
fixupins (q, (long) amnt, nlines, h, hdramnt);
pcoalesce (q);
prm (q);
return p;
}
P *binsc (p, c)
P *p;
char c;
{
if (p->b->o.crlf && c == '\n')
return binsm (p, "\r\n", 2);
else
return binsm (p, &c, 1);
}
P *
binss (p, s)
P *p;
char *s;
{
return binsm (p, s, strlen (s));
}
/* Read 'size' bytes from file or stream. Stops and returns amnt. read
* when requested size has been read or when end of file condition occurs.
* Returns with -2 in error for read error or 0 in error for success.
*/
static int
bkread (fi, buff, size)
char *buff;
{
int a, b;
if (!size)
{
error = 0;
return 0;
}
for (a = b = 0;
(a < size) && ((b = jread (fi, buff + a, size - a)) > 0);
a += b);
if (b < 0)
error = -2;
else
error = 0;
return a;
}
/* Read up to 'max' bytes from a file into a buffer */
/* Returns with 0 in error or -2 in error for read error */
B *
bread (fi, max)
long max;
{
H anchor, *l;
long lines = 0, total = 0;
int amnt;
char *seg;
izque (H, link, &anchor);
error = 0;
while (seg = vlock (vmem, (l = halloc ())->seg),
!error
&& (amnt =
bkread (fi, seg, max >= SEGSIZ ? SEGSIZ : (int) max)))
{
total += amnt;
max -= amnt;
l->hole = amnt;
lines += (l->nlines = mcnt (seg, '\n', amnt));
vchanged (seg);
vunlock (seg);
enqueb (H, link, &anchor, l);
}
hfree (l);
vunlock (seg);
if (!total)
return bmk (NULL);
l = anchor.link.next;
deque (H, link, &anchor);
return bmkchn (l, NULL, total, lines);
}
/* Parse file name.
*
* Removes ',xxx,yyy' from end of name and puts their value into skip and amnt
* Replaces ~user/ with directory of given user
* Replaces ~/ with $HOME
*
* Returns new variable length string.
*/
char *
parsens (s, skip, amnt)
char *s;
long *skip, *amnt;
{
char *n = vsncpy (NULL, 0, sz (s));
int x;
*skip = 0;
*amnt = MAXLONG;
for (x = sLEN (n) - 1;
x > 0 && (n[x] >= '0' && n[x] <= '9' || n[x] == 'x'
|| n[x] == 'X'); --x);
if (n[x] == ',')
{
n[x] = 0;
if (n[x + 1] == 'x' || n[x + 1] == 'X')
sscanf (n + x + 2, "%lx", skip);
else if (n[x + 1] == '0'
&& (n[x + 2] == 'x' || n[x + 2] == 'X'))
sscanf (n + x + 3, "%lx", skip);
else if (n[x + 1] == '0')
sscanf (n + x + 1, "%lo", skip);
else
sscanf (n + x + 1, "%ld", skip);
for (--x;
x > 0 && (n[x] >= '0' && n[x] <= '9' || n[x] == 'x'
|| n[x] == 'X'); --x);
if (n[x] == ',')
{
n[x] = 0;
*amnt = *skip;
if (n[x + 1] == 'x' || n[x + 1] == 'X')
sscanf (n + x + 2, "%lx", skip);
else if (n[x + 1] == '0'
&& (n[x + 2] == 'x' || n[x + 2] == 'X'))
sscanf (n + x + 3, "%lx", skip);
else if (n[x + 1] == '0')
sscanf (n + x + 1, "%lo", skip);
else
sscanf (n + x + 1, "%ld", skip);
}
}
#ifndef __MSDOS__
if (n[0] == '~') {
for (x = 1; n[x] && n[x] != '/'; ++x);
if (n[x] == '/') {
if (x == 1) {
char *z;
s = getenv ("HOME");
z = vsncpy (NULL, 0, sz (s));
z = vsncpy (z, sLEN (z), sz (n + x));
vsrm (n);
n = z;
} else {
struct passwd *passwd;
n[x] = 0;
passwd = getpwnam (n + 1);
n[x] = '/';
if (passwd) {
char *z = vsncpy (NULL, 0, sz (passwd->pw_dir));
z = vsncpy (z, sLEN (z), sz (n + x));
vsrm (n);
n = z;
}
}
}
}
#endif
return n;
}
/* Load file into new buffer and return the new buffer */
/* Returns with error set to 0 for success,
* -1 for new file (file doesn't exist)
* -2 for read error
* -3 for seek error
* -4 for open error
*/
B *
bload (s)
char *s;
{
char buffer[SEGSIZ];
FILE *fi;
B *b;
long skip, amnt;
char *n;
int nowrite = 0;
if (!s || !s[0])
{
error = -1;
b = bmk (NULL);
setopt (&b->o, "");
b->rdonly = b->o.readonly;
b->er = error;
return b;
}
n = parsens (s, &skip, &amnt);
/* Open file or stream */
ossep (n);
#ifndef __MSDOS__
if (n[0] == '!')
{
nescape (maint->t);
ttclsn ();
fi = popen (n + 1, "r");
}
else
#endif
if (!strcmp (n, "-"))
fi = stdin;
else
{
fi = fopen (n, "r+");
if (!fi)
nowrite = 1;
else
fclose (fi);
fi = fopen (n, "r");
if (!fi)
nowrite = 0;
}
joesep (n);
/* Abort if couldn't open */
if (!fi)
{
if (errno == ENOENT)
error = -1;
else
error = -4;
b = bmk (NULL);
setopt (&b->o, n);
b->rdonly = b->o.readonly;
goto opnerr;
}
/* Skip data if we need to */
if (skip && lseek (fileno (fi), skip, 0) < 0)
{
int r;
while (skip > SEGSIZ)
{
r = bkread (fileno (fi), buffer, SEGSIZ);
if (r != SEGSIZ || error)
{
error = -3;
goto err;
}
skip -= SEGSIZ;
}
skip -= bkread (fileno (fi), buffer, (int) skip);
if (skip || error)
{
error = -3;
goto err;
}
}
/* Read from stream into new buffer */
b = bread (fileno (fi), amnt);
setopt (&b->o, n);
b->rdonly = b->o.readonly;
/* Close stream */
err:;
#ifndef __MSDOS__
if (s[0] == '!')
pclose (fi);
else
#endif
if (strcmp (n, "-"))
fclose (fi);
opnerr:;
if (s[0] == '!')
ttopnn (), nreturn (maint->t);
/* Set name */
b->name = joesep (strdup (s));
/* Set flags */
if (error || s[0] == '!' || skip || amnt != MAXLONG)
b->backup = 1, b->changed = 0;
else if (!strcmp (n, "-"))
b->backup = 1, b->changed = 1;
else
b->backup = 0, b->changed = 0;
if (nowrite)
b->rdonly = b->o.readonly = 1;
/* Eliminate parsed name */
vsrm (n);
b->er = error;
return b;
}
/* Find already loaded buffer or load file into new buffer */
B *
bfind (s)
char *s;
{
B *b;
if (!s || !s[0])
{
error = -1;
b = bmk (NULL);
setopt (&b->o, "");
b->rdonly = b->o.readonly;
b->internal = 0;
b->er = error;
return b;
}
for (b = bufs.link.next; b != &bufs; b = b->link.next)
if (b->name && !strcmp (s, b->name))
{
if (!b->orphan)
++b->count;
else
b->orphan = 0;
error = 0;
b->internal = 0;
return b;
}
b = bload (s);
b->internal = 0;
return b;
}
char **
getbufs ()
{
char **s = vamk (16);
B *b;
for (b = bufs.link.next; b != &bufs; b = b->link.next)
if (b->name)
s = vaadd (s, vsncpy (NULL, 0, sz (b->name)));
return s;
}
/* Find an orphaned buffer */
B *
borphan ()
{
B *b;
for (b = bufs.link.next; b != &bufs; b = b->link.next)
if (b->orphan)
{
b->orphan = 0;
return b;
}
return 0;
}
/* Write 'size' bytes from file beginning at 'p' to open file 'fd'.
* Returns error.
* error is set to -5 for write error or 0 for success.
* Don't attempt to write past the end of the file
*/
int
bsavefd (p, fd, size)
P *p;
long size;
{
P *np = pdup (p);
int amnt;
while (size > (amnt = GSIZE (np->hdr) - np->ofst))
{
if (np->ofst < np->hdr->hole)
{
if (jwrite
(fd, np->ptr + np->ofst,
np->hdr->hole - np->ofst) < 0)
goto err;
if (jwrite
(fd, np->ptr + np->hdr->ehole,
SEGSIZ - np->hdr->ehole) < 0)
goto err;
}
else
if (jwrite
(fd, np->ptr + np->ofst + GGAPSZ (np->hdr),
amnt) < 0)
goto err;
size -= amnt;
pnext (np);
}
if (size)
if (np->ofst < np->hdr->hole) {
if (size > np->hdr->hole - np->ofst) {
if (jwrite
(fd, np->ptr + np->ofst,
np->hdr->hole - np->ofst) < 0)
goto err;
if (jwrite
(fd, np->ptr + np->hdr->ehole,
(int) size - np->hdr->hole +
np->ofst) < 0)
goto err;
} else {
if (jwrite
(fd, np->ptr + np->ofst,
(int) size) < 0)
goto err;
}
} else {
if (jwrite
(fd, np->ptr + np->ofst + GGAPSZ (np->hdr),
(int) size) < 0)
goto err;
}
prm (np);
return error = 0;
err:;
prm (np);
return error = 5;
}
/* Save 'size' bytes beginning at 'p' in file 's' */
int
bsave (p, s, size)
P *p;
char *s;
long size;
{
FILE *f;
long skip, amnt;
s = parsens (s, &skip, &amnt);
if (amnt < size)
size = amnt;
ossep (s);
#ifndef __MSDOS__
if (s[0] == '!')
{
nescape (maint->t);
ttclsn ();
f = popen (s + 1, "w");
}
else
#endif
if (s[0] == '>' && s[1] == '>')
f = fopen (s + 2, "a");
else if (!strcmp (s, "-"))
{
nescape (maint->t);
ttclsn ();
f = stdout;
}
else if (skip || amnt != MAXLONG)
f = fopen (s, "r+");
else
f = fopen (s, "w");
joesep (s);
if (!f)
{
error = -4;
goto opnerr;
}
fflush (f);
if (skip && lseek (fileno (f), skip, 0) < 0)
{
error = -3;
goto err;
}
bsavefd (p, fileno (f), size);
if (!error && force && size && !skip && amnt == MAXLONG)
{
P *q = pdup (p);
char nl = '\n';
pfwrd (q, size - 1);
if (brc (q) != '\n' && jwrite (fileno (f), &nl, 1) < 0)
error = -5;
prm (q);
}
err:;
#ifndef __MSDOS__
if (s[0] == '!')
pclose (f);
else
#endif
if (strcmp (s, "-"))
fclose (f);
else
fflush (f);
opnerr:;
if (s[0] == '!' || !strcmp (s, "-"))
ttopnn (), nreturn (maint->t);
return error;
}
int
brc (p)
P *p;
{
if (p->ofst == GSIZE (p->hdr))
return MAXINT;
if (p->ofst >= p->hdr->hole)
return p->ptr[p->ofst + p->hdr->ehole - p->hdr->hole];
else
return p->ptr[p->ofst];
}
char *
brmem (p, blk, size)
P *p;
char *blk;
int size;
{
char *bk = blk;
P *np;
int amnt;
np = pdup (p);
while (size > (amnt = GSIZE (np->hdr) - np->ofst))
{
grmem (np->hdr, np->ptr, np->ofst, bk, amnt);
bk += amnt;
size -= amnt;
pnext (np);
}
if (size)
grmem (np->hdr, np->ptr, np->ofst, bk, size);
prm (np);
return blk;
}
char *
brs (p, size)
P *p;
int size;
{
char *s = (char *) malloc (size + 1);
s[size] = 0;
return brmem (p, s, size);
}
char *
brvs (p, size)
P *p;
int size;
{
char *s = vstrunc (NULL, size);
return brmem (p, s, size);
}
/* Save edit buffers when editor dies */
extern char *ctime ();
void
ttsig (sig)
{
long tim = time (0);
B *b;
FILE *f;
int tmpfd;
struct stat sbuf;
if ((tmpfd = open ("DEADJOE", O_RDWR | O_EXCL | O_CREAT, 0600)) < 0)
{
if (lstat ("DEADJOE", &sbuf) < 0)
_exit (-1);
if (!S_ISREG (sbuf.st_mode) || sbuf.st_uid != geteuid ())
_exit (-1);
/*
A race condition still exists between the lstat() and the open()
systemcall, which leads to a possible denial-of-service attack
by setting the file access mode to 600 for every file the
user executing joe has permissions to.
This can't be fixed w/o breacking the behavior of the orig. joe!
*/
if ((tmpfd = open ("DEADJOE", O_RDWR | O_APPEND)) < 0)
_exit (-1);
if (fchmod (tmpfd, S_IRUSR | S_IWUSR) < 0)
_exit (-1);
}
if ((f = fdopen (tmpfd, "a")) == NULL)
_exit (-1);
fprintf (f, "\n*** Modified files in JOE when it aborted on %s",
ctime (&tim));
if (sig)
fprintf (f, "*** JOE was aborted by signal %d\n", sig);
else
fprintf (f,
"*** JOE was aborted because the terminal closed\n");
fflush (f);
for (b = bufs.link.next; b != &bufs; b = b->link.next)
if (b->changed)
{
if (b->name)
fprintf (f, "\n*** File \'%s\'\n", b->name);
else
fprintf (f, "\n*** File \'(Unnamed)\'\n");
fflush (f);
bsavefd (b->bof, fileno (f), b->eof->byte);
}
if (sig)
ttclsn ();
_exit (1);
}
joe-2.9.6/b.h 0100600 0032337 0023564 00000007265 07265143612 012300 0 ustar xgrac student #ifndef _Ib
#define _Ib 1
#include "config.h"
#include "queue.h"
#include "rc.h"
#include "vfile.h"
#define stdsiz 8192
/* 31744 */
extern char stdbuf[stdsiz];
typedef struct buffer B;
typedef struct point P;
typedef struct header H;
struct header {
LINK (H) link; /* ??? */
long seg; /* ??? */
int hole; /* ??? */
int ehole; /* ??? */
int nlines; /* ??? */
};
struct point {
LINK (P) link; /* ??? */
B *b; /* ??? */
int ofst; /* ??? */
char *ptr; /* ??? */
H *hdr; /* ??? */
long byte; /* ??? */
long line; /* ??? */
long col; /* ??? */
long xcol; /* ??? */
int valcol; /* ??? */
int end; /* ??? */
P **owner; /* ??? */
};
struct buffer {
LINK (B) link;
P *bof;
P *eof;
char *name;
int orphan;
int count;
int changed;
int backup;
void *undo;
P *marks[10]; /* Bookmarks */
OPTIONS o; /* Options */
P *oldcur; /* Last cursor position before orphaning */
P *oldtop; /* Last top screen position before orphaning */
int rdonly; /* Set for read-only */
int internal; /* Set for internal buffers */
int er; /* Error code when file was loaded */
};
extern int force; /* Set to have final '\n' added to file */
extern int tabwidth; /* Default tab width */
extern VFILE *vmem; /* Virtual memory file used for buffer system */
extern char *msgs[];
B *bmk ();
void brm ();
B *bfind ();
P *pdup ();
P *pdupown ();
P *poffline ();
P *ponline ();
B *bonline ();
B *boffline ();
void prm ();
P *pset ();
P *p_goto_bof (P *p); /* move cursor to begging of file */
P *p_goto_eof (P *p); /* move cursor to end of file */
P *p_goto_bol (P *p); /* move cursor to begging of line */
P *p_goto_eol (P *p); /* move cursor to end of line */
int pisbof ();
int piseof ();
int piseol ();
int pisbol ();
int pisbow ();
int piseow ();
#define piscol(p) ((p)->valcol?(p)->col:(pfcol(p),(p)->col))
int pisblank ();
long pisindent ();
int pnext ();
int pprev ();
int pgetc ();
P *pfwrd ();
int prgetc ();
P *pbkwd ();
P *pgoto ();
P *pfcol ();
P *pnextl ();
P *pprevl ();
P *pline ();
P *pcolwse ();
P *pcol ();
P *pcoli ();
void pbackws ();
void pfill ();
P *pfind ();
P *pifind ();
P *prfind ();
P *prifind ();
/* B *bcpy(P *from,P *to);
* Copy text between from and to into a new buffer
*/
B *bcpy ();
void pcoalesce ();
void bdel ();
/* P *binsb(P *p,B *b);
* Insert an entire buffer 'b' into another buffer at 'p'
*/
P *binsb ();
/* P *binsm(P *p,char *blk,int amnt);
* Insert a block 'blk' of size 'amnt' into buffer at 'p'
*/
P *binsm ();
/* P *binsc(P *p,char c);
* Insert character into buffer at P
*/
P *binsc ();
/* P *binss(P *p,char *s);
* Insert zero terminated string into buffer at P
*/
P *binss ();
/* B *bload(char *s);
* Load a file into a new buffer
*
* Returns with errno set to 0 for success,
* -1 for new file (file doesn't exist)
* -2 for read error
* -3 for seek error
* -4 for open error
*/
B *bread ();
B *bload ();
B *bfind ();
B *borphan ();
/* int bsave(P *p,char *s,long size);
* Save 'size' bytes beginning at 'p' into file with name in 's'
*/
int bsavefd ();
int bsave ();
char *parsens ();
/* int brc(P *p);
* Get character at pointer or return MAXINT if pointer is at end of buffer
*/
int brc ();
/* char *brmem(P *p,char *blk,int size);
* Copy 'size' bytes from a buffer beginning at p into block 'blk'
*/
char *brmem ();
/* char *brs(P *p,int size);
* Copy 'size' bytes from a buffer beginning at p into a zero-terminated
* C-string in an malloc block.
*/
char *brs ();
/* char *brvs(P *p,int size);
* Copy 'size' bytes from a buffer beginning at p into a variable length
* string.
*/
char *brvs ();
B *bnext ();
B *bprev ();
#define error berror
extern int berror;
char **getbufs ();
#endif
joe-2.9.6/w.c 0100644 0032337 0023564 00000043004 07262722314 012316 0 ustar xgrac student /*
Window system
Copyright (C) 1992 Joseph H. Allen
This file is part of JOE (Joe's Own Editor)
*/
#include "config.h"
#include "b.h"
#include "scrn.h"
#include "queue.h"
#include "main.h"
#include "poshist.h"
#include "blocks.h"
#include "utils.h"
#include "w.h"
extern int dspasis; /* Set to display chars above 127 as-is */
extern int staen; /* 0 if top-most status line not displayed */
/* Count no. of main windows */
int countmain (SCREEN * t) {
int nmain = 1;
W *m = t->curwin->main;
W *q;
for (q = t->curwin->link.next; q != t->curwin; q = q->link.next)
if (q->main != m)
{
++nmain;
m = q->main;
}
return nmain;
}
/* Redraw a window */
void wredraw (W *w) {
msetI (w->t->t->updtab + w->y, 1, w->h);
}
/* Find first window in a group */
W *findtopw (W *w) {
W *x;
for (x = w; x->link.prev->main == w->main && x->link.prev != w;
x = x->link.prev);
return x;
}
/* Determine height of a window. Returns reqh if it is set, otherwise
* used fixed or hh scaled to the current screen size */
int geth (W *w) {
if (w->reqh)
return w->reqh;
else if (w->fixed)
return w->fixed;
else
return (((long) w->t->h - w->t->wind) * w->hh) / 1000;
}
/* Set the height of a window */
void seth (W *w, int h) {
long tmp;
w->reqh = h;
tmp = 1000L * h;
w->hh =
tmp / (w->t->h - w->t->wind) +
(tmp % (w->t->h - w->t->wind) ? 1 : 0);
}
/* Determine height of a family of windows. Uses 'reqh' if it's set */
int getgrouph (W *w) {
W *x;
int h;
/* Find first window in family */
x = findtopw (w);
/* Add heights of all windows in family */
for (w = x, h = geth (w);
w->link.next != x && w->link.next->main == x->main;
w = w->link.next, h += geth (w));
return h;
}
/* Determine minimum height of a family */
int getminh (W *w) {
W *x;
int h;
x = findtopw (w);
for (w = x, h = (w->fixed ? w->fixed : 2);
w->link.next != x && w->link.next->main == x->main;
w = w->link.next, h += (w->fixed ? w->fixed : 2));
return h;
}
/* Find last window in a group */
W *findbotw (W *w) {
W *x;
for (x = w; x->link.next->main == w->main && x->link.next != w;
x = x->link.next);
return x;
}
/* Demote group of window to end of window list. Returns true if top window
was demoted */
int demotegroup (W *w) {
W *top = findtopw (w);
W *bot = findbotw (w);
W *next;
int flg = 0;
for (w = top; w != bot; w = next)
{
next = w->link.next;
if (w == w->t->topwin)
flg = 1, w->t->topwin = next;
else
demote (W, link, w->t->topwin, w);
w->y = -1;
}
if (w == w->t->topwin)
flg = 1;
else
demote (W, link, w->t->topwin, w);
w->y = -1;
return flg;
}
/* Find last window on the screen */
W *lastw (SCREEN *t) {
W *x;
for (x = t->topwin; x->link.next != t->topwin && x->link.next->y >= 0;
x = x->link.next);
return x;
}
/* Create a screen object */
SCREEN *scr;
SCREEN *screate (SCRN *scrn) {
SCREEN *t = (SCREEN *) malloc (sizeof (SCREEN));
t->t = scrn;
t->w = scrn->co;
t->h = scrn->li;
t->topwin = 0;
t->curwin = 0;
t->wind = skiptop;
scr = t;
return t;
}
void sresize (SCREEN *t) {
SCRN *scrn = t->t;
W *w;
t->w = scrn->co;
t->h = scrn->li;
if (t->h - t->wind < FITHEIGHT)
t->wind = t->h - FITHEIGHT;
if (t->wind < 0)
t->wind = 0;
w = t->topwin;
do
w->y = -1, w->w = t->w - 1;
while (w = w->link.next, w != t->topwin);
wfit (t);
updall ();
}
void updall (void) {
int y;
for (y = 0; y != scr->h; ++y)
scr->t->updtab[y] = 1;
}
void scrins (B *b, long l, long n, int flg) {
W *w;
if (w = scr->topwin)
do
if (w->y >= 0)
{
if (w->object && w->watom->ins)
w->watom->ins (w->object, b, l, n,
flg);
}
while (w = w->link.next, w != scr->topwin);
}
void scrdel (B *b, long l, long n, int flg) {
W *w;
if (w = scr->topwin)
do
if (w->y >= 0)
{
if (w->object && w->watom->del)
w->watom->del (w->object, b, l, n,
flg);
}
while (w = w->link.next, w != scr->topwin);
}
/* Fit as many windows on the screen as is possible beginning with the window
* at topwin. Give any extra space which couldn't be used to fit in another
* window to the last text window on the screen. This function guarentees
* to fit on the window with the cursor in it (moves topwin to next group
* of windows until window with cursor fits on screen).
*/
static int doabort ();
extern volatile int dostaupd;
void wfit (SCREEN *t) {
int y; /* Where next window goes */
int left; /* Lines left on screen */
W *w; /* Current window we're fitting */
W *pw; /* Main window of previous family */
int req; /* Amount this family needs */
int adj; /* Amount family needs to be adjusted */
int flg = 0; /* Set if cursor window was placed on screen */
int ret;
dostaupd = 1;
tryagain:
y = t->wind;
left = t->h - y;
pw = 0;
w = t->topwin;
do
{
w->ny = -1;
w->nh = geth (w);
}
while ((w = w->link.next) != t->topwin);
/* Fit a group of windows on the screen */
w = t->topwin;
do
{
req = getgrouph (w);
if (req > left) /* If group is taller than lines left */
adj = req - left; /* then family gets shorter */
else
adj = 0;
/* Fit a family of windows on the screen */
do
{
w->ny = y; /* Set window's y position */
if (!w->win)
pw = w, w->nh -= adj; /* Adjust main window of the group */
if (!w->win && w->nh < 2)
while (w->nh < 2)
w->nh +=
doabort (w->link.next,
&ret);
if (w == t->curwin)
flg = 1; /* Set if we got window with cursor */
y += w->nh;
left -= w->nh; /* Increment y value by height of window */
w = w->link.next; /* Next window */
}
while (w != t->topwin && w->main == w->link.prev->main);
}
while (w != t->topwin && left >= FITHEIGHT);
/* We can't use extra space to fit a new family on, so give space to parent of
* previous family */
pw->nh += left;
/* Adjust that family's children which are below the parent */
while ((pw = pw->link.next) != w)
pw->ny += left;
/* Make sure the cursor window got on the screen */
if (!flg)
{
t->topwin = findbotw (t->topwin)->link.next;
goto tryagain;
}
/* All of the windows are now on the screen. Scroll the screen to reflect what
* happened
*/
w = t->topwin;
do
if (w->y >= 0 && w->ny >= 0)
if (w->ny > w->y)
{
W *l = pw = w;
while (pw->link.next != t->topwin &&
(pw->link.next->y < 0
|| pw->link.next->ny < 0
|| pw->link.next->ny >
pw->link.next->y))
{
pw = pw->link.next;
if (pw->ny >= 0 && pw->y >= 0)
l = pw;
}
/* Scroll windows between l and w */
loop1:
if (l->ny >= 0 && l->y >= 0)
nscrldn (t->t, l->y,
l->ny + uns_min (l->h,
l->nh),
l->ny - l->y);
if (w != l)
{
l = l->link.prev;
goto loop1;
}
w = pw->link.next;
}
else if (w->ny < w->y)
{
W *l = pw = w;
while (pw->link.next != t->topwin &&
(pw->link.next->y < 0 ||
pw->link.next->ny < 0 ||
pw->link.next->ny <
pw->link.next->y))
{
pw = pw->link.next;
if (pw->ny >= 0 && pw->y >= 0)
l = pw;
}
/* Scroll windows between l and w */
loop0:
if (w->ny >= 0 && w->y >= 0)
nscrlup (t->t, w->ny,
w->y + uns_min (w->h,
w->nh),
w->y - w->ny);
if (w != l)
{
w = w->link.next;
goto loop0;
}
w = pw->link.next;
}
else
w = w->link.next;
else
w = w->link.next;
while (w != t->topwin);
/* Update current height and position values */
w = t->topwin;
do
{
if (w->ny >= 0)
{
if (w->object)
{
if (w->watom->move)
w->watom->move (w->object, w->x,
w->ny);
if (w->watom->resize)
w->watom->resize (w->object,
w->w, w->nh);
}
if (w->y == -1)
msetI (t->t->updtab + w->ny, 1, w->nh);
w->y = w->ny;
}
else
w->y = -1;
w->h = w->nh;
w->reqh = 0;
}
while (w = w->link.next, w != t->topwin);
}
/* Goto next window */
int wnext (SCREEN *t) {
if (t->curwin->link.next != t->curwin)
{
t->curwin = t->curwin->link.next;
if (t->curwin->y == -1)
wfit (t);
return 0;
}
else
return -1;
}
/* Goto previous window */
int wprev (SCREEN *t) {
if (t->curwin->link.prev != t->curwin)
{
t->curwin = t->curwin->link.prev;
if (t->curwin->y == -1)
{
t->topwin = findtopw (t->curwin);
wfit (t);
}
return 0;
}
else
return -1;
}
/* Grow window */
int wgrow (W *w) {
W *nextw;
/* If we're the last window on the screen, shrink the previous window */
if ((w->link.next == w->t->topwin || w->link.next->y == -1) &&
w != w->t->topwin)
return wshrink (w->link.prev->main);
/* Get to next variable size window */
for (nextw = w->link.next; nextw->fixed && nextw != w->t->topwin;
nextw = nextw->link.next);
/* Is it below us, on screen and big enough to take space from? */
if (nextw == w->t->topwin || nextw->y == -1 || nextw->h <= FITHEIGHT)
return -1;
/* Increase this window's height */
seth (w, w->h + 1);
/* Decrease next window's height */
seth (nextw, nextw->h - 1);
/* Do it */
wfit (w->t);
return 0;
}
/* Shrink window */
int wshrink (W *w) {
W *nextw;
/* If we're the last window on the screen, grow the previous window */
if ((w->link.next == w->t->topwin || w->link.next->y == -1) &&
w != w->t->topwin)
return wgrow (w->link.prev->main);
/* Is this window too small already? */
if (w->h <= FITHEIGHT)
return -1;
/* Get to window below us */
for (nextw = w->link.next;
nextw != w->t->topwin && nextw->fixed; nextw = nextw->link.next);
if (nextw == w->t->topwin)
return -1;
/* Decrease the size of this window */
seth (w, w->h - 1);
/* Increase the size of next window */
seth (nextw, nextw->h + 1);
/* Do it */
wfit (w->t);
return 0;
}
/* Show all windows */
void wshowall (SCREEN *t) {
int n = 0;
int set;
W *w;
/* Count no. of main windows */
w = t->topwin;
do
if (!w->win)
++n;
while (w = w->link.next, w != t->topwin);
/* Compute size to set each window */
if ((set = (t->h - t->wind) / n) < FITHEIGHT)
set = FITHEIGHT;
/* Set size of each variable size window */
w = t->topwin;
do
if (!w->win)
{
int h = getminh (w);
if (h >= set)
seth (w, 2);
else
seth (w, set - (h - 2));
w->orgwin = 0;
}
while (w = w->link.next, w != t->topwin);
/* Do it */
wfit (t);
}
void wspread (SCREEN *t) {
int n = 0;
W *w = t->topwin;
do
if (w->y >= 0 && !w->win)
++n;
while (w = w->link.next, w != t->topwin);
if (!n)
{
wfit (t);
return;
}
if ((t->h - t->wind) / n >= FITHEIGHT)
n = (t->h - t->wind) / n;
else
n = FITHEIGHT;
w = t->topwin;
do
if (!w->win)
{
int h = getminh (w);
if (h >= n)
seth (w, 2);
else
seth (w, n - (h - 2));
w->orgwin = 0;
}
while (w = w->link.next, w != t->topwin);
wfit (t);
}
/* Show just one family of windows */
void wshowone (W *w) {
W *q = w->t->topwin;
do
if (!q->win)
{
seth (q, w->t->h - w->t->wind - (getminh (q) - 2));
q->orgwin = 0;
}
while (q = q->link.next, q != w->t->topwin);
wfit (w->t);
}
/* Create a window */
W *wcreate (SCREEN *t, WATOM *watom, W *where, W *target, W *original, int height, char *huh, int *notify) {
W *new;
if (height < 1)
return 0;
/* Create the window */
new = (W *) malloc (sizeof (W));
new->notify = notify;
new->t = t;
new->w = t->w - 1;
seth (new, height);
new->h = new->reqh;
new->y = -1;
new->ny = 0;
new->nh = 0;
new->x = 0;
new->huh = huh;
new->orgwin = original;
new->watom = watom;
new->object = 0;
new->msgb = 0;
new->msgt = 0;
/* Set window's target and family */
if (new->win = target)
{ /* A subwindow */
new->main = target->main;
new->fixed = height;
}
else
{ /* A parent window */
new->main = new;
new->fixed = 0;
}
/* Get space for window */
if (original)
if (original->h - height <= 2)
{
/* Not enough space for window */
free (new);
return 0;
}
else
seth (original, original->h - height);
/* Create new keyboard handler for window */
if (watom->context)
new->kbd = mkkbd (getcontext (watom->context));
else
new->kbd = 0;
/* Put window on the screen */
if (where)
enquef (W, link, where, new);
else
{
if (t->topwin)
enqueb (W, link, t->topwin, new);
else
izque (W, link, new), t->curwin = t->topwin = new;
}
return new;
}
/* Abort group of windows */
static int doabort (W *w, int *ret) {
int amnt = geth (w);
W *z;
w->y = -2;
if (w->t->topwin == w)
w->t->topwin = w->link.next;
loop:
z = w->t->topwin;
do
{
if (z->orgwin == w)
z->orgwin = 0;
if ((z->win == w || z->main == w) && z->y != -2)
{
amnt += doabort (z, ret);
goto loop;
}
}
while (z = z->link.next, z != w->t->topwin);
if (w->orgwin)
seth (w->orgwin, geth (w->orgwin) + geth (w));
if (w->t->curwin == w)
if (w->t->curwin->win)
w->t->curwin = w->t->curwin->win;
else if (w->orgwin)
w->t->curwin = w->orgwin;
else
w->t->curwin = w->link.next;
if (qempty (W, link, w))
{
leave = 1;
amnt = 0;
}
deque (W, link, w);
if (w->watom->abort && w->object)
{
*ret = w->watom->abort (w->object, MAXINT);
if (w->notify)
*w->notify = -1;
}
else
{
*ret = -1;
if (w->notify)
*w->notify = 1;
}
rmkbd (w->kbd);
free (w);
windie (w);
return amnt;
}
/* Abort a window and its children */
int wabort (W *w) {
SCREEN *t = w->t;
int ret;
if (w != w->main)
{
doabort (w, &ret);
if (!leave)
wfit (t);
}
else
{
doabort (w, &ret);
if (!leave)
{
if (lastw (t)->link.next != t->topwin)
wfit (t);
else
wspread (t);
}
}
return ret;
}
/* Generate text with formatting escape sequences */
void genfmt (SCRN *t, int x, int y, int ofst, char *s, int flg) {
int *scrn = t->scrn + y * t->co + x;
int atr = 0;
int col = 0;
int c;
while (c = *s++)
if (c == '\\')
switch (c = *s++)
{
case 'u':
case 'U':
atr ^= UNDERLINE;
break;
case 'i':
case 'I':
atr ^= INVERSE;
break;
case 'b':
case 'B':
atr ^= BOLD;
break;
case 'd':
case 'D':
atr ^= DIM;
break;
case 'f':
case 'F':
atr ^= BLINK;
break;
case 0:
--s;
break;
default:
if (col++ >= ofst)
{
outatr (t, scrn, x, y, c, atr);
++scrn;
++x;
}
break;
}
else if (col++ >= ofst)
{
if (c == '\t')
c = ' ';
outatr (t, scrn, x, y, c, atr);
++scrn;
++x;
}
if (flg)
eraeol (t, x, y);
}
/* Generate text: no formatting */
void gentxt (SCRN * t, int x, int y, int ofst, char *s, int len, int flg) {
int *scrn = t->scrn + y * t->co + x;
int col;
int c;
int a;
for (col = 0; col != len; ++col)
if (col >= ofst)
{
c = (unsigned) s[col];
if (c == '\t')
c = ' ';
xlat (a, c);
outatr (t, scrn, x, y, c, a);
++scrn;
++x;
}
if (flg)
eraeol (t, x, y);
}
/* Determine column width of string with format codes */
int fmtlen (char *s) {
int col = 0;
while (*s)
{
if (*s == '\\')
switch (*++s)
{
case 'u':
case 'i':
case 'd':
case 'f':
case 'b':
case 'U':
case 'I':
case 'D':
case 'F':
case 'B':
++s;
goto cont;
case 0:
--s;
}
++col;
++s;
cont:;
}
return col;
}
/* Return offset within format string which corresponds to a particular
column */
int fmtpos (char *s, int goal) {
char *org = s;
int col = 0;
while (*s && col != goal)
{
if (*s == '\\')
switch (*++s)
{
case 'u':
case 'i':
case 'd':
case 'f':
case 'b':
case 'U':
case 'I':
case 'D':
case 'F':
case 'B':
++s;
goto cont;
case 0:
--s;
}
++col;
++s;
cont:;
}
return s - org + goal - col;
}
/* Display a message and skip the next key */
static void mdisp (SCRN *t, int y, char *s) {
int ofst;
int len;
len = fmtlen (s);
if (len <= (t->co - 1))
ofst = 0;
else
ofst = len - (t->co - 1);
genfmt (t, 0, y, ofst, s, 1);
t->updtab[y] = 1;
}
void msgout (W *w) {
SCRN *t = w->t->t;
if (w->msgb)
{
mdisp (t, w->y + w->h - 1, w->msgb);
w->msgb = 0;
}
if (w->msgt)
{
mdisp (t, w->y + ((w->h > 1 && (w->y || !staen)) ? 1 : 0),
w->msgt);
w->msgt = 0;
}
}
/* Set temporary message */
char msgbuf[MSGBUFSIZE];
void msgnw (BASE *w, char *s) {
w->parent->msgb = s;
}
void msgnwt (BASE *w, char *s) {
w->parent->msgt = s;
}
int urtn (BASE *b, int k) {
if (b->parent->watom->rtn)
return b->parent->watom->rtn (b, k);
else
return -1;
}
int utype (BASE *b, int k) {
if (b->parent->watom->type)
return b->parent->watom->type (b, k);
else
return -1;
}
/* Window user commands */
int uprevw (BASE *bw) {
return wprev (bw->parent->t);
}
int unextw (BASE *bw) {
return wnext (bw->parent->t);
}
int ugroww (BASE *bw) {
return wgrow (bw->parent);
}
int ushrnk (BASE *bw) {
return wshrink (bw->parent);
}
int uexpld (BASE *bw) {
if (bw->parent->t->h - bw->parent->t->wind == getgrouph (bw->parent))
wshowall (bw->parent->t);
else
wshowone (bw->parent);
return 0;
}
int uretyp (BASE *bw) {
nredraw (bw->parent->t->t);
return 0;
}
joe-2.9.6/w.h 0100600 0032337 0023564 00000013520 07264414442 012315 0 ustar xgrac student /*
Window management
Copyright (C) 1992 Joseph H. Allen
This file is part of JOE (Joe's Own Editor)
*/
#ifndef _Iw
#define _Iw 1
#include "config.h"
#include "queue.h"
#include "scrn.h"
#include "kbd.h"
typedef struct watom WATOM;
typedef struct screen SCREEN;
typedef struct window W;
typedef struct base BASE;
struct watom {
char *context; /* Context name */
void (*disp) (); /* Display window */
void (*follow) (); /* Called to have window follow cursor */
int (*abort) (); /* Common user functions */
int (*rtn) ();
int (*type) ();
void (*resize) (); /* Called when window changed size */
void (*move) (); /* Called when window moved */
void (*ins) (); /* Called on line insertions */
void (*del) (); /* Called on line deletions */
int what; /* Type of this thing */
};
struct screen {
SCRN *t; /* Screen data on this screen is output to */
int wind; /* Number of help lines on this screen */
W *topwin; /* Top-most window showing on screen */
W *curwin; /* Window cursor is in */
int w, h; /* Width and height of this screen */
};
struct window {
LINK (W) link; /* Linked list of windows in order they
appear on the screen */
SCREEN *t; /* Screen this thing is on */
int x, y, w, h; /* Position and size of window */
/* Currently, x=0, w=width of screen. */
/* y== -1 if window is not on screen */
int ny, nh; /* Temporary values for wfit */
int reqh; /* Requested new height or 0 for same */
/* This is an argument for wfit */
int fixed; /* If this is zero, use 'hh'. If not, this
is a fixed size window and this variable
gives its height */
int hh; /* Height window would be on a screen with
1000 lines. When the screen size changes
this is used to calculate the window's
real height */
W *win; /* Window this one operates on */
W *main; /* Main window of this family */
W *orgwin; /* Window where space from this window came */
int curx, cury; /* Cursor position within window */
KBD *kbd; /* Keyboard handler for this window */
WATOM *watom; /* The type of this window */
void *object; /* Object which inherits this */
char *msgt; /* Message at top of window */
char *msgb; /* Message at bottom of window */
char *huh; /* Name of window for context sensitive hlp */
int *notify; /* Address of kill notification flag */
};
/* Anything which goes in window.object must start like this: */
struct base {
W *parent;
};
/* Minimum text window height */
#define FITHEIGHT 4
/***************/
/* Subroutines */
/***************/
/* int getgrouph(W *);
* Get height of a family of windows
*/
int getgrouph ();
/* W *findtopw(W *);
* Find first (top-most) window of a family
*/
W *findtopw ();
/* W *findbotw(W *);
* Find last (bottom-most) window a family
*/
W *findbotw ();
int demotegroup ();
/* W *lastw(SCREEN *t);
* Find last window on screen
*/
W *lastw ();
/* Determine number of main windows
*/
int countmain ();
/* void wfit(SCREEN *t);
*
* Fit all of the windows onto the screen
*/
void wfit ();
/*****************/
/* Main routines */
/*****************/
/* SCREEN *screate(SCRN *);
*
* Create a screen
*/
SCREEN *screate ();
/* void sresize(SCREEN *t);
* Screen size changed
*/
void sresize ();
/* void chsize(SCREEN *t,int mul,int div)
* Resize windows: each window is multiplied by the fraction mul/div
*/
void chsize ();
/* W *wcreate(SCREEN *t,WATOM *watom,W *where,W *target,W *original,int height);
*
* Try to create a window
*
* 't' Is the screen the window is placed on
* 'watom' Type of new window
* 'where' The window is placed after this window, or if 'where'==0, the
* window is placed on the end of the screen
* 'target' The window operates on this window. The window becomes a
* member of 'target's family or starts a new family if
* 'target'==0.
* 'original' Attempt to get 'height' from this window. When the window is
* aborted, the space gets returned to 'original' if it still
* exists. If 'original'==0, the window will force other
* windows to go off of the screen.
* 'height' The height of the window
*
* Returns the new window or returns 0 if there was not enough space to
* create the window and maintain family integrity.
*/
W *wcreate ();
/* int wabort(W *w);
*
* Kill a window and it's children
*/
int wabort ();
/* int wnext(SCREEN *);
*
* Switch to next window
*/
int wnext ();
/* int wprev(SCREEN *);
*
* Switch to previous window
*/
int wprev ();
/* int wgrow(W *);
*
* increase size of window. Return 0 for success, -1 for fail.
*/
int wgrow ();
/* int wshrink(W *);
*
* Decrease size of window. Returns 0 for success, -1 for fail.
*/
int wshrink ();
/* void wshowone(W *);
*
* Show only one window on the screen
*/
void wshowone ();
/* void wshowall(SCREEN *);
*
* Show all windows on the screen, including the given one
*/
void wshowall ();
/* void wredraw(W *);
*
* Force complete redraw of window
*/
void wredraw ();
/* void updall()
*
* Redraw all windows
*/
void updall ();
void genfmt ();
void gentxt ();
int fmtlen ();
int fmtpos ();
/* void msgnw[t](W *w,char *text);
* Display a message which will be eliminated on the next keypress.
* msgnw displays message on bottom line of window
* msgnwt displays message on top line of window
*/
void msgnw ();
void msgnwt ();
#define MSGBUFSIZE 80
extern char msgbuf[MSGBUFSIZE]; /* Message composition buffer for msgnw/msgnwt */
void msgout (); /* Output msgnw/msgnwt messages */
/* Common user functions */
int urtn (); /* User hit return */
int utype (); /* User types a character */
int uretyp (); /* Refresh the screen */
int ugroww (); /* Grow current window */
int uexpld (); /* Explode current window or show all windows */
int ushrnk (); /* Shrink current window */
int unextw (); /* Goto next window */
int uprevw (); /* Goto previous window */
void scrdel ();
void scrins ();
#endif
joe-2.9.6/INFO 0100600 0032337 0023564 00000015026 07262717537 012370 0 ustar xgrac student
Joe's Own Editor 2.9.x
A Free ASCII-Text Screen Editor for UNIX
JOE is the professional freeware ASCII text screen editor for UNIX.
It makes full use of the power and versatility of UNIX, but lacks the steep
learning curve and basic nonsense you have to deal with in every other UNIX
editor. JOE has the feel of most IBM PC text editors: The key-sequences are
reminiscent of WordStar and Turbo-C. JOE is much more powerful than those
editors, however. JOE has all of the features a UNIX user should expect:
full use of termcap/terminfo, excellent screen update optimizations (JOE is
fully useable at 2400 baud), simple installation, and all of the
UNIX-integration features of VI.
JOE's initialization file determines much of JOE's personality and
the name of the initialization file is simply the name of the editor
executable followed by "rc". JOE comes with four "rc" files in addition to
the basic "joerc", which allow it to emulate these editors:
JPICO - An enhanced version of the Pine mailer system's PICO
editor.
JSTAR - A complete immitation of WordStar including many "JOE"
extensions.
RJOE - A restricted version of JOE which allowed you to edit
only the files specified on the command line.
JMACS - A GNU-EMACS immitation which is about one order of
magnitude smaller than real GNU-EMACS.
Features:
JOE has a well thought-out user-interface with great attention to
detail. The Page Up and Page Down functions do not move the cursor relative
to the edges of the screen. Left and Right arrow keys work at the beginning
and ends of lines. The cursor can move past the ends of lines without
jumping, but also without inserting or deleting extra spaces at the ends of
lines. Control characters and characters above 127 can be displayed and
entered- even ^Q and ^S. The cursor's row and column number can be
displayed in the status line.
The key layout is made to reduce terminal incompatibility nonsense.
^Q and ^S are not used and both ^H and DEL are mapped to backspace. Case
does not matter in key sequences- ^K E, ^K e, and ^K ^E are each mapped to
the same function. The arrow keys and PageUp, PageDown, Home, End, Insert
and Delete keypad keys are read from the termcap entry and are assigned to
the proper functions. A simple initialization file, similar to Semware's
Q-EDIT, allows key-bindings, simple macros and help windows to be defined.
JOE has full termcap/terminfo support and will work on any terminal.
JOE has the best screen update optimization algorithm available. It uses
VT100-style scrolling regions the way they are supposed to be used (I.E.,
without building insert and delete line functions out of them) and has a
powerful line shifting (insert/delete character) algorithm which works even
if text goes past the ends of lines. JOE has deferred screen update to
handle typeahead and uses the baud rate reported by 'stty' to ensure that
deferral is not bypassed by tty buffering.
JOE has multiple windows and lacks the confusing notion of a named
buffers. You just have files and windows. When there are more windows than
can fit on the screen, the Goto-Next-Window function scrolls through them.
The same file can have multiple windows opened on it.
JOE has VI-style unix integration. You can filter a highlighted
block through a UNIX command. Also, each place in joe which accepts a file
name (including the command line) will also accept:
!command to pipe into or out of a command
>>filename to append to a file
filename,start,size to edit a portion of a file/device
- to use stdin or stdout
File names on the command line may be preceeded by +nnn to start
editing at a specified line.
JOE has shell windows. You can run a shell in a window and any
output from commands run in the shell gets stored in a buffer.
JOE has an orthogonal event-driven design. Each prompt is actually
a normal edit buffer containing a history of all of the responses entered
for that prompt. You can use all of the normal edit commands to create file
names and search strings. You can use the up arrow key (or search backwards
and any other appropriate edit command) to go back through the history of
previous responses. Prompts are reentrant- meaning that edit commands which
require prompts can still be used inside of prompts.
JOE has TAB-completion and file selection menus. If you hit tab in
a file name prompt, the name is either completed or a menu of possible
matches appears.
JOE stores edit files in a doubly linked list of gap buffers which
can spill into a temporary file. You can edit files of any size up to the
amount of free disk space and there are no line-length restrictions. Since
the buffering system is block-based, JOE will incur only a minimum of
swapping on heavily loaded systems.
When you ask for help, one of six small help reference cards appears
on the screen and remains while you continue to use the editor. Here is the
first help card:
CURSOR GO TO BLOCK DELETE MISC EXIT
^B left ^F right ^U prev. screen ^KB begin ^D char. ^KJ reformat ^KX save
^P up ^N down ^V next screen ^KK end ^Y line ^T options ^C abort
^Z previous word ^A beg. of line ^KM move ^W >word ^@ insert ^KZ shell
^X next word ^E end of line ^KC copy ^O word< ^R retype FILE
SEARCH ^KU top of file ^KW file ^J >line SPELL ^KE new
^KF find text ^KV end of file ^KY delete ^_ undo ^[N word ^KR insert
^L find next ^KL to line No. ^K/ filter ^^ redo ^[L file ^KD save
JOE has a powerful set of editing commands suitable for editing both
text files and programs:
- search and replace system, including powerful regular
expressions (including matching of balanced C expressions).
- tags file search
- paragraph format
- undo and redo
- position history allows you to get back to previous
editing contexts and allows you to quickly flip between
editing contexts
- multiple keyboard macros
- block move/copy/delete/filter
- rectangle (columnar) mode
- overtype/insert modes
- indent/unindent
- goto matching ( [ {
- auto-indent mode
Plus many options can be set:
- can have EMACS-style cursor re-centering on scrolls
- characters between 128-255 can be shown as-is for
non-english character sets
- Final newline can be forced on end of file
- Can start with a help screen on
- Left/Right margin settings
- Tab width
- Indentation step and fill character
Any questions, problems, suggestions send to Marek 'Marx' Grac
(xgrac@fi.muni.cz)
joe-2.9.6/LIST 0100600 0032337 0023564 00000011507 05703421055 012371 0 ustar xgrac student Joe commands grouped by function
Background programs
-------------------
bknd Run a shell in a window
killproc Kill program in current window
run Run a unix command in a window
Blocks
------
blkcpy Copy marked block to cursor
blkdel Delete marked block
blkmove Move marked block to cursor
blksave Save marked block into a file
copy Copy block to kill-ring
drop Set markb. If it was already set, eliminate it.
filt Filter block or file through a unix command
markb Set beginning of block mark
markk Set end of block mark
markl Mark current line
nmark Eliminate markb and markk
picokill Delete line or block
pop Restore markb and markk values from stack
psh Push markb and markk values onto a stack
swap Switch cursor with markb
tomarkb Move cursor to markb
tomarkbk Move cursor to markb or markk
tomarkk Move cursor to markk
yank Insert top of kill ring
yankpop Scroll through kill ring
yapp Append next kill to top of kill ring
Buffers
-------
bufed Buffer menu
edit Load file into window
nbuf Load next buffer into current window
pbuf Load previous buffer into current window
Cursor Motion
-------------
bof Move cursor to beginning of file
bol Move cursor to beginning of line
bop Move to beginning of a paragraph
bos Move to beginning of screen
bkwdc Search backwards for a character
byte Move cursor to specific byte offset into the file.
col Move cursor to specific column number.
dnarw Move cursor down one line
eof Move cursor to end of file
eol Move cursor to end of line
eop Move cursor to end of paragraph
fwrdc Search forward for matching character
gomark Move cursor to a bookmark
line Move cursor to specified line
ltarw Move cursor left
nedge Move cursor to next edge
nextpos Move cursor to next position in cursor position history
nextword Move cursor to end of next word
pedge Move cursor to previous edge
prevpos Move cursor to previous position in cursor position history
prevword Move cursor to beginning of previous word
rtarw Move cursor right
setmark Set a bookmark
tomatch Move cursor to matching delimiter
tos Move cursor to top of screen
uparw Move cursor up
Deletion
--------
backs Backspace
backw Backspace a word
delbol Delete to beginning of line
delch Delete character under cursor
deleol Delete to end of line
dellin Delete entire line
delw Delete word to right
Error parsing
-------------
nxterr Goto next parsed error
parserr Parse errors in current file
prverr Go to previous parsed error
Exit
----
abort Abort current buffer/window. Prompt if it is changed.
abortbuf Abort current buffer/window if it is not changed
ask Prompt to save current file
exsave Save file and exit
lose Prompt to lose changes to current file
Files
-----
save Save file
insf Insert a file
Formatting
----------
center Center line
fmtblk Format all paragraphs in a block
format Format current paragraph
lindent Indent to the left
rindent Indent to the right
Help
----
help Turn help on or off
hnext Switch to next help screen
hprev Switch to previous help screen
Inserting
---------
ctrl Type next key
insc Insert a space
open Insert newline
quote Insert a control character
quote8 Insert a meta character
rtn Return key
type Insert typed character
Macros
------
macros Insert keyboard macros into current file
play Execute a macro
query Macro query
record Record a macro
stop Stop recording macro
Menu
----
backsmenu Undo in file completion menu
bofmenu Move to beginning of menu
bolmenu Move to beginning of line in a menu
dnarwmenu Move down one line in a menu
eolmenu Move cursor to end of line in a menu
eofmenu Move cursor to end of menu
ltarwmenu Move cursor left in a menu
rtarwmenu Move cursor right in menu
uparwmenu Move cursor up in menu
Misc
----
execmd Execute a joe command
math Calculator
mode Mode prompt
msg Display a message
notmod Clear the modified flag
retype Refresh screen
shell Suspend process or execute a sub-shell
stat Display cursor position
tag Tags file search
txt Insert text
Prompts
-------
complete Complete a file-name in a prompt
Repeat
------
arg Prompt for repeat argument
uarg Universal argument
Scrolling
---------
crawll Pan screen left
crawlr Pan screen right
dnslide Scroll screen down 1 line
pgdn Scroll screen down
pgup Scroll screen up
upslide Scroll up one line
Search and replace
------------------
ffirst Find text
fnext Repeat previous search
isrch Incremental search forward
qrepl Search and replace
rfirst Search backwards for text
rsrch Reverse incremental search
Windows
-------
explode Display one window or display all windows
dupw Duplicate current window
groww Increase size of window
nextw Move cursor to next window
prevw Go to previous window
shrinkw Shrink window
splitw Split window into two
tw0 Eliminate this window
tw1 Show only one window
Undo
----
redo Re-execute the latest undone change
undo Undo last change
joe-2.9.6/NEWS 0100600 0032337 0023564 00000014551 07265402263 012401 0 ustar xgrac student Overview of Changes in JOE 2.9.6 (13 Apr 2001)
- JOE can be compiled on Windows platform again
- BUGFIX:: problem with ${sysconfdir}/joerc was solved
- BUGFIX:: security patch for sprintf
- BUGFIX:: partially solved problem on Solaris with SegFault
- BUGFIX:: patch joe-2.8-security (slightly changed)
- BUGFIX:: patch joe-2.8-port
- BUGFIX:: patch joe-2.8-mips
- BUGFIX:: patch joe-2.8-vsmk
- BUGFIX:: patch joe2.8-time
- *rc files where moved from $(prefix)/lib to $(prefix)/etc or $sysconfdir
- Makefile.in (and Makefile) was rewritten
- special prefix for package (more in Makefile.in)
- use of system independent 'mkinstalldirs'
- rc files are not rewritten
- TEST FEATURE:: added autoconf support
program can be installed by ./configure; make; make install
- BUGFIX (v2.9.4):: go to previous word problem solved
- JOE can be compiled without locale.h again
- BUGFIX:: patch joe2.8-axphack.patch
- BUGFIX:: patch joe2.8-resize2.patch
- BUGFIX:: fixed problem with :include in rc files
- BUGFIX (v2.9.5):: portability problem with is_blank on nonGNU systems
Overview of Changes in JOE 2.9.5 (28 Mar 2001)
- new BUG:: can't be compiled on non-GNU systems (is_blank()) fixed in v2.9.6
- BUGFIX:: Fixed problem with resizing.
- SECURITY:: .[joe|rjoe|jpico|..]rc in actual directory is ignored
because in this file can be defined which program run.
Overview of Changes in JOE 2.9.4 (27 Mar 2001)
- new BUG:: go to previous word; goes one character before this word
fixed in v2.9.6
- FEATURE:: locale (LC_CTYPE) is accepted when skipping/deleting/... words
Overview of Changes in JOE 2.9 (22 Mar 2001)
- version 2.8 with patches from RedHat/Suse
Overview of Changes in JOE 2.8
- Fixed problem with TERMPATH string
- Added stupid two-letter names to termcap file
- Improved jmacs help and command set
- Improved README file
Overview of Changes in JOE 2.7
- putenv() was not portable
- utime was not portable
- special utime handling for NeXT
- forgot to \\ the \s in the default termcap entry
- changed some key defaults in jpicorc
- add IXOFF in termio/termios list
- left margin limit was incorrect
- allow '.' and '/' in file names for error parsing
- Needed ptem.h and stream.h for SCO_UNIX window size structure (?)
- wordwrap no longer propogates indent prefix
- paragraph format was broken for tab indented paragraphs
- pipe through shell now goes through stderr too
- added '-crlf' option
- looks for termcap file in JOERC/termcap
Overview of Changes in JOE 2.6
- Fixed stupid bug in termcap.c which prevented terminfo from working
- ESC h was missing from jpicorc
- Changes suggested by Dan Nelson:
- backup files now attempt to have same permissions and times as original
- Stat command now ands chars with 255 (don't know why this worked on my system
without this...)
- Maybe change shell invocation name- have to check this more
Overview of Changes in JOE 2.5
- No longer use ^[ O, ^[ A, ^[ B, ^[ C, or ^[ D for anything because they
interfere with arrow keys.
- Couldn't create new files because of bug in readonly setting
- fwrdc/bkwdc were crashing the editor except when called from wordstar
- 'tr' command was not called in a portable way in jmacs
- 'tr' was causing problems with the spell-check macros as well
- filter region was not working: had to add 'query' in ^[ | macro
- Changed incremental search so that whatever key the command is bound to
can be used to repeat the search (used to only be able to use ^S)
Overview of Changes in JOE 2.4
- Closing message was incorrect when exit macros (macros where the last
command is abortbuf) were used.
- SuperPico rc file added
- Write block now writes the entire file if no block is set
- Added pico kill function for pico emulation
(tried to do this with 'psh,markk,blkdel' where blkdel deletes lines if
no block is set, but it didn't group the deletes right in the yank
buffer)
- Filter block would leave the marks set
- Fixed ^@ in joe mode
- Fixed help screen glitches in wordstar mode
- If joe can't make a backup file it now prompts for you to save anyway
- Eliminated IDLEOUT compile option. Now is the user gives - on the
command line, joe uses /dev/tty.
- Added %o %O %a %A %X and %R status line messages
- Starts out in read only mode if loaded file can not be written to
- If joe can't find the termcap/terminfo entry, it instead uses the default
- termcap routines are now included even if you use terminfo. If your
terminal can't be found in the terminfo database, it will look in
the termcap database too.
- The JOETERM environment variable can be used to bypass the TERM
environment variable setting.
Overview of Changes in JOE 2.3
- Search & Replace bugs fixed
- replace would mess up the end mark of a marked block
- a search would trash ^KB if only ^KB was set
- regex problem with \*
- Was using TCSANOW in posix driver. Should have been using TCSADRAIN
- Format paragraph now correctly formats quoted news articles
- Attempted fix for SCO
- Fix for coherent
- Fix for old IRIX/SGI
- Fixed bug where if you used search & replace in a macro, and exiting the
search & replace loop with right arrow key, then when you played the macro
you got an extra ^[ in the input queue
- Added file hooks
- Added function to insert current keyboard macro into current file
- Added range checks to numeric option settings
- Restricted joe rc file added
- Added ':def' feature for rc files
Overview of Changes in JOE 2.2
- First attempt at MS-DOS version of joe
- Direct screen write
- Modifications for dos file/drive names
- Use TEMP variable to figure out where to store temporary file
- Smaller virtual memory page size
- Backslashes in file name problem
- CR before an LF looks like an LF
- Backward search ignore-case was not working
- Scalable window height was not working fully
- Spaces in file-names gave a problem with backup file creation
- TILDE option is not available in all versions of BSD
- Allow : as seperate for termcap filename list
- Next error / Prev. error was not tracking right
- tabs not displayed right in nxterr/prverr messages
- Block moves where the cursor was to the right of the block was broken
Overview of Changes in JOE 2.1
- rc file wasn't giving correct error messages for missing options
- the '-nobackups' options was mispelled: '- nobackups'
- editor was crashing because of problem in undo
- update bypass in utype has a problem when wordwrapping and scrolling
joe-2.9.6/TODO 0100600 0032337 0023564 00000003277 07264422264 012377 0 ustar xgrac student FEATURES
=-=-=-=-
-=- syntax higlighting
-=- gettext (possibility of translate messages from joe)
from joe2.8
-=- picture mode
-=- brief emulation? EDT emulation?
-=- save editor state
-=- CR-LF mode for joe editing DOS files in linux?
-=- xedit and folding stuff
- with seperate valid-line database?
- display update algorithm will break
-=- hexadecimal edit mode
-=- fixed record length edit mode
-=- verticle windows
- difficult to get scrolling to work right
PROGRAM REDeSIGN:
=-=-=-=-=-=-=-=-=-=
-=- why to use list of help screens and array of help screens
when later is only array used ?
-=- prepare sources to use gettext
-=- add prototypes for functions
-=- clean sources
-=- add documentation
PORTABILITY
=-=-=-=-=-=
-=- WARNING: MSDOS compatibility can be broken by my changes
I try to use ANSI/ISO C but sometimes
I have to use POSIX extentsions so if you want to
have a DOS version, plz mail me your patches
-=- MSDOS
- how to give memory back during shell escapes?
-=- make identifier length significant in first 8 (6?) places
for old C compilers
BuGS
=-=-
Emacs emulation improvements:
- Rectangle mode for emacs yank system
- Overtype mode works for yank
- Query save loop? for kill-emacs and compile
- Emacs reload from file function? ^X ^V
(it just works out if ^X ^V kills all instances of the buffer)
- Bufed should display unnamed buffers
- ESC args should work differently in emacs
- nextword,nextword,prevword sequence
doesn't work for marking next successive word at ends of lines
- exiting options and i-search with ESC is not pretty
(it isn't in emacs either)
- Allow either direct screen access or normal tty support
for DOS version.
joe-2.9.6/COPYING 0100600 0032337 0023564 00000030310 05644713463 012732 0 ustar xgrac student
GNU GENERAL PUBLIC LICENSE
Version 1, February 1989
Copyright (C) 1989 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The license agreements of most software companies try to keep users
at the mercy of those companies. By contrast, our General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. The
General Public License applies to the Free Software Foundation's
software and to any other program whose authors commit to using it.
You can use it for your programs, too.
When we speak of free software, we are referring to freedom, not
price. Specifically, the General Public License is designed to make
sure that you have the freedom to give away or sell copies of free
software, that you receive source code or can get it if you want it,
that you can change the software or use pieces of it in new free
programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of a such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must tell them their rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License. The
"Program", below, refers to any such program or work, and a "work based
on the Program" means either the Program or any work containing the
Program or a portion of it, either verbatim or with modifications. Each
licensee is addressed as "you".
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this
General Public License and to the absence of any warranty; and give any
other recipients of the Program a copy of this General Public License
along with the Program. You may charge a fee for the physical act of
transferring a copy.
2. You may modify your copy or copies of the Program 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 the Program or any part thereof, either
with or without modifications, to be licensed at no charge to all
third parties under the terms of this General Public License (except
that you may choose to grant warranty protection to some or all
third parties, at your option).
c) If the modified program normally reads commands interactively when
run, you must cause it, when started running for such interactive use
in the simplest and most usual way, to print or display an
announcement including an appropriate copyright notice and a notice
that there is no warranty (or else, saying that you provide a
warranty) and that users may redistribute the program under these
conditions, and telling the user how to view a copy of this General
Public License.
d) You may charge a 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 independent work with the Program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other work under the scope of these terms.
3. You may copy and distribute the Program (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 charge
for the cost of distribution) 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.)
Source code for a work means the preferred form of the work for making
modifications to it. 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, or for standard header files or definitions files that
accompany that operating system.
4. You may not copy, modify, sublicense, distribute or transfer the
Program except as expressly provided under this General Public License.
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
the Program is void, and will automatically terminate your rights to use
the Program under this License. However, parties who have received
copies, or rights to use copies, from you under this General Public
License will not have their licenses terminated so long as such parties
remain in full compliance.
5. By copying, distributing or modifying the Program (or any work based
on the Program) you indicate your acceptance of this license to do so,
and all its terms and conditions.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original
licensor to copy, distribute or modify the Program subject to these
terms and conditions. You may not impose any further restrictions on the
recipients' exercise of the rights granted herein.
7. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of the license which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
the license, you may choose any version ever published by the Free Software
Foundation.
8. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "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
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively convey
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19xx name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your
program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
program `Gnomovision' (a program to direct compilers to make passes
at assemblers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
That's all there is to it!
joe-2.9.6/bw.c 0100600 0032337 0023564 00000046740 07265143252 012463 0 ustar xgrac student /*
Edit buffer window generation
Copyright (C) 1992 Joseph H. Allen
This file is part of JOE (Joe's Own Editor)
*/
#include <string.h>
#include <stdio.h>
#include "config.h"
#include "tty.h"
#include "vfile.h"
#include "termcap.h"
#include "kbd.h"
#include "b.h"
#include "scrn.h"
#include "w.h"
#include "ublock.h"
#include "utils.h"
#include "blocks.h"
#include "bw.h"
/* Display modes */
int dspasis = 0;
int marking = 0;
extern int square;
extern int staen;
P *getto (P *p, P *cur, P *top, long line) {
long dist = MAXLONG;
long d;
P *best;
if (!p) {
if (d = (line - cur->line >= 0 ? line - cur->line : cur->line - line), d < dist) {
dist = d, best = cur;
}
if (d = (line - top->line >= 0 ? line - top->line : top->line - line), d < dist) {
dist = d, best = top;
}
p = pdup (best);
p_goto_bol (p);
}
while (line > p->line) {
if (!pnextl (p)) {
break;
}
}
if (line < p->line) {
while (line < p->line) {
pprevl (p);
}
p_goto_bol (p);
}
return p;
}
/* Scroll window to follow cursor */
int mid = 0;
void bwfllw (BW *w) {
P *newtop;
if (w->cursor->line < w->top->line)
{
newtop = pdup (w->cursor);
p_goto_bol (newtop);
if (mid)
if (newtop->line >= w->h / 2)
pline (newtop, newtop->line - w->h / 2);
else
pset (newtop, newtop->b->bof);
if (w->top->line - newtop->line < w->h)
nscrldn (w->t->t, w->y, w->y + w->h,
(int) (w->top->line - newtop->line));
else
msetI (w->t->t->updtab + w->y, 1, w->h);
pset (w->top, newtop);
prm (newtop);
}
else if (w->cursor->line >= w->top->line + w->h)
{
newtop = pdup (w->top);
if (mid)
newtop =
getto (NULL, w->cursor, w->top,
w->cursor->line - w->h / 2);
else
newtop =
getto (NULL, w->cursor, w->top,
w->cursor->line - (w->h - 1));
if (newtop->line - w->top->line < w->h)
nscrlup (w->t->t,
w->y,
w->y + w->h,
(int) (newtop->line - w->top->line));
else
msetI (w->t->t->updtab + w->y, 1, w->h);
pset (w->top, newtop);
prm (newtop);
}
/* Adjust column */
if (w->cursor->xcol < w->offset)
{
w->offset = w->cursor->xcol;
msetI (w->t->t->updtab + w->y, 1, w->h);
}
else if (w->cursor->xcol >= w->offset + w->w)
{
w->offset = w->cursor->xcol - (w->w - 1);
msetI (w->t->t->updtab + w->y, 1, w->h);
}
}
/* Scroll a buffer window after an insert occured. 'flg' is set to 1 if
* the first line was split
*/
void
bwins (w, l, n, flg)
BW *w;
long l, n;
int flg;
{
if (l + flg + n < w->top->line + w->h && l + flg >= w->top->line
&& l + flg <= w->b->eof->line)
{
if (flg)
w->t->t->sary[w->y + l - w->top->line] =
w->t->t->li;
nscrldn (w->t->t, (int) (w->y + l + flg - w->top->line),
w->y + w->h, (int) n);
}
if (l < w->top->line + w->h && l >= w->top->line)
if (n >= w->h - (l - w->top->line))
msetI (w->t->t->updtab + w->y + l - w->top->line, 1,
w->h - (int) (l - w->top->line));
else
msetI (w->t->t->updtab + w->y + l - w->top->line, 1,
(int) n + 1);
}
/* Scroll current windows after a delete */
void
bwdel (w, l, n, flg)
BW *w;
long l, n;
int flg;
{
/* Update the line where the delete began */
if (l < w->top->line + w->h && l >= w->top->line)
w->t->t->updtab[w->y + l - w->top->line] = 1;
/* Update the line where the delete ended */
if (l + n < w->top->line + w->h && l + n >= w->top->line)
w->t->t->updtab[w->y + l + n - w->top->line] = 1;
if (l < w->top->line + w->h &&
(l + n >= w->top->line + w->h ||
l + n == w->b->eof->line
&& w->b->eof->line >= w->top->line + w->h))
if (l >= w->top->line)
/* Update window from l to end */
msetI (w->t->t->updtab + w->y + l - w->top->line, 1,
w->h - (int) (l - w->top->line));
else
/* Update entire window */
msetI (w->t->t->updtab + w->y, 1, w->h);
else if (l < w->top->line + w->h && l + n == w->b->eof->line &&
w->b->eof->line < w->top->line + w->h)
if (l >= w->top->line)
/* Update window from l to end of file */
msetI (w->t->t->updtab + w->y + l - w->top->line, 1,
(int) n);
else
/* Update from beginning of window to end of file */
msetI (w->t->t->updtab + w->y, 1,
(int) (w->b->eof->line - w->top->line));
else if (l + n < w->top->line + w->h && l + n > w->top->line
&& l + n < w->b->eof->line)
if (l + flg >= w->top->line)
nscrlup (w->t->t,
(int) (w->y + l + flg - w->top->line),
w->y + w->h, (int) n);
else
nscrlup (w->t->t, w->y, w->y + w->h,
(int) (l + n - w->top->line));
}
/* Update a single line */
static int
lgen (t, y, screen, x, w, p, scr, from, to)
SCRN *t;
int y;
int *screen; /* Screen line address */
int w; /* Window */
P *p; /* Buffer pointer */
long scr; /* Starting column to display */
long from, to; /* Range for marked block */
{
int ox = x;
int done = 1;
long col = 0;
long byte = p->byte;
char *bp; /* Buffer pointer, 0 if not set */
int amnt; /* Amount left in this segment of the buffer */
int c, ta, c1;
unsigned char bc;
/* Initialize bp and amnt from p */
if (p->ofst >= p->hdr->hole)
{
bp = p->ptr + p->hdr->ehole + p->ofst - p->hdr->hole;
amnt = SEGSIZ - p->hdr->ehole - (p->ofst - p->hdr->hole);
}
else
{
bp = p->ptr + p->ofst;
amnt = p->hdr->hole - p->ofst;
}
if (col == scr)
goto loop;
lp: /* Display next character */
if (amnt)
do
{
bc = *bp++;
if (p->b->o.crlf && bc == '\r')
{
++byte;
if (!--amnt)
{
pppl:
if (bp == p->ptr + SEGSIZ)
{
if (pnext (p))
{
bp = p->ptr;
amnt =
p->
hdr->
hole;
}
else
goto nnnl;
}
else
{
bp =
p->ptr +
p->hdr->ehole;
amnt =
SEGSIZ -
p->hdr->ehole;
if (!amnt)
goto pppl;
}
}
if (*bp == '\n')
{
++bp;
++byte;
++amnt;
goto eobl;
}
nnnl:
--byte; ++amnt;
}
if (square)
if (bc == '\t')
{
long tcol =
col + p->b->o.tab -
col % p->b->o.tab;
if (tcol > from && tcol <= to)
c1 = INVERSE;
else
c1 = 0;
}
else if (col >= from && col < to)
c1 = INVERSE;
else
c1 = 0;
else if (byte >= from && byte <