home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
msdos
/
sysutl
/
history.arc
/
EDIT.C
next >
Wrap
Text File
|
1988-03-21
|
16KB
|
688 lines
/* history -- command history mechanism, Copyright 1985-6 Michael M Rubenstein */
/* Portions Copyright 1987, 1988, Russell Nelson */
/* History:19,1 */
/* 01-29-88 19:59:01 add C-A and C-E for home and end respectively. */
/* 10-18-87 12:12:06 give an error if they compile with other than TINY. */
/* 10-18-87 11:51:06 use msdos(8) to read keystrokes. */
/* 07-05-87 13:57:09 lowercase filenames properly this time. */
/* 07-04-87 23:49:11 don't do an automatic search. */
/* 07-03-87 22:07:56 Use '\0' for the null character. */
/* 07-03-87 21:22:23 expand_filename didn't put a trailing \ after directories. */
/* 07-03-87 21:03:57 filename expansion didn't check 'len'. */
/* 07-03-87 19:42:20 in filename completion, files with wildcards don't get wildcards added */
/* 07-03-87 19:36:31 move argc, argv code out of history_init() */
/* 07-03-87 15:49:27 change copyright message */
#include <ctype.h>
#include <dos.h>
#include <dir.h>
#define FALSE 0
#define TRUE 1
#define NULL ((void *) 0)
/* some interesting characters */
#define CTL 0x1f
#define NUL 0
#define CTLA (CTL & 'A')
#define CTLB (CTL & 'B')
#define CTLD (CTL & 'D')
#define CTLE (CTL & 'E')
#define CTLF (CTL & 'F')
#define BEL (CTL & 'G')
#define BS (CTL & 'H')
#define LF (CTL & 'J')
#define CR (CTL & 'M')
#define CTLL (CTL & 'L')
#define CTLQ (CTL & 'Q')
#define CTLT (CTL & 'T')
#define CTLU (CTL & 'U')
#define CTLW (CTL & 'W')
#define CTLX (CTL & 'X')
#define CTLY (CTL & 'Y')
#define ESC (CTL & '[')
#define STATUS (CTL & ']')
#define DEL 0x7f
/* extended characters */
#define F1 256 + 59
#define F2 256 + 60
#define F3 256 + 61
#define F4 256 + 62
#define F5 256 + 63
#define F6 256 + 64
#define F7 256 + 65
#define F8 256 + 66
#define F9 256 + 67
#define F10 256 + 68
#define HOME 256 + 71
#define UP 256 + 72
#define LEFT 256 + 75
#define RIGHT 256 + 77
#define END 256 + 79
#define DOWN 256 + 80
#define INS 256 + 82
#define KDEL 256 + 83
#define CTLLEFT 256 + 115
#define CTLRIGHT 256 + 116
int insert = FALSE; /* insert mode switch */
unsigned char line[256];
unsigned lineoff, lineseg; /* offset and seg of line */
unsigned char *cur; /* current position in line */
int len; /* max length of line */
unsigned startpos, endpos, prevpos; /* screen positions */
int vpage, /* video page */
maxcols, /* cols on screen */
cursor, /* standard cursor */
icursor; /* insert cursor */
extern void setup();
#ifndef __TINY__
#error Must be compiled with -mt
#endif
void exit(int c)
{ _exit(c);}
void _setenvp(void){} /* dummy out _setenvp */
void main(int argc, char *argv[])
{
unsigned len, j;
--argc;
for (j = 0; j <= 1; j++) {
if (argc) {
argc--;
if ((len = atoi(*argv++)) < 256) len = 256;
else if (len > 32767) len = 32767;
}
else len = 256;
init_history(j, len);
}
setup();
}
/* get a line with editing & history */
getline()
{
int c;
unsigned char *p;
static unsigned oldseg = 0;
/* the first time we're called it's from COMMAND.COM. Save the segment */
/* so we can recognize calls from COMMAND.COM. */
if (oldseg == 0) {
oldseg = lineseg;
}
select_history( (lineseg == oldseg) ? 0 : 1);
/* set up for input */
len = peekb(lineseg, lineoff) & 0xff;
memset(cur = line, 0, len);
insert = FALSE;
init_pos();
getvpage();
reset_history();
/* main editing loop */
for (;;)
{
c = getcon();
switch (c)
{
case CR: /* done with line */
setcursor(cursor);
putch('\r');
setpos(endpos);
if (line[0] != '\0')
puthist();
storeline();
return;
case STATUS: /* type out some info */
cur = line;
init_pos();
showln();
break;
case LF: /* expand filenames */
findfiles();
break;
case CTLB:
case LEFT: /* back one character */
if (cur != line)
backup();
break;
case CTLLEFT: /* back one word */
backwd();
break;
case CTLRIGHT:
/* forward one word */
while (isalnum(*cur))
forward();
while (*cur != 0 && !isalnum(*cur))
forward();
break;
case DEL:
case BS: /* backspace and delete */
if (cur == line)
break;
backup(); /* NOTE fall through */
case CTLD:
case KDEL: /* delete current char */
if (*cur != '\0')
delchr();
break;
case CTLW:
case F9: /* delete word left */
backwd();
/* NOTE fall through */
case CTLT:
case F10: /* delete word right */
while (isalnum(*cur))
delchr();
while (*cur != 0 && !isalnum(*cur))
delchr();
break;
/* get pattern if at beginning else forward */
case F1: if (cur == line && line[0] == '\0')
{
getpat();
break;
}
case CTLF:
case RIGHT: /* forward one character */
if (*cur != 0)
forward();
break;
case INS: /* insert char */
insert = !insert;
setcursor(insert? icursor : cursor);
break;
case CTLU:
case CTLX:
case ESC: /* delete line */
delln();
reset_history();
break;
case CTLY:
case F8: /* delete to end of line */
while (*cur != 0)
delchr();
break;
case CTLA:
case HOME: home();
break;
case F3: getpat();
case CTLE:
case END: while (*cur != 0)
forward();
break;
case UP: prevhist();
break;
case DOWN: nexthist();
break;
case CTLL:
case F7: search();
break;
case NUL: /* ignore nulls */
break;
case F2: getpat();
c = getcon();
if (*cur == '\0')
break;
for (p = cur + 1; *p != '\0' && *p != c; ++p)
;
if (*p != '\0')
while (cur < p)
forward();
break;
case F4: getpat();
c = getcon();
if (*cur == '\0')
break;
for (p = cur + 1; *p != '\0'&& *p != c; ++p)
;
if (*p != '\0')
while (*cur != c)
delchr();
break;
case F5: storeline();
break;
case F6:
case CTLQ: c = getcon();
if (c >= 256) break;
/* NOTE fall through */
default: if (c > 255)
continue;
if (cur - line == len - 1)
bell();
else
{
if (insert)
inschr();
*cur = c;
forward();
showln();
#ifdef SEARCH
search();
#endif
}
}
}
}
/* get extended character from console */
getcon()
{
int c;
_AH = 8;
geninterrupt(0x21);
c = _AL;
if (c == '\0' && kbhit()) {
_AH = 8;
geninterrupt(0x21);
c = _AL;
c += 256;
}
return c;
}
/* get pattern from line buffer */
getpat()
{
int i, n;
if (cur == line && line[0] == '\0')
{
for (i = 0, n = peekb(lineseg, lineoff + 1) & 0xff; i < n; ++i)
line[i] = peekb(lineseg, lineoff + 2 + i);
line[i] = '\0';
home();
showln();
}
}
/* store the line */
storeline()
{
register unsigned char
*p;
register int i;
for (i = 0, p = line; *p != '\0'; ++i, ++p)
pokeb(lineseg, lineoff + 2 + i, *p);
pokeb(lineseg, lineoff + 2 + i, CR);
pokeb(lineseg, lineoff + 1, i);
}
/* back one word */
backwd()
{
if (cur == line)
return;
backup();
while (cur != line && !isalnum(*cur))
backup();
while (cur != line && isalnum(*(cur - 1)))
backup();
}
/* delete character */
delchr()
{
unsigned char *p;
unsigned pos;
pos = getpos();
for (p = cur; (*p = *(p + 1)) != '\0'; ++p)
pctl(*p);
pctl(' ');
pctl(' ');
setpos(pos);
}
/* insert a character in line */
inschr(void)
{
unsigned char *p;
for (p = cur; *p != '\0'; ++p)
;
if (p > line + len - 2)
p = line + len - 2;
*(p + 1) = '\0';
while (p > cur)
{
*p = *(p - 1);
--p;
}
*cur = ' ';
}
/* delete entire line */
delln(void)
{
home();
while (*cur != '\0')
{
if (*cur < ' ' || *cur == DEL)
putch(' ');
putch(' ');
++cur;
}
home();
init_pos();
memset(cur = line, 0, len);
}
/* move cursor to start of line */
home(void)
{
cur = line;
setpos(startpos);
}
/* show line from current position */
showln(void)
{
unsigned char *p;
if (*cur != 0)
{
p = cur;
while (*cur != '\0')
forward();
home();
while (cur < p)
forward();
}
}
/* back up one character */
backup(void)
{
unsigned pos;
int row, col;
--cur;
pos = getpos();
row = (pos >> 8) & 0xff;
col = pos & 0xff;
col -= (*cur < ' ' || *cur == DEL) ? 2 : 1;
if (col < 0)
{
--row;
col = 79;
}
setpos((row << 8) + col);
}
/* forward one character */
forward(void)
{
pctl(*(cur++));
}
/* insert a printable character */
insprintable(char c)
{
if (cur - line == len - 1) return;
inschr();
*cur = c;
forward();
}
findfiles(void)
{
struct ffblk ourFF;
char far *oldDta;
char *oldCur, *scur;
char findname[64];
char *fn1, *fn2;
int foundChars;
int j;
if (cur == line)
return;
/* get the word to the left of the cursor into findname */
oldCur = cur;
for (;;) {
if (cur == line) break;
backup();
if (isspace(*cur)) {
forward();
break;
}
}
scur = cur;
fn1 = fn2 = findname;
foundChars = 0;
while (scur != oldCur) {
switch(*fn1++ = *scur++) {
case '.': /* remember if it has extension */
foundChars |= 1;
break;
case '*': /* remember ambiguous names */
case '?':
foundChars |= 2;
break;
case '/': /* remember where the real fn starts */
case '\\': /* also don't remember dots in paths */
case ':':
fn2 = fn1;
foundChars &= ~1;
break;
}
}
*fn1 = 0; /* null terminate it */
/* if no wildcards, tack on a star, or a star dot star */
if (foundChars == 1) strcat(findname, "*");
else if (foundChars == 0) strcat(findname, "*.*");
oldDta = getdta();
if (foundChars & 2) {
j = oldCur - cur; /* remove the word. */
while (j--) delchr();
if (!findfirst(findname, &ourFF, FA_DIREC)) {
do {
copyFn(findname, fn2, &ourFF.ff_name);
insprintable(' ');
} while (!findnext(&ourFF));
}
} else {
if (expandFilename(findname, fn2)) { /* only if a filename was found. */
j = oldCur - cur; /* remove the word. */
while (j--) delchr();
copyFn(findname, fn2, fn2); /* our filename starts here */
}
showln();
setdta(oldDta);
}
}
copyFn(char *findname, char *fn2, char *fn)
{
char *fn1;
while (findname != fn2) insprintable(*findname++);
while (*fn != '\0') insprintable(tolower(*fn++));
}
int expandFilename(char *findname, char *fn2)
{
struct ffblk ourFF;
char *fn0, *fn1;
if (findfirst(findname, &ourFF, FA_DIREC)) { /* no files match */
bell();
return (FALSE);
} else { /* at least one file */
strcpy(fn2, &ourFF.ff_name);
if (ourFF.ff_attrib & FA_DIREC) strcat(fn2, "\\");
if (findnext(&ourFF)) return (TRUE); /* one file matches */
else {
do {
fn0 = fn2;
fn1 = ourFF.ff_name;
while (*fn0++ != '\0') {
if (fn0[-1] != *fn1++) break;
}
fn0[-1] = 0;
} while (!findnext(&ourFF));
bell();
return (TRUE);
}
}
}
/* put character to console, converting controls to printables */
pctl(int c)
{
if (c == DEL)
{
pc('^');
pc('?');
return;
}
if (c < ' ')
{
pc('^');
pc(c + '@');
return;
}
pc(c);
}
/* initialize positions */
init_pos(void)
{
prevpos = endpos = (startpos = getpos()) & 0xff00;
}
/* put character to console */
pc(int c)
{
unsigned pos;
putch(c);
pos = getpos();
if (pos == endpos && prevpos > endpos)
startpos -= 0x0100;
else
if ((pos & 0x00ff) == 0 & pos > endpos)
endpos = pos;
prevpos = pos;
}
/* audible alarm */
bell(void)
{
putch(BEL);
}
/* put a character to the screen */
putch(char ch)
{
_DL = ch;
_AH = 2;
geninterrupt(0x21);
}
/* get various screen & cursor characteristics */
getvpage(void)
{
struct REGS r;
r.x.ax = 0x0f00;
int86(0x10, &r, &r);
vpage = r.x.bx;
maxcols = r.x.ax >> 8;
r.x.ax = 0x0300;
int86(0x10, &r, &r);
cursor = r.x.cx;
icursor = (((cursor & 0xff) - 4) << 8) + (cursor & 0xff);
}
/* get current screen position */
getpos(void)
{
struct REGS r;
r.x.ax = 0x0300;
r.x.bx = vpage;
int86(0x10, &r, &r);
return r.x.dx;
}
/* set screen position */
setpos(p)
unsigned p;
{
struct REGS r;
r.x.ax = 0x0200;
r.x.bx = vpage;
r.x.dx = p;
int86(0x10, &r, &r);
prevpos = p;
}
/* set cursor type */
setcursor(unsigned c)
{
struct REGS r;
r.x.ax = 0x0100;
r.x.cx = c;
int86(0x10, &r, &r);
}