Unix PC keyboard driver with meta key and other features (source)

Ford Prefect ford at elgar.UUCP
Sun May 29 14:30:17 AEST 1988


Well, I finally came to the conclusion that it is legal to post this...

Here is source code to the CAPCTRL3.5 driver distributed by "The Store!".
It is derived from the binary as distributed (free, without any copyright)
by AT&T.  I have added a few features that I had been desparately needing.

For anyone who doesn't know, CAPCTRL is a package which exchanges the
functions of the "Caps Lock" key and the right "Ctrl" key on the Unix PC
keyboard.  It is a loadable device driver which is a complete replacement
for the normal keyboard/mouse driver.  This posting is an equivalent driver
in source code form.

Once I had a source code equivalent of CAPCTRL, I proceded to make a few
essential improvements.  I have not made any major changes in the program
logic, so the result is still more-or-less what originally came from AT&T.

The one thing that deserves to be fixed that I haven't fixed is the codes
generated by certain keys on the keyboard.  These can be fixed by using the
"keyfix" program, so I didn't fix them in the driver.  I'm sure that not
everybody defines exactly the same keymap with keyfix anyway.  The
particular keys I am referring to are such codes as control-^, control-2,
control-space, etc.  They still do not work the right way in this new
driver, but keyfix can still fix them.

These are the changes I have made to the driver:

	The "Ctrl" key to the left of the spacebar is now a "meta" key.  A
	meta key causes a bit (bit 7, 0x80) to be set in codes generated
	while the meta key is held down.  So, pressing the 'a' key normally
	generates 0x61, but if the meta key is held down, the result is
	0xe1 ("meta-a").  This is mostly just useful in Emacs, which has
	commands bound to certain meta- key combinations.  It also allows
	generating all 256 character values from the keyboard.  Note that
	this is a backward-incompatible change if you are used to using
	that control key.  Use the one to the left of the A key.

	The screen-saver blanking is now canceled by ANY key, the most
	useful example being the shift key.  Using the shift key is better,
	because it's "always" safe to hit, as opposed to the space bar or
	some other printing key which is what the old driver forces you to
	use.  This is another backward-incompatible change; you must get
	used to hitting shift or control rather than the space bar, which
	is probably what most people use.  Hitting the space bar still
	works, but the space character is entered into the system (usually
	harmless, but annoying at the least), so shift is recommended.  I
	have seen at least 8 different screen-savers on various terminals
	and computers, and they all work the way my changed driver does
	except for ADDS terminals, which are well known for being
	braindamaged.

	Key repeat now begins slowly and then speeds up to 15 characters
	per second if the key is held down.

	The kernel debugger activation code is now 0xff instead of
	control-B.  This is much less dangerous.  The debugger will only be
	activated if the 0xff is actually in the keymap, not if meta-rubout
	is typed.  This allows meta-rubout to be used in Emacs, for
	example.  0xff is generated by "Break" in the default keymap; I
	recommend mapping it to control-Esc.

	The mouse pointer is now kept within the screen bounds.  The normal
	driver allows the pointer to be off the bottom of the screen,
	requiring extra mouse motion to get it back to the "real" screen
	area.



****************		WARNING!		****************

Installing this driver will REPLACE the CAPCTRL driver if you have it
installed on your system.  If you think you might not like any of the above
improvements, MAKE A COPY of /etc/lddrv/kbd.o so that you can put it back
if you like it better.  My installation scripts assume that any driver
called 'kbd' is an older version of my driver, and overwrite it with the
version being installed.

****************		********		****************



	The reason I took the trouble to reverse engineer this driver was
that I didn't like the way it had so many hard-coded characteristics, just
like the one it replaced.  The ironic thing is that this version I am
posting is just as hard-coded as the others, just with different hard-coded
parameters.  Someday I will modify it to be completely configurable, but in
the mean time, here is source code to basically the same program that
everybody already has.

