Category : Utilities for DOS and Windows Machines
Archive   : HISTORY.ZIP
Filename : HISTORY.C

 
Output of file : HISTORY.C contained in archive : HISTORY.ZIP
/* history -- command history mechanism */
/* copyright 1985-6 Michael M Rubenstein */

/* version 1.0 6 Dec 86 */

#include
#define FALSE 0
#define TRUE 1
#define NULL ((void *) 0)

struct regs { unsigned ax, bx, cx, dx, si, di, ds, es; };

/* use bdos functions directly to save memory */
#define conin() (bdos(8) & 0xff)
#define conrdy() (bdos(11) & 0xff)
#define conout(c) bdos(2, c)
#define strout(s) bdos(9, s)
#define argbuf ((char *) 0x81)

/* some interesting characters */
#define CTL 0x1f
#define NUL 0
#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 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 */
char line[255];

unsigned lineoff, lineseg; /* offset and seg of line */
char *cur; /* current position in line */
int len; /* max length of line */
unsigned startpos, endpos; /* screen positions */
int vpage, /* video page */
maxcols, /* cols on screen */
cursor, /* standard cursor */
icursor; /* insert cursor */

char *histbuf, *endhistbuf; /* history buffer */
unsigned lhistbuf; /* length of history buffer */

char *first, /* logical first hist line */
*next, /* logical next hist line */
*curhist; /* current hist line */

char *backhist(), *fwdhist(), *nxt(), *prv();

extern void *sbrk();

/* We don't need the standard Aztec initialization, so the main routine */
/* is named Croot to replace it, rather than main */
Croot()
{
/* get history buffer */
if ((lhistbuf = atoi(argbuf)) < 256)
lhistbuf = 256;
else
if (lhistbuf > 32767)
lhistbuf = 32767;
if ((histbuf = sbrk(lhistbuf)) == (char *) -1)
{
strout("history: insuff mem\n\r$");
return;
}
endhistbuf = histbuf + lhistbuf - 1;
first = next = histbuf + 1;
*first = *histbuf = '\0';

/* set up TSR */
setup();
}

/* get a line with editing & history */
getline()
{
unsigned i;
int c;
char *p;
struct regs r;
static unsigned oldseg = 0;
int usehist;

/* the first time we're called it's from COMMAND.COM. Save the segment */
/* so we can recognize calls from COMMAND.COM. Only those calls will use */
/* the history mechanism. Editing will apply to all. */
if (oldseg == 0)
oldseg = lineseg;
usehist = (lineseg == oldseg);

/* set up for input */
len = peekb(lineoff, lineseg);
memset(cur = line, 0, len);
insert = FALSE;
endpos = (startpos = getpos()) & 0xff00;
getvpage();
curhist = next;

/* main editing loop */
for (;;)
{
c = conin();
if (c == 0 && conrdy())
c = conin() + 256;
switch (c)
{
case CR: /* done with line */
setcursor(cursor);
for (p = line, i = 0; *p != '\0'; ++i, ++p)
pokeb(lineoff + 2 + i, lineseg, *p);
pokeb(lineoff + 2 + i, lineseg, CR);
pokeb(lineoff + 1, lineseg, i);
conout('\r');
setpos(endpos);
if (usehist && i != 0)
puthist();
return;

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 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;

case RIGHT: /* forward one character */
if (*cur != 0)
forward();
break;

case INS: /* insert char */
setcursor((insert = !insert) ? icursor : cursor);
break;

case CTLU:
case CTLX:
case ESC: /* delete line */
delln();
curhist = next;
break;

case CTLY:
case F8: /* delete to end of line */
while (*cur != 0)
delchr();
break;

case HOME: home();
break;

case F3:
case END: while (*cur != 0)
forward();
break;

case F1:
case UP: if (usehist && (p = backhist(curhist)) != NULL)
gethist(p);
break;

case DOWN: if (usehist && (p = fwdhist(curhist)))
gethist(p);
break;

case CTLL:
case F7: if (usehist)
search();
break;

case NUL: /* ignore nulls */
break;

case F6:
case CTLQ: c = conin();
if (c == 0 && conrdy())
{
conin();
break;
}
/* NOTE fall through */
default: if (c > 255)
continue;
if (cur - line == len - 1)
bell();
else
{
if (insert)
inschr();
*cur = c;
forward();
showln();
}
}
}
}

