Open Computing ``Hands-On'': ``Wizard's Grabbag'' Column: March 1994: Listings

Listing 1. The termprint utility provides a simple interface for printing one or more specified files on the local printer attached to the user's terminal.

A. Listing of the termprint Bourne shell program:

 1  #!/bin/sh
 2  # @(#) termprint  Print data on local-terminal printer
 3  # Author: Greg Hinkel , July 1991
 4  # Modified by Becca Thomas , November 1993
 5  $DBG_SH                         # Dormant debugging directive (Apr. 92)
 6  
 7  # Remind the user to put their printer online.
 8  echo "Make sure your printer is online." >/dev/tty; sleep 3
 9  
10  # Constants:
11  CTRL_L=`echo X | tr X '\014'`   # Store formfeed (Control-L) character
12  PrintOn=""                      # Hard code if don't have tput
13  PrintOff=""                     # Hard code if necessary
14  Tmpfile=/tmp/`basename $0`$$    # File containing text to print
15  
16  # Set trap to erase temp file and announce signal receipt:
17  trap 'rm -f $Tmpfile 2>/dev/null; exit' 0
18  trap 'echo "Interrupted by signal" >&2; exit' 1 2 3 15
19  
20  # Figure out how to do echo without newline:
21  if [ -z "`echo 'hello\c' | sed 's/[^c]//g'`" ]; then
22      N='';  C='\c'
23  else
24      N='-n';  C=''
25  fi
26  
27  # Process command-line argument(s):
28  case $# in
29      0)  # Naive users might invoke without arguments and no pipe:
30          [ -t 0 ] && echo "Usage: termprint file ...">&2 && exit 1
31          # It might be appropriate to replace Control-L with a
32          # Control-M to avoid ejecting blank pages:
33          (echo $N "$CTRL_L$C" ; cat -) > $Tmpfile ;; # Store stdin
34      *)  for File in $* ; do
35              if [ ! -r $File ]; then
36                  echo "Cannot read \"$File\"" >&2
37              else
38                  (echo $N "$CTRL_L$C" ; cat $File) >> $Tmpfile
39              fi
40          done ; shift ;;
41  esac
42  
43  #  Exit if there are no files to print:
44  if [ ! -s "$Tmpfile" ]; then
45      echo "Exiting, no readable files were located" >&2 ; exit 2
46  fi
47  
48  # Get local-terminal printer-control codes if not already defined:
49  : ${PrintOn:="`tput mc5`"}      # Get printer-on and
50  : ${PrintOff:="`tput mc4`"} # printer-off capability
51  
52  # Make sure the printer-on and printer-off capabilities exist:
53  if [ ! "$PrintOn" -o ! "$PrintOff" ]; then
54      echo "Your terminal \"$TERM\" can't control your local printer" >&2
55      exit 3
56  fi
57  
58  # Output printer-on code, files, formfeed, printer-off code:
59  echo $N "$PrintOn$C"; cat $Tmpfile;
60  echo $N "$CTRL_L$C"; echo $N "$PrintOff$C"

B. Sample usage:

$ termprint file

$ pr file | termprint

Listing 2. Source for Jerry Peek's tcap Program.

static char *rcsid = "$Header$";
/*
 **	tcap - termcaps for shell scripts.
 **	Usage: tcap [-a] cap
 */
#include <stdio.h>
#include <ctype.h>

extern char *tgetdefstr(), *tgetstr(), *tgoto();
extern int tgetdefnum(), tgetnum();

typedef struct tbl
{   char *str;
    short val;
} lookuptbl;

#define STRING  1
#define STR1ARG 2
#define STR2ARG 3
#define NUMBER  4
#define FLAG    5

