home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 11 Util
/
11-Util.zip
/
OS2HIST.ZIP
/
HISTEDIT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-02-19
|
15KB
|
574 lines
/* +--------------------------------------------------------------------+
| HISTORY - Command line editor for OS/2 |
| Main module File: EDIT.C |
+--------------------------------------------------------------------+ */
#include "keydefs.h"
/* +--------------------------------------------------------------------+
| Constants |
+--------------------------------------------------------------------+ */
#define TRUE 1
#define FALSE 0
#define NULL 0L
#define BACKSPACE 8
#define CTRLU 21
#define CTRLB 2
#define CTRLF 6
#define MAXHIST 32
#define MAXMACRO 32
#define MACROMEM 1024
#define CMDLENGTH 256
#define BELLKEY 7
#define TABKEY 9
#define CTRLA 1
#define CTRLD 4
#define CTRLE 5
#define CTRLK 11
#define CURSBOTTOM 0x0C
#define CURSTOP1 0x0B
#define CURSTOP2 3
#define RAWMODE 4
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
/* +--------------------------------------------------------------------+
| Types |
+--------------------------------------------------------------------+ */
typedef struct CursorType {
unsigned int startline;
unsigned int endline;
unsigned int width;
unsigned int attribute;
} CURSORTYPE;
typedef struct KeyChar {
unsigned char asciicode;
unsigned char scancode;
unsigned char nlsstatus;
unsigned char nlsshifts;
unsigned int shiftstate;
unsigned long timestamp;
} KEYCHAR;
typedef struct BufLen {
unsigned int inlength;
unsigned int outlength;
} BUFLEN;
typedef struct HistRec {
char buffer[CMDLENGTH+1];
int buflen;
} HISTREC;
typedef struct HistMacro {
char *name;
char *expansion;
unsigned int flags;
} HISTMACRO;
typedef struct VideoMode {
unsigned int length;
unsigned char type;
unsigned char color;
unsigned int scrwidth;
unsigned int scrheight;
unsigned int horizres;
unsigned int vertres;
} VIDEOMODE;
typedef struct KbdStatus {
unsigned int length;
unsigned int mask;
unsigned int turnaroundchar;
unsigned int interimflags;
unsigned int shiftstate;
} KBDSTATUS;
/* +--------------------------------------------------------------------+
| Externals |
+--------------------------------------------------------------------+ */
extern far pascal KBDCHARIN(struct KeyChar far *,int,int);
extern far pascal VIOGETCURTYPE(CURSORTYPE far *, int);
extern far pascal VIOSETCURTYPE(CURSORTYPE far *, int);
extern far pascal VIOWRTTTY(char far *,int,int);
extern far pascal VIOSETCURPOS(int,int,int);
extern far pascal VIOGETCURPOS(int far *,int far *,int);
extern far pascal DOSBEEP(int, int);
extern far pascal VIOGETMODE(VIDEOMODE far *,int);
extern far pascal KBDGETSTATUS(KBDSTATUS far *, int);
extern far pascal DOSSETSIGHANDLER(long,long far *,int far *,int,int);
/* +--------------------------------------------------------------------+
| Globals |
+--------------------------------------------------------------------+ */
HISTMACRO macros[MAXMACRO] = {0}; /* history macros */
int maxmacro = 0; /* current macro # */
char macromem[MACROMEM] = {0}; /* memory for macros */
char *freemem = macromem; /* free memory pointer */
HISTREC history[MAXHIST] = {0}; /* history records */
char cmdline[CMDLENGTH+1]; /* input command line */
int curhist = 0; /* current position */
int redisplay = FALSE; /* if true, redisplay text */
int dirty = FALSE; /* if true, cmdline is dirty */
int cursx,cursy; /* current position */
int insmode = FALSE; /* TRUE if in insert mode */
CURSORTYPE curstype; /* cursor data */
VIDEOMODE videomode; /* current video mode */
KBDSTATUS kbdstatus; /* keyboard status */
int twolines = 0; /* true if two lines */
int cursor; /* cursor for edit line */
int maxlen; /* max length of edit line */
int curlen; /* cur length of edit line */
/* +--------------------------------------------------------------------+
| strlen(x) |
| returns length of string |
+--------------------------------------------------------------------+ */
static int strlen(x)
char *x;
{
int len = 0;
while (*x++) len++;
return len;
}
/* +--------------------------------------------------------------------+
| allocmem(nbytes) |
| allocates memory or returns NULL if no memory available |
+--------------------------------------------------------------------+ */
static char *allocmem(nbytes)
int nbytes;
{
char *x;
if ((freemem+nbytes) >= (¯omem[MACROMEM-1])) return NULL;
memset(freemem,0,nbytes);
x = freemem;
freemem += nbytes;
return x;
}
/* +--------------------------------------------------------------------+
| addmacro(name,expansion) -> 0 (success) or 1 (fail) |
| adds macro to list |
+--------------------------------------------------------------------+ */
int far pascal addmacro(name,expansion)
char *name;
char *expansion;
{
char *lname;
char *lexpand;
int namelen;
int explen;
if (maxmacro >= MAXMACRO) return 1;
namelen = strlen(name)+1;
explen = strlen(expansion)+1;
lname = allocmem(namelen);
lexpand = allocmem(explen);
if (!lname || !lexpand) return 1;
memcpy(lname,name,namelen,0);
memcpy(lexpand,expansion,explen,0);
macros[maxmacro].name = lname;
macros[maxmacro].expansion = lexpand;
maxmacro++;
return 0;
}
/* +--------------------------------------------------------------------+
| memset(buf,c,cnt) |
| clears buffer |
+--------------------------------------------------------------------+ */
static memset(buf,c,cnt)
char *buf;
char c;
int cnt;
{
register int i;
register char *bp;
i = cnt;
bp = buf;
while (i) {*bp++ = c; i--;}
}
/* +--------------------------------------------------------------------+
| memcpy(dest,src,cnt,dir) |
| Copies data from src to dest |
+--------------------------------------------------------------------+ */
static memcpy(dest,src,cnt,dir)
char *dest;
char *src;
int cnt;
int dir;
{
register char *in,*out;
register int i;
i = cnt;
if (dir < 0) {
in = src + cnt - 1;
out = dest + cnt - 1;
while (i) {*out-- = *in--; i--;}
}
else {
in = src;
out = dest;
while (i) {*out++ = *in++; i--;}
}
}
/* +--------------------------------------------------------------------+
| showbuf(buf,buflength,cursor) |
| Writes buffer out, expanding tabs and other special characters |
+--------------------------------------------------------------------+ */
showbuf(buf,buflength,cursor)
char *buf;
int buflength;
int cursor;
{
int xp,yp;
int newxp,newyp;
int i;
int oldatt;
oldatt = curstype.attribute;
curstype.attribute = -1;
VIOSETCURTYPE((CURSORTYPE far *) &curstype,0);
if (twolines && (videomode.scrheight-1 != cursy)) {
VIOSETCURPOS(cursy+1,0,0);
VIOWRTTTY("\033[K",3,0);
}
VIOSETCURPOS(cursy,cursx,0);
VIOWRTTTY(buf,buflength,0);
VIOWRTTTY((char far *) "\033[K",3,0); /* clear to EOL */
curspos(buf,buflength,curlen,cursor,&xp,&yp);
VIOGETCURPOS(&newyp,&newxp,0); /* get new cursor pos */
curstype.attribute = oldatt;
VIOSETCURTYPE((CURSORTYPE far *) &curstype,0);
VIOSETCURPOS(yp,xp,0);
}
/* +--------------------------------------------------------------------+
| showcurs(buf,buflength,cursor,changeflg) |
| shows cursor at correct posn on screen |
+--------------------------------------------------------------------+ */
showcurs(buf,buflength,cursor)
char *buf;
int buflength;
int cursor;
{
int xp,yp;
curspos(buf,buflength,curlen,cursor,&xp,&yp);
VIOSETCURPOS(yp,xp,0);
}
/* +--------------------------------------------------------------------+
| curspos(buf,buflen,curlen,cursor,&xp,&yp) |
| returns the cursor's position if put on the character specified |
+--------------------------------------------------------------------+ */
curspos(buf,buflen,curlen,cursor,xcursp,ycursp)
char *buf;
int buflen;
int curlen;
int cursor;
int *xcursp,*ycursp;
{
char *cp;
int outxp,outyp;
int xp,yp;
int xtra = 0;
xp = cursx;
yp = cursy;
cp = buf;
outxp = xp;
outyp = yp;
while (curlen) {
switch (*cp) {
case BELLKEY: break;
case TABKEY: if ((xp % 8) == 0) xp++;
while (xp % 8) {
xp++;
}
break;
default: xp++;
}
if (xp >= videomode.scrwidth) {
xp = 0; yp++; xtra++;
if (cursor) outyp++;
if (yp >= videomode.scrheight) {
yp = videomode.scrheight-1;
cursy--;
outyp--;
}
}
cp++;
if ((cp - buf) > buflen) break;
curlen--;
if (cursor) {
cursor--;
outxp = xp;
}
}
*xcursp = outxp;
*ycursp = outyp;
if (xtra) twolines = TRUE;
}
/* +--------------------------------------------------------------------+
| findprev(cur) |
| Locates previous good entry in the history list. |
+--------------------------------------------------------------------+ */
static int findprev(cur,orig)
int cur;
int orig;
{
int pos;
pos = ((cur + MAXHIST) - 1) % MAXHIST;
while (pos != cur) {
if ((pos == orig) || history[pos].buflen) return pos;
pos = ((pos + MAXHIST) - 1) % MAXHIST;
}
return -1;
}
/* +--------------------------------------------------------------------+
| findnext(cur) |
| Locates previous good entry in the history list. |
+--------------------------------------------------------------------+ */
static int findnext(cur,orig)
int cur;
int orig;
{
int pos;
pos = (cur + 1) % MAXHIST;
while (pos != cur) {
if ((pos == orig) || history[pos].buflen) return pos;
pos = (pos + 1) % MAXHIST;
}
return -1;
}
/* +--------------------------------------------------------------------+
| setedit(hist) |
| Sets up edit line so we are editing history # "hist" |
+--------------------------------------------------------------------+ */
setedit(hist)
int hist;
{
curlen = history[hist].buflen;
curlen = min(curlen,maxlen);
curlen = min(CMDLENGTH,curlen);
memcpy(cmdline,history[hist].buffer,curlen,1);
redisplay = TRUE;
cursor = curlen;
}
/* +--------------------------------------------------------------------+
| editstringin(buf,buflen,iowait,kbhandle) |
| will be the replacement for kbdstringin someday |
+--------------------------------------------------------------------+ */
int pascal editstringin(resbuf,buflen,iowait,kbdhandle)
char far *resbuf;
BUFLEN far *buflen;
unsigned int iowait;
unsigned int kbdhandle;
{
int kchr; /* char read from keyboard */
int res;
int i;
KEYCHAR kc;
char *buf;
int editline; /* history # we're editing now */
/* if we're in cooked mode or we don't want to wait for characters,
let the base keyboard subsystem do the work for us */
KBDGETSTATUS( (KBDSTATUS far *) &kbdstatus, 0);
kbdstatus.length = sizeof(KBDSTATUS);
kbdstatus.mask = 0;
if (iowait || (kbdstatus.mask & RAWMODE)) return -1;
if (buflen->inlength >= CMDLENGTH) return -1; /* request too big */
curlen = 0;
cursor = 0;
redisplay = FALSE;
memset(cmdline,0,CMDLENGTH);
maxlen = min(CMDLENGTH,buflen->inlength);
twolines = FALSE;
VIOGETCURPOS( (int far *) &cursy, (int far *) &cursx, 0);
VIOGETCURTYPE( (CURSORTYPE far *) &curstype, 0);
curstype.endline = CURSBOTTOM;
curstype.startline = CURSTOP1;
videomode.length = sizeof(VIDEOMODE);
VIOGETMODE((VIDEOMODE far *) &videomode,0);
insmode = FALSE;
editline = curhist;
history[editline].buflen = 0;
memset(history[editline].buffer,0,CMDLENGTH); /* clear out space */
VIOSETCURTYPE(&curstype,0); /* fix cursor type */
for (;;) {
res = KBDCHARIN(&kc,iowait,kbdhandle);
if (res) {
return res;
}
if (kc.asciicode) kchr = kc.asciicode;
else kchr = 0x100 + kc.scancode;
switch (kchr) {
case BACKSPACE:
if (cursor == curlen) {
if (curlen > 0) {
curlen--;
cursor--;
}
}
else {
if (cursor > 0) {
memcpy(&cmdline[cursor-1],
&cmdline[cursor],
curlen-cursor,1);
cursor--;
curlen--;
}
}
redisplay = TRUE; /* more than cursor */
dirty = TRUE;
break;
case CTRLA:
case HOMEKEY:
cursor = 0;
break;
case CTRLE:
case ENDKEY:
cursor = curlen;
break;
case CTRLK:
curlen = cursor;
dirty = TRUE;
redisplay = TRUE;
break;
case ENTERKEY:
memcpy(resbuf,cmdline,curlen,1);
*(resbuf+curlen) = '\r';
buflen->outlength = curlen;
if (dirty && curlen) {
memcpy(history[curhist].buffer,cmdline,curlen,1);
history[curhist].buflen = curlen;
curhist = curhist + 1;
if (curhist >= MAXHIST) curhist = 0;
}
curstype.startline = CURSTOP1;
VIOSETCURTYPE(&curstype,0);
showbuf(cmdline,curlen,curlen);
VIOWRTTTY((char far *) "\r",1,0);
return 0;
case UPKEY:
case DOWNKEY:
if (kchr == UPKEY) res = findprev(editline,curhist);
else res = findnext(editline,curhist);
if (res == -1) break; /* none there */
setedit(res);
editline = res;
dirty = FALSE;
break;
case LEFTKEY:
case CTRLB:
if (cursor > 0) cursor--;
break;
case RIGHTKEY:
case CTRLF:
if (cursor < curlen) cursor++;
break;
case CTRLU:
case ESCKEY:
curlen = 0;
cursor = 0;
VIOSETCURPOS(cursy,cursx,0);
VIOWRTTTY((char far *) "\033[K",3,0);
if (twolines && (videomode.scrheight-1 != cursy)) {
VIOSETCURPOS(cursy+1,0,0);
VIOWRTTTY((char far *) "\033[K",5,0);
}
VIOSETCURPOS(cursy,cursx,0);
break;
case INSKEY:
insmode = !insmode;
curstype.startline = insmode ? CURSTOP2 : CURSTOP1;
VIOSETCURTYPE(&curstype,0);
break;
case CTRLD:
case DELKEY:
if (cursor == curlen) break;
if (curlen == 0) break;
memcpy(&cmdline[cursor],&cmdline[cursor+1],
curlen-cursor,1);
curlen--;
redisplay = TRUE;
dirty = TRUE;
break;
default:
if (kchr & 0x100) break;
if ((kchr < 32) &&
(kchr != 26) && (kchr != TABKEY)) break;
if ((insmode || (cursor == curlen))
&& (curlen >= maxlen)) {
DOSBEEP(1000,100);
break;
}
dirty = TRUE;
if (!insmode) {
cmdline[cursor] = kc.asciicode;
cursor++;
curlen = max(cursor,curlen);
}
else {
memcpy(&cmdline[cursor+1],
&cmdline[cursor],curlen-cursor,
-1);
curlen++;
cmdline[cursor] = kc.asciicode;
cursor++;
}
redisplay = TRUE;
break;
}
if (redisplay) showbuf(cmdline,curlen,cursor);
else showcurs(cmdline,curlen,cursor);
redisplay = FALSE;
}
}