[net.sources] Actual tricks, shells, csh aliases and the like, 3 of 3

nancy@resonex.UUCP (Nancy Blachman) (10/17/84)

> [Know anybody with a GREAT .login or .cshrc?]

> I'm interested in collecting the little tricks, shell scripts, awk
> hacks, csh aliases, and such that people have built to make their daily
> life a little easier or more automatic.  Being a fairly new system
> administrator I don't have the big toolbox that years of messing around
> will leave you with.  If you have any hacks you're proud of (or that
> you aren't proud of, but which work anyway), and you're willing to make
> them public, mail them to me.  I'll collect, collate, shuffle, sort,
> munge, judge, select and discard them and then "summarize to the net".

This article centers on C programs and awk scripts I received in response to
my solicitation.  The first article concentrates on  aliases, and .cshrc and 
.login files.  The second article in this series focuses shell scripts. 

/\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\/
> Nancy Blachman {allegra,hplabs,ihnp4,sun}!resonex!nancy  (408)720 8600 x37 <
/\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\/

::::::::::::::
programs/1
::::::::::::::
Return-Path: <hplabs!intelca!t4test!chip>
Received: by resonex.UUCP (4.12/4.7)
	id AA25189; Sat, 15 Sep 84 03:18:36 pdt
Date: Sat, 15 Sep 84 02:45:08 pdt
From: <hplabs!intelca!t4test!chip>
Received: by HP-VENUS id AA22558; Sat, 15 Sep 84 02:45:08 pdt
Message-Id: <8409150945.AA22558@HP-VENUS>
To: intelca!hplabs!resonex!nancy
Subject: Re: Tricks, shell and awk scripts, csh aliases and the like
Newsgroups: net.unix,net.unix-wizards,net.wanted
References: <164@resonex.UUCP>

One thing I've put together is a bunch of scripts which give you a
status line on a DEC type terminal.  The thing is hardwired into VTxxx
type stuff rather than termcap for two reasons.  First, the cursor
save/restore function isn't part of termcap.  Secondly, the set
scrolling region is part of termcap, but it is for VT100 type
terminals.  Since we only have DEC terminals, it doesn't hurt us too
much.

Some history:  I used to like to display my current working directory
on my prompt line.  Later I wanted my terminal line there too.  (That
was in case a terminal I was on locked up, I could quickly tell what
terminal to kill.)  Later, when I had four accounts on the machine I
thought it would be nice to display my login name in my prompt.  The
straw which broke the camel's back was that we bought another VAX, and
I wanted to be able to see which machine I was logged on.  As you might
imagine, my prompt now extended about 60 columns across the screen.  My
answer was to take everything out of my prompt except the history
number and stick it at a status line at the bottom of my screen.

Below is a shar archive of the status line files.  You do a `source
stat.init' to get stuff initialized.  Then `son' and `soff' (which are
aliased to source the two other scripts) turn the status line on and
off.  These also define a bunch of aliases which help you work with
programs which don't like the status line.  So, I put a `source
/usr/public/stat.init' followed by a `son' in my `.login'.  (I don't
turn it on with my `.cshrc', my shell escapes would then get awfully
sloooooow.)

Also, you would need to add `vt100s' and `vt131s' to /etc/termcap.
This is to keep screen stuff (e.g. more, vi, etc.) happy if you run
them with the status line on.  This is what I use:

    ################      VT131 with 24th line reserved
    ################ d13s|vt131s|VT131S|vt-131s|pt131s|pt-131s|dec
    vt131s:\
	    :li#23:tc=vt131

You will definately want to change the terminal identification stuff in
`stat.init'.  We run Eunice, so I use the `grep' to convert the Unix
style terminal line identification to a VMS terminal port.  

You can redefine `statin' in the `stat.init' script to put whatever you 
want on the status line.