lookuptbl tcaps[] = {
	"AL",  STR1ARG,
	"Bj",  STRING,
	"Bl",  STRING,
	"Br",  STRING,
	"CC",  STRING,
	"Cj",  STRING,
	"CM",  STR2ARG,
	"DC",  STR1ARG,
	"DL",  STR1ARG,
	"DO",  STR1ARG,
	"EP",  FLAG,
	"Ge",  STRING,
	"Gs",  STRING,
	"HD",  FLAG,
	"Hl",  STRING,
	"IC",  STR1ARG,
	"K1",  STRING,
	"K2",  STRING,
	"K3",  STRING,
	"K4",  STRING,
	"K5",  STRING,
	"LC",  FLAG,
	"LE",  STR1ARG,
	"Lj",  STRING,
	"NL",  FLAG,
	"OP",  FLAG,
	"RI",  STR1ARG,
	"Rj",  STRING,
	"SF",  STR1ARG,
	"SR",  STR1ARG,
	"Tj",  STRING,
	"Tl",  STRING,
	"Tr",  STRING,
	"UC",  FLAG,
	"UP",  STR1ARG,
	"Vl",  STRING,
	"Xc",  STRING,
	"ae",  STRING,
	"al",  STRING,
	"am",  FLAG,
	"as",  STRING,
	"bc",  STRING,
	"bl",  STRING,
	"bs",  FLAG,
	"bt",  STRING,
	"bw",  FLAG,
	"cd",  STRING,
	"ce",  STRING,
	"ch",  STR1ARG,
	"cl",  STRING,
	"cm",  STR2ARG,
	"co",  NUMBER,
	"cr",  STRING,
	"cs",  STR2ARG,
	"ct",  STRING,
	"cv",  STR1ARG,
	"dB",  NUMBER,
	"dC",  NUMBER,
	"dF",  NUMBER,
	"dN",  NUMBER,
	"dT",  NUMBER,
	"dV",  NUMBER,
	"da",  FLAG,
	"db",  FLAG,
	"dc",  STRING,
	"dl",  STRING,
	"dm",  STRING,
	"do",  STRING,
	"ds",  STRING,
	"ec",  STR1ARG,
	"ed",  STRING,
	"ei",  STRING,
	"eo",  FLAG,
	"es",  FLAG,
	"ff",  STRING,
	"fs",  STRING,
	"gn",  FLAG,
	"hc",  FLAG,
	"hd",  STRING,
	"ho",  STRING,
	"hs",  FLAG,
	"hu",  STRING,
	"hz",  FLAG,
	"ic",  STRING,
	"if",  STRING,
	"im",  STRING,
	"in",  FLAG,
	"ip",  STRING,
	"is",  STRING,
	"it",  NUMBER,
	"k0",  STRING,
	"k1",  STRING,
	"k2",  STRING,
	"k3",  STRING,
	"k4",  STRING,
	"k5",  STRING,
	"k6",  STRING,
	"k7",  STRING,
	"k8",  STRING,
	"k9",  STRING,
	"kA",  STRING,
	"kC",  STRING,
	"kD",  STRING,
	"kE",  STRING,
	"kF",  STRING,
	"kH",  STRING,
	"kI",  STRING,
	"kL",  STRING,
	"kM",  STRING,
	"kN",  STRING,
	"kP",  STRING,
	"kR",  STRING,
	"kS",  STRING,
	"kT",  STRING,
	"ka",  STRING,
	"kb",  STRING,
	"kd",  STRING,
	"ke",  STRING,
	"kh",  STRING,
	"kl",  STRING,
	"km",  FLAG,
	"kn",  NUMBER,
	"ko",  STRING,
	"kr",  STRING,
	"ks",  STRING,
	"kt",  STRING,
	"ku",  STRING,
	"l0",  STRING,
	"l1",  STRING,
	"l2",  STRING,
	"l3",  STRING,
	"l4",  STRING,
	"l5",  STRING,
	"l6",  STRING,
	"l7",  STRING,
	"l8",  STRING,
	"l9",  STRING,
	"le",  STRING,
	"li",  NUMBER,
	"ll",  STRING,
	"lm",  NUMBER,
	"ma",  STRING,
	"mb",  STRING,
	"md",  STRING,
	"me",  STRING,
	"mh",  STRING,
	"mi",  FLAG,
	"mk",  STRING,
	"ml",  STRING,
	"mm",  STRING,
	"mo",  STRING,
	"mp",  STRING,
	"mr",  STRING,
	"ms",  FLAG,
	"mu",  STRING,
	"nc",  FLAG,
	"nd",  STRING,
	"nl",  STRING,
	"ns",  FLAG,
	"nw",  STRING,
	"os",  FLAG,
	"pO",  STR1ARG,
	"pb",  NUMBER,
	"pc",  STRING,
	"pf",  STRING,
	"po",  STRING,
	"ps",  STRING,
	"pt",  FLAG,
	"rP",  STRING,
	"rc",  STRING,
	"rf",  STRING,
	"rp",  STR2ARG,
	"rs",  STRING,
	"sa",  STR2ARG,
	"sc",  STRING,
	"se",  STRING,
	"sf",  STRING,
	"sg",  NUMBER,
	"so",  STRING,
	"sr",  STRING,
	"st",  STRING,
	"ta",  STRING,
	"tc",  STRING,
	"te",  STRING,
	"ti",  STRING,
	"ts",  STR1ARG,
	"uc",  STRING,
	"ue",  STRING,
	"ug",  NUMBER,
	"ul",  FLAG,
	"up",  STRING,
	"us",  STRING,
	"vb",  STRING,
	"ve",  STRING,
	"vi",  STRING,
	"vs",  STRING,
	"vt",  NUMBER,
	"wi",  STRING,
	"ws",  NUMBER,
	"xb",  FLAG,
	"xn",  FLAG,
	"xo",  FLAG,
	"xr",  FLAG,
	"xs",  FLAG,
	"xt",  FLAG,
	"xv",  FLAG,
	"xx",  FLAG,
};

