This is djf.c in view mode; [Download] [Up]
/* Djf--Deskjet 500 printer filter
* Reimer Mellin & Uwe Meyer-Gruhl August 1991 with help of Christian Baur
* based on iwf by:
*
* Eric P. Scott, San Francisco State University, November 1990
* Copyright 1990, 1991 by Eric P. Scott. All rights reserved.
*
* This file (and the accompanying djwraps.psw) are freely
* redistributable in their original, unmodified forms. The
* author grants you a nonexclusive, royalty-free license to use
* this software, and modify it as needed provided that this
* copyright notice remains, and any changes are clearly
* indicated as such. No part may be incorporated in products or
* packages sold for profit without express permission of the
* copyright holder.
*
* Send bug reports, enhancements, etc. to <eps@cs.sfsu.edu>
* and <ram@ramsys.sta.sub.org>
*
* This software makes certain assumptions that are valid in NeXT
* Software Release 2.0, and may not hold in future releases.
* NO WARRANTY is expressed or implied--use at your own risk!
*
* It's not the best code in the world--far from it--such is the
* price of working under time pressure...
*
* What it doesn't do:
* 8-bit ASCII
* trap SIGINT to guarantee writing accounting record
*
* Revision History
* 11/ 6/90 EPS 1.0 release
* 11/ 7/90 EPS 1.1 release
* fixed "creeping pixel" bug
* changed ysize default from 792 to length*12
* internal EPS 1.2
* <streams/error.h> => <objc/error.h>
* recognize R (Resolution) argument
* 3/28/91 EPS 2.0 release
* significant rewrite to use machportdevice
* instead of offscreen window
* add "sidedoor" code for no PublicWindowServer
*
* Deskjet revision History:
* August 91 ram 1.1
* adapted to DeskJet
* September 91 umg 1.2
* changes for PIN-optimization, cleanup, dither & halftone dicts by
* Christian Baur
* November 91 ram 1.3
* rewrite of compression-routines with help of pclcomp
* fixes for A4
* December 91 umg 1.4
* rewrite of compression part to improve speed
* more fixes for A4 (larger printable area)
* compile-time variables to support DJ+ and DJ
* December 91 ram 1.5
* ymaf (yet more A4 fixes, won 1/4" :-), final testing and bundling
* for release.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libc.h>
#include <limits.h>
#include <mach_error.h>
#include <pwd.h>
#include <signal.h>
#include <cthreads.h>
#include <servers/netname.h>
#include <windowserver/printmessage.h>
#include <sys/table.h>
#include <servers/bootstrap.h>
#import <dpsclient/dpsclient.h>
#import <dpsclient/psops.h>
#import <objc/error.h>
#ifndef lint
static char rcsid[] = "$Id: djf.c,v 1.5 91/12/06 01:10:05 ram Exp $";
static char sccsid_[] = "@(#)sidedoor.c\t1.0 (SFSU) 3/27/91";
#endif
/* moved to Makefile */
/* #define noUSE_1 /* slow & inefficient! */
/* #define USE_3 /* Disable for DJ+ and DJ */
int literal;
char *host;
int indent;
int length;
char *name;
int width;
int xsize, ysize;
int linect, pagect;
int status; /* exit status (0=ok; 1=reprint; 2=flush) */
port_t pport; /* port for machportdevice */
netname_name_t djfportname; /* name for machportdevice */
NXPrintPageMessage ppm; /* Mach messaging area */
#define KODMSGID 0xdeadbeef
mutex_t mutex1;
/*
* CR -> CR+LF, LF -> CR+LF
*/
static char setup[] = { 27, '&', 'k', '3', 'G' };
static char job_init[] = { 27, '&', 'l', '0', 'l', '6', 'd', '7', '2', 'p',
'0', 'e', '7', '1', 'F' };
/* sizing > a4 gives another 1/4" */
static char job_exit[] = { 27, '&', 'l', '1', 'L' };
static char page_init[] = { 27, '*', 'p', '0', 'x', 'p', '1', 'y', 'r', '1', 'A' }; /* *p0x1yr1a gives yet another 1/8" 'headroom' */
static char page_exit[] = { 27, '*', 'r', 'B', 27, '&', 'l', '0', 'H' };
#define sendsequence(s) (void) fwrite(s, 1, sizeof(s), stdout)
int main(int argc, char **argv)
{
extern void *malloc(); /* stupid ANSI!!! */
extern void minit75(int w, int h, char *portname);
extern void minit100(int w, int h, char *portname);
extern void minit150(int w, int h, char *portname);
extern void minit300(int, int, char *);
extern int optind;
extern char *optarg;
void _textpl(DPSContext ctx, char *buf, unsigned long count);
int c, res, l;
char *b;
FILE *af;
DPSContext pctx;
struct passwd *pw;
cthread_t rthread;/* reader thread */
static msg_header_t kod;
char buf[8192];
/* init some vars */
xsize = ysize = linect = pagect = status =
width = length = indent = literal = 0;
#ifdef DEBUG
{
int i;
(void) fprintf(stderr, "argc=%d,argv= ", argc);
for (i = 0; i < argc; i++)
(void) fprintf(stderr, "%s ", argv[i]);
(void) fprintf(stderr, "\n");
}
#endif
/* determine resolution from argv[0] */
b = (char *) rindex(argv[0], '/');
if (b == NULL)
b = argv[0];
else
b++;
if (sscanf(b, "dj%df", &res) != 1) {
res = 300; /* default resolution !! */
}
#ifdef DEBUG
(void) fprintf(stderr, "res = %d\n", res);
#endif
while ((c = getopt(argc, argv, "cf:h:i:l:n:p:w:x:y:R:")) != EOF) {
switch (c) {
/* see lpd(1) */
/* cifplot generated file ?? */
case 'c':
literal++;
break;
/* formatted file-name ?? */
case 'f': /* file--NeXT extension */
break;
/* hostname */
case 'h':
host = optarg;
break;
/* number of chars to indent */
case 'i':
indent = atoi(optarg);
break;
/* length in chars ?? */
case 'l':
length = atoi(optarg);
if (length > 198)
length = 198; /* 11" * 72 pt /4 pt */
break;
/* */
case 'n':
name = optarg;
break;
/* printer name */
case 'p': /* printer--NeXT extension */
break;
/* width in char ? */
case 'w':
width = atoi(optarg);
if (width > 266)
width = 266; /* 33.33cpi */
break;
/* width in pixel */
case 'x':
xsize = atoi(optarg);
break;
/* height in pixel */
case 'y':
ysize = atoi(optarg);
break;
/* resolution : 300|400 always 400 */
case 'R': /* Resolution--NeXT extension [2.0] */
res = atoi( optarg );
if( (res != 75) && (res != 100) && (res != 150) && (res != 300))
res = 300;
break;
default:
usage:
(void) fprintf(stderr, "Usage: %s [options] [acctfile]\n",
*argv);
(void) fputs("\t-c don't interpret control characters\n",
stderr);
(void) fputs("\t-hhost host name of job owner\n", stderr);
(void) fputs("\t-i# indent\n", stderr);
(void) fputs("\t-l# page length in lines\n", stderr);
(void) fputs("\t-nname login name of job owner\n", stderr);
(void) fputs("\t-w# page width in characters\n", stderr);
(void) fputs("\t-x# horizontal page size in pixels\n", stderr);
(void) fputs("\t-y# vertical page size in pixels\n", stderr);
exit(2); /* can't use <sysexits.h>!!! */
break;
}
}
af = (FILE *) NULL;
switch (argc - optind) {
case 0:
break;
case 1:
if (argv[optind][0] && !(af = fopen(argv[optind], "a"))) {
(void) perror(argv[optind]);
exit(2);
}
break;
default:
goto usage;
}
if (length <= 0)
length = 66; /* lines */
if (width <= 0)
width = 132; /* chars */
if (indent >= width)
indent = width - 1;
if (xsize <= 0 || xsize > (8 * res))
xsize = 8 * res;
if (ysize <= 0 || ysize > ( 11.315 * res)) /* 11.69 - 1/4 - 1/8 */
ysize = 11.315 * res; /* change to 11 - 1/4 - 1/8 for US Letter */
/* <stdio.h> declares this as int but man page says void */
(void) setvbuf(stdout, (char *) NULL, _IOFBF, 32768);
sendsequence(setup);
if ((c = getchar()) == EOF)
exit(0);
if (c != '%') {
normal: /* text mode filter */
(void) seteuid(getuid());
/* indent in chars, length = # lines */
#ifdef IWF
(void) printf("\033L%03u\033H%04u", indent, length * 24);
#else
(void) printf("\033&a%dL", indent);
#endif
/* width = # chars in line */
#ifdef IWF
putchar('\033'); /* set type size */
putchar(width <= 72 ? 'n' :
width <= 80 ? 'N' :
width <= 96 ? 'E' :
width <= 107 ? 'e' :
width <= 120 ? 'q' :
width <= 136 ? 'Q' :
width <= 144 ? 'p' : 'P');
/* tab stops */
for (l = 9; l < width; l += 8)
(void) printf("\033u%03u", l);
#else
/* TESTEN !!! */
(void) printf("\033(s%dH", width / 8);
#endif
do {
rerun:
switch (c) { /* "but it's one instr. on a VAX" */
case '\0':
case '\001':
case '\002':
case '\003':
case '\004':
case '\005':
case '\006':
case '\007':
case '\013':
case '\016':
case '\017':
case '\020':
case '\021':
case '\022':
case '\023':
case '\024':
case '\025':
case '\026':
case '\027':
case '\030':
case '\032':
case '\033':
case '\034':
case '\035':
case '\036':
case '\037':
putchar(literal ? c : ' ');
break;
case '\031': /* Only at Berkeley... */
if ((c = getchar()) == EOF) {
l = '\031';
putchar(literal ? l : ' ');
goto done;
}
if (c == '\001') {
(void) fflush(stdout);
(void) kill(getpid(), SIGSTOP);
continue;
}
putchar(literal ? '\031' : ' ');
goto rerun;
case '\n':
linect++;
if (linect < length)
goto anyway;
/* FALL THROUGH */
case '\f':
pagect++;
linect = 0;
/* FALL THROUGH */
case '\b': /* you expected intelligence? */
case '\t':
case '\r':
default:
anyway:
putchar(c);
break;
}
l = c;
} while ((c = getchar()) != EOF);
done:
switch (l) {
default:
putchar('\n');
linect++;
if (linect >= length)
pagect++;
/* FALL THROUGH */
case '\n':
case '\r':
putchar('\f');
pagect++;
/* FALL THROUGH */
case '\f':
break;
}
}
else {
/* Postscript mode */
int reader(any_t arg);
#ifdef DEBUG
(void) fprintf(stderr, "postscript mode: xsize = %d, ysize = %d\n",
xsize, ysize);
#endif
if ((c = getchar()) == EOF) {
(void) seteuid(getuid());
l = '%';
putchar(l);
goto done;
}
if (c != '!') {
putchar('%');
goto normal;
}
/* Now PostScript */
pctx = (DPSContext)NULL;
NX_DURING
/* attempt to connect to Window Server using defaults */
pctx = DPSCreateContext((void *)NULL, (void *)NULL,
_textpl, DPSDefaultErrorProc);
NX_HANDLER
if (NXLocalHandler.code != dps_err_cantConnect)
NX_RERAISE();
NX_DURING
void sidedoor();
sidedoor(); /* try to climb in through side door */
pctx = DPSCreateContext((void *)NULL, (void *)NULL,
_textpl, DPSDefaultErrorProc);
NX_HANDLER
if (NXLocalHandler.code != dps_err_cantConnect)
NX_RERAISE();
NX_ENDHANDLER
if (!pctx) {
/* This is so lame. NeXT should make _NXDpsReporter public!!! */
(void) fputs(
"DPS client library error: Could not form connection, host ", stderr);
(void) fputs((char *)NXLocalHandler.data2, stderr);
putc('\n', stderr);
}
NX_ENDHANDLER
if (!pctx)
exit(2);
DPSSetContext(pctx); /* per postscript.321 this is unneeded */
(void) seteuid(getuid());
if ((c = port_allocate(task_self(), &pport)) != KERN_SUCCESS) {
mach_error("port_allocate failed", c);
exit(2);
}
(void) sprintf(djfportname, "djf-%d", getpid());
if ((c = netname_check_in(name_server_port, djfportname,
PORT_NULL, pport)) != KERN_SUCCESS) {
mach_error("netname_check_in failed", c);
exit(2);
}
(void) printf("\033E\033*t%dR", res); /* reset, res DPI */
if (pw = getpwnam(name ? name : "nobody"))
DPSPrintf(pctx, "%d %d setjobuser\n", pw->pw_uid,
pw->pw_gid);
/* endpwent() ? */
#ifdef DEBUG
(void) fprintf(stderr, "calling minitxxx()\n");
#endif
switch (res) {
case 75:
minit75(xsize, ysize, djfportname); /* from djwraps.psw */
break;
case 100:
minit100(xsize, ysize, djfportname); /* from djwraps.psw */
break;
case 150:
minit150(xsize, ysize, djfportname); /* from djwraps.psw */
break;
case 300:
minit300(xsize, ysize, djfportname);
/* from djwraps.psw */
break;
default:
(void) fprintf(stderr,"djf: Unknown resolution of %d chosen.\n",res);
break;
}
DPSWaitContext(pctx);
#ifdef DEBUG
(void) fprintf(stderr, "making threads\n");
#endif
/*
* I don't want to rewrite things to use DPSAddPort() and friends, and C
* Threads are probably the lesser of several evils.
*/
mutex1 = mutex_alloc();
rthread = cthread_fork((cthread_fn_t) reader, (any_t) 0);
mutex_lock(mutex1);
#ifdef DEBUG
(void) fprintf(stderr, "after making thread\n");
#endif
DPSPrintf(pctx, "/-saveDJ-%d- save def\n/note {} def\n\
/envelope {} def\n%%%%BeginDocument: DJGraphic\n", getpid());
mutex_unlock(mutex1);
NX_DURING
#ifdef DEBUG
(void) fprintf(stderr, "before printing postscript\n");
#endif
b = buf;
*b++ = '%';
*b++ = '!';
l = 0; /* sick, disgusting! */
while ((c = getchar()) != EOF) {
*b++ = c;
if (c == '\n' || b > &buf[sizeof(buf)]) {
/* what a crock... */
if (buf[0] == '%') {
if (buf[1] == '%') {
if (!l)
DPSWaitContext(pctx);
l = 1;
}
}
else
l = 0;
DPSWritePostScript(pctx, buf, b - buf);
b = buf;
}
}
if (b > buf) {
*b++ = '\n';
DPSWritePostScript(pctx, buf, b - buf);
}
DPSWaitContext(pctx);
#ifdef DEBUG
(void) fprintf(stderr, "before showpage\n");
#endif
if (pagect == 0) { /* wrong, but expected */
mutex_lock(mutex1);
DPSPrintf(pctx, "\nshowpage\n");
mutex_unlock(mutex1);
DPSWaitContext(pctx);
}
NX_HANDLER
if (NXLocalHandler.code != dps_err_ps)
NX_RERAISE();
else {
mutex_lock(mutex1);
DPSPrintError(stderr,
(DPSBinObjSeq)(NXLocalHandler.data2));
putc('\n', stderr);
mutex_unlock(mutex1);
}
status = 2;
NX_ENDHANDLER
mutex_lock(mutex1);
DPSPrintf(pctx, "%%%%EndDocument\n-saveDJ-%d- restore\n",
getpid());
mutex_unlock(mutex1);
DPSWaitContext(pctx);
PSnulldevice();
DPSWaitContext(pctx);
/* fake "EOF" on port */
kod.msg_simple = TRUE;
kod.msg_size = sizeof kod;
kod.msg_type = MSG_TYPE_NORMAL;
kod.msg_local_port = PORT_NULL;
kod.msg_remote_port = pport;
kod.msg_id = KODMSGID;
if ((c = msg_send(&kod, MSG_OPTION_NONE, 0)) != SEND_SUCCESS) {
mutex_lock(mutex1);
mach_error("msg_send failed", c);
mutex_unlock(mutex1);
}
else
pagect = (int)cthread_join(rthread);
if (*djfportname &&
(c = netname_check_out(name_server_port, djfportname,
PORT_NULL)) != KERN_SUCCESS) {
mutex_lock(mutex1);
mach_error("netname_check_out failed", c);
mutex_unlock(mutex1);
}
(void) port_deallocate(task_self(), pport);
DPSDestroySpace(DPSSpaceFromContext(pctx));
}
if (af) {
if (name) {
mutex_lock(mutex1);
(void) fprintf(af, "%4d.00\t", pagect);
if (host)
(void) fprintf(af, "%s:", host);
(void) fprintf(af, "%s\n", name);
mutex_unlock(mutex1);
}
(void) fclose(af);
}
exit(status);
}
/*
* Beginn der Deskjet 500 Codierung;
* Hier erstmal alle statischen Variablen zur Compression
* werden nur von PrintPage() und PrintScanLine() benutzt
*/
#define MODES 4 /* Mode 0-3 */
static int in_mode; /* current mode */
static unsigned char *seed_row;
static unsigned char obuf1[1024], obuf2[1024];
static unsigned char *testrow = obuf1, *bestrow = obuf2;
static int testsize, bestsize;
/*
* Compression Routines taken from pclcomp by Tony Parkhurst
* Email address: tony@sdd.hp.com -or- hp-sdd!tony
*/
#ifdef USE_1
/*
** Output_1() does mode 1 compression (run length encoding)
*/
int
Output_1(src, dest, count)
unsigned char *src, *dest;
register int count;
{
unsigned char *optr = dest, *iptr;
int k,c;
iptr = src;
while ( count ){
c = *iptr++; /* get value to work with */
count--;
k = 0;
while ( *iptr == c && k < 255 && count ){
k++;
iptr++;
count--;
}
*optr++ = k; /* output repeat count */
*optr++ = c; /* output value */
}
count = optr - dest; /* for return value */
return ( count );
}
#endif
/*
******************************************************************************
**
** Output_2() does PCL compression mode 2 on the data.
** This mode is a combination of modes 0 and 1.
**
******************************************************************************
*/
int
Output_2(src, dest, count)
unsigned char *src, *dest;
register int count;
{
unsigned char *outptr, *inptr;
unsigned char *saveptr;
unsigned char data; /* data byte */
unsigned char lastbyte; /* last byte */
int repcount; /* repeat count */
int litcount; /* literal count */
/*
** src points to the intput data.
** dest points to the output buffer.
** count is the number of intput bytes.
*/
inptr = src;
outptr = dest;
/*
** Start loop thru data. Check for possible repeat at beginning.
*/
while ( count )
{
data = *inptr++; /* get value to work with */
count--;
repcount = 0; /* no repeat count yet */
/*
** Check for repeat, since we are not in the middle
** of a literal run, it does not have to be more than
** two bytes of similar data.
*/
while ( count && *inptr == data )
{
repcount++;
inptr++;
count--;
}
/*
** Now, if we are out of data (count == 0), then
** if the repeated byte was zero, then ignore it
** completely (don't bother outputing the trailing zeros).
**
** To always strip zero's, simply remove the "zerostrip"
** from the test.
*/
if ( count == 0 && data == 0)
break; /* done */
/*
** If there was a repeat (repcount > 0), then we
** can output the command here, otherwise, we
** need to go into literal run mode.
**
** Note: This is a while loop because the repeat count
** may actually be greater than 127.
*/
if ( repcount >= 1 ) /* repeat mode */
{
while (repcount > 127)
{
*outptr++ = 129; /* count 127 */
*outptr++ = data; /* value */
repcount-= 128; /* offset */
}
if (repcount > 0)
{
*outptr++ = 256 - repcount; /* count */
*outptr++ = data; /* value */
/*
** Now pop to the top of the loop
** looking for more repeat counts.
*/
continue; /* top of loop */
}
/*
** Special case. If we have arrived at this point,
** then repcount is now equal to 0. This means
** that when we entered this section, repcount
** was a multiple of 128 (i.e. 128 :-).
**
** This means that there were 129 identical bytes,
** so the output does a replicate of 127 which
** gives 128 bytes, and we now have one byte left
** over which should NOT be output as a repeat
** run, rather it should be merged into the following
** literal run (if it exists).
**
** So, we will simply fall thru to the next section
** of code which assumes that we are working on
** a literal run.
*/
}
/*
** Literal run. At this point, the current data byte
** does NOT match the following byte. We will transfer
** these non-identical bytes until:
**
** 1) we run out of input data (count == 0).
** 2) we run out of room in this output block (128)
** 3) we come across a value which occurs at least
** three times in a row. A value occuring only
** twice in a row does NOT justify dropping
** out of a literal run.
**
** Special case: If we run out of room in the output block
** (which is 128 bytes), the last two values are the same,
** AND there is more input, it makes sense to restart
** the repeat detector in case the following bytes are
** repeats of the two. A simple check of the following
** byte will determine this.
** (This case falls out with the test for triples below).
**
** Special case: If we run out of room in the output block
** (which is 128 bytes), the last value is the same as
** the next one on the input, then it is better to let
** that byte be used in a possible replicate run following
** the literal run. If the last byte matches ONLY the
** following byte, (and not the one after that, it is
** a wash, but for best results, we will test the
** following two bytes.
**
*/
litcount = 0;
saveptr = outptr++; /* save location of the command byte */
*outptr++ = data; /* save the first byte. */
lastbyte = data; /* remember for testing */
while ( count && litcount < 127 )
{
data = *inptr++;
count--;
litcount++;
*outptr++ = data;
/*
** Test to see if this byte matched the last one.
** If so, check the next one for a triple.
*/
if ( lastbyte == data && count && *inptr == data )
{
/*
** We have a triple, adjust accordingly.
**
** Add two bytes back onto the input.
*/
count += 2;
inptr -= 2;
outptr -= 2;
litcount -= 2;
break; /* out of loop */
}
lastbyte = data; /* save data byte */
}
/*
** Check the special case number 2 above.
*/
if ( litcount == 127 && count > 1 && data == *inptr
&& data == inptr[1] )
{
/* Restore the last byte to the input stream */
count += 1;
inptr -= 1;
outptr -= 1;
litcount -= 1;
}
/*
** Save the literal run count.
*/
*saveptr = litcount;
/*
** Now go back to the top and look for repeats.
*/
}
count = outptr - dest; /* for return value */
return ( count );
}
#ifdef USE_3
/*
** Output_3() does mode 3 compression (delta row encoding).
*/
int
Output_3( new, dest, count)
unsigned char *new, *dest;
int count;
{
unsigned char *sptr=seed_row, *nptr=new, *dptr=dest;
int i,j;
unsigned char command;
/* can't calc difference if no seed */
if (seed_row == NULL)
return INT_MAX;
while ( count > 0 ){
i = 0;
/* find first diff */
while ( *sptr == *nptr && i < count ){
i++;
sptr++;
nptr++;
}
if ( i >= count ) /* too far to find diff */
return(dptr - dest); /* bail */
count -= i;
/* now count how many bytes to change */
for ( j = 1; j < 8; j++) /* j == 0 is already known */
if ( j > count || sptr[j] == nptr[j] )
break;
j--; /* adjust */
command = (j << 5);
command += MIN( i, 31 );
*dptr++ = command;
if ( i == 31 )
*dptr++ = 0;
i -= MIN (i, 31);
while( i ){
*dptr++ = MIN ( i, 255 );
if ( i == 255 )
*dptr++ = 0;
i -= MIN ( i, 255 );
}
while (j-- >= 0){
*dptr++ = *nptr++;
sptr++;
count--;
}
}
return ( dptr - dest );
}
#endif
/*
* print a scanline and select the modes
*/
void PrintScanLine(char *buf, int anz)
{
int minmode;
unsigned char *temprow;
printf("\033*b"); /* prepare */
/* Anything is better than this */
bestsize = INT_MAX;
#ifdef USE_3
testsize = Output_3( buf, testrow, anz);
if (testsize < bestsize) {
temprow = testrow;
testrow = bestrow;
bestrow = temprow;
bestsize = testsize;
minmode = 3;
}
#endif
/* mode 2 is always tested */
testsize = Output_2( buf, testrow, anz);
if (testsize < bestsize) {
temprow = testrow;
testrow = bestrow;
bestrow = temprow;
bestsize = testsize;
minmode = 2;
}
#ifdef USE_1
/* Don't check mode 1 (it is almost never better than mode 2) and */
/* mode 0 (mode 2 is about 1% longer in worst case) */
testsize = Output_1( buf, testrow, anz);
if (testsize < bestsize) {
temprow = testrow;
testrow = bestrow;
bestrow = temprow;
bestsize = testsize;
minmode = 1;
}
#endif
/* Mode 0 is cheap and always there */
testsize = anz;
if (testsize < bestsize) {
bestrow = buf;
bestsize = testsize;
minmode = 0;
}
if ( in_mode != minmode ) {
printf("%1dm", minmode);
in_mode = minmode;
}
/* <esc>*b has already been output */
printf("%1dW", bestsize);
if ( fwrite( bestrow, 1, bestsize, stdout) < bestsize ) {
/* check for error and exit */
if ( ferror(stdout) )
{
perror("Output error");
exit(-2);
}
}
}
/*
* small improvement for speed:
* if we know that we are printing (one of the pins 0-49 is active) it is
* faster to print a null line, than skipping it via *b%dY. This way the
* printing head doesn't need to print, move vertically and restart printing.
*/
#define PINS 50
void PrintPage(void)
{
/* output the whole Page to the printer */
register char *sp, *p;
register int i;
int in_seq = -1, empty_lines = 0;
sendsequence(page_init); /* start plot at current position */
in_mode = -1; /* invalidate some vars */
seed_row = NULL;
for (i = ppm.pixelsHigh, sp = (char *) ppm.printerData;
i > 0; i--, sp += ppm.bytesPerRow) {
/* Im Druck einer 50er Zeile? */
if (in_seq >= 0) {
mutex_lock(mutex1);
PrintScanLine(sp, ppm.bytesPerRow);
mutex_unlock(mutex1);
/* Ende der ganzen Zeile? */
if (++in_seq == PINS)
in_seq = -1;
}
else {
for (p = sp + ppm.bytesPerRow - 1; p >= sp && *p == 0; p--)
;
/* Leere Zeile? */
if (p < sp)
empty_lines++;
else {
/* Volle Zeile nach leeren Zeilen */
if (empty_lines > 0) {
(void) fprintf(stdout, "\033*b%dY", empty_lines);
}
mutex_lock(mutex1);
PrintScanLine(sp, ppm.bytesPerRow);
mutex_unlock(mutex1);
empty_lines = 0;
/* Erster Pin */
in_seq = 0;
}
}
seed_row = sp;
}
sendsequence(page_exit); /* Eject page */
}
/* msg_receive blocks until something happens, so this runs in
* its own thread. I'm trying to do a minimum amount of mutex
* locking (set fingers=crossed).
*
* This code could stand a serious rethink...
*/
int reader(any_t arg)
{
register msg_return_t m;
sendsequence(job_init);
for (;;) {
ppm.msgHeader.msg_size = sizeof ppm;
ppm.msgHeader.msg_local_port = pport;
if ((m = msg_receive(&ppm.msgHeader, RCV_INTERRUPT |
RCV_NO_SENDERS, 0)) != RCV_SUCCESS) {
mutex_lock(mutex1);
mach_error("msg_receive failed", m);
mutex_unlock(mutex1);
break;
}
if (ppm.msgHeader.msg_id == KODMSGID)
break;
if (ppm.msgHeader.msg_id != NX_PRINTPAGEMSGID ||
ppm.printPageVersion != 3)
continue; /* munchers */
if (*djfportname) { /* recall send rights */
register kern_return_t s;
if ((s = netname_check_out(name_server_port,
djfportname, PORT_NULL)) != KERN_SUCCESS) {
mutex_lock(mutex1);
mach_error("netname_check_out failed", s);
mutex_unlock(mutex1);
}
*djfportname = '\0';
if (ppm.oolImageParam.msg_type_long_size != 8) {
/* woke up in the wrong universe... */
if (port_deallocate(task_self(), pport) ==
KERN_SUCCESS)
pport = PORT_NULL;
return (0);
}
}
if (ppm.pixelsWide > xsize)
ppm.pixelsWide = xsize; /* uh-oh! */
PrintPage();
pagect++;
/* unmap and ACK page */
(void) vm_deallocate(task_self(),
(vm_address_t) ppm.printerData,
(vm_size_t) ppm.oolImageParam.msg_type_long_number);
ppm.msgHeader.msg_simple = TRUE;
ppm.msgHeader.msg_size = sizeof ppm.msgHeader;
ppm.msgHeader.msg_type = MSG_TYPE_NORMAL;
ppm.msgHeader.msg_local_port = PORT_NULL;
ppm.msgHeader.msg_id = NX_PRINTPAGEMSGID;
if ((m = msg_send(&ppm.msgHeader, MSG_OPTION_NONE, 0)) !=
SEND_SUCCESS) {
mutex_lock(mutex1);
mach_error("msg_send failed", m);
mutex_unlock(mutex1);
break;
}
}
sendsequence(job_exit); /* Perforationssprung ein */
return pagect;
}
/* DPSCreateContext[WithTimeoutFromZone] looks in two places for
* a port to the Window Server:
*
* 1) The Bootstrap Server for "WindowServer"
* 2) The Network Name Server for "NextStep(tm) Window Server"
*
* If PublicWindowServer is *not* set, then (2) won't be checked
* in, and (1) will be checked in with a subset bootstrap port
* and available only to descendents of loginwindow (i.e.
* Workspace and its descendents).
*
* This horrible hack set us up to inherit from loginwindow, as
* if we were a proper descendent.
*
* Most is lifted straight from the 2.0 Reference.
* table() is undocumented according to NextAnswers.
*
* N.B. when a user with PublicWindowServer==No logs out, the
* subset port is destroyed and neither (1) nor (2) will work.
* No one said life was fair.
*
* This code *must* run as root; djf must be set-uid root if
* we're to be standalone (not running under control of lpd).
*
*/
/* this shouldn't ever be called... */
void _textpl(DPSContext ctx, char *buf, unsigned long count)
{
(void) write(2, buf, count);
}
void sidedoor()
{
register host_priv_t hpriv;
register unsigned int hidx, tidx;
processor_set_name_array_t hlist;
unsigned int hcount;
processor_set_t ppriv;
task_array_t tlist;
unsigned int tcount;
int pid, mypid;
port_t b;
struct tbl_procinfo pi;
if (!(hpriv = host_priv_self())) { /* must run as root! */
(void) fputs("couldn't get host privileged port\n", stderr);
return;
}
/* superuser privileges are not required beyond this point */
if (host_processor_sets(hpriv, &hlist, &hcount) != KERN_SUCCESS)
(void) fputs("couldn't get processor sets\n", stderr);
else {
mypid = getpid();
for (hidx = 0; hidx < hcount; hidx++) {
if (host_processor_set_priv(hpriv, hlist[hidx], &ppriv) !=
KERN_SUCCESS)
ppriv = hlist[hidx];
if (processor_set_tasks(ppriv, &tlist, &tcount) ==
KERN_SUCCESS) {
for (tidx = 0; tidx < tcount; tidx++) {
if (unix_pid(tlist[tidx], &pid) ==
KERN_SUCCESS && pid > 3) {
if (pid == mypid)
continue;
if (table(TBL_PROCINFO, pid, (char *)&pi, 1,
sizeof pi) == 1 &&
pi.pi_status == PI_ACTIVE && pi.pi_ppid == 1 &&
pi.pi_ttyd < 0 && pi.pi_uid == 0 &&
!strncmp(pi.pi_comm, "loginwindow", PI_COMLEN) &&
task_get_bootstrap_port(tlist[tidx], &b) ==
KERN_SUCCESS && b != PORT_NULL) {
if (task_set_bootstrap_port(task_self(), b) ==
KERN_SUCCESS)
bootstrap_port = b;
else
(void) port_deallocate(task_self(), b);
}
}
(void) port_deallocate(task_self(), tlist[tidx]);
}
(void) vm_deallocate(task_self(), (vm_address_t) tlist,
tcount * sizeof(port_t));
}
else
(void) fprintf(stderr,
"couldn't get tasks for processor set %d\n", hidx);
(void) port_deallocate(task_self(), ppriv);
if (hlist[hidx] != ppriv)
(void) port_deallocate(task_self(), hlist[hidx]);
}
(void) vm_deallocate(task_self(), (vm_address_t) hlist,
hcount * sizeof(processor_set_name_t));
}
(void) port_deallocate(task_self(), hpriv);
/* have I deallocated everything I should? */
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.