"nkbd.shar" is after my signature, and this time I checked... it includes
"nkbd.c"!  :-)

				Enjoy,

					-=] Ford [=-

"Once there were parking lots,		(In Real Life:  Mike Ditto)
now it's a peaceful oasis.		ford%kenobi at crash.CTS.COM
This was a Pizza Hut,			...!sdcsvax!crash!kenobi!ford
now it's all covered with daisies." -- Talking Heads


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	nkbd.c
#	INSTALL
#	Size
#	Install
#	Name
#	Remove
#	Files
# This archive created: Sat May 28 17:58:54 1988
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(494 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
D=-O
CFLAGS= $D
DRIVER=nkbd
SHARFILES = Makefile nkbd.c INSTALL Size Install Name Remove Files

install : nkbd.o
	./INSTALL

all : $(DRIVER)+IN

installable : $(DRIVER)+IN

$(DRIVER)+IN : $(DRIVER).o
	cpio -oBc < Files > $(DRIVER)+IN

floppy : $(DRIVER)+IN
	echo "Insert a formatted floppy disk and press return"; read foo
	dd if=$(DRIVER)+IN of=/dev/rfp021 bs=16384

$(DRIVER).shar : $(SHARFILES)
	shar -cv $(SHARFILES) > $(DRIVER).shar

clean :
	rm $(DRIVER).o $(DRIVER)+IN

clobber : clean

SHAR_EOF
if test 494 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 494 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'nkbd.c'" '(11209 characters)'
if test -f 'nkbd.c'
then
	echo shar: will not over-write existing file "'nkbd.c'"
else
cat << \SHAR_EOF > 'nkbd.c'
/************************************************************
 *
 * This file is my interpretation of the "CAPCTRL" keyboard
 * driver, which is distributed free by AT&T via "The
 * STORE!".  The original was probably written by AT&T and/or
 * Convergent Technologies, but, since it is distributed
 * without charge and contains no visible copyright notice, I
 * consider both the original driver and my interpretation in
 * source code form to be in the public domain, and I do not
 * claim any rights to this software.  I do not know what
 * AT&T and/or Convergent Technologies say about this, and I
 * do not claim to be describing their official policy.
 *
 *				-=] Ford [=-
 *				(A.K.A. Michael Ditto)
 *				Omnicron Data Systems
 *				P.O. Box 1721
 *				Bonita, CA  92002
 *
 *				ford at kenobi.UUCP
 *
 ************************************************************/

/************************************************************
 *
 * Note that this is slightly modified from the original
 * CAPCTRL3.51, in that the screen-blanking is now disabled
 * by ANY key press, rather than only ones which generate a
 * code, and that the key to the left of the spacebar acts as
 * a "meta" key, setting bit seven of codes generated while
 * it is held down.  Also, key repeat begins slowly and
 * speeds up as the key is held down.  The mouse coordinates
 * can no longer be outside the screen limits.
 *
 * This version still uses the keymap table that is in
 * /usr/include/sys/kbd.h, which means that most people will
 * still want to use "keyfix" to remap the keys to the way
 * they should be.  I will soon be making a version with
 * completely redfinable keycodes, including configurable
 * shift, control, capslock and meta keys.
 *
 * No other significant changes have been made, and there are
 * still unused variables and functions that are only
 * included because the original driver included them (also
 * not using them), for example: kbinit(), the second half of
 * ldkeynew[] and ldkeyold[], and the kbdopen() and
 * kbdclose() routines which were included by the original
 * for no apparrent reason (its installation script created a
 * /dev/kbd which did absolutely nothing)
 *
 ************************************************************/



#include <sys/types.h>
#include <sys/conf.h>
#include <sys/tty.h>
#include <sys/termio.h>
#include <sys/systm.h>
#include <sys/drv.h>
#include <sys/iohw.h>
#include <sys/mouse.h>

#define GEN_KT
#define keymap ldkeymap
#define kprefix ldkprefix
#include <sys/kbd.h>
#undef kprefix
#undef keymap

extern struct drv_int kbddrv;
extern struct msinfo msinfo;
extern char dbuse, dbkbuf[];
extern short dbkput;
extern char dsabldbg, dbctlb;
extern long scrticks;
extern char scrsav;
extern time_t ktime;

unsigned char ldkstate=0;
unsigned short ldkeyold[16] = 0, ldkeynew[16] = 0;
unsigned char ldknumlock=0, ldkcaplock=0, ldkshift=0, ldkctrl=0, ldkmeta=0;
char ldkreptstate=0;
char ldkerptkbd;
short ldkreptcode;
int (*kbsave[3])();

void kplunk(), kwakeup(), kbinit();
void kbdinit(), kbdrelease(), kbdopen(), kbdclose();
void ldmscan(), ldkscan(), ldkupdn(), ldkhigh(), ldmscoord();
void ldkrept(), ldkillrept();
int ldklow(), ldkxlat(), ldkout();

void kbdinit()
{
    short oldpri=spl7();
    kbsave[0] = ldmisc[KHIGH];
    ldmisc[KHIGH] = (int (*)())ldkhigh;
    kbsave[1] = kbddrv.routine;
    kbddrv.routine = ldklow;
    kbsave[2] = ldmisc[MSCOORD];
    ldmisc[MSCOORD] = (int (*)())ldmscoord;
    splx(oldpri);
}

void kbdrelease()
{
    short oldpri=spl7();
    ldmisc[KHIGH] = kbsave[0];
    kbddrv.routine = kbsave[1];
    ldmisc[MSCOORD] = kbsave[2];
    splx(oldpri);
}

void kbdopen()
{
}

void kbdclose()
{
}

int ldklow()
{
    register unsigned char x;
    x = *C_DATA_ADDR >> 8;
    ktime = lbolt;
    if (scrticks<0)
	scrticks = ~scrticks;
    switch (ldkstate)
    {
    case 2:
	if ( (x==BEGMOUSE) || (x==BEGEMOUSE) )
	{
	    ldkstate = 1;
	    break;
	}
	if (x!=BEGKBD)
	{
	    ldkstate = 0;
	    ldkscan(x);
	    break;
	}
	ldkstate = 1;
	ldmscan(BEGKBD);
	break;
    case 0:
	if ( (x==BEGMOUSE) || (x==BEGEMOUSE) )
	{
	    ldkstate = 1;
	    break;
	}
	ldkscan(x);
	break;
    case 1:
	if (x==BEGKBD)
	{
	    ldkstate = 2;
	    break;
	}
	ldmscan(x);
	break;

    }
    return 1;
}

void ldmscan(code)
unsigned char code;
{
    register short x0, x1;
    register struct msinfo *mi = &msinfo;
    static unsigned char x2=0, x3[3];
    if (x2<2)
    {
	if (code&0x80)
	{
	    x2 = 0;
	    return;
	}
	x3[x2++] = code;
	return;
    }
    x2 = 0;
    x1 = code & 0x7f;
    x0 = x3[1];
    code = x3[0];
    if (!(code & MSX))
	x0 = -x0;
    if (!(code & MSY))
	x1 = -x1;
    mi->physmx += x0;
    mi->physmy -= x1;
    if (mi->physmx < 0)
	mi->physmx = 0;
    else
	if (mi->physmx > VIDWIDTH-1)
	    mi->physmx = VIDWIDTH-1;
    if (mi->physmy < 0)
	mi->physmy = 0;
    else
	if (mi->physmy > VIDHEIGHT-1)
	    mi->physmy = VIDHEIGHT-1;
    if ( mi->mb != (code & MBUTALL) )
	ldkillrept();
    mi->mb = (code & (unsigned char)MBUTALL);
    (*ldmisc[WDOWAKE])();
}

void ldkscan(code)
unsigned char code;
{
    register unsigned char code7;
    register unsigned short i, bit, changed, new;

    code7 = (code & 0x7f);
    if (code7 != KALLUP)
    {
	i = code7 >> 4;
	ldkeynew[i] |= 1 << (code7 & 0xf);
	if (!(code & 0x80))
	    return;
    }
    else
    {
	ldkillrept();
	for ( i=0 ; i<8 ; ++i )
	    ldkeynew[i] = 0;
    }

    if (scrsav)
	(*ldmisc[WDOWAKE])();

    for ( i=0 ; i<8 ; ++i )
    {
	new = ldkeynew[i];
	changed = ldkeyold[i] ^ new;
	ldkeyold[i] = new;
	ldkeynew[i] = 0;
	if (changed)
	    for ( bit=0 ; bit<16 ; ++bit )
	    {
		if (changed & 1)
		    ldkupdn((i<<4)+bit, new&1);
		changed >>= 1;
		new >>= 1;
	    }
    }
}


void ldkupdn(key, flag)
register unsigned char key;
register int flag;
{
    register short x0;
    short x1;

    switch (key)
    {
    case KSHIFT2:
    case KSHIFT1:
	if (flag)
	    ++ldkshift;
	else
	    --ldkshift;
	goto fix;
    case KCTRL1:
	if (flag)
	    ++ldkmeta;
	else
	    --ldkmeta;
	goto fix;
    case KCAPLCK:
	if (flag)
	    ++ldkctrl;
	else
	    --ldkctrl;
	goto fix;
    fix:
	if (ldkerptkbd)
	{
	    x0 = ldkxlat(ldkerptkbd, &x1);
	    if (x0 != ILLK)
		ldkreptcode = x0;
	}
	return;
    default:
	if (flag==0)
	{
	    if (ldkerptkbd==key)
		ldkillrept();
	    return;
	}
	if (key == KCTRL2)
	{
	    ldkcaplock = !ldkcaplock;
	    ldkout(ldkcaplock+CAPLED);
	    return;
	}

	if (key == KNUMLCK)
	{
	    ldknumlock = !ldknumlock;
	    ldkout(ldknumlock+NUMLED);
	    return;
	}

	x0 = ldkxlat(key, &x1);
	if (x0 != ILLK)
	{
	    ldkerptkbd = key;
	    ldkhigh(x0, x1);
	}
    }
}


int ldkxlat(key, res)
unsigned char key;
register short *res;
{
    register short x0;
    register char x1;
    register struct keydef *x2;
    *res = 1;
    x2 = &ldkeymap[key];
    x1 = x2->kt_flags;
    if ( (x1&NUMLCK) && ldknumlock )
    {
	switch (key)
	{
	case KLEFT:
	    x0 = '-';
	    break;
	case KPREV:
	    x0 = '1';
	    break;
	case KUP:
	    x0 = '2';
	    break;
	case KNEXT:
	    x0 = '3';
	    break;
	case KDOWN:
	    x0 = '0';
	    break;
	case KRIGHT:
	    x0 = '.';
	    break;
	case KRFRSH:
	    x0 = '8';
	    break;
	case KPRINT:
	    x0 = '7';
	    break;
	case KPAGE:
	    x0 = '9';
	    break;
	case KEND:
	    x0 = '6';
	    break;
	case KBEG:
	    x0 = '4';
	    break;
	case KHOME:
	    x0 = '5';
	    break;
	default:
	    panic("bad keymap");
	}
    }
    else
    {
	if (ldkctrl)
	    x0 = x2->kt_codes[2];
	else
	    if ( ldkshift || (ldkcaplock && (x1&CAPLCK)) )
		x0 = x2->kt_codes[1];
	    else
		x0 = x2->kt_codes[0];
	if (!(x1&REPT))
	    *res = 0;
    }
    return x0;
}


#define START_REPTRATE	(REPTRATE*2)
#define END_REPTRATE	(1)

void ldkrept()
{
    static short reptrate;
    switch (ldkreptstate)
    {
    case 3:
	ldkreptstate = 1;
	timeout(ldkrept, 0, REPTDLAY);
	reptrate = START_REPTRATE*4;
	break;
    case 1:
	ldkhigh(ldkreptcode, 2);
	if (reptrate>END_REPTRATE*4)
	    --reptrate;
	timeout(ldkrept, 0, reptrate>>2);
	break;
    case 2:
	ldkreptstate = 0;
	ldkerptkbd = 0;
	break;
    }
}


void ldkillrept()
{
    register oldpri=spl6();
    if (ldkreptstate)
	ldkreptstate=2;
    splx(oldpri);
}


void ldkhigh(code, reptflag)
short code;
int reptflag;
{
    register char prefix;
    register char *p;
    register struct tty *tp;
    int oldpri;
    char byte;

    prefix = code>>8;
    byte = code&0xff;
    if (prefix == 0xff)
	if (byte == 0xff)
	    return;

    /* send keys to the debugger, if running */
    if (dbuse)
    {
	if (prefix)
	    return;
	dbkbuf[dbkput++] = byte;
	dbkput &= 0x1f;
	return;
    }

    /* activate the debugger */
    if (!dsabldbg && !prefix && (unsigned char)byte==(unsigned char)0xff)
    {
	dbctlb=1;
	return;
    }

    if (reptflag==0)				/* non-repeatable */
	ldkillrept();
    else
	if (reptflag==1)			/* repeatable, just pressed */
	{
	    oldpri = spl6();
	    ldkreptcode = code;
	    if (!ldkreptstate)
	    {
		ldkreptstate = 3;
		ldkrept();
	    }
	    else
		ldkreptstate = 3;
	    splx(oldpri);
	}

    /* if it's a key for a "system" process, pass it on to ldmisc[KSPECIAL] */
    if (prefix<0)
    {
	(*ldmisc[KSPECIAL])(code);
	return;
    }

    /* find selected window, if any */
    if (!(tp = (struct tty *)(*ldmisc[GET_TTY])()))
	return;

    /* don't repeat if the previous keys have not been read */
    if (reptflag==2)
	if (!(tp->t_lflag & ICANON))
	    if ( (tp->t_rawq.c_cc) || (tp->t_canq.c_cc) )
		return;

    /* send the prefix, if any */
    if (prefix>0)
    {
	p = ldkprefix[prefix-1];
	while (prefix = *p++)
	    kplunk(tp, prefix);
    }
    else
    {
	if (ldkmeta)
	    byte |= 0x80;
	if (byte==0x1b)				/* do something magic */
	    (*ldmisc[SKPLUNK])();		/* with Escape??? */
    }

    /* send the actual byte */
    kplunk(tp, byte);
    kwakeup(tp);
}


void kplunk(tp, ch)
register struct tty *tp;
unsigned char ch;
{
    if (tp->t_iflag & IXON)
    {
	if ( (tp->t_iflag&ISTRIP) || (tp->t_cflag&CSIZE)!=CS8 )
	    ch &= 0x7f;
	if (tp->t_state & TTSTOP)
	{
	    if ( (ch == CSTART)
		|| (tp->t_iflag & IXANY) )
		(*tp->t_proc)(tp, T_RESUME);
	}
	else
	{
	    if (ch==CSTOP)
		(*tp->t_proc)(tp, T_SUSPEND);
	}
	if (ch==CSTART || ch==CSTOP)
	    return;
    }
    if (!tp->t_rbuf.c_ptr || !tp->t_rbuf.c_count)
    {
	kwakeup(tp);
	if (!tp->t_rbuf.c_ptr || !tp->t_rbuf.c_count)
	    return;
    }
    tp->t_rbuf.c_ptr[tp->t_rbuf.c_size - tp->t_rbuf.c_count--] = ch;
}

int kwakeflag=0;

void kwakeup(tp)
register struct tty *tp;
{
    int oldpri;
    if (++kwakeflag == 1)
    {
	oldpri = spl5();
	(*linesw[tp->t_line].l_input)(tp);
	splx(oldpri);
	kwakeflag = 0;
    }
}

int ldkout(code)
register char code;
{
    register int oldpri;
    oldpri = spl6();
    if (!(*C_CMND_ADDR & 2))
    {
	splx(oldpri);
	return 0;
    }
    *C_DATA_ADDR = (code<<8);
    splx(oldpri);
    return 1;
}


void kbinit()
{
    while (!ldkout(KBDRST))
	;
    while (!ldkout(KBDRST))
	;
    while (!ldkout(KBDRST))
	;
    while (!ldkout(KBDRST))
	;
    while (!ldkout(0))
	;
    ktime = lbolt;
}


void ldmscoord(xp, yp, bp)
long *xp, *yp;
char *bp;
{
    register struct msinfo *mi = &msinfo;
    *xp = mi->physmx;
    *yp = mi->physmy;
    *bp = mi->mb;
}
SHAR_EOF
if test 11209 -ne "`wc -c < 'nkbd.c'`"
then
	echo shar: error transmitting "'nkbd.c'" '(should have been 11209 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'INSTALL'" '(908 characters)'
if test -f 'INSTALL'
then
	echo shar: will not over-write existing file "'INSTALL'"
else
cat << \SHAR_EOF > 'INSTALL'
set -e		# exit if anything goes wrong

DRIVER=kbd
NDRIVER=nkbd

if [ ! -f ${NDRIVER}.o ]
then
	echo "you must make ${NDRIVER}.o before running INSTALL" 1>&2
	exit 1
fi

rm -f /dev/kbd		# get rid of the useless /dev/kbd put there by CAPCTRL

/etc/masterupd -d ${DRIVER} 2>/dev/null || :

/etc/masterupd -a init release ${DRIVER} || exit

cp ${NDRIVER}.o /etc/lddrv/${DRIVER}.o

cd /etc/lddrv

# remove the driver if it's already running

./lddrv -q ${DRIVER} && ./lddrv -d ${DRIVER}

# allocate and load the module

if ./lddrv -a ${DRIVER}
then
	echo "Driver ${DRIVER} successfully loaded"
else
	echo "Error: Driver ${DRIVER} failed loading stage" 1>&2
	exit 1
fi

# load the driver at boot time

grep "^${DRIVER}\$" drivers > /dev/null || echo ${DRIVER} >> drivers


if [ -x /etc/daemons/keyfixes ]
then
	/etc/daemons/keyfixes
else
	echo "Remember to run "keyfix" now if you normally do it at boot time."
fi
SHAR_EOF
if test 908 -ne "`wc -c < 'INSTALL'`"
then
	echo shar: error transmitting "'INSTALL'" '(should have been 908 characters)'
fi
chmod +x 'INSTALL'
fi # end of overwriting check
echo shar: extracting "'Size'" '(3 characters)'
if test -f 'Size'
then
	echo shar: will not over-write existing file "'Size'"
else
cat << \SHAR_EOF > 'Size'
42
SHAR_EOF
if test 3 -ne "`wc -c < 'Size'`"
then
	echo shar: error transmitting "'Size'" '(should have been 3 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Install'" '(381 characters)'
if test -f 'Install'
then
	echo shar: will not over-write existing file "'Install'"
else
cat << \SHAR_EOF > 'Install'
# Install script for new keyboard driver

./INSTALL || exit 1

cd /etc/lddrv

# put an entry in InstDrv
echo '/^File=kbd$/-1;+2d
w' | ed - InstDrv		# remove any previous entry
echo 'Name=New keyboard driver (with caplock/ctrl/meta switch)
File=kbd
Comment=based on the CAPCTRL3.5 program from AT&T's "The Store!"' >> InstDrv

echo "The new keyboard driver is now installed"
exit 0
SHAR_EOF
if test 381 -ne "`wc -c < 'Install'`"
then
	echo shar: error transmitting "'Install'" '(should have been 381 characters)'
fi
chmod +x 'Install'
fi # end of overwriting check
echo shar: extracting "'Name'" '(61 characters)'
if test -f 'Name'
then
	echo shar: will not over-write existing file "'Name'"
else
cat << \SHAR_EOF > 'Name'
New! Improved! keyboard driver with CAPS<->CTRL and META key
SHAR_EOF
if test 61 -ne "`wc -c < 'Name'`"
then
	echo shar: error transmitting "'Name'" '(should have been 61 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Remove'" '(315 characters)'
if test -f 'Remove'
then
	echo shar: will not over-write existing file "'Remove'"
else
cat << \SHAR_EOF > 'Remove'
DRIVER=kbd

rm -f /dev/$DRIVER

cd /etc/lddrv
./lddrv -dv $DRIVER
echo 'kstate/w 0' | adb -w /unix /dev/kmem	# make sure state = 'keyboard'
echo '/^kbd$/d
w' | ed - drivers
rm -f ifile.kbd kbd kbd.o

echo '/^File=kbd$/-1;+2d
w' | ed - InstDrv

/etc/masterupd -d kbd

echo "The new CAPCTRL driver has been removed."
SHAR_EOF
if test 315 -ne "`wc -c < 'Remove'`"
then
	echo shar: error transmitting "'Remove'" '(should have been 315 characters)'
fi
chmod +x 'Remove'
fi # end of overwriting check
echo shar: extracting "'Files'" '(46 characters)'
if test -f 'Files'
then
	echo shar: will not over-write existing file "'Files'"
else
cat << \SHAR_EOF > 'Files'
Size
Install
Name
Remove
Files
INSTALL
nkbd.o
SHAR_EOF
if test 46 -ne "`wc -c < 'Files'`"
then
	echo shar: error transmitting "'Files'" '(should have been 46 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Unix-pc.sources mailing list