putx(c) { putchar (c); }

main (argc, argv)
    int argc;
    char **argv;
{
    char tcbuf[1024];
    char *cp, *arg;
    int i, tgetnum(), tgetflag();
    static int aflag = 0;

    if (tgetent(tcbuf, getenv ("TERM")) <= 0) {
	(void) fprintf (stderr, "tcap: cannot find termcap for %s.\n", 
		getenv ("TERM"));
	exit (1);
    }
    cp = (char *) malloc (256);
    argv++;
    while (*argv) {
	arg = *argv++;
	if (strcmp (arg, "-a") == 0) {
	    aflag = 1;
	    continue;
	}
	i = lookup (arg, tcaps);
	if (i < 0) {
	    (void) fprintf (stderr, "tcap: no such termcap: %s\n", arg);
	    exit (2);
	}
	switch (tcaps[i].val & 017) {
	case STRING:
	    if (aflag)
		show (tgetdefstr (arg, &cp));
	    else
		tputs (tgetdefstr (arg, &cp), 1, putx);
	    break;
	case STR1ARG:
	    if (aflag)
		show (tgetstr (arg, &cp));
	    else
		if (argv != NULL && isdigit (**argv))
		    tputs (tgoto (tgetstr (arg, &cp),
			atoi (*argv++), 0), 1, putx);
		else {
		    (void) fprintf (stderr, "tcap: error in arguments to %s\n",
				arg);
		    exit(3);
		}
	    break;
	case STR2ARG:
	    if (aflag)
		show (tgetstr (arg, &cp));
	    else
		if (argv != NULL && argv[1] != NULL &&
		    isdigit (**argv) && isdigit (*(argv[1])))
		    tputs (tgoto (tgetstr (arg, &cp),
			atoi (*argv++), atoi (*argv++)), 1, putx);
		else {
		    (void) fprintf (stderr, "tcap: error in arguments to %s\n",
				arg);
		    exit(3);
		}
	    break;
	case NUMBER:
	    if (aflag)
		(void) printf ("%d\n", tgetdefnum (arg));
	    break;
	case FLAG:
	    if (aflag)
		(void) printf (tgetflag (arg) ? "true\n" : "false\n");
	    break;
	}
    }
    exit (0);
}



#define MAXLUPN 3      /* longer than longest possible name */

/* Lookup name in table.  Will take nonambiguous abbreviations.  If
   you want to insist that a certain table entry must be spelled
   out, enter it twice in the table.  Table entries must be sorted
   by name, and a name which is a substring of a longer name comes
   earlier in the table.  Accepts upper or lower case if table entry
   is lower case.

   Returns:
    > 0 table entry index
     -1 not found
     -2 ambiguous
*/
int lookup (name, table)
    char *name;
    lookuptbl *table;
{
    register char  *namptr,
		   *tblptr;
    int ind;
    int value = 0;
    short length;
    short longest = 0;
    int ambig = 0;
    char lname[MAXLUPN];

    if (name == NULL)
	return -1;
    namptr = name;
    tblptr = lname;
    for (;;) {
	if ((*tblptr++ = isupper (*namptr)? tolower (*namptr++): *namptr++)
	    == '\0')
	    break;
	if (tblptr >= &lname[MAXLUPN])
	    return -1;
    }

    for (ind = 0; (tblptr = table->str) != 0; table++, ind++) {
	namptr = lname;
	for (; *tblptr == *namptr; tblptr++, namptr++) {
	    if (*tblptr == '\0')
		break;
	}
	if (*namptr == '\0') {  /* end of name or exact match */
	    length = namptr - lname;
	    if (longest < length) {
		longest = length;
		ambig = 0;
		value = ind;
		if (*tblptr == '\0')
		    break;          /* exact match */
	    }
	    else /* longest == length */
		ambig = 1;
	}
	else if ( *namptr < *tblptr )
	    break;
    }
    if (ambig)
	return -2;
    if (longest)
	return value;
    return -1;
}

show (str)
    char *str;
{
    char c;

    if (str == (char *)0) {
	(void) printf ("NULL\n");
	return;
    }
    while (c = *str++ & 127)
	if (c < ' ') {
	    if (c == 27)
		(void) printf ("\n");
	    (void) printf ("^%c", c + '@');
	} else if (c == 127)
	    (void) printf ("^?");
	else
	    (void) printf ("%c", c);
    (void) printf ("\n");
    return;
}

