#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README Makefile spr.c sprint.1
# Wrapped by steveb@shade on Tue Aug  7 12:57:38 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3379 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
XSpr is a replacement utility for /usr/bin/sprint, the screenprinting
Xprogram on your AT&T UNIX-PC.  As distributed, it can do a screen
Xdump in Epson 24-pin LQ format (180x180 dpi) or it can dump the
Xscreen into a file using the Portable Bitmap (PBM) file format.
X
XIn order to compile spr, you will need to have installed
Xthe PBMPLUS package (22nov89 distribution) from Jef Poskanzer
X(jef@well.sf.ca.us) which was posted not too long ago to
Xcomp.sources.unix.  Specifically, you will need the library
X(libpbm.a) from that package, which contains most of the
XPBM-specific routines.
X
XNote that you have an option when compiling the PBMPLUS package
Xwhether you want ASCII data files or binary data files.  I
Xstrongly recommend the binary format PBM data files; they should
Xbe about 8 times smaller than the ASCII version.  This does
Xmean that you can't send PBM files through the mail as-is,
Xhowever if you have an image of any size you wouldn't want to
Xdo that anyway!
X
XAlso regarding the PBMPLUS package: the actual utility programs
Xthemselves are NOT required.  The Makefile assumes that you have
Xinstalled libpbm.a in /usr/lib, but that is the only explicit
Xneed for the PBMPLUS package.  However, the PBM utilities
Xare very handy to have around if you want to look at Sun raster
Ximages, Macpaint pictures, X bitmaps or whatever, especially
Xif you also compile pbmto3b1, also distributed by me.
X
XSpr is installed as /usr/bin/sprint (make sure to save the old
Xone just in case!)  It is called when <SHIFT> <PRINT> is pressed
Xon the console.  At this point the screen contents are dumped
Xinto memory, and an options window will pop up.  The default
Xoption is to print the image to the printer (Epson_R) using the
Xdouble-height option to make the print easier to read.  This
Xwindow is implemented using standard form(3) TAM calls.  Specifying
Xa filename in this window causes the image to be written to a file
Xin PBM format instead.
X
XN.B.:  if the filename you give is not absolute (i.e. doesn't start
Xwith a '/'), it will be written into /usr/tmp.  This is because
Xspr is called from WMGR and not the process in the current
Xwindow, therefore there is no way for spr to know what your idea of
Xthe current directory is!
X
Xsprint can also be invoked from the command line by root or the
Xconsole user's id.  See the man page for details.
X
XTo invoke, simply:
X
X	sprint -d -f sprint.out
Xor
X	Press <SHIFT> and <PRINT> keys at the same time.
X
X
XTO INSTALL:
X
X1.	Edit the Makefile and make sure the compiler variables are
X	set correctly (use the set for gcc if you have it; settings
X	for ccc and plain cc are also included, though not tested
X	very well.)  Check the setting of the PBMLIB variable to
X	make sure it points to your libpbm.a.  Check the LPRCMD
X	definition in the Makefile to make sure it's appropriate for
X	your system.  It should be a command that takes standard
X	input and dumps all 8 bits to your Epson.  (i.e. raw)
X
X2.	make
X
X3.	Barring any problems, you should have an 'sprint' executable.
X	As root, do 'cp /usr/bin/sprint /usr/bin/sprint.att' to make
X	a backup copy of the original sprint, then
X	'mv sprint /usr/bin/sprint' to install spr.
X
X4.	Send all bug reports/fixes/comments/suggestions to me at the
X	address below.
X
X
XHave fun!
X
X
X			----------------------------
X			Steve Barber
X			steveb@shade.ann-arbor.mi.us
X			...!sharkey!shade!steveb
X			----------------------------
END_OF_FILE
if test 3379 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1279 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X#
X# Makefile for "spr", the /usr/bin/sprint replacement for Epson 24-pin printers.
X# Copyright (C) 1990 by Stephen W. Barber   steveb@shade.ann-arbor.mi.us
X#
X
X# Set LPRCMD below to be the command to pipe printer output to.
XLPRCMD=-DLPRCMD=\""/usr/bin/lp -dEpson_R"\"
X
X###############################################################################
X# Use these options if you have gcc
XCC=gcc
XCFLAGS=$(LPRCMD) -O -fstrength-reduce -fcombine-regs
XLDFLAGS=-s -shlib
XLIBS=-lpbm
X###############################################################################
X# Use these options if you have ccc  (NOT TESTED)
X#CC=ccc
X#CFLAGS=$(LPRCMD) -O
X#LDFLAGS=-s
X#LIBS=-lpbm
X###############################################################################
X# Use these options if you don't have either gcc or ccc  (NOT TESTED)
X#CC=cc
X#CFLAGS=$(LPRCMD) -O
X#LDFLAGS=-s
X#LIBS=-lpbm
X###############################################################################
X
X
Xall:	sprint sprint.1
X
Xsprint:	spr.o /usr/lib/libpbm.a
X	$(CC) $(LDFLAGS) spr.o -o sprint $(LIBS)
X
Xspr.o:	spr.c
X	$(CC) $(CFLAGS) -c spr.c
X
Xsprint.1:	s.spr.1
X	get s.spr.1
X	mv -f spr.1 sprint.1
X
Xclean:
X	rm -f spr.o sprint a.out core
X
Xshar:	spr.shar
X
Xspr.shar:	README Makefile spr.c sprint.1
X	shar -b -o spr.shar README Makefile spr.c sprint.1
END_OF_FILE
if test 1279 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'spr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'spr.c'\"
else
echo shar: Extracting \"'spr.c'\" \(11109 characters\)
sed "s/^X//" >'spr.c' <<'END_OF_FILE'
X/******************************************************************************
X ******************************************************************************
X
X				    spr.c
X
X       A replacement screendump program for the AT&T UNIX-PC (7300/3B1).
X
X			      Copyright (C) 1990 by
X				Stephen W. Barber
X			  steveb@shade.Ann-Arbor.MI.US
X
X ******************************************************************************
X ******************************************************************************/
X
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <string.h>
X#include <memory.h>
X#include <ctype.h>
X#include <tam.h>
X#include <form.h>
X#include <kcodes.h>
X#include <status.h>
X#include <sys/types.h>
X#include <utmp.h>
X#include <pwd.h>
X
X
X/*************************************************************************/
X
Xtypedef enum { false = 0, true = 1} bool;
X
X
X#ifndef LINT
Xstatic char sccsid[] = "@(#)spr.c	1.11";
X#endif
X
Xstatic char WIN_LABEL[] =
X    "spr.c screen dump utility 1.11 (C) 1990 by Stephen W. Barber";
X
X/* Command to pipe printer output to */
Xstatic char LPR_STRING[] =	LPRCMD;	   /* LPRCMD defined in Makefile */
X
X/* executing from the command line? */
Xbool cmdline;
X
Xchar double_result[9];
Xchar filename_result[256];
Xchar pathname[256];
X
Xchar *empty_filename = "";
Xchar *yes_string = "Yes";
Xchar *no_string = "No";
X
Xchar errorstring[127];
X
X/* structures for menus and forms */
X
Xstatic mitem_t yesno_items[3] =
X{
X	"Yes", 0, 1,
X	"No", 0, 2,
X	(char *)NULL, 0, 0
X};
X
Xmenu_t double_yn_menu =
X{
X    NULL, NULL, "Select <Yes> or <No> and press <Enter>:", 0, 1,
X    0, 0, M_SINGLE | M_NOHELP | M_NORESIZE, {0}, 0, NULL, 0, 0, 0,
X    &yesno_items[0], &yesno_items[0], NULL
X};
X
Xfield_t option_fields[] =
X{
X    { /* double height? */
X	/* fl_name */	"Double height:",
X	/* fl_row */	0,
X	/* fl_ncol */	0,
X	/* fl_fcol */	15,
X	/* fl_len */	3,
X	/* fl_flags */	F_MONLY,
X	/* fl_value */	double_result,
X	/* fl_menu */	&double_yn_menu,
X	/* fl_prompt */	"Print 2 dots vertically for every horizontal dot?"
X    },
X    { /* filename, none=printer */
X	"Filename:", 1, 0, 15, 45, 0, filename_result, NULL,
X	"Name of PBM file (default prefix /usr/tmp) or blank line to print:"
X    },
X    { /* end of table */
X	(char *)NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL
X    }
X};
X
Xform_t options_form =
X{
X    /* f_label */	WIN_LABEL,
X    /* f_name */	"Screen Print Options",
X    /* f_flags */	F_NOHELP | F_WINNEW,
X    /* f_win */		0,
X    /* f_track */	0,
X    /* f_fields */	&option_fields[0],
X    /* f_curfl */	&option_fields[0]
X};
X
X
X/* option flags to be set after displaying the menu */
X
Xbool double_height;
X
X/* screen and printer bitmaps */
Xunsigned short screen_dump[348][45];
Xunsigned char pbuf[720][46];
X
X
X/****************/
X/* PROGRAM CODE */
X/****************/
X
X
X/*
X * errormsg(msg)
X *
X * Display an error message in a popup window.
X */
Xvoid errormsg(msg)
Xchar *msg;
X{
X    if (cmdline)
X	fprintf(stderr, "%s", msg);
X    else
X	eprintf(ST_OTHER, ST_DISPLAY, (char *)NULL, msg);
X}
X
X
X/*
X * filedump()
X *
X * Dump the screen dump to a PBM file.
X */
Xvoid filedump()
X{
X    unsigned int x_bit, x, x_word, y;
X    unsigned char out;
X    FILE *fp;
X    extern FILE *fopen();
X
X    /* PBM definitions */
X    typedef unsigned char bit;
X    bit row[720];
X    extern void pbm_writepbminit(), pbm_writepbmrow(), pbm_writepbm();
X
X#define BLACK	1
X#define WHITE	0
X
X    if ((fp = fopen(pathname, "w")) == NULL)
X    {
X	if (cmdline)
X	    perror(pathname);
X	else
X	    printf(" Error writing file\n %s !\nAborting.", pathname);
X	return;
X    }
X    else if (!cmdline)
X    {
X	printf(" \n Writing %s ...", pathname);
X	fflush(stdout);
X    }
X
X    /* write out the header information in PBM format */
X    pbm_writepbminit(fp, 720, double_height ? 696 : 348);
X
X    /* compute each PBM-format row, then write it to the file */
X    for (y = 0; y < 348; y++)
X    {
X	/* We compute each bitmask just once (16 computations total) and */
X	/* apply it across every word in the row, then go on to the next. */
X	for (x = 0, x_bit = 1; x < 16; x++, x_bit <<= 1)
X	{
X	    for (x_word = 0; x_word < 45; x_word++)
X	    {
X	        row[(x_word << 4) + x] =
X		    (((screen_dump[y][x_word] & x_bit) != 0) ? WHITE : BLACK);
X	    }
X	}
X
X	/* write the row for this y position to disk */
X	pbm_writepbmrow(fp, row, 720);
X
X	/* if double height, write it twice */
X	if (double_height)
X	    pbm_writepbmrow(fp, row, 720);
X    }
X
X    /* we're done! */
X    fclose(fp);
X}
X
X
X/*
X * printerdump()
X *
X * Dump the screen dump directly to the printer.
X */
Xvoid printerdump()
X{
X    unsigned short y_bit, y, x, y_base, x_bitmask, x_word, y_major;
X    unsigned char bckgnd, out;
X    FILE *pfp;
X    extern FILE *popen();
X
X    open("/dev/null", O_RDONLY);	/* These are to fix a bug in 	*/
X    open("/dev/null", O_WRONLY);	/* /usr/bin/lp - it won't do    */
X    dup(1);				/* anything unless stdio exists */
X    pfp = popen(LPR_STRING, "w");
X    if (!pfp)
X    {
X	sprintf(errorstring, "Couldn't open pipe to '%s'!  Aborted!",
X		LPR_STRING);
X	errormsg(errorstring);
X	return;
X    }
X
X    /* Set unidirectional mode <ESC>U<1>, 24/180th" line feeds <ESC>3<24> */
X    fputs("\033U\001\0333\030", pfp);
X
X    if (double_height)
X    {
X	for (y_major = 0; y_major < 87; y_major += 3)
X	{
X	    /* Send header for a line of 720w x 24h 180dpi graphics */
X	    fputs("\033*\047\320\002", pfp);
X
X	    for (x = 0; x < 720; x++)
X	    {
X		x_bitmask = (1 << (x & 15));
X		x_word = x >> 4;
X
X		for (y = 0; y < 3; y++)
X		{
X		    out = 0;
X		    y_base = ((y_major + y) << 2);
X
X		    for (y_bit = 0; y_bit < 4; y_bit++)
X		    {
X			/* We can get away without a bounds check here, */
X			/* it works out perfectly for 348x2 height      */
X			if ((screen_dump[y_base + y_bit][x_word] & x_bitmask)
X			      != 0)
X				out |= (192 >> (y_bit << 1));
X		    }
X		    /* spit out the data as we compute it */
X		    putc(out, pfp);
X		}
X	    }
X
X	    /* Go to the start of the next line */
X	    fputs("\r\n", pfp);
X	}
X    }
X    else
X    {
X	for (y_major = 0; y_major < 45; y_major += 3)
X	{
X	    /* Send header for a line of 720w x 24h 180dpi graphics */
X	    fputs("\033*\047\320\002", pfp);
X
X	    for (x = 0; x < 720; x++)
X	    {
X		x_bitmask = (1 << (x & 15));
X		x_word = x >> 4;
X
X		for (y = 0; y < 3; y++)
X		{
X		    out = 0;
X		    y_base = ((y_major + y) << 3);
X
X		    for (y_bit = 0; y_bit < 8; y_bit++)
X		    {
X			if ((y_base + y_bit < 348) &&
X			    (screen_dump[y_base + y_bit][x_word] & x_bitmask)
X			      != 0)
X				out |= (128 >> y_bit);
X		    }
X		    /* spit out the data as we compute it */
X		    putc(out, pfp);
X		}
X	    }
X
X	    /* Go to the start of the next line */
X	    fputs("\r\n", pfp);
X	}
X    }
X
X
X    /* space a little and reset the printer to bi-directional, 1/6" line feed */
X    fputs("\n\0332\033U", pfp);
X    putc('\0', pfp);
X    pclose(pfp);
X}
X
X
X
X/*
X *
X * MAIN PROGRAM
X *
X */
X
X
Xmain(argc, argv)
X    int argc;
X    char **argv;
X{
X    char *ptr;
X    int ret;
X    unsigned char **p;
X    bool done, isfile;
X    WSTAT saveset;
X    struct utmp *utp;
X    struct passwd *pwp;
X    char username[9];
X
X    extern char *ttyname(), *malloc();
X    extern struct utmp *getutent();
X    extern struct passwd *getpwnam();
X
X    while((utp = getutent()) != NULL)
X    {
X	if ((utp->ut_line[0] == 'w') ||
X			(!strncmp(utp->ut_line, "console", 7)))
X	{
X	    strncpy(username, utp->ut_user, 8);
X	    username[8] = '\0';
X	    pwp = getpwnam(username);
X	    if (!pwp)
X	    {
X		fprintf(stderr, "Who the heck are you anyway???\n");
X		exit(-1);
X	    }
X	    if ((setgid(pwp->pw_gid) < 0) || (setuid(pwp->pw_uid) < 0))
X	    {
X		fprintf(stderr, "%s: Permission denied\n", argv[0]);
X		exit(-1);
X	    }
X	    umask(0133);
X	    break;
X	}
X    }
X    if (!utp)
X    {
X	fprintf(stderr, "Couldn't find you in /etc/utmp?!\n");
X	exit(-2);
X    }
X
X    /* Find out if we're on the console */
X    ptr = ttyname();	/* returns "/dev/tty001" format string */
X    if (!ptr || (*(ptr + 5) != 'w'))
X    {
X	fprintf(stderr, "%s: Must be run from console\n", argv[0]);
X	exit(1);
X    }
X
X    /* First things first - dump the screen ASAP */
X    if ((ret = ioctl(0, WIOCREAD, &screen_dump[0][0])) < 0)
X    {
X	sprintf(errorstring,
X		"%s: ioctl(0, WIOCREAD) returned %d", argv[0], ret);
X	errormsg(errorstring);
X	exit(3);
X    }
X
X    /* Process arguments */
X    cmdline = false;
X    if (argc > 1)
X    {
X	int c;
X	bool print;
X	extern int getopt(), optind;
X	extern char *optarg;
X
X	cmdline = true;
X	print = false;
X	double_height = false;
X	pathname[0] = '\0';
X	optind = 1;
X	while ((c = getopt(argc, argv, "dpf:")) != EOF)
X	{
X	    switch(c)
X	    {
X		case 'd':
X		    double_height = true;
X		    break;
X		case 'p':
X		    print = true;
X		    break;
X		case 'f':
X		    strncpy(pathname, optarg, sizeof(pathname));
X		    break;
X		case '?':
X		    fprintf(stderr, "Huh?\n");
X		    break;
X	    }
X	}
X	if (strlen(pathname) > 0)
X	    filedump();
X	else
X	    print = true;
X
X	if (print)
X	    printerdump();
X
X	exit(0);
X    }
X
X    close(0);
X    close(1);
X    close(2);
X
X    if (open("/dev/window", O_RDWR) < 0)
X    {
X	perror(argv[0]);
X	exit(1);
X    }
X    dup(0);
X    dup(0);
X
X    winit();
X    keypad(0, 1);
X    wgetstat(0, &saveset);
X
X    /* initialize some of the forms defaults */
X    strcpy(double_result, yes_string);
X    strcpy(filename_result, empty_filename);
X
X    /* Now put up the options form */
X    if ((ret = form(&options_form, F_BEGIN)) < 0)
X    {
X	sprintf(errorstring,
X		"%s: Error %d starting form", argv[0], ret);
X	errormsg(errorstring);
X	wexit(5);
X    }
X
X    done = false;
X    while (!done)
X    {
X        if ((ret = form(&options_form, F_INPUT)) < 0)
X	{
X	    sprintf(errorstring,
X		    "%s: Error %d running form", argv[0], ret);
X	    errormsg(errorstring);
X	    wexit(3);
X	}
X
X	wcmd(0, "");
X
X	if (ret == '\012')
X	    done = true;
X	if ((ret == Cancl) || (ret == Close) || (ret == Exit))
X	    wexit(6);
X	
X	if (done)
X	{
X	    ptr = strtok(filename_result, " \t\n");
X	    isfile = (ptr && strlen(ptr));
X
X	    /* check to make sure we're not going to overwrite another file */
X	    /* assume a file is in /usr/tmp unless given as an absolute path */
X	    if (isfile)
X	    {
X		if (filename_result[0] != '/')
X		{
X		    strcpy(pathname, "/usr/tmp/");
X		    strcat(pathname, filename_result);
X		}
X		else
X		    strcpy(pathname, filename_result);
X
X		if (!access(pathname, 0))
X		{
X		    done = false;
X		    write(1, "\007\007", 2);
X		    wcmd(0, "FILE EXISTS, PLEASE CHOSE ANOTHER NAME.");
X		}
X	    }
X	}
X    }
X    ret = form(&options_form, F_END);
X
X    /* Did the user specify the double-height option? */
X    double_height = (tolower(double_result[0]) == 'y') ? true : false;
X
X    /* The form manager closed our window, so let's grab another... */
X    close(0);
X    close(1);
X    close(2);
X
X    if (open("/dev/window", O_RDWR) < 0)
X    {
X	wexit(10);
X    }
X    dup(0);
X    dup(0);
X
X    saveset.uflags &= ~NBORDER;
X    saveset.begx = saveset.begy = 10;
X    saveset.height = 3;
X    saveset.width = 60;
X    wsetstat(1, &saveset);
X
X    /* Now we can do the actual processing */
X
X    if (isfile)
X    {
X	/* We got some kind of a filename, so we'll try to save it */
X	filedump();
X    }
X    else
X    {
X	/* no filename - print the sucker */
X	puts("  \n  Spooling, please wait...");
X
X	printerdump();
X    }
X    
X    wexit(0);
X}
END_OF_FILE
if test 11109 -ne `wc -c <'spr.c'`; then
    echo shar: \"'spr.c'\" unpacked with wrong size!
