home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume22
/
popi
/
part06
< prev
next >
Wrap
Text File
|
1991-08-22
|
43KB
|
1,751 lines
Newsgroups: comp.sources.misc
From: Rich Burridge <richb@Aus.Sun.COM>
Subject: v22i045: popi - The Digital Darkroom, Part06/09
Message-ID: <1991Aug22.153121.15839@sparky.IMD.Sterling.COM>
X-Md4-Signature: a25b763670f84dfa349e2d1c6007b880
Date: Thu, 22 Aug 1991 15:31:21 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: Rich Burridge <richb@Aus.Sun.COM>
Posting-number: Volume 22, Issue 45
Archive-name: popi/part06
Environment: Xlib, Xview, SunView
Supersedes: popi: Volume 9, Issue 47-55
#! /bin/sh
# 1. Remove everything above the #! /bin/sh line
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh to create the files:
# ibmpc.c
# mgr.c
# news.c
# next.m
# This archive created: Wed Aug 21 10:36:03 EST 1991
#
#
export PATH; PATH=/bin:$PATH
#
if [ -f ibmpc.c ]
then
echo shar: will not over-write existing file ibmpc.c
else
echo shar: extracting 'ibmpc.c', 21588 characters
cat > ibmpc.c <<'Funky_Stuff'
/*LINTLIBRARY*/
#ifndef lint
static char sccsid[] = "@(#)ibmpc.c 1.2 90/12/28" ;
#endif
/* Popi device driver for a PC using one of:
* Borland Turbo C
* Microsoft C
* MIX Power C
* Written by Stephen Frede, Softway Pty Ltd.
*
* Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
* This version is based on the code in his Prentice Hall book,
* "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
* which is copyright (c) 1988 by Bell Telephone Laboratories, Inc.
*
* Permission is given to distribute these extensions, as long as these
* introductory messages are not removed, and no monies are exchanged.
*
* No responsibility is taken for any errors or inaccuracies inherent
* either to the comments or the code of this program, but if reported
* (see README file) then an attempt will be made to fix them.
*/
/*
* There is still some work to be done here:
* + vid_detect() needs to be written.
* + HGC code needs to be fixed properly.
* + other standard modes need to be added.
* + Dithering or something needs to be added for EGA (sim to CGA).
* + Handle image allocation properly with far pointers
* where appropriate (ie unavoidable).
*/
#if defined(__STDC__) && defined(__TURBOC__)
/* The user has (with commendable intentions) used the Turbo C
* ANSI compatibility flag. Unfortunately, we need the nonstandard
* extensions to include <graphics.h> and use far pointers.
*/
#include "Unfortunately, can't use ANSI compatibility flag."
#endif /* __STDC__ && __TURBOC__ */
#include "popi.h"
/* I don't know what token Power C defines to distinguish itself.
* But it does define a max() macro in stdlib.h include file.
* Hopefully no other vendor is silly enough to do this, so we
* can use that to distinguish Power C.
*/
#if defined(__STDC__) && defined(max)
#define __POWERC__ 1
#endif /* __STDC__ && max */
/* We assume that the compiler has these files header files. */
#include <dos.h>
#include <conio.h>
/* We only use the __TURBOC__ token to test for graphics related
* features from here on, so if we have an old version with no
* graphics support, just pretend we are a generic compiler.
*/
#if defined(__TURBOC__)
# if __TURBOC__ < 0x0200
# undef __TURBOC__
# endif /* __TURBOC__ < 0x0200 */
#endif /* __TURBOC__ */
#if __TURBOC__ || __POWERC__
# include <graphics.h>
#endif /* __TURBOC__ || __POWERC__ */
#if __MSC__
#include <graph.h>
#endif /* __MSC__ */
#if defined(__TURBOC__)
# ifndef BGIPATH
# define STRBGIPATH ""
# else
# define STR(x) #x
# define STRBGIPATH STR(BGIPATH)
# endif /* BGIPATH */
#endif /* __TURBOC__ */
#ifndef MK_FP
#define MK_FP(segment,offset) ((void far *) \
(((unsigned long)(segment) << 16) | (unsigned)(offset)))
#endif /* MK_FP */
/* These are the exportable routines used by the popi program.
*
* disp_init(argc, argv) - called from main at the start.
* disp_finish() - called from main prior to exit.
* disp_imgstart() - called prior to drawing an image.
* disp_imgend() - called after drawing an image.
* disp_putline(lines, y) - to draw an image scanline triple.
* disp_getchar() - to get the next character typed.
* disp_prompt() - display popi prompt and clear input buffer.
* disp_error(errtype,pos) - display error message.
* disp_percentdone(n) - display percentage value of conversion.
*/
/*
* Bios function call definitions
*/
#define BIOS_VIDFN 0x10 /* Video functions */
#define VID_PALETTE 0x10 /* palette access function */
#define PAL_SETPAL 0x00 /* update single palette register */
#define PAL_SETPALBLOCK 0x02 /* update all palette registers */
#define PAL_GETPALBLOCK 0x09 /* read all palette registers */
#define PAL_GETDACBLOCK 0x17 /* read current VGA DAC values */
#define PAL_SETDACBLOCK 0x12 /* set new VGA DAC values */
#define VID_SETPIXEL 0x0C /* store pixel value */
#define VID_DISPLAY 0x1A /* video display combination */
#define VID_SUBSYSTEM 0x12 /* video subsystem configuration */
/*
* Arguments to the vid_vgapalette and vid_setpalette functions
*/
#define PAL_SAVE 0 /* Save existing values */
#define PAL_RESTORE 1 /* Restore saved values */
#define PAL_SETGREY 2 /* Set greyscale mapping */
#define PAL_SETLIN 3 /* Set 1:1 mapping (vid_setpalette) */
/* Bios Addresses */
#define SEG_VIDBIOS 0x0040 /* Segment of video BIOS addresses */
#define BIOSADDR_MODE 0x0049 /* Current BIOS video mode number */
#define BIOSADDR_CRTCPORT 0x0063 /* Port Address of CRTC */
/* Fixed port addresses */
#define HGC_SWITCH 0x03BF
/* Prototypes for local functions */
void vid_vgapalette P((int));
void vid_setpalette P((int));
void vid_setmode P((unsigned char));
void vid_sethgc P((void));
void vid_setpixel P((int, int, pixel_t));
unsigned char vid_detect P((void));
/* Array containing threshold values for dithering. */
pixel_t thresh[BITSPERPIXEL][BITSPERPIXEL] =
{
{ 0, 128, 32, 160, 8, 136, 40, 168, },
{ 192, 64, 224, 96, 200, 72, 232, 104, },
{ 48, 176, 16, 144, 56, 184, 24, 152, },
{ 240, 112, 208, 80, 248, 120, 216, 88, },
{ 12, 140, 44, 172, 4, 132, 36, 164, },
{ 204, 76, 236, 108, 196, 68, 228, 100, },
{ 60, 188, 28, 156, 52, 180, 20, 148, },
{ 252, 124, 220, 92, 244, 116, 212, 84, },
};
struct VidDriver
{
unsigned char bios_mode; /* Bios mode no. */
unsigned int xsize, /* Pixels/scanline */
ysize; /* Scanlines/image */
/* Segment to which screen buffer is mapped */
unsigned int ScreenMem;
unsigned int interlace, /* no. lines interlaced */
interlace_offset; /* memory offset for interlace */
unsigned char PixelsPerByte;
};
static struct VidDriver VidDrivers[] =
{
#define VID_VGA 0
{
0x13, 320, 200, 0xA000, 1, 0, 1,
},
#define VID_EGA 1
{
0x10, 640, 350, 0xA000, 2, 0x2000, 8,
},
#define VID_CGA 2
{
0x06, 640, 200, 0xB800, 2, 0x2000, 8,
},
#define VID_MDA 3
{
0x06, 640, 200, 0xB800, 2, 0x2000, 8,
},
#define VID_MCGA 4
{
0x06, 640, 200, 0xB800, 2, 0x2000, 8,
},
#define VID_STD 4 /* Last standard adapter */
/* From here on, adapters have no bios support. The bios
* number will be stored in the appropriate place in the video
* bios data area (this is useful eg if a mouse is being used,
* so it gets the graphics cursor correct).
*/
#define VID_HGC 5
{
0x06, 720, 348, 0xB000, 4, 0x2000, 8,
},
};
#define VID_NONE -1 /* Unknown video adapter */
/* When VidAdapter is VID_LIB, use compile-time dependant
* library routines. For example, the Turbo C graphics library
* allows custom drivers to be added for nonstandard adapters.
*/
#define VID_LIB -2
static struct VidDriver
*VidDriver = 0;
static int
VidAdapter = VID_NONE,
vid_xbytes,
vid_xoff_bytes,
vid_yoff;
#if __TURBOC__
static int
tc_driver,
tc_mode,
tc_error;
#endif /* __TURBOC__ */
static unsigned char far
*ScreenMem;
/* Pointer to current mode in Bios video display data area */
static char far
*VidModeBiosAddr = MK_FP(SEG_VIDBIOS, BIOSADDR_MODE);
/* Pointer to CRTC register port number in Bios dideo display area */
static short far
*CrtcPortBiosAddr = MK_FP(SEG_VIDBIOS, BIOSADDR_CRTCPORT);
static char
VidInitMode;
/*
* Routine to map VGA palette registers (256 colour mode)
* to and from a greyscale display.
*/
#define BITSPERBYTE 8
#define BITSPERVGACOLOUR 6
/* no. VGA DAC registers */
#define SIZE_DACS 256
/* no. distinct greyscale values */
#define NUM_GREY (1 << BITSPERVGACOLOUR)
/* no. palette registers that map
* to the same greyscale value */
#define GREY_SAME (SIZE_DACS / NUM_GREY)
/* no. underlying colours on vga */
#define PRIMARY_COLOURS 3
static void
vid_vgapalette(action)
int action;
{
union REGS regs;
struct SREGS sreg;
static unsigned char SaveDacs[SIZE_DACS * PRIMARY_COLOURS],
*GreyDacs = 0;
switch(action)
{
case PAL_SAVE:
/* Save existing palette */
regs.h.ah = VID_PALETTE;
regs.h.al = PAL_GETPALBLOCK;
regs.x.bx = 0; /* first palette register */
regs.x.cx = SIZE_DACS; /* read all palette registers */
segread(&sreg);
sreg.es = FP_SEG(SaveDacs);
regs.x.dx = FP_OFF(SaveDacs);
int86x(BIOS_VIDFN, ®s, ®s, &sreg);
break;
case PAL_RESTORE:
/* restore saved palette */
regs.h.ah = VID_PALETTE;
regs.h.al = PAL_SETDACBLOCK;
regs.x.bx = 0; /* first palette register */
regs.x.cx = SIZE_DACS; /* read all palette registers */
segread(&sreg);
sreg.es = FP_SEG(SaveDacs);
regs.x.dx = FP_OFF(SaveDacs);
int86x(BIOS_VIDFN, ®s, ®s, &sreg);
break;
case PAL_SETGREY:
/* set palette to greyscale */
if (GreyDacs == 0)
{
unsigned char *p,
c;
if ((GreyDacs = malloc(SIZE_DACS*PRIMARY_COLOURS))
== 0)
{
sprintf(ErrBuf, "Dacs allocation failed");
error(ERR_SYS);
return;
}
for (p = GreyDacs, c = 0; c < NUM_GREY; ++c)
{
int i;
for (i = 0; i < PRIMARY_COLOURS * GREY_SAME; ++i)
*p++ = c;
}
}
regs.h.ah = VID_PALETTE;
regs.h.al = PAL_SETDACBLOCK;
regs.x.bx = 0; /* first palette register */
regs.x.cx = SIZE_DACS; /* read all palette registers */
segread(&sreg);
sreg.es = FP_SEG(GreyDacs);
regs.x.dx = FP_OFF(GreyDacs);
int86x(BIOS_VIDFN, ®s, ®s, &sreg);
break;
}
}
/*
* Routine to map 16 palette registers.
*/
#define SIZE_PALETTE 17 /* 16 + overscan */
static void
vid_setpalette(action)
int action;
{
union REGS regs;
struct SREGS sreg;
static unsigned char SavePalette[SIZE_PALETTE],
*GreyPalette = 0;
unsigned char palette;
switch (action)
{
case PAL_SAVE:
/* Save existing palette */
regs.h.ah = VID_PALETTE;
regs.h.al = PAL_GETPALBLOCK;
segread(&sreg);
sreg.es = FP_SEG(SavePalette);
regs.x.dx = FP_OFF(SavePalette);
int86x(BIOS_VIDFN, ®s, ®s, &sreg);
break;
case PAL_RESTORE:
/* restore saved palette */
regs.h.ah = VID_PALETTE;
regs.h.al = PAL_SETPALBLOCK;
segread(&sreg);
sreg.es = FP_SEG(SavePalette);
regs.x.dx = FP_OFF(SavePalette);
int86x(BIOS_VIDFN, ®s, ®s, &sreg);
break;
case PAL_SETGREY:
/* set palette to greyscale */
if (GreyPalette == 0)
{
if ((GreyPalette = (unsigned char *) malloc(SIZE_PALETTE)) == 0)
{
sprintf(ErrBuf, "Palette allocation failed");
error(ERR_SYS);
return;
}
GreyPalette[0] = 000;
GreyPalette[1] = 070;
GreyPalette[2] = 007;
GreyPalette[3] = 077;
GreyPalette[SIZE_PALETTE-1] = SavePalette[SIZE_PALETTE-1];
}
regs.h.ah = VID_PALETTE;
regs.h.al = PAL_SETPALBLOCK;
segread(&sreg);
sreg.es = FP_SEG(GreyPalette);
regs.x.dx = FP_OFF(GreyPalette);
int86x(BIOS_VIDFN, ®s, ®s, &sreg);
break;
case PAL_SETLIN:
for (palette = 0; palette < SIZE_PALETTE; ++palette)
{
union REGS regs;
regs.h.ah = VID_PALETTE;
regs.h.al = PAL_SETPAL;
regs.h.bh = palette;
regs.h.bl = palette;
int86(BIOS_VIDFN, ®s, ®s);
}
break;
}
}
static void
vid_setmode(mode)
unsigned char mode;
{
union REGS regs;
regs.h.ah = 0;
regs.h.al = mode;
int86(BIOS_VIDFN, ®s, ®s);
}
static void
vid_setpixel(x, y, value)
int x, y;
pixel_t value;
{
union REGS regs;
regs.h.al = value;
regs.h.ah = VID_SETPIXEL;
regs.h.bh = 0; /* video page */
regs.x.cx = (unsigned) x;
regs.x.dx = (unsigned) y;
int86(BIOS_VIDFN, ®s, ®s);
}
static unsigned char
vid_chkherc()
{
return VID_MDA;
}
/*
* Detect installed graphics hardware.
*/
static unsigned char
vid_detect()
{
union REGS regs;
regs.h.ah = VID_DISPLAY;
regs.h.al = 0; /* get video display combination */
int86(BIOS_VIDFN, ®s, ®s);
if (regs.h.al == 0x1a)
{
/* VGA or MCGA present - what is the active display? */
switch(regs.h.bl)
{
case 1:
/* MDA or hercules */
return vid_chkherc();
case 2:
return VID_CGA;
case 4:
case 5:
return VID_EGA;
case 7:
case 8:
return VID_VGA;
case 10:
case 11:
case 12:
return VID_MCGA;
default:
return VID_NONE;
}
}
/* System doesn't have a VGA or MCGA - check for EGA */
regs.h.ah = VID_SUBSYSTEM;
regs.h.bl = 0x10; /* get video configuration information */
int86(BIOS_VIDFN, ®s, ®s);
if (regs.h.bl != 0x10)
{
/* EGA BIOS present */
return VID_EGA;
}
return VID_NONE;
}
/*ARGSUSED*/
void
disp_init(argc,argv) /* called from main at the start. */
int argc;
char *argv[];
{
/* Some compilers (eg Power C) don't get the initialisation right,
* so repeat it here.
*/
VidModeBiosAddr = MK_FP(SEG_VIDBIOS, BIOSADDR_MODE);
CrtcPortBiosAddr = MK_FP(SEG_VIDBIOS, BIOSADDR_CRTCPORT);
VidInitMode = *VidModeBiosAddr;
VidAdapter = vid_detect();
#if __TURBOC__
tc_driver = DETECT;
detectgraph(&tc_driver, &tc_mode);
switch (tc_driver)
{
case VGA:
VidAdapter = VID_VGA;
break;
case EGA:
case EGA64:
VidAdapter = VID_EGA;
break;
case CGA:
VidAdapter = VID_CGA;
break;
default:
initgraph(&tc_driver, &tc_mode, STRBGIPATH);
tc_error = graphresult();
if (tc_error < 0)
{
sprintf(ErrBuf, "initgraph error (%s)",
grapherrormsg(tc_error));
error(ERR_WARN);
VidAdapter = VID_NONE;
return;
}
else
VidAdapter = VID_LIB;
}
#endif /* __TURBOC__ */
#if __MSC__
if (_setvideomode(_VRES2COLOR))
VidAdapter = VID_VGA;
else if (_setvideomode(_ERESNOCOLOR))
VidAdapter = VID_EGA;
else if (_setvideomode(_HRESBW))
;
else
VidAdapter = VID_NONE;
#endif /* __MSC__ */
#if __POWERC__
if (setvmode(17) == 17)
VidAdapter = VID_VGA;
else if (setvmode(15) == 15)
VidAdapter = VID_EGA;
else if (setvmode(6) == 6)
VidAdapter = VID_CGA;
else if (setvmode(99) == 99)
VidAdapter = VID_HGC;
#endif /* __POWERC__ */
/* This is also a last minute addition that needs to
* be cleaned up - again, next release.
*/
for (++argv; *argv; ++argv)
{
char *card;
if (**argv == '-')
switch ((*argv)[1])
{
case 'c': /* card */
card = *argv + 2;
if (strcmp(card, "vga") == 0)
VidAdapter = VID_VGA;
else if (strcmp(card, "ega") == 0)
VidAdapter = VID_EGA;
else if (strcmp(card, "cga") == 0)
VidAdapter = VID_CGA;
else if (strcmp(card, "hgc") == 0)
VidAdapter = VID_HGC;
else if (strcmp(card, "lib") == 0)
VidAdapter = VID_LIB;
}
}
if (VidAdapter == VID_NONE)
{
vid_setmode(VidInitMode);
sprintf(ErrBuf, "No graphics hardware detected");
error(ERR_WARN);
return;
}
switch (VidAdapter)
{
case VID_LIB:
return;
case VID_VGA:
vid_setpalette(PAL_SAVE);
vid_setpalette(PAL_SETLIN);/**/
vid_vgapalette(PAL_SAVE);
break;
case VID_EGA:
vid_setpalette(PAL_SAVE);
break;
case VID_CGA:
break;
}
vid_setmode(VidInitMode);
VidDriver = &VidDrivers[VidAdapter];
if (Xsize > VidDriver->xsize)
Xsize = VidDriver->xsize;
if (Ysize > VidDriver->ysize)
Ysize = VidDriver->ysize;
vid_xbytes = VidDriver->xsize / VidDriver->PixelsPerByte;
vid_yoff = (VidDriver->ysize - Ysize) / 2;
vid_xoff_bytes =
((VidDriver->xsize - Xsize) / 2) / VidDriver->PixelsPerByte;
ScreenMem = MK_FP(VidDriver->ScreenMem, 0);
}
void
disp_finish() /* called from main prior to exit. */
{
#if __TURBOC__
if (VidAdapter == VID_LIB)
closegraph();
#endif /* __TURBOC__ */
}
/*
* Set up Hercules Graphics Card 720 * 348 graphics mode
*/
static void
vid_sethgc()
{
unsigned short ModeControl = 0x03b8;
unsigned short CrtcAddress = 0x03b4;
unsigned short CrtcData = CrtcAddress + 1;
outportb(HGC_SWITCH, 0x01); /* allow graphics mode */
outportb(ModeControl, 0x00); /* Video disabled during setup */
/* Horizontal total: 54 "characters" (at 16 pixels/char) */
outportb(CrtcAddress, 0x00);
outportb(CrtcData, 0x35);
/* Horizontal displayed: 45 "characters" */
outportb(CrtcAddress, 0x01);
outportb(CrtcData, 0x2d);
/* Horizontal sync position: at 45th character */
outportb(CrtcAddress, 0x02);
outportb(CrtcData, 0x2e);
/* Horizontal sync width: 7 character clocks */
outportb(CrtcAddress, 0x03);
outportb(CrtcData, 0x07);
/* Vertical total: 94 "characters" (at 4 scanlines/char) */
outportb(CrtcAddress, 0x04);
outportb(CrtcData, 0x5b);
/* Vertical adjust: 2 scanlines */
outportb(CrtcAddress, 0x05);
outportb(CrtcData, 0x02);
/* Vertical displayed: 87 "character" rows */
outportb(CrtcAddress, 0x06);
outportb(CrtcData, 0x57);
/* Vertical sync position: after 87th char row */
outportb(CrtcAddress, 0x07);
outportb(CrtcData, 0x57);
/* Max scan line: 4 lines/char */
outportb(CrtcAddress, 0x09);
outportb(CrtcData, 0x03);
*VidModeBiosAddr = 6; /* Microsoft mouse: HGC using CRT page 0 */
outportb(ModeControl, 0x0a); /* Video enabled, Graphics mode */
}
void
disp_imgstart() /* called prior to drawing an image. */
{
if (VidAdapter == VID_NONE)
return;
if (VidAdapter == VID_LIB)
{
#if __TURBOC__
setgraphmode(tc_mode);
#endif /* __TURBOC__ */
return;
}
if (VidAdapter <= VID_STD)
vid_setmode(VidDriver->bios_mode);
else
*VidModeBiosAddr = VidDriver->bios_mode; /* fake it */
switch (VidAdapter)
{
case VID_VGA:
vid_vgapalette(PAL_SETGREY);
break;
case VID_EGA:
vid_setpalette(PAL_SETGREY);
break;
case VID_HGC:
vid_sethgc();
break;
}
}
void
disp_imgend() /* called after drawing an image. */
{
(void) getch();
switch (VidAdapter)
{
case VID_VGA:
vid_vgapalette(PAL_RESTORE);
vid_setpalette(PAL_RESTORE);
break;
case VID_EGA:
vid_setpalette(PAL_RESTORE);
break;
}
vid_setmode(VidInitMode);
}
void
disp_putline(lines, y) /* called to draw image scanline y. */
pixel_t **lines;
int y;
{
register int x;
register unsigned char far *p;
pixel_t *line;
if (VidAdapter == VID_NONE)
return;
line = ntsc_luma(lines);
if (VidAdapter == VID_LIB)
{
for (x = 0; x < Xsize; ++x)
{
pixel_t val;
val = *line++ < thresh[y % BITSPERPIXEL][x % BITSPERPIXEL] ?
(pixel_t) 0 : (pixel_t) 1;
#if __TURBOC__
putpixel(x, y, val);
#endif /* __TURBOC__ */
#if __MSC__
_setcolor(val);
_setpixel(x, y);
#endif /* __MSC__ */
#if __POWERC__
pen_color(val);
setpixel(x, y);
#endif /* __POWERC__ */
}
return;
}
p = &ScreenMem[
(
((y + vid_yoff) % VidDriver->interlace)
*
VidDriver->interlace_offset
)
+
(y + vid_yoff) / VidDriver->interlace * vid_xbytes
/*
+
vid_xoff_bytes
*/
];
switch (VidAdapter)
{
case VID_VGA:
for (x = 0; x < Xsize; ++x)
*p++ = *line++;
break;
case VID_EGA:
/* 4 grey levels isn't enough - need to do dithering as well,
* or perhaps fake it with some colours.
*/
for (x = 0; x < Xsize; ++x)
vid_setpixel(x, y, *line++ / 64);
break;
case VID_CGA:
for (x = 0; x < Xsize;)
{
register unsigned char t;
register unsigned char val;
register unsigned char byte;
register int pixel;
byte = 0;
for (pixel = 8; pixel > 0; ++x)
{
t = thresh[y % BITSPERPIXEL][x % BITSPERPIXEL];
val = *line++;
byte |= (val > t * 2 / 3 ? 1 : 0) << --pixel;
byte |= (val > (t * 2 + Zsize) / 3 ? 1 : 0) << --pixel;
}
*p++ = byte;
}
break;
case VID_HGC:
for (x = 0; x < Xsize;)
{
register char t;
register unsigned char byte;
register int pixel;
byte = 0;
for (pixel = 8; pixel > 0; ++x)
{
t = *line++ < thresh[y % BITSPERPIXEL][x % BITSPERPIXEL] ?
(pixel_t) 0 : (pixel_t) 1;
byte |= t << --pixel;
}
*p++ = byte;
}
break;
}
}
int
disp_getchar() /* get next user typed character. */
{
static unsigned char line[255] = {254,0,'\r'};
static unsigned char *lp = 0;
if (!lp){
union REGS regs;
struct SREGS sreg;
regs.h.ah = 10;
segread(&sreg);
sreg.ds = FP_SEG(line);
regs.x.dx = FP_OFF(line);
int86x(0x21, ®s, ®s, &sreg);
regs.h.ah = 2;
regs.h.dl = '\n';
int86(0x21, ®s, ®s);
lp = &line[2];
}
if (*lp == '\r'){
lp = NULL;
return('\n');
}
return(*lp++);
}
int
disp_prompt() /* display popi prompt. */
{
static char prompt[] = "-> ";
PRINTF(prompt);
return sizeof prompt - 1;
}
void
disp_error(errtype, pos) /* display error message. */
int errtype,
pos;
{
extern int errno;
extern char *sys_errlist[];
if (errtype & ERR_PARSE)
{
int i;
for (i=1; i < pos; ++i)
PUTC('-', stderr);
PUTC('^', stderr);
PUTC('\n', stderr);
}
FPRINTF(stderr, "%s\n", ErrBuf);
/* we assume errno hasn't been reset by the preceding output */
if (errtype & ERR_SYS)
FPRINTF(stderr, "\t(%s)\n", sys_errlist[errno]);
}
void
disp_percentdone(percent)
int percent;
{
static int lastpercent = 100;
if (!Verbose)
return;
if (percent == 100)
{
printf("\r \n");
return;
}
if (percent != lastpercent)
{
printf("\r%2d%% ", percent);
fflush(stdout);
lastpercent = percent;
}
}
Funky_Stuff
len=`wc -c < ibmpc.c`
if [ $len != 21588 ] ; then
echo error: ibmpc.c was $len bytes long, should have been 21588
fi
fi # end of overwriting check
if [ -f mgr.c ]
then
echo shar: will not over-write existing file mgr.c
else
echo shar: extracting 'mgr.c', 7730 characters
cat > mgr.c <<'Funky_Stuff'
/*LINTLIBRARY*/
/* @(#)mgr.c 1.2 90/12/28
*
* MGR dependent graphics routines used by popi.
* written by Rich Burridge - Sun Microsystems.
*
* Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
* This version is based on the code in his Prentice Hall book,
* "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
* which is copyright (c) 1988 by Bell Telephone Laboratories, Inc.
*
* Permission is given to distribute these extensions, as long as these
* introductory messages are not removed, and no monies are exchanged.
*
* No responsibility is taken for any errors or inaccuracies inherent
* either to the comments or the code of this program, but if reported
* (see README file) then an attempt will be made to fix them.
*/
#include "dump.h"
#include "term.h"
#include "popi.h"
#include "graphics.h"
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#define B_FONT 1 /* Font descriptors. */
#define N_FONT 2
#define ICONIC 0 /* States that the popi display can be in. */
#define OPEN 1
#define PR_ICON 1 /* Descriptor for closed icon image. */
#define PR_SCAN 2 /* Descriptor for current popi scan line. */
#define BOLD_FONT "cour7x14b"
#define NORMAL_FONT "cour7x14r"
#define ICONHEIGHT 64 /* Height of the popi icon. */
#define ICONWIDTH 64 /* Width of the popi icon. */
char fontname[MAXLINE] ; /* Full pathname of each font. */
int local_mode; /* Used by load_icon for correct line mode. */
int mgr_infd ; /* MGR input connection file descriptor. */
int mgr_outfd ; /* MGR output connection file descriptor. */
short icon_image[] = {
#include "popi.icon"
} ;
#ifdef NO_43SELECT
int fullmask ; /* Full mask of file descriptors to check on. */
int readmask ; /* Readmask used in select call. */
#else
fd_set fullmask ; /* Full mask of file descriptors to check on. */
fd_set readmask ; /* Readmask used in select call. */
#endif /* NO_43SELECT */
SIGRET
clean(code)
int code ;
{
m_bitdestroy(1) ;
m_pop() ;
m_ttyreset() ;
m_clear() ;
exit(code) ;
}
cleanup() /* Cleanup before exiting. */
{
clean(0) ;
}
close_frame()
{
reshape(ICONIC) ;
m_clearmode(M_ACTIVATE) ;
iconic = 1 ;
}
draw_scanline(lines, y) /* Display image scanline on the screen. */
unsigned char **lines ;
int y ;
{
int fd, size ;
unsigned char *line ;
line = ntsc_luma(lines);
halftone(line, y) ;
IOCTL(mgr_outfd, TIOCLGET, &local_mode) ;
local_mode |= LLITOUT ;
IOCTL(mgr_outfd, TIOCLSET, &local_mode) ;
size = (Xsize / 8) + 1 ;
m_bitldto(Xsize, 1, 0, 0, PR_SCAN, size) ;
m_flush() ;
WRITE(mgr_outfd, mptr, size) ;
local_mode &= ~LLITOUT ;
IOCTL(mgr_outfd, TIOCLSET, &local_mode) ;
m_bitcopyto(0, y+100, Xsize, 1, 0, 0, 0, PR_SCAN) ;
}
drawarea(x, y, width, height, op)
int x, y, width, height ;
enum op_type op ;
{
m_func(ops[(int) op]) ;
m_bitwrite(x, y, width, height) ;
}
drawline(x1, y1, x2, y2)
int x1, y1, x2, y2 ;
{
m_func(B_COPY) ;
m_line(x1, y1, x2, y2) ;
}
drawtext(x, y, fontno, str)
enum font_type fontno ;
int x, y ;
char *str ;
{
if (fontno == NFONT) m_font(N_FONT) ;
else if (fontno == BFONT) m_font(B_FONT) ;
m_func(B_XOR) ;
if (str[strlen(str)-1] == '\n') str[strlen(str)-1] = '\0' ;
m_stringto(0, x, y+4, str) ;
m_movecursor(2500, 2500) ;
}
get_next_char(c) /* Process events, and return when character typed. */
char *c ;
{
int chr ;
static struct timeval tval = { 0, 0 } ;
m_flush() ;
for (;;)
{
readmask = fullmask ;
#ifdef NO_43SELECT
SELECT(32, &readmask, 0, 0, &tval) ;
if (readmask && (1 << mgr_infd))
#else
SELECT(FD_SETSIZE, &readmask, (fd_set *) 0, (fd_set *) 0, &tval) ;
if (FD_ISSET(mgr_infd, &readmask))
#endif /* NO_4.3SELECT */
{
if ((chr = m_getchar()) == EOF)
{
clearerr(m_termin) ;
continue ;
}
switch (chr)
{
case '\032' :
case '\033' : close_frame() ; /* Turn window iconic. */
break ;
case '\034' : clean(1) ; /* Window destroyed. */
case '\035' : if (iconic) iconic = 0 ;
case '\036' : reshape(OPEN) ;
case '\037' : paint_canvas() ; /* Repaint popi canvas. */
break ;
default : *c = chr ;
return ;
}
}
}
}
init_fonts()
{
char path[MAXLINE] ; /* Directory path for font files. */
#ifdef MGRHOME
STRCPY(path, MGRHOME) ;
#else
STRCPY(path, "/usr/mgr") ;
#endif
SPRINTF(fontname, "%s/font/%s", path, NORMAL_FONT) ;
m_loadfont(NFONT, fontname) ;
nfont_width = 7 ;
SPRINTF(fontname, "%s/font/%s", path, BOLD_FONT) ;
m_loadfont(BFONT, fontname) ;
}
init_ws_type()
{
m_setup(M_FLUSH) ; /* Setup I/O; turn on flushing. */
m_push(P_BITMAP | P_MENU | P_EVENT | P_FONT | P_FLAGS | P_POSITION) ;
mgr_infd = fileno(m_termin) ;
mgr_outfd = fileno(m_termout) ;
SIGNAL(SIGHUP, clean) ;
SIGNAL(SIGINT, clean) ;
SIGNAL(SIGTERM, clean) ;
m_ttyset() ;
m_setraw() ;
m_setmode(M_NOWRAP) ;
m_setmode(M_ABS) ;
m_setmode(ACTIVATE) ;
m_clearmode(M_NOINPUT) ;
m_func(B_COPY) ;
mptr = (unsigned char *) malloc((unsigned) Xsize) ;
ops[(int) GCLR] = B_CLEAR ;
ops[(int) GSET] = B_SET ;
return 0 ;
}
load_colors() /* Hardwired to a monochrome version. */
{
iscolor = 0 ;
}
load_icon(pixrect, ibuf)
int pixrect ;
short ibuf[256] ;
{
int size ;
IOCTL(mgr_outfd, TIOCLGET, &local_mode) ;
local_mode |= LLITOUT ;
IOCTL(mgr_outfd, TIOCLSET, &local_mode) ;
size = ICONHEIGHT * (((64 + 15) &~ 15) >> 3) ;
m_bitldto(ICONWIDTH, ICONHEIGHT, 0, 0, pixrect, size) ;
m_flush() ;
WRITE(mgr_outfd, (char *) ibuf, size) ;
local_mode &= ~LLITOUT ;
IOCTL(mgr_outfd, TIOCLSET, &local_mode) ;
}
make_items(argc, argv) /* Create icon, frame, canvas etc.. */
int argc ;
char *argv[] ;
{
#ifdef NO_43SELECT
fullmask = 1 << mgr_infd ;
#else
FD_ZERO(&fullmask) ;
FD_SET(mgr_infd, &fullmask) ;
#endif /* NO_4.3SELECT */
m_setevent(BUTTON_2U, "\032") ; /* Middle mouse button released. */
m_setevent(BUTTON_1U, "\033") ; /* Right mouse button released. */
m_setevent(DESTROY, "\034") ; /* Window has been destroyed. */
m_setevent(ACTIVATE, "\035") ; /* Window has been activated. */
m_setevent(RESHAPE, "\036") ; /* Check for window being reshaped. */
m_setevent(REDRAW, "\037") ; /* Check for window being redrawn. */
m_movecursor(2500, 2500) ; /* Move character cursor offscreen. */
m_font(N_FONT) ; /* Default is the normal font. */
load_icon(PR_ICON, icon_image) ;
reshape(OPEN) ;
m_clear() ; /* Clear popi window. */
load_colors() ; /* Hardwired to monochrome. */
}
reshape(type)
int type ;
{
int x, y, w, h ; /* Position and size of popi window. */
get_size(&x, &y, &w, &h) ;
switch (type)
{
case ICONIC : m_shapewindow(x, y, ICONWIDTH+10, ICONHEIGHT+10) ;
m_clear() ;
m_bitcopyto(0, 0, ICONWIDTH, ICONHEIGHT,
0, 0, 0, PR_ICON) ;
break ;
case OPEN : m_shapewindow(x, y, TXsize+10, TYsize+10) ;
}
m_movecursor(2500, 2500) ;
}
/*ARGUSED*/
set_cursor(type) /* Doesn't appear to be any way to set the cursor. */
enum cur_type type ;
{
}
start_tool() /* Null routine. */
{
}
Funky_Stuff
len=`wc -c < mgr.c`
if [ $len != 7730 ] ; then
echo error: mgr.c was $len bytes long, should have been 7730
fi
fi # end of overwriting check
if [ -f news.c ]
then
echo shar: will not over-write existing file news.c
else
echo shar: extracting 'news.c', 5319 characters
cat > news.c <<'Funky_Stuff'
/*LINTLIBRARY*/
/* @(#)news.c 1.2 90/12/28
*
* C wrappers for News dependent graphics routines used by popi.
* written by Rich Burridge - Sun Microsystems Australia.
*
* Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
* This version is based on the code in his Prentice Hall book,
* "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
* which is copyright (c) 1988 by Bell Telephone Laboratories, Inc.
*
* Permission is given to distribute these extensions, as long as these
* introductory messages are not removed, and no monies are exchanged.
*
* No responsibility is taken for any errors or inaccuracies inherent
* either to the comments or the code of this program, but if reported
* (see README file) then an attempt will be made to fix them.
*/
#include "popi.h"
#include "graphics.h"
#include <sys/types.h>
/* Various pseudo events generated by the popi program. */
#define KEYBOARD 100 /* Keyboard character was pressed. */
#define REPAINT 101 /* Popi canvas needs repainting. */
extern FILE *PostScript ;
extern FILE *PostScriptInput ;
unsigned short icon_image[] = {
#include "popi.icon"
} ;
cleanup() /* Null routine for the NeWS version. */
{
FPRINTF(PostScript, "/destroy Frame send\n") ;
FFLUSH(PostScript) ;
}
draw_scanline(lines, y) /* Display image scanline on the screen. */
unsigned char **lines ;
int y ;
{
int depth, i ;
unsigned char *line;
line = ntsc_luma(lines);
depth = (iscolor) ? 8 : 1 ;
FPRINTF(PostScript, "/ScanLine %1d 1 %1d { } { < \n", Xsize, depth) ;
if (iscolor)
{
for (i = 0; i < Xsize; i++)
FPRINTF(PostScript, "%.2X ", line[i]) ;
}
else
{
mptr = (unsigned char *) Emalloc((Xsize / 8) + 1) ;
halftone(line, y) ;
for (i = 0; i < (Xsize / 8) + 1; i++)
FPRINTF(PostScript, "%.2X ", 255 - mptr[i]) ;
}
FPRINTF(PostScript, "> } buildimage def\n") ;
FPRINTF(PostScript, "%1d PSDrawScanLine\n", y) ;
FFLUSH(PostScript) ;
}
drawarea(x, y, width, height, op)
int x, y, width, height ;
enum op_type op ;
{
FPRINTF(PostScript, "%d %d %d %d %d PSDrawArea\n",
x, y, width, height, (int) op) ;
FFLUSH(PostScript) ;
}
drawline(x1, y1, x2, y2)
int x1, y1, x2, y2 ;
{
FPRINTF(PostScript, "%d %d %d %d PSDrawLine\n", x1, y1, x2, y2) ;
}
drawtext(x, y, fontno, str)
enum font_type fontno ;
int x, y ;
char *str ;
{
int i ;
char font, fonttype[6], line[MAXLINE] ;
if (fontno == NFONT) STRCPY(fonttype, "NFont") ;
else if (fontno == BFONT) STRCPY(fonttype, "BFont") ;
line[0] = '\0' ;
for (i = 0; i < strlen(str); i++)
switch (str[i])
{
case '\\' : STRCAT(line,"\\\\") ;
break ;
case '(' : STRCAT(line,"\\(") ;
break ;
case ')' : STRCAT(line,"\\)") ;
break ;
default : STRNCAT(line, &str[i], 1) ;
}
FPRINTF(PostScript, "%s %d %d (%s) PSDrawText\n", fonttype, x, y, line) ;
}
get_next_char(c) /* Process events, and return when character is typed. */
char *c ;
{
int ch, type ;
for (;;)
{
FFLUSH(PostScript) ;
if (pscanf(PostScriptInput, "%d", &type) == EOF) exit(0) ;
switch (type)
{
case KEYBOARD : pscanf(PostScriptInput, "%d", &ch) ;
*c = ch ;
return ;
case REPAINT : paint_canvas() ;
}
}
/*NOTREACHED*/
}
init_fonts()
{
FPRINTF(PostScript, "PSInitFonts\n") ;
nfont_width = 9 ;
}
init_ws_type()
{
if (ps_open_PostScript() < 0) return -1 ;
if (send_ps_file(NEWSFILE) == -1)
{
FCLOSE(PostScript) ;
return(-1) ;
}
FFLUSH(PostScript) ;
if (ferror(PostScript))
{
FCLOSE(PostScript) ;
return(-1) ;
}
FPRINTF(PostScript, "PSIsColor\n") ;
pscanf(PostScriptInput, "%d", &iscolor) ;
FPRINTF(PostScript, "PSInitialise\n") ;
return(0) ;
}
load_colors() /* Create and load popi color map. */
{
int i ;
u_char red[CMAPLEN], green[CMAPLEN], blue[CMAPLEN] ;
for (i = 0; i < CMAPLEN; i++)
red[i] = green[i] = blue[i] = 255 - i ;
FPRINTF(PostScript, "%d PSMakeColorTable\n", 256) ;
for (i = 0; i < 256; i++)
FPRINTF(PostScript, "%d %d %d %d PSLoadColor\n",
red[i], green[i], blue[i], i) ;
}
make_icon()
{
int i, j ;
FPRINTF(PostScript,"/PopiIcon 64 64 1 { } { <\n") ;
for (i = 0; i < 32; i++)
{
for (j = 0; j < 8; j++) FPRINTF(PostScript,"%.4X ", icon_image[i*8+j]) ;
FPRINTF(PostScript,"\n") ;
}
FPRINTF(PostScript,"> } buildimage def\n") ;
}
make_items(argc, argv) /* Create icon, frame, canvas etc.. */
int argc ;
char *argv[] ;
{
make_icon() ;
FPRINTF(PostScript, "%d %d %d %d %d %d %d PSMakeItems\n",
wx, wy, TXsize, TYsize,
ix, iy, iconic) ;
load_colors() ;
}
send_ps_file(fname)
char *fname ;
{
FILE *stream ;
int c ;
if ((stream = fopen(fname,"r")) == NULL) return -1 ;
while ((c = getc(stream)) != EOF) PUTC(c, PostScript) ;
FCLOSE(stream) ;
return 0 ;
}
set_cursor(type)
enum cur_type type ;
{
FPRINTF(PostScript, "%d PSSetCursor\n", (int) type) ;
}
start_tool() /* Null routine in the NeWS version. */
{
}
Funky_Stuff
len=`wc -c < news.c`
if [ $len != 5319 ] ; then
echo error: news.c was $len bytes long, should have been 5319
fi
fi # end of overwriting check
if [ -f next.m ]
then
echo shar: will not over-write existing file next.m
else
echo shar: extracting 'next.m', 5771 characters
cat > next.m <<'Funky_Stuff'
/*LINTLIBRARY*/
/* @(#)next.m 1.1 90/12/12
*
* Popi device driver for a NeXT machine
* Written by Joe Freeman.
*
* Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
* This version is based on the code in his Prentice Hall book,
* "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
* which is copyright (c) 1988 by Bell Telephone Laboratories, Inc.
*
* Permission is given to distribute these extensions, as long as these
* introductory messages are not removed, and no monies are exchanged.
*
* No responsibility is taken for any errors or inaccuracies inherent
* either to the comments or the code of this program, but if reported
* (see README file) then an attempt will be made to fix them.
*/
#include "popi.h"
#import "appkit/appkit.h" /* lazy tsk tsk */
/* These are the exportable routines used by the popi program.
*
* These are:
*
* disp_init(argc, argv) - called from main at the start.
* disp_finish() - called from main prior to exit.
* disp_imgstart() - called prior to drawing an image.
* disp_imgend() - called after drawing an image.
* disp_putline(line, y) - to draw an image scanline.
* disp_getchar() - to get the next character typed.
* disp_prompt() - display popi prompt and clear input buffer.
* disp_error(errtype) - display error message.
* disp_percentdone(n) - display percentage value of conversion.
*/
#define RES 8
int dither[RES][RES] = { /* dither matrix */
{ 0, 128, 32, 160, 8, 136, 40, 168, },
{ 192, 64, 224, 96, 200, 72, 232, 104, },
{ 48, 176, 16, 144, 56, 184, 24, 152, },
{ 240, 112, 208, 80, 248, 120, 216, 88, },
{ 12, 140, 44, 172, 4, 132, 36, 164, },
{ 204, 76, 236, 108, 196, 68, 228, 100, },
{ 60, 188, 28, 156, 52, 180, 20, 148, },
{ 252, 124, 220, 92, 244, 116, 212, 84, },
} ;
id NXApp;
id drawWindow,percentWindow;
#define PERCENTHEIGHT 50
#define PERCENTWIDTH 120
#define LOGHEIGHT 250
#define LOGWIDTH 200
#define DRAWBASEX 250
#define DRAWBASEY 250
/*ARGSUSED*/
void
disp_init(argc,argv) /* called from main at the atart. */
int argc;
char *argv[];
{
NXRect bound;
NXApp = [Application new];
[NXApp setAppName:"popi"];
bound.origin.x = DRAWBASEX;
bound.origin.y = DRAWBASEY;
bound.size.width = Xsize; bound.size.height = Ysize;
drawWindow = [Window newContent:&bound
style:NX_TITLEDSTYLE
backing: NX_RETAINED
buttonMask: NX_MINIATURIZEBUTTONMASK
defer : NO];
[[drawWindow contentView] setFlip:YES]; /* start at top */
[drawWindow orderFront:nil];
[drawWindow setTitle:"popi image window"];
[drawWindow display];
bound.origin.x = DRAWBASEX - PERCENTWIDTH;
bound.origin.y = DRAWBASEY + Ysize - PERCENTHEIGHT;
bound.size.width = PERCENTWIDTH; bound.size.height = PERCENTHEIGHT;
percentWindow = [Panel newContent:&bound
style:NX_TITLEDSTYLE
backing: NX_RETAINED
buttonMask: 0
defer: NO];
[percentWindow setTitle:"percent done"];
bound.origin.x = 40.0; bound.origin.y = 350;
bound.size.width = LOGWIDTH; bound.size.height = LOGHEIGHT;
[percentWindow display];
bound.origin.x = 0.0; bound.origin.y = DRAWBASEY;
bound.size.width = DRAWBASEX ; bound.size.height = Ysize - PERCENTHEIGHT;
NXPing();
}
void
disp_finish() /* called from main prior to exit. */
{
[drawWindow free];
[percentWindow free];
[NXApp free];
}
void
disp_imgstart() /* called prior to drawing an image. */
{
}
void
disp_imgend() /* called after drawing an image. */
{
[drawWindow flushWindow];
NXPing();
}
void
disp_putline(line, y) /* called to draw image scanline y. */
pixel_t *line;
int y;
{
NXRect theRect;
[[drawWindow contentView] lockFocus];
PSgsave();
theRect.origin.x = 0.0;
theRect.origin.y = (float)y;
theRect.size.width = (float)Xsize;
theRect.size.height = (float)1.0;
NXImageBitmap(&theRect, Xsize, 1.0,
8, 1, NX_PLANAR, NX_MONOTONICMASK,
line, NULL,NULL, NULL, NULL);
PSgrestore();
[[drawWindow contentView] unlockFocus];
}
disp_getchar() /* get next user typed character. */
{
return(getchar());
}
disp_prompt() /* display popi prompt. */
{
char *prompt = "-> ";
PRINTF(prompt);
return sizeof prompt - 1;
}
void
disp_error(errtype, pos) /* display error message. */
int errtype,
pos;
{
extern int errno;
extern char *sys_errlist[];
if (errtype & ERR_PARSE)
{
int i;
for (i=1; i < pos; ++i)
PUTC('-', stderr);
PUTC('^', stderr);
PUTC('\n', stderr);
}
FPRINTF(stderr, "%s\n", ErrBuf);
/* we assume errno hasn't been reset by the preceding output */
if (errtype & ERR_SYS)
FPRINTF(stderr, "\t(%s)\n", sys_errlist[errno]);
}
void
disp_percentdone(percent)
int percent;
{
static int lastpercent = 100;
static NXRect bound;
if (!Verbose)
return;
if (percent == 100)
{
[percentWindow orderOut:nil];
return;
}
if ((percent == 0) && (lastpercent != 0))
{
[[percentWindow contentView] lockFocus];
[[percentWindow contentView] getBounds:&bound];
NXDrawGrayBezel( &bound, &bound);
[[percentWindow contentView] unlockFocus];
[percentWindow orderFront:nil];
NXPing();
bound.origin.x = bound.origin.y = 10.0;
bound.size.height = PERCENTHEIGHT - (2.0 * 10.0);
lastpercent = percent;
}
if (percent != lastpercent && percent % 5 == 0)
{
[[percentWindow contentView] lockFocus];
bound.size.width = (float)percent;
NXDrawButton(&bound,&bound);
[[percentWindow contentView] unlockFocus];
NXPing();
lastpercent = percent;
}
}
Funky_Stuff
len=`wc -c < next.m`
if [ $len != 5771 ] ; then
echo error: next.m was $len bytes long, should have been 5771
fi
fi # end of overwriting check
exit 0 # Just in case...