char *
tgetdefstr (cap, ptr)
    char *cap, *ptr;
{
    char *x;
    static char *bs = "\b",
		*ht = "\t",
		*nl = "\n",
		*cr = "\r",
		*ff = "\f",
		*nu = "\0",
		*bl = "\007",
		*nlcr = "\n\r";

    if ((x = tgetstr (cap, ptr)) != (char *) 0)
	return (x);
    if (strcmp (cap, "pc") == 0)
	return (nu);
    if (strcmp (cap, "bc") == 0)
	return (bs);
    if (strcmp (cap, "ta") == 0)
	return (ht);
    if (strcmp (cap, "nl") == 0)
	return (nl);
    if (strcmp (cap, "cr") == 0)
	return (cr);
    if (strcmp (cap, "ff") == 0)
	return (ff);
    if (strcmp (cap, "nw") == 0)
	return (nlcr);
    if (strcmp (cap, "bl") == 0)
	return (bl);
    if (strcmp (cap, "ho") == 0)
	return (tgoto (tgetstr ("cm", ptr), 0, 0));
    if (strcmp (cap, "ll") == 0)
	return (tgoto (tgetstr ("cm", ptr), tgetnum ("li") - 1, 0));
    if (strcmp (cap, "rs") == 0)
	return (tgetstr ("is", ptr));
    if (strcmp (cap, "is") == 0)
	return (tgetstr ("rs", ptr));
    if (strcmp (cap, "rf") == 0)
	return (tgetstr ("if", ptr));
    if (strcmp (cap, "if") == 0)
	return (tgetstr ("rf", ptr));

    return ((char *) 0);
}


tgetdefnum (cap)
    char *cap;
{
    int x;

    if ((x = tgetnum (cap)) != -1)
	return (x);
    if (strcmp (cap, "ws") == 0)
	return (tgetnum ("co"));
    return (0);
}

Listing 3: A script can be used to manage .rhosts files by renaming them.

A. Listing of the script:

 1  #! /bin/sh
 2  # rhyes/rhno Enable/disable use of remote .rhosts file
 3  # Author: Jerry Peek, May 1992
 4  # set -x        # uncomment for debugging
 5  
 6  # Get name of invoked script:
 7  Thisprog="`basename $0`"
 8  
 9  # Get account name of invoking user:
10  if [ "$USER" ]; then
11      Username=$USER
12  elif [ "$LOGNAME" ]; then
13      Username=$LOGNAME
14  else
15      echo "Can't determine your account name." >&2; exit 2
16  fi
17  
18  # Determine home directory for user:
19  if [ "$HOME" ]; then
20      Homedir=$HOME
21  elif [ "$LOGDIR" ]; then
22      Homedir=$LOGDIR
23  else
24      echo "Can't determine your home directory name." >&2; exit 3
25  fi
26  
27  # Handle invocation without a remote host name:
28  case $# in
29      0)  # No argument specified, so rename local file:
30          case "$Thisprog" in
31              rhyes)  if [ ! -f $Homedir/.rhosts.moved ]; then
32                          echo "Exiting, no $Homedir/.rhosts.moved" >&2
33                          exit 2
34                      fi
35                      mv $Homedir/.rhosts.moved $Homedir/.rhosts ;;
36              rhno)   if [ ! -f $Homedir/.rhosts ]; then
37                          echo "Exiting, no $Homedir/.rhosts" >&2
38                          exit 2
39                      fi
40                      mv $Homedir/.rhosts $Homedir/.rhosts.moved ;;
41              *)  echo "$Thisprog: Invalid program name" >&2
42                  exit 1 ;;
43          esac
44          exit 0 ;;
45  esac
46  
47  # Create proper file-name order for rename operation:
48  case "$Thisprog" in
49      rhyes)  Cmdargs=".rhosts.moved .rhosts" ;;
50      rhno)   Cmdargs=".rhosts .rhosts.moved" ;;
51      *)      echo "$0: Help!  Shouldn't get here!" 1>&2
52              exit 1 ;;
53  esac
54  
55  # Perform operation for all remote hosts:
56  for host
57      do
58          echo "Connecting to $host ..."
59          cat << ENDCMDS | ftp -n $host   # Don't use .netrc
60      user $Username
61      rename $Cmdargs
62      quit
63  ENDCMD
64  done

B. Sample usage session:

%  rhyes snake 
Password:   ...type snake password
%  rsh snake some-command
    ...
%  rhno snake 
Password:   ...type snake password
%  rsh snake some-command
Permission denied.
% []

Copyright © 1995 The McGraw-Hill Companies, Inc. All Rights Reserved.
Edited by Becca Thomas / Online Editor / UnixWorld Online / beccat@wcmh.com

[Go to Contents] [Search Editorial]

Last Modified: Wednesday, 23-Aug-95 17:09:29 PDT