Well...after all this, I hope you use VT1xx/VT2xx terminals.
Otherwise, this won't be real exciting.  (Unless you want to rewrite
`statterm.c')

---

Chip Rosenthal, Intel/Santa Clara
{ idi|intelca|icalqa|kremvax|qubix|ucscc } ! t4test ! { chip|news }

-----  cut here  -----------------------------------------------------------

: This is a shar archive.  Extract with sh, not csh.
: This archive contains the following files
:  Makefile stat.init stat.on stat.off statterm.c
: Total number of files: 5
echo x - Makefile [file 1 of 5]
sed 's/^|//' > Makefile << '!-FUNKY-STUFF-!'
|BIN=	/usr/public
|OBJS=	statterm
|
|IOBJS=	$(BIN)/statterm \
|	$(BIN)/stat.init \
|	$(BIN)/stat.on \
|	$(BIN)/stat.off
|
|SOURCES=Makefile \
|	stat.init \
|	stat.on \
|	stat.off \
|	statterm.c
|
|all:		$(OBJS)
|install:	$(IOBJS)
|shar:		stat.shar
|
|statterm:		statterm.c
|			cc -O statterm.c -o statterm
|
|$(BIN)/statterm:	statterm
|			cp $? $@
|			chmod 755 $@
|
|$(BIN)/stat.init:	stat.init
|			cp $? $@
|			chmod 755 $@
|
|$(BIN)/stat.on:		stat.on
|			cp $? $@
|			chmod 755 $@
|
|$(BIN)/stat.off:	stat.off
|			cp $? $@
|			chmod 755 $@
|
|stat.shar:		$(SOURCES)
|			shar $(SOURCES) > $@
|
|
!-FUNKY-STUFF-!
echo x - stat.init [file 2 of 5]
sed 's/^|//' > stat.init << '!-FUNKY-STUFF-!'
|alias a 'alias'
|
|# run statterm to verify terminal can do status line
|statterm
|if $status then
|    # status line not available on this terminal -- see if a
|    # baseterm is defined.  if so, then maybe $TERM is just
|    # messed up from earlier invocation of stat.init.
|    if $?baseterm then
|	# baseterm has been defined -- see if it will work
|	set temp=$TERM
|	setenv TERM $baseterm
|	statterm
|	if $status then
|	    # nope -- baseterm will not work either
|	    setenv TERM $temp
|	    unset temp
|	    goto failed
|	else
|	    # yes -- baseterm will work
|	    echo "changing terminal type from $temp to $TERM"
|	    unset temp
|	endif
|    else
|	# no baseterm defined
|	goto failed
|    endif
|endif
|
|# status line will work with this terminal
|set baseterm=$TERM
|set ignoreeof
|
|# find user's system (ick)
|set system=`tr '[A-Z]' '[a-z]' < /usr/include/whoami`
|
|# find user's tty (ick ick ick)
|set temp=`tty`'$'
|set tty=`grep "$temp" /etc/dev.com | sed -e 's/^.*_\(.*\):.*/\1/'`
|unset temp
|
|# setup terminal strings
|set statin="`statterm in '${system}\\!${user}' '(${tty})'`" 
|set statout="`statterm out`" 
|set statoff="`statterm off`"
|echo -n "$statoff"
|
|# setup status commands
|#   son - turn on status mode
|#   soff - turn off status mode
|#   stat - draw status line
|#   nostat - erase status line
|#   termstat - setenv the terminal with status line protected
|#   termnorm - setenv the terminal without a status line
|#   ns - execute a command without a status line
|a son		'source /usr/public/stat.on'
|a soff		'source /usr/public/stat.off'
|a stat		';'
|a nostat	';'
|a termstat	';'
|a termnorm	';'
|a ns		'nostat ; termnorm ; \!* ; termstat ; stat ; echo ""'
|
|# alias the commands which maintain the status line
|a cd		'chdir \!* ; stat'
|a popd		'popd ; stat'
|a pushd		'pushd \!* ; stat'
|
|# alias the commands which (might) munch the status line
|a clear		'clear \!* ; stat'
|a mail		'mail \!* ; stat'
|a more		'more \!* ; stat'
|
|# alias the commands which should be done with the status line off
|a lo		'ns logout \!*'
|a LO		'ns logout \!*'
|a rn		'ns /local/bin/rn \!*'
|a pn		'ns /local/bin/pn \!*'
|a reply		'ns /local/bin/reply \!*'
|a sus		'ns suspend \!*'
|a vi		'ns /usr/ucb/vi \!*'
|a view		'ns /usr/ucb/view \!*'
|
|# that is all folks.  the status stuff is initialized
|# now all you need is a 'son' to turn it on
|exit 0
|
|failed:
|set baseterm=$TERM
|set temp="status line is not available for terminal type $TERM"
|echo $temp
|set statin=";"
|set statout=";"
|if 	$?statoff == 0 then
|    set statoff=";"
|endif
|alias son echo "$temp"
|alias off 'source /usr/public/stat.off'
|unset temp
|soff
|exit 1
|
!-FUNKY-STUFF-!
echo x - stat.on [file 3 of 5]
sed 's/^|//' > stat.on << '!-FUNKY-STUFF-!'
|a stat		'echo -n "${statin}${cwd}${statout}"'
|a nostat	'echo -n "$statoff"'
|a termstat	'setenv TERM ${baseterm}s'
|a termnorm	'setenv TERM $baseterm'
|termstat
|stat
|echo ""
|set statmode
!-FUNKY-STUFF-!
echo x - stat.off [file 4 of 5]
sed 's/^|//' > stat.off << '!-FUNKY-STUFF-!'
|setenv TERM $baseterm
|echo -n "$statoff"
|unset statmode
|a termstat	';'
|a termnorm	';'
|a stat ';'
|a nostat ';'
!-FUNKY-STUFF-!
echo x - statterm.c [file 5 of 5]
sed 's/^|//' > statterm.c << '!-FUNKY-STUFF-!'
|/*
| * FILE:	statterm
| * VERSION:	V0.01 [preliminary]
| * DATE:	Mon Aug 27 16:43:13 PDT 1984
| * AUTHOR:      Chip Rosenthal/Intel Corporation
| * ADDRESS:	t4test!chip
| * PACKAGE:     'stat' terminal status line package
| * DESCRIPTION:	produces terminal escape sequences to implement status line
| * COMPILATION: cc -C statterm.c -o statterm
| *
| * REVISION NOTES:
| *
| * V1.00  Original program.
| *
| *
| * USAGE:
| *
| *    statterm 
| *        Verifies that the status line will work with current terminal.
| *        Returns a zero exit status if it will, nonzero if it won't.
| *
| *    statterm in [arg ...]
| *        Creates a string which opens up the status line.  Any
| *        arguments are placed at the beginning of the status
| *        line, and the cursor is left there.
| *
| *    statterm out
| *        Create string which closes the status line and returns
| *        cursor to position it was in prior to the last execution
| *        of a 'statterm in' string.
| *
| *    statterm off
| *        Creates a string which removes the status line.
| *
| *
| *    EXAMPLE:
| *        # this is a cshell script
| *        statterm 
| *        if $status then
| *            echo "status line will not work on this terminal"
| *            exit
| *        endif
| *        echo -n `statterm in $user`
| *        echo -n `pwd`
| *        echo `statterm out`
| *
| *
| * BUGS:       
| *
| *    This program is hardwired into the DEC VT100 terminal escape sequences.
| *    This is done because (unfortunately) 'termcap' doesn't offer a cursor
| *    position save/restore feature.
| *
| */
|
|#include <stdio.h>
|#define strmatch(A,B) (strcmp((A),(B))==0)
|
|/*
| * VT100 Terminal Escape Definitions -- all parameters are strings
| */
|#define ESC 	      putchar(27);              /* escape character          */
|#define CSI 	      ESC;putchar('[');         /* command string            */
|#define DECSC 	      ESC;putchar('7');         /* save cursor position      */
|#define DECRC 	      ESC;putchar('8');         /* restore cursor position   */
|#define CUP(L,C)      CSI;printf("%s;%sH",L,C); /* set cursor to line/col    */
|#define CUU1	      CSI;printf("1A");        /* cursor up one line        */
|#define CUD1	      CSI;printf("1B");        /* cursor down one line      */
|#define EL(MODE)      CSI;printf("%sK",MODE);   /* erase line                */
|#define ED(MODE)      CSI;printf("%sJ",MODE);   /* erase display             */
|#define DECSETBM(T,B) CSI;printf("%s;%sr",T,B); /* top/bot of scroll area    */
|/*
| * erasing modes:
| *   mode "0" - from cursor to end
| *   mode "1" - from beginning to cursor
| *   mode "2" - entire
| */
|
|
|main(argc,argv)
|int argc;
|char *argv[];
|{
|    char *term, *getenv();
|    int i;
|
|    if ( argc == 1 ) {
|	term=getenv("TERM");
|	if ( term == NULL )
|	    exit(1);
|	if ( strmatch(term,"vt100") || strmatch(term,"vt131") )
|	    exit(0);
|	else
|	    exit(1);
|    }
|
|    if ( strmatch(argv[1],"in") ) {
|	/*
|	 * Save cursor position, go to line 24, print out the arguments, and
|	 * erase the rest of the status line.  Cursor remains in status line.
|	 */
|	DECSC;
|	CUP("24","1");
|	for ( i=2 ; i<argc ; ++i ) 
|	    printf("%s  ",argv[i]);
|	EL("0");
|    } else if ( strmatch(argv[1],"out") ) {
|	/*
|	 * Protect status line from scrolling and restore cursor to location 
|	 * prior to the last 'in' call.  Move the cursor up and down one line.
|	 * This will keep it out of the status line area if it was there when 
|	 * 'in' was called.
|	 */
|	DECSETBM("1","23");
|	DECRC;
|	CUU1;
|	CUD1;
|    } else if ( strmatch(argv[1],"off") ) {
|	/*
|	 * Save the current cursor position, unprotect the status line, erase 
|	 * the status line, and restore the cursor position.
|	 */
|	DECSC;
|	DECSETBM("1","24");
|	CUP("24","1");
|	EL("2");
|	DECRC;
|    } else
|	exit(1);
|
|}
!-FUNKY-STUFF-!
exit



::::::::::::::
programs/2
::::::::::::::
Return-Path: <ihnp4!mcnc!malloy@ittral>
Received: by resonex.UUCP (4.12/4.7)
	id AA19435; Fri, 14 Sep 84 09:08:51 pdt
From: ihnp4!mcnc!malloy@ittral
Received: by ihnp4.ATT.UUCP; id AA24487; 14 Sep 84 11:05:59 CDT (Fri)
Received: by mcnc (4.12/4.7) id AA06398; Thu, 13 Sep 84 21:35:18 edt
Date: Thu, 13 Sep 84 21:35:18 edt
Original-From: <malloy%ittral@mcnc>
Message-Id: <8409140135.AA06398@mcnc>
To: ihnp4!resonex!nancy@mcnc
Subject: Tricks

Well it depends upon what you mean.  The big problem with having lots of aliases
and such is they start taking up large amounts of memory.  Take it from someone
who knows.  But here's a few things.  Some you no doubt already have, and most
are trivial, but it's better to be complete then to leave anything out.  You
can always just delete this.	== William P. Malloy (ittral!malloy}
---------------------------------------------------------------------
In a .cshrc, a warning and a work around.  Apparently not known by most people
but obvious to people have who been around.  Our users keep bumping into it
about once a year like clock work.
# reason for setting variables only if a prompt already exists
# If it sets prompt in a non-interactive shell, for instance vi(1)
# firing up a sub-shell to expand shell meta-characters, the set prompt
# will stomp on alot of shell variables used for the expansion (like ~)
#
if ( $?prompt ) then
   set mail=/usr/spool/mail/malloy
   set prompt=\`
   set histchars=",;"
endif
Note the setting of histchars.  A little known, but for me much loved feature
of csh is the ability to change the history characters "!^" from their default
values.  The pair `,;' are easier to reach, don't require shifting, and don't
appear in mail paths.  Typing `mail mcnc\!ihnp4\!resonex\!nancy' gets to be
a pain every time you want to mail someone.

alias , 'redo \,* ~/.cmd ~/.cmd1 ; source ~/.cmd1 '

This little alias allows you to have command editing in the csh.  It's quite
useful, particularly when you've got a LONG painful command line.  The , is
just the history character and is ! for most people.  The command redo is a
simple C program.
--------------- redo.c  -------------------
#include <stdio.h>

/* redo -- outputs a command file (last arg )used to edit and 
   re-ex a command.  Next to last arg is dest file of the command. 

   NOTE: if you use a non-standard history character, i.e. not !
   then you must `setenv HISTCHARS $histchars' in your .login
   If you do not `set histchars=",;"' for instance then it will
   automagically default to !    -- 12/2/83 wpm

   First arg is the history ref . To use:
    alias , 'redo \,* ~/cmd ~/cmd1 ; source ~/cmd1 '
    , 25    to edit & re-execute ,25
    , , or ,  to edit & re-execute ,,
    , v     to edit & re-execute ,v ,etc. 
    
*/

main(argc, argv)
   int argc;
   char *argv[];
{
   FILE *fp;
   char *t, *getenv();

   fp = fopen(argv[argc-1], "w");
   if ((t = getenv("HISTCHARS")) != NULL)
      t[1] = '\0';
   else
      t = "!";
   fprintf(fp, "echo \"%s", t);
   if ( (argc < 4) || (strcmp(argv[1], t) == 0) )
      fputs("-2", fp);
   else 
      fputs(argv[1], fp);
   fputs(":q\" >! ", fp);
   fputs(argv[argc-2], fp);
   putc('\n', fp);
   fputs("ex +open ", fp);
   fputs(argv[argc-2], fp);
   putc('\n', fp);
   fputs("/usr/local/typein2 < ", fp);
   fputs(argv[argc-2], fp);
   putc('\n', fp);
   fclose(fp);
   exit(0);
}
------------------ (end of redo.c, begining of typein2.c) --------------------
#include <stdio.h>
#include <sgtty.h>

main(argc, argv)
	int argc;
	char **argv;
{
	register char *cp;
	struct sgttyb stb, stb2;
	int pendin = LPENDIN;
	int c,i,j;
	char buff[2];
	char buff2[256];

	i=0;
	while ((c=getchar()) != EOF) {
			buff2[i++]=c;
	}
	ioctl(2, TIOCGETP, &stb);
	stb2 = stb;
	stb.sg_flags &= ~ECHO;
	ioctl(2, TIOCSETN, &stb);
	for (j=0; j<i; j++) {
			ioctl(2, TIOCSTI, &buff2[j]);
			putchar(buff2[j]);
	}
	ioctl(2, TIOCSETN, &stb2);
	ioctl(2, TIOCLBIS, &pendin);
	exit(0);
}
---------------------------- (end of typein2.c) ------------------------
A couple of oldies but still the simplest.  cd and back aliases.
alias back 'set back=$old; set old=$cwd; cd $back; unset back; dirs'
alias cd 'set old=$cwd; chdir \,*; set prompt = "< $cwd:t > "'

# this is a useful feature for vi
setenv EXINIT 'map #1 Gi/\<A\>"add@a|map #2 1G\!Gvispell|set ai sw=3'

You f2 key will run a file through the spell program, and put the words it
doesn't find in the dictionary at the bottom of the file.  Then typing f1 will
cause it to delete the last line in the file, and search for the string in
the rest of the file.
------------------------------ (source for vispell) -------------
#! /bin/sh
#
tee /tmp/vis$$
echo SpellingList
spell /tmp/vis$$
rm /tmp/vis$$
------------------------------- (end of vispell) ------------------
Stuff from our /.cshrc file.  psa lets you see what's going on in the system
and what people are doing.  Useful to see if people are hanging themselves.
alias psa 'ps axu | sed "/getty/d" | sort -f | more'

A simple alias to compile C programs (C adm.c expands to cc adm.c -o adm).
alias C 'cc \,:* -o \,^:r'

Useful to see what's going on in the system without those !@#$% bells.
alias moremsgs "tr -d '\07' </usr/adm/messages | more"

Like fg.
alias pj '%-'

A feature we use in our root .cshrc allowing indivual superusers to get their
own enviornment.  Useful if people want their own enviornment anywhere people
share an account.
if ( $user == "malloy" ) then
   source /t/malloy/.root
endif

--------------- (here's some things I picked up off the net) --------------
>From ittvax!decvax!harpo!utah-cs!seismo!hao!denelcor!udenva!koala!aburt Fri Aug 10 09:19:37 1984
Subject: Perversions of source -h and other csh aliases
Newsgroups: net.unix,net.unix-wizards,net.sources

For your enjoyment, here are some interesting lunch hour csh aliases that 
I've created.
{this is to slow, my version is a little faster}
My personal favorite is the "history editor" -- allows you to edit
you csh history.  The alias:

	alias hed history -h !* > $hed; vi + $hed; source -h $hed

will allow you to invoke 'vi' on your current history.  (If, for
instance, you typed in a long, tedious line and put in an extra space,
among other things.  The ^...^...  mechanism to remove it can be quite
tedious; 'hed's is easy.)  Before anyone starts flaming that vi is too
slow, history can do it (even if it's tough to type and you're prone to
more typos doing the history), etc. -- if you don't like it, don't use it.

Hed works particularly well if you move the command in question to the
end of the file; then '!!' will execute it after you ZZ from vi.  The
only drawback to this is that it trashes your current event numbers
(they get incremented during the source -h).  By using 'hed 10' you
only edit the last 10 entries in your history.  A temp file, which I
keep in $hed (set to /tmp/hed.$$ from my .login), is used each time for
the history.  Obvious changes to this are to use /tmp/hed.$$ straight
out and add "rm /tmp/hed.$$" to the end of the list.  If you don't like
waiting for the rm, and your /tmp doesn't get cleared out periodically,
put a # in front of the name to make it a disposable file.

This may be slower than the vi/emacs mode in the ksh I keep hearing about, but
it does give the functionality.

A slight modification to 'hed'...

	alias hedf history -h !-0:1 > !-0:2; vi + !-0:2; source -h !-0:2

allows you to specify a file to place the history into instead of a temp
file.

Another modification yields:

	alias heh echo \!* > $hed; vi + $hed; source -h $hed

Which lets you edit then add to your history a specific history sequence.
'Heh' for History edit history.

By inserting a 'source \!-0:2' before the source -h in any of the
above has the effect of executing the commands AND placing them on the
history list (from which we may conclude that 'alias so source \!* ; 
source -h \!*' is a useful item: it sources a file then places each line
into your history).

On rare occasions you'll have to put extra quotes/escapes around things
when editing the temp file so it gets sourced right.  Particularly around
aliases with raw history substitutions in them (the \!* type of thing).
The easiest is to try it first; if it fails, edit it again.  After all,
two 'hed's are better than one...

Regarding the use of !-0:1 instead of !:1 for the first argument to the
current command -- At least one csh is known to accept the former but not
the latter.  (The same csh dumps core (therefore logging you out) on receipt
of the !# history selector.  This is version 1.0 of 4.2BSD csh on a Sun-2.
The 1.1 csh exhibits this behavior:

	echo a !#
	a echo a echo

adding an extra arg 0 to the end.  Is this common to other cshs out there?)

So, for those whose csh's allow !:1, use that where I have !-0:1, etc.

Another interesting perversion is an alias'd whereis:

	alias wheres ls -l \{'`echo $path | sed "s/ /,/g"`'\}/'`echo \!-0:1 | sed "s/^./[&]/"`'

It does an ls -l on every file (passed as arg 1) in any directory on
your current path.  (No aliases, though adding an if at the front
should do the trick.)  The idea is to turn your $path list into a comma
separates list, stick that between {}, and append / and arg 1 to that.
Alas, if the file doesn't exist in one of the directories, you get
errors from ls saying it doesn't exist in a given directory.  So, arg 1
is turned into a pattern, which is allowed to fail; the pattern is,
e.g., foo --> [f]oo.  So the second arg to ls only expands to the
existing files.
---------------------------- (end of net article) ------------------------
--
Address: William P. Malloy, ITT Telecom, B & CC Engineering Group, Raleigh NC
	 {ihnp4!mcnc, burl, ncsu, decvax!ittvax}!ittral!malloy


::::::::::::::
awk/1
::::::::::::::
Return-Path: <hplabs!ucbvax!rbbb@rice.ARPA>
Received: by resonex.UUCP (4.12/4.7)
	id AA09425; Thu, 20 Sep 84 08:49:09 pdt
Received: by HP-VENUS id AA14843; Thu, 20 Sep 84 08:39:25 pdt
Received: from rice.ARPA (rice.ARPA.ARPA) by UCB-VAX.ARPA (4.24/4.31)
	id AA05702; Wed, 19 Sep 84 12:42:45 pdt
Received: from iapetus by rice.ARPA (AA04768); Wed, 19 Sep 84 14:31:55 CDT
Received: by iapetus (AA22731); Wed, 19 Sep 84 14:23:54 CDT
Date:       Wed, 19 Sep 84 11:44:38 CST
From: David Chase <hplabs!ucbvax!rbbb@rice.ARPA>
Subject:    Re: Tricks, shell and awk scripts, csh aliases and the like
To: resonex!nancy@BERKELEY
Message-Id: <464460278.rbbb@Iapetus.ARPA>
In-Reply-To: a message from hplabs!resonex!nancy@UCB-VAX.ARPA dated 12 Sep 84 9:26:22-PDT (Wed)

Here is my favorite awk script.  It turns a list of csrc's from memory
errors on an 11/780 (with MS780C controller) into board and chip position
for certain Mostek memory boards.  This script saved me many headaches,
because the tables in the appendix of the technical manual were hard to read
and contained errors (errors that were noticed as deviations from a pattern
when entering this script).

#
# Incredible sleazy awk file to attack memory errors
# Included here is the local configuration, because some decoding
# is board specific
# 
BEGIN	{
# Boards understood by this program

#	mk4118 = mostek mk8016 fully populated with mk4116 chips (512k)
	known["mk4118"] = 1

#	mk4116 = mostek mk8016 half populated with mk4116 chips (256k)
	known["mk4116"] = 1

#	mk8016 = mostek mk8016 fully populated with mk4108 chips (256k)
	known["mk4108"] = 1

#	m8210 = DEC 256k board; don't know how to decode this guy (256k)
	known["m8210"] = 0

# To add different boards, (i.e., not conforming to this system)
# append to the "pos" map, and make "keys[<array><bank><new board>]"
# reference the appended chip addresses.

# Local configuration
# boards is indexed by slot number
	boards["0"] = "m8210"
	boards["1"] = "m8210"
	boards["2"] = "m8210"
	boards["3"] = "m8210"
	boards["4"] = "m8210"
	boards["5"] = "m8210"
	boards["6"] = "mk4116"
	boards["7"] = "mk4116"
	boards["8"] = "mk4116"
	boards["9"] = "mk4116"
	boards["a"] = "mk4116"
	boards["b"] = "mk4116"
	boards["c"] = "mk4118"
	boards["d"] = "mk4118"
	boards["e"] = "mk4118"
	boards["f"] = "mk4118"
	
#	bit in error for a given CRC calculation
#	bits are identified by "u" (upper), "l" (lower), and "c" (check)
#	folowed by the bit number.

  	bit["01"] = "c0"
  	bit["02"] = "c1"
	bit["04"] = "c2"
	bit["08"] = "c3"
	bit["10"] = "c4"
	bit["19"] = "l01"
	bit["1a"] = "l02"
	bit["1c"] = "l04"
	bit["1f"] = "l07"
	bit["20"] = "c5"
	bit["38"] = "l00"
	bit["3b"] = "l03"
	bit["3d"] = "l05"
	bit["3e"] = "l06"
	bit["40"] = "c6"
	bit["49"] = "l09"
	bit["4a"] = "l10"
	bit["4c"] = "l12"
	bit["4f"] = "l15"
	bit["51"] = "l17"
	bit["52"] = "l18"
	bit["54"] = "l20"
	bit["57"] = "l23"
	bit["58"] = "l24"
	bit["5b"] = "l27"
	bit["5d"] = "l29"
	bit["5e"] = "l30"
	bit["68"] = "l08"
	bit["6b"] = "l11"
	bit["6d"] = "l13"
	bit["6e"] = "l14"
	bit["70"] = "l16"
	bit["73"] = "l19"
	bit["75"] = "l21"
	bit["76"] = "l22"
	bit["79"] = "l25"
	bit["7a"] = "l26"
	bit["7c"] = "l28"
	bit["7e"] = "l31"
	bit["80"] = "c7"
	bit["89"] = "u01"
	bit["8a"] = "u02"
	bit["8c"] = "u04"
	bit["8f"] = "u07"
	bit["91"] = "u09"
	bit["92"] = "u10"
	bit["94"] = "u12"
	bit["97"] = "u15"
	bit["98"] = "u16"
	bit["9b"] = "u19"
	bit["9d"] = "u21"
	bit["9e"] = "u22"
	bit["a8"] = "u00"
	bit["ab"] = "u03"
	bit["ad"] = "u05"
	bit["ae"] = "u06"
	bit["b0"] = "u08"
	bit["b3"] = "u11"
	bit["b5"] = "u13"
	bit["b6"] = "u14"
	bit["b9"] = "u17"
	bit["ba"] = "u18"
	bit["bc"] = "u20"
	bit["bf"] = "u23"
	bit["c1"] = "u25"
	bit["c2"] = "u26"
	bit["c4"] = "u28"
	bit["c7"] = "u31"
	bit["e0"] = "u24"
	bit["e3"] = "u27"
	bit["e5"] = "u29"
	bit["e6"] = "u30"

#	binary decoding of hex digits

	hex["0"]  = "0000"
	hex["1"]  = "0001"
	hex["2"]  = "0010"
	hex["3"]  = "0011"
	hex["4"]  = "0100"
	hex["5"]  = "0101"
	hex["6"]  = "0110"
	hex["7"]  = "0111"
	hex["8"]  = "1000"
	hex["9"]  = "1001"
	hex["a"]  = "1010"
	hex["b"]  = "1011"
	hex["c"]  = "1100"
	hex["d"]  = "1101"
	hex["e"]  = "1110"
	hex["f"]  = "1111"

#	chip positions for a given bit, collected across all possible
#	boards.  Each group of 3 letters represents a position.
#	See keys for a better description.

	pos["u31"] =  "i01h01g01f01"
	pos["u30"] =  "e01d01c01b01"
	pos["u29"] =  "i02h02g02f02"
	pos["u28"] =  "e02d02c02b02"
	pos["u27"] =  "i03h03g03f03"
	pos["u26"] =  "e03d03c03b03"
	pos["u25"] =  "i04h04g04f04"
	pos["u24"] =  "e04d04c04b04"
	pos["u23"] =  "a01a02a03a04"
	pos["u22"] =  "i05h05g05f05"
	pos["u21"] =  "e05d05c05b05"
	pos["u20"] =  "i06h06g06f06"
	pos["u19"] =  "e06d06c06b06"
	pos["u18"] =  "i07h07g07f07"
	pos["u17"] =  "e07d07c07b07"
	pos["u16"] =  "i08h08g08f08"
	pos["u15"] =  "e08d08c08b08"
	pos["u14"] =  "a05a06a07a08"
	pos["u13"] =  "i09h09g09f09"
	pos["u12"] =  "e09d09c09b09"
	pos["u11"] =  "i10h10g10f10"
	pos["u10"] =  "e10d10c10b10"
	pos["u09"] =  "i11h11g11f11"
	pos["u08"] =  "e11d11c11b11"
	pos["u07"] =  "i12h12g12f12"
	pos["u06"] =  "e12d12c12b12"
	pos["u05"] =  "a09a10a11a12"
	pos["u04"] =  "i13h13g13f13"
	pos["u03"] =  "e13d13c13b13"
	pos["u02"] =  "i14h14g14f14"
	pos["u01"] =  "e14d14c14b14"
	pos["u00"] =  "i15h15g15f15"
	pos["c7"] =   "e15d15c15b15"
	pos["c6"] =   "i16h16g16f16"
	pos["c5"] =   "e16d16c16b16"
	pos["c4"] =   "a13a14a15a16"
	pos["l31"] =  "i17h17g17f17"
	pos["l30"] =  "e17d17c17b17"
	pos["l29"] =  "i18h18g18f18"
	pos["l28"] =  "e18d18c18b18"
	pos["l27"] =  "i19h19g19f19"
	pos["l26"] =  "e19d19c19b19"
	pos["l25"] =  "i20h20g20f20"
	pos["l24"] =  "e20d20c20b20"
	pos["l23"] =  "a17a18a19a20"
	pos["l22"] =  "i21h21g21f21"
	pos["l21"] =  "e21d21c21b21"
	pos["l20"] =  "i22h22g22f22"
	pos["l19"] =  "e22d22c22b22"
	pos["l18"] =  "i23h23g23f23"
	pos["l17"] =  "e23d23c23b23"
	pos["l16"] =  "i24h24g24f24"
	pos["l15"] =  "e24d24c24b24"
	pos["l14"] =  "a21a22a23a24"
	pos["l13"] =  "i25h25g25f25"
	pos["l12"] =  "e25d25c25b25"
	pos["l11"] =  "i26h26g26f26"
	pos["l10"] =  "e26d26c26b26"
	pos["l09"] =  "i27h27g27f27"
	pos["l08"] =  "e27d27c27b27"
	pos["l07"] =  "i28h28g28f28"
	pos["l06"] =  "e28d28c28b28"
	pos["l05"] =  "a25a26a27a28"
	pos["l04"] =  "i29h29g29f29"
	pos["l03"] =  "e29d29c29b29"
	pos["l02"] =  "i30h30g30f30"
	pos["l01"] =  "e30d30c30b30"
	pos["l00"] =  "i31h31g31f31"
	pos["c3"] =   "e31d31c31b31"
	pos["c2"] =   "i32h32g32f32"
	pos["c1"] =   "e32d32c32b32"
	pos["c0"] =   "a29a30a31a32"

#	keys is indexed by <board #> <bank> <board type>
#	and yields an index into  a particular pos string
#	for example, board 0, bit 0 on an mk4118 board
#	gives a key of 4.  If the bit in error was c0, then
#	the chip in error is a32 (from the 4th group of 3
#	in pos["c0"].  To change this map, create new keys
#	and (if necessary) append to the pos entries.
#	If it could be more than one chip, then use a multiple
#	digit key (e.g, see the keys for the mk4108 board).

	keys["00mk4118"] = "4"
	keys["20mk4118"] = "4"
	keys["40mk4118"] = "4"
	keys["60mk4118"] = "4"
	keys["80mk4118"] = "4"
	keys["a0mk4118"] = "4"
	keys["c0mk4118"] = "4"
	keys["e0mk4118"] = "4"
	keys["01mk4118"] = "2"
	keys["21mk4118"] = "2"
	keys["41mk4118"] = "2"
	keys["61mk4118"] = "2"
	keys["81mk4118"] = "2"
	keys["a1mk4118"] = "2"
	keys["c1mk4118"] = "2"
	keys["e1mk4118"] = "2"
	keys["10mk4118"] = "3"
	keys["30mk4118"] = "3"
	keys["50mk4118"] = "3"
	keys["70mk4118"] = "3"
	keys["90mk4118"] = "3"
	keys["b0mk4118"] = "3"
	keys["d0mk4118"] = "3"
	keys["f0mk4118"] = "3"
	keys["11mk4118"] = "1"
	keys["31mk4118"] = "1"
	keys["51mk4118"] = "1"
	keys["71mk4118"] = "1"
	keys["91mk4118"] = "1"
	keys["b1mk4118"] = "1"
	keys["d1mk4118"] = "1"
	keys["f1mk4118"] = "1"
	 
	keys["00mk4116"] = "4"
	keys["20mk4116"] = "4"
	keys["40mk4116"] = "4"
	keys["60mk4116"] = "4"
	keys["80mk4116"] = "4"
	keys["a0mk4116"] = "4"
	keys["c0mk4116"] = "4"
	keys["e0mk4116"] = "4"
	keys["01mk4116"] = "2"
	keys["21mk4116"] = "2"
	keys["41mk4116"] = "2"
	keys["61mk4116"] = "2"
	keys["81mk4116"] = "2"
	keys["a1mk4116"] = "2"
	keys["c1mk4116"] = "2"
	keys["e1mk4116"] = "2"
	keys["10mk4116"] = "4"
	keys["30mk4116"] = "4"
	keys["50mk4116"] = "4"
	keys["70mk4116"] = "4"
	keys["90mk4116"] = "4"
	keys["b0mk4116"] = "4"
	keys["d0mk4116"] = "4"
	keys["f0mk4116"] = "4"
	keys["11mk4116"] = "2"
	keys["31mk4116"] = "2"
	keys["51mk4116"] = "2"
	keys["71mk4116"] = "2"
	keys["91mk4116"] = "2"
	keys["b1mk4116"] = "2"
	keys["d1mk4116"] = "2"
	keys["f1mk4116"] = "2"
	 
	keys["00mk4108"] = "34"
	keys["20mk4108"] = "34"
	keys["40mk4108"] = "34"
	keys["60mk4108"] = "34"
	keys["80mk4108"] = "34"
	keys["a0mk4108"] = "34"
	keys["c0mk4108"] = "34"
	keys["e0mk4108"] = "34"
	keys["01mk4108"] = "12"
	keys["21mk4108"] = "12"
	keys["41mk4108"] = "12"
	keys["61mk4108"] = "12"
	keys["81mk4108"] = "12"
	keys["a1mk4108"] = "12"
	keys["c1mk4108"] = "12"
	keys["e1mk4108"] = "12"
	keys["10mk4108"] = "34"
	keys["30mk4108"] = "34"
	keys["50mk4108"] = "34"
	keys["70mk4108"] = "34"
	keys["90mk4108"] = "34"
	keys["b0mk4108"] = "34"
	keys["d0mk4108"] = "34"
	keys["f0mk4108"] = "34"
	keys["11mk4108"] = "12"
	keys["31mk4108"] = "12"
	keys["51mk4108"] = "12"
	keys["71mk4108"] = "12"
	keys["91mk4108"] = "12"
	keys["b1mk4108"] = "12"
	keys["d1mk4108"] = "12"
	keys["f1mk4108"] = "12"
	}

	{csrc     = $1
	syndrome = substr (csrc,7,2)
	board    = substr (csrc,2,1)
	boardtype = boards[board]
	bank     = substr (hex [substr (csrc,3,1)],1,1)
	chips    = bit[syndrome]
	if (known[boardtype])
	{  where	 = pos[chips]
	   key	 = keys[board bank boardtype]
	   sbegin   = 3 * (substr(key,1,1) - 1) + 1
	   thechip  = substr(where,sbegin,3)
	   if (length(key) > 1) 
	   {   sbegin   = 3 * (substr(key,2,1) - 1) + 1
	       thechip  = thechip " and/or " substr(where,sbegin,3)
	   }
#	   printf "\n"
#	   print "csrc =      "	csrc
#	   print "syndrome =  "	syndrome
#	   print "board =     "	board
#	   print "bank =      "	bank
#	   print "chips =     "	chips
#	   print "locations = "	where
#	   print "boardtype = " boardtype
#	   print "key =       " key
#	   print "the chip is "	thechip
	   errors[board "-" thechip]++;
	}
	else 
	{
#	   printf "\n"
#	   print "Board type " boardtype " is unknown"
	   errors["unknown-unknown"]++;
	}
}
	
END { for (i in errors) {
	n = split(i,list,"-");
	printf "%d errors for board %s, chip %s\n",errors[i],list[1],list[2];
	}
}