/* 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()
{
char *p;
unsigned pos;

pos = getpos();

for (p = cur; (*p = *(p + 1)) != '\0'; ++p)
pctl(*p);

conout(' ');
conout(' ');
setend();
setpos(pos);
}

/* insert a character in line */
inschr()
{
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()
{
home();
while (*cur != '\0')
{
if (*cur < ' ' || *cur == DEL)
conout(' ');
conout(' ');
++cur;
}
home();
endpos = (startpos = getpos()) & 0xff00;
memset(cur = line, 0, len);
}

/* move cursor to start of line */
home()
{
cur = line;
setpos(startpos);
}

/* show line from current position */
showln()
{
char *p;
unsigned pos;

if (*cur != 0)
{
pos = getpos();
p = cur;
while (*cur != '\0')
forward();
cur = p;
setpos(pos);
}
}

/* back up one character */
backup()
{
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()
{
pctl(*(cur++));
if (*cur == '\0')
setend();
}

/* set end screen position */
setend()
{
unsigned pos;

if (((pos = getpos()) & 0x00ff) == 0)
{
if (pos == endpos)
startpos -= 0x0100;
endpos = pos;
}
}

/* go to previous history line */
char *backhist(p)
char *p;
{
if (p == first)
{
bell();
return NULL;
}
p = prv(p);
while (*(p = prv(p)) != '\0')
;
return nxt(p);
}

/* go to next history line */
char *fwdhist(p)
char *p;
{
if (p == next)
{
bell();
return NULL;
}
while (*(p = nxt(p)) != '\0')
;
return nxt(p);
}

/* go to previous history character */
char *prv(p)
char *p;
{
return (p == histbuf) ? endhistbuf : --p;
}

/* go to next history character */
char *nxt(p)
char *p;
{
return (p == endhistbuf) ? histbuf : ++p;
}

/* make history line current and copy to line buffer */
gethist(p)
char *p;
{
int i;

curhist = p;
delln();
cur = line;
for (i = 0; *p != '\0' && i < len - 1; ++i)
{
*cur = *p;
forward();
p = nxt(p);
}
*cur = '\0';
home();
}

/* save a history line */
puthist()
{
int c;
char *p, *q;
unsigned i;

q = line;
do
{
c = *(next) = *(q++);
next = nxt(next);
if (next == first)
first = fwdhist(nxt(first));
} while (c != '\0');
*next = '\0';
}

/* search for history line */
search()
{
char *p, *q, *r;

for (p = curhist; (p = backhist(p)) != NULL;)
{
for (q = p, r = line;
q != '\0' && r < cur && tolower(*q) == tolower(*r);
q = nxt(q), ++r)
;
if (r == cur)
{
gethist(p);
while (cur < r)
forward();
return;
}
}
}

/* put character to console, converting controls to printables */
pctl(c)
int c;
{
if (c == DEL)
{
conout('^');
conout('?');
return;
}

if (c < ' ')
{
conout('^');
conout (c + '@');
return;
}

conout(c);
}

/* audible alarm */
bell()
{
conout(BEL);
}

/* get various screen & cursor characteristics */
getvpage()
{
struct regs r;

r.ax = 0x0f00;
sysint(0x10, &r, &r);
vpage = r.bx;
maxcols = r.ax >> 8;

r.ax = 0x0300;
sysint(0x10, &r, &r);
cursor = r.cx;
icursor = (((cursor & 0xff) - 4) << 8) + (cursor & 0xff);
}

/* get current screen position */
getpos()
{
struct regs r;

r.ax = 0x0300;
r.bx = vpage;
sysint(0x10, &r, &r);
return r.dx;
}

/* set screen position */
setpos(p)
unsigned p;
{
struct regs r;

r.ax = 0x0200;
r.bx = vpage;
r.dx = p;
sysint(0x10, &r, &r);
}

/* set cursor type */
setcursor(c)
unsigned c;
{
struct regs r;

r.ax = 0x0100;
r.cx = c;
sysint(0x10, &r, &r);
}


  3 Responses to “Category : Utilities for DOS and Windows Machines
Archive   : HISTORY.ZIP
Filename : HISTORY.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/