fi
# end of 'spr.c'
fi
if test -f 'sprint.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sprint.1'\"
else
echo shar: Extracting \"'sprint.1'\" \(2477 characters\)
sed "s/^X//" >'sprint.1' <<'END_OF_FILE'
X.TH SPRINT 1 "18 April 1990"
X.SH NAME
X\fBsprint\fR - perform a screen dump to a PBM-format file or
Xto an Epson LQ printer.
X.SH SYNOPSIS
X/usr/bin/sprint - when started by the window manager
X
Xsprint [-d] [-p] [-f filename] - when issued by the user
X.SH DESCRIPTION
X.PP
X\fBsprint\fR can be invoked in one of two ways.  Usually it will be started
Xby the operating system when the user presses the <SHIFT> <PRINT> key
Xcombination.  Sometimes, however, the user may find it desirable to
Xissue \fBsprint\fR as a command.
X.PP
XWhen the user requests a screen dump by pressing <SHIFT> <PRINT>,
Xa window will pop up presenting two options to the user.
X.IP "\fBDouble height:\fR"
XIf the "Double height" value is set to "Yes", the image resulting from the
Xscreen dump will be twice as tall.  This option is provided to help
Xcompensate for the fact that the screen does not have a 1:1 aspect ratio.
XWhile not perfect, it does make text easier to read on the printed copy.
XWhen dumping to a file this option is probably unnecessary.
X.IP "\fBFilename:\fR"
XIf the user enters a filename, the screen is dumped to a file in Portable
XBitmap (PBM) format.  Otherwise, the screen will be dumped directly to the
Xprinter in Epson LQ (24-pin) format.  Filenames should be specified
Xexplicitly, since sprint is started up by the system, with no idea what
Xthe user's currect directory is.  If the supplied
Xfilename does not begin with a '/', the file will be written into /usr/tmp.
X.PP
XWhen issued as a command, \fBsprint\fR takes these arguments:
X.IP "\fB-d\fR"
XDouble height.  This option enables double-height mode.  See above for details.
X.IP "\fB-p\fR"
XPrint.  Causes the screendump to be passed to the printer in Epson LQ
Xformat.  This is the default unless -f is specified.
X.IP "\fB-f filename\fR"
XSpecifies a filename to dump the screen into.  The PBM (Portable Bitmap)
Xformat is used.
X.PP
X\fBsprint\fR takes precautions to prevent security breaches.  When invoked
Xas a command, it may only be run by the user logged in on the console
Xor by root.
X.SH "SEE ALSO"
Xlp(1), pbm(5)
X.SH AUTHOR
XCopyright (C) 1990 by Stephen W. Barber
X
XPermission to use, copy, modify, and distribute this software and its
Xdocumentation for any purpose and without fee is hereby granted, provided
Xthat the above copyright notice appear in all copies and that both that
Xcopyright notice and this permission notice appear in supporting
Xdocumentation.  This software is provided "as is" without express or
Ximplied warranty.
END_OF_FILE
if test 2477 -ne `wc -c <'sprint.1'`; then
    echo shar: \"'sprint.1'\" unpacked with wrong size!
fi
# end of 'sprint.1'
fi
echo shar: End of shell archive.
exit 0


