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.