/* Program to do color -> monochrome translation of X11 dumps
 * Seth Finkelstein (sethf@athena.mit.edu)
 * Copyright 1989
 * Adapted from xim.c, by Philip Thompson (phils@athena.mit.edu)
 * License appears below
 */

#define debug debug_flag
#define progname progName
#define out_file stdout
/***********************************************************************
*  File:   xim.c
*  Author: Philip Thompson
*  $Date: 89/02/18 21:05:56 $
*  $Revision: 3.0 $
*  Purpose: To view a variety of images on X displays and make them
*       suitable for printing as bitmaps.  "Xim" displays images up to
*       24-bits deep with an 'ImageHeader' on 8-bit color and bitmap
*       displays.  Various dithering and halftoning techniques are used
*       to achieve this image portability.
*
*  Copyright (c) 1988  Philip R. Thompson
*                Computer Resource Laboratory (CRL)
*                Dept. of Architecture and Planning
*                M.I.T., Rm 9-526
*                Cambridge, MA  02139
*   This  software and its documentation may be used, copied, modified,
*   and distributed for any purpose without fee, provided:
*       --  The above copyright notice appears in all copies.
*       --  This disclaimer appears in all source code copies.
*       --  The names of M.I.T. and the CRL are not used in advertising
*           or publicity pertaining to distribution of the software
*           without prior specific written permission from me or CRL.
*   I provide this software freely as a public service.  It is NOT a
*   commercial product, and therefore is not subject to an an implied
*   warranty of merchantability or fitness for a particular purpose.  I
*   provide it as is, without warranty. This software was not sponsored,
*   developed or connected with any grants, funds, salaries, etc.
*
*   This software is furnished  only on the basis that any party who
*   receives it indemnifies and holds harmless the parties who furnish
*   it against any claims, demands, or liabilities connected with using
*   it, furnishing it to others, or providing it to a third party.
*
*   Philip R. Thompson (phils@athena.mit.edu)
***********************************************************************/
/*
#ifndef lint
static char xim_rcs_id[] =
    "$Header: xim.c,v 3.0 89/02/18 21:05:56 phils Locked $";
#endif lint
*/

#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <X11/Xlib.h>

#define ABS(a) ((a) < 0 ? -(a) : (a))

typedef unsigned long xwdval;

typedef struct _xwd7_file_header {
	xwdval header_size;	  /* Size of the entire file header (bytes). */
	xwdval file_version;	  /* XWD_FILE_VERSION */
	xwdval pixmap_format;	  /* Pixmap format */
	xwdval pixmap_depth;	  /* Pixmap depth */
	xwdval pixmap_width;	  /* Pixmap width */
	xwdval pixmap_height;	  /* Pixmap height */
	xwdval xoffset;           /* Bitmap x offset */
	xwdval byte_order;        /* MSBFirst, LSBFirst */
	xwdval bitmap_unit;       /* Bitmap unit */
	xwdval bitmap_bit_order;  /* MSBFirst, LSBFirst */
	xwdval bitmap_pad;	  /* Bitmap scanline pad */
	xwdval bits_per_pixel;	  /* Bits per pixel */
	xwdval bytes_per_line;	  /* Bytes per scanline */
	xwdval visual_class;	  /* Class of colormap */
	xwdval red_mask;	  /* Z red mask */
	xwdval green_mask;	  /* Z green mask */
	xwdval blue_mask;	  /* Z blue mask */
	xwdval bits_per_rgb;	  /* Log base 2 of distinct color values */
	xwdval colormap_entries;  /* Number of entries in colormap */
	xwdval ncolors;		  /* Number of Color structures */
	xwdval window_width;	  /* Window width */
	xwdval window_height;	  /* Window height */
	long window_x;		  /* Window upper left X coordinate */
	long window_y;		  /* Window upper left Y coordinate */
	xwdval window_bdrwidth;	  /* Window border width */
} XWD7FileHeader;
XWD7FileHeader xf7;
u_char *expand_image();

#define rnd(x)  ((int)((x)+0.5))    /* round off a float to an int */

typedef unsigned char  byte;

int dm4[4][4] = {
     0,  8,  2, 10,
    12,  4, 14,  6,
     3, 11,  1,  9,
    15,  7, 13,  5
};
int dm8[8][8] = {
     0, 32,  8, 40,  2, 34, 10, 42,
    48, 16, 56, 24, 50, 18, 58, 26,
    12, 44,  4, 36, 14, 46,  6, 38,
    60, 28, 52, 20, 62, 30, 54, 22,
     3, 35, 11, 43,  1, 33,  9, 41,
    51, 19, 59, 27, 49, 17, 57, 25,
    15, 47,  7, 39, 13, 45,  5, 37,
    63, 31, 55, 23, 61, 29, 53, 21
};
int dm16[16][16];

extern char  *malloc(), *calloc();
char *progName;
int  dither_bw(), fs_bw(), mfs_bw();
int  (*bw)() = fs_bw;
int  ditherFactor = 8;
int  threshold = 32767;
int  *dm = &(dm8[0][0]);
int  enhance = 0;
Bool  debug_flag = False;
u_long  blackpixel, whitepixel;
unsigned buf_size;

main(argc, argv)
int argc;
char **argv;
{

    register  i;
    register byte  *buffer; 
    int  buf_width, buf_height, ncolors; 
    char  *win_name = NULL;
    Bool  inverse_flag = False;
	FILE  *in_fp = stdin, *popen(), *fopen();
	extern int pclose(), fclose();
	int (*closefunc)() = fclose;
    XColor  colors[256]; /* fg_color, bg_color;*/
    unsigned long swaptest = 1;
    unsigned status;
    int win_name_size;
    XColor *x11colors;
    int expand = 1;

    progName = argv[0];
    for (i=1; i < argc; i++) {
        char *ptr = NULL;
        if (strcmp(argv[i], "-in") == 0) {   /* compressed file ? */
            ptr = rindex(argv[++i], '.');
            if (ptr && strcmp(ptr, ".Z") == 0) {
                char popen_cmd[80];
                (void)strcpy(popen_cmd, "zcat ");
                (void)strcat(popen_cmd, argv[i]);
                in_fp = popen(popen_cmd, "r");
				closefunc = pclose;
            } else
                in_fp = fopen(argv[i], "r");
            if (in_fp == NULL)
                error("Can't open input file: %s ", argv[i]);
/*            win_name = argv[i];*/
            continue;
        }
        if (strncmp(argv[i], "-mf", 3) == 0) {
            if ((ptr=rindex(argv[i],'=')) != NULL)
                (void)sscanf(ptr+1,"%d", &threshold);
            bw = mfs_bw;
            continue;
        }
        if (strncmp(argv[i], "-fs", 3) == 0) {      /* default */
            if ((ptr=rindex(argv[i],'=')) != NULL)
                (void)sscanf(ptr+1,"%d", &threshold);
            bw = fs_bw;
            continue;
        }
        if (strncmp(argv[i], "-dit", 4) == 0) {
            if ((ptr=rindex(argv[i],'=')) != NULL) {
                (void)sscanf(ptr+1,"%d", &ditherFactor);
                dm = &(dm4[0][0]);
            }
            bw = dither_bw;
            continue;
        }
        if (strncmp(argv[i], "-en", 3) == 0) {
            if ((ptr=rindex(argv[i],'=')) != NULL)
                (void)sscanf(ptr+1,"%d", &enhance);
            else
                enhance = 9;
            continue;
        }
        if (strncmp(argv[i], "-sca", 3) == 0) {
            if ((ptr=rindex(argv[i],'=')) != NULL)
                (void)sscanf(ptr+1,"%d", &expand);
            continue;
        }
        if (strncmp(argv[i], "-re", 3) == 0) {
            inverse_flag = True;
            continue;
        }
        if (strncmp(argv[i], "-de", 3) == 0) {
            debug_flag = True;
            continue;
        }
        error("Usage: %s [-in <file>][-reverse][-dither[=4] | -mfs][-enhance[=1-9]][-debug]",
          progName);
    }

    if (ditherFactor < 2 || ditherFactor > 8)
    error("Dither level must be from 2 to 8 in color");

    /*
     * Read in header information.
     */
    if(fread((char *)&xf7, sizeof(xf7), 1, in_fp) != 1)
      Error("Unable to read dump file header.");

     if (*(char *) &swaptest)
        _swaplong((char *) &xf7, sizeof(xf7));

    /*
     * check to see if the dump file is in the proper format.
     */
    if (xf7.file_version != 7) {
	    fprintf(stderr,
            "%s: XWD file format version missmatch. Got %d\n",
            progName,xf7.file_version);
    }

    if (xf7.header_size < sizeof(xf7)) {
      fprintf(stderr,"%s: XWD header size is too small.",progName);
      Error("exiting.");
    }

    ncolors = xf7.ncolors;

    /*
     * Calloc window name.
     */
    win_name_size = ABS(xf7.header_size - sizeof(xf7));
    if (debug_flag)
      fprintf(stderr,"%s: callocing win_name, size = %d\n",
      progName,win_name_size);
    if((win_name = calloc((unsigned) win_name_size, sizeof(char))) == NULL)
      Error("Can't calloc window name storage.");

    /*
     * Read in window name.
     */
    if(fread(win_name, sizeof(char), win_name_size, in_fp) != win_name_size)
      Error("Unable to read window name from dump file.");
    if(debug_flag) fprintf(stderr,"win_name =%s\n", win_name);

    /* Calloc the color map buffer.
     */
    if(ncolors = xf7.ncolors) {
      x11colors = (XColor *)calloc((unsigned)ncolors,sizeof(XColor));
      if(fread((char *) x11colors, sizeof(XColor), ncolors, in_fp) != ncolors)
        Error("Unable to read color map from dump file.");
      if(debug_flag)
        fprintf(stderr,"Read %d colors\n", ncolors);
      if (*(char *) &swaptest) {
          for (i = 0; i < ncolors; i++) {
              _swaplong((char *) &x11colors[i].pixel, sizeof(long));
              _swapshort((char *) &x11colors[i].red, 3 * sizeof(short));
          }
      }
    }

    buf_size = xf7.pixmap_width * xf7.pixmap_height;
    /*
     * Calloc the pixel buffer.
     */
    if((buffer = (u_char *) calloc(buf_size, 1)) == NULL)
      Error("Can't calloc data buffer.");

    /*
     * Read in the pixmap buffer.
     */
    if((status = fread((char *)buffer, sizeof(char), (int)buf_size, in_fp))
       != buf_size)
      Error("Unable to read pixmap from dump file.");

    buf_width = xf7.pixmap_width;
    buf_height = xf7.pixmap_height;
    buf_size = (unsigned)(buf_width * buf_height);

    /* use provided colormap */
        if (debug_flag)
        (void)fprintf(stderr,"ncolors %d\n", ncolors);
        for (i=0; i < ncolors; i++) {
            colors[i].pixel = (u_long)i;
            colors[i].red = (u_short) x11colors[i].red;
            colors[i].green = (u_short) x11colors[i].green;
            colors[i].blue = (u_short) x11colors[i].blue;
            colors[i].flags = DoRed | DoGreen | DoBlue;
        }

        if (inverse_flag)
        for (i=0; i < ncolors; i++) {
            colors[i].red = ~colors[i].red;
            colors[i].green = ~colors[i].green;
            colors[i].blue = ~colors[i].blue;
        }

        /* make a bitmap image, but first */

        ColorToBW(buffer, buf_size, colors, &ncolors);

        if (bw == dither_bw)
            NormalizeDM(ditherFactor);
        if (enhance) {
            edge_enhance(buffer, buf_width, buf_height, buf_size);
        }
        /* Translate pixmap into a bitmap for monochrome display. */
        BWToBitmap(buffer, buf_width, buf_height, colors);

    buf_width = 8*((buf_width + 7)/8);
    buf_size = (buf_width * buf_height)/8;

    /*
     * Calculate header size.
    if (debug) fprintf(stderr,"%s: Calculating header size.\n",progname);
    xf7_size = sizeof(xf7) + win_name_size;
     */


    /*
     * Write out header information.
     */
    if (debug) fprintf(stderr,"%s: Constructing and dumping file header.\n",progname);
/*  xf7.header_size = (xwdval) header_size;*/
                                /* Size of the entire file header (bytes). */
  xf7.file_version= (xwdval) 7;   		/* XWD_FILE_VERSION */
  xf7.pixmap_format= (xwdval) 2;          	/* Pixmap format */
  xf7.pixmap_depth= (xwdval) 1;          	/* Pixmap depth */
  xf7.pixmap_width= (xwdval) buf_width;     	/* Pixmap width */
  xf7.pixmap_height= (xwdval) buf_height;      	/* Pixmap height */
  xf7.xoffset= (xwdval) 0;           		/* Bitmap x offset */
  xf7.byte_order= (xwdval) LSBFirst;            /* MSBFirst, LSBFirst */
  xf7.bitmap_unit= (xwdval) 8;          	/* Bitmap unit */
  xf7.bitmap_bit_order= (xwdval) LSBFirst;      /* MSBFirst, LSBFirst */
  xf7.bitmap_pad= (xwdval) 8;    		/* Bitmap scanline pad */
  xf7.bits_per_pixel= (xwdval) 1;        	/* Bits per pixel */
  /* Note: some bitmaps may need the following tweaked by +1 or +2... */
  xf7.bytes_per_line= (xwdval) ((buf_width+7)/8);  /* Bytes per scanline */
  xf7.visual_class= (xwdval) StaticColor;       /* Class of colormap */
  xf7.red_mask= (xwdval) 0;       		/* Z red mask */
  xf7.green_mask= (xwdval) 0;     		/* Z green mask */
  xf7.blue_mask= (xwdval) 0;      		/* Z blue mask */
  xf7.bits_per_rgb= (xwdval) 1;    /* Log base 2 of distinct color values */
  xf7.colormap_entries= (xwdval) 2;  /* Number of entries in colormap */
  xf7.ncolors= (xwdval) 2;                /* Number of Color structures */
  xf7.window_width= (xwdval) buf_width;    	/* Window width */
  xf7.window_height= (xwdval) buf_height;      /* Window height */
  xf7.window_x= (xwdval) 0; 	     /* Window upper left X coordinate */
  xf7.window_y= (xwdval) 0;          /* Window upper left Y coordinate */
  xf7.window_bdrwidth= (xwdval) 0;   /* Window border width */

  ncolors = 2;
  x11colors[0].pixel = 0;
  x11colors[0].red = x11colors[0].green = x11colors[0].blue = 65535;

  x11colors[1].pixel = 1;
  x11colors[1].red = x11colors[1].green = x11colors[1].blue = 0;

    /*
     * Write out header information.
     */
    if (debug) fprintf(stderr,"%s: Constructing and dumping file header.\n",progname);


    if (*(char *) &swaptest) {
      _swaplong((char *) &xf7, sizeof(xf7));
      for (i = 0; i < ncolors; i++) {
          _swaplong((char *) &x11colors[i].pixel, sizeof(long));
          _swapshort((char *) &x11colors[i].red, 3 * sizeof(short));
      }
    }

    (void) fwrite((char *)&xf7, sizeof(xf7), 1, out_file);
    (void) fwrite(win_name, win_name_size, 1, out_file);

    if (debug) fprintf(stderr,"%s: Dumping %d colors.\n",progname,ncolors);
    (void) fwrite((char *) x11colors, sizeof(XColor), ncolors, out_file);

    /*
     * Write out the buffer.
     */
    if (debug) fprintf(stderr,"%s: Dumping pixmap.\n",progname);
    (void) fwrite((char *)buffer, (int) buf_size, 1, out_file);

    /*
     * Close the output file.
     */
    if (debug) fprintf(stderr,"%s: Closing output file.\n",progname);
    (void) fclose(out_file);

    /*
     * Free the picture buffer.
     */
    if (debug) fprintf(stderr,"%s: Freeing picture buffer.\n",progname);
    free((char *)buffer);

    /*
     * Free window name string.
     */
    if (debug) fprintf(stderr,"%s: Freeing window name string.\n",progname);
    free(win_name);
    exit(0);

}  /* end main */


/* This edge enhancing is taken from the ACM Transaction on Graphics
*  Vol. 6, No. 4, October 1987.  Dot diffusion is not implemented.
*/
edge_enhance(buf, width, height, bufsize)
register byte *buf;
int width, height;
unsigned bufsize;
{
    register i, x, y, lbyt, hbyt, tmp;
    register byte *tbuf;
    register float phi;

    if (debug_flag)
        fprintf(stderr,"enhancing... ");
    if ((tbuf = (byte *)malloc(bufsize)) == NULL)
        error("Can't malloc() core for edge enhancementi.\n");
    bcopy((char *)buf, (char *)tbuf, (int)bufsize);

    lbyt = width-1;
    hbyt = width+1;
    i = lbyt;
    if (enhance == 9) {             /* is much faster, default */
        for (y=2; y < height; y++) {
            i += 2;
            for (x=2; x < width; x++,i++) {
                tmp = (9 * tbuf[i]) - (tbuf[i-hbyt] + tbuf[i-width]+
                 tbuf[i-lbyt] + tbuf[i-1] + tbuf[i+1] + tbuf[i+lbyt] +
                 tbuf[i+width] + tbuf[i+hbyt]);
                if (tmp > 255)
                    buf[i] = 255;
                else if (tmp < 0)
                    buf[i] = 0;
                else
                    buf[i] = (byte)tmp;
            }
        }
    } else {                        /* allows greater control */
        phi = enhance / 10.0;
        for (y=2; y < height; y++) {
            i += 2;
            for (x=2; x < width; x++,i++) {
                tmp = (tbuf[i-hbyt] + tbuf[i-width] + tbuf[i-lbyt] +
                    tbuf[i-1] + tbuf[i] + tbuf[i+1] +
                    tbuf[i+lbyt] + tbuf[i+width] + tbuf[i+hbyt]) / 9.0;
                tmp = rnd((tbuf[i]-(phi*tmp)) / (1.0-phi));
                if (tmp > 255)
                    buf[i] = 255;
                else if (tmp < 0)
                    buf[i] = 0;
                else
                    buf[i] = (byte)tmp;
            }
        }
    }
    free((char *)tbuf);
}

int *error1, *error2;

/* Grey to monochrome conversion. Performed in place - overwrites 
* the source pixmap and transforms it into a bitmap in the process.
*/
BWToBitmap(buf,width,height,map)
register byte  *buf;
int  width, height;
XColor  map[];
{
    register byte  *mbuffer, mvalue;   /* monochrome buffer */
    register byte  *mpbuffer;          /* monochrome pixel buffer */
    register  row, col, bit;

    if (debug_flag)
        fprintf(stderr,"BWToBitmap... ");
    error1 = (int *)malloc((unsigned)(width+1) * sizeof(int));
    error2 = (int *)malloc((unsigned)(width+1) * sizeof(int));
    mbuffer= (byte *)calloc((unsigned)width*height/8, sizeof(byte));
    if ((error1 == NULL) || (error2 == NULL) || (mbuffer == NULL))
        error("calloc() in BWToBitmap conversion");
    mpbuffer = mbuffer = buf;

    if ( xf7.bitmap_bit_order == LSBFirst) {
/*    if (XBitmapBitOrder(dpy) == LSBFirst) {*/
        for (row=0; row < height; row++)
            for (col=0; col < width; ) {
                mvalue = 0x00;
                for (bit=0; (bit < 8) && (col < width); bit++,col++)
                    if ((*bw)(*mpbuffer++, map, col, row))
                        mvalue |= (0x01 << bit);    /*  for Vax */
                *mbuffer++ = mvalue;
            }
    } else {
        for (row=0; row < height; row++)
            for (col=0; col < width; ) {
                mvalue = 0x00;
                for (bit=0; (bit < 8) && (col < width); bit++,col++)
                    if ((*bw)(*mpbuffer++, map, col, row))
                        mvalue |= (0x80 >> bit);    /*  for RT, Sun  */
                *mbuffer++ = mvalue;
            }
    }
    free((char *)buf);
    buf = mbuffer;
    free((char *)error1);
    free((char *)error2);
}


/*************************
* code for dithering     *
*************************/
extern int dither_bw(pixel,map,count,line)
unsigned int pixel;
XColor map[]; 
register count, line;
{   
    if (map[pixel].red > dm[((line%ditherFactor)*ditherFactor) +
            (count%ditherFactor)])
        return(0);
    else
        return(1);
}


/*****************************
* code for floyd steinberg   *
*****************************/
/* ARGSUSED */
extern int fs_bw(pixel, map, count, line)
unsigned int pixel;
XColor map[]; 
register count;
{
    int  onoff, *te; 
    int  intensity, pixerr;

    if (count == 0) {
        te = error1;
        error1 = error2;
        error2 = te;
        error2[0] = 0;
    }  
    intensity = map[pixel].red + error1[count];
    if (intensity > 65535)
        intensity = 65535;
    else
        if (intensity < 0)
            intensity = 0;
    if (intensity < threshold) {
        onoff = 1;
        pixerr = intensity;
    } else {
        onoff = 0;
        pixerr = intensity - 65535;
    }
    error1[count+1] += (int)(3*pixerr)/8;
    error2[count+1] = (int)pixerr/4;
    error2[count] += (int)(3*pixerr)/8;
    return(onoff);
}


/***************************************
* code for modified floyd steinberg    *
****************************************/
/* ARGSUSED */
extern int mfs_bw(pixel,map,count,line)
unsigned int pixel;
XColor map[]; 
register count;
{
    int  onoff, *te;
    int  intensity, pixerr;

    if (count == 0) {
        te = error1;
        error1 = error2;
        error2 = te;
        error2[0] = 0;
    }  
    intensity = map[pixel].red + error1[count];
    if (intensity > 65535)
        intensity = 65535;
    else if (intensity < 0)
        intensity = 0;

    if (intensity < threshold) {
        onoff = 1;
        pixerr = threshold - intensity;
    }
    else {
        onoff = 0;
        pixerr = threshold - intensity;
    }
    error1[count+1] += (int)(3*pixerr)/8;
    error2[count+1] = (int)pixerr/4;
    error2[count] += (int)(3*pixerr)/8;
    return(onoff);
}

/* Normalize dither matrix to 65535 maximum value.
*/
NormalizeDM(dimension)
int dimension;
{
    int i, matsize;
    float normalValue;

    matsize = dimension * dimension;
    normalValue = 65536.0 / (float)matsize;
    for (i=0; i < matsize; i++) {
        dm[i] = rnd(dm[i] * normalValue);
        if (debug_flag) {
            fprintf(stderr,"%8d", dm[i]);
            if  (((i+1) % dimension) == 0)
                fprintf(stderr,"\n");
        }
    }
}

/* Transformation from RGB to the Y (or luminence) factor from
*  YIQ encoding.
*/
int GreyValue(red, green, blue)
u_short red, green, blue;
{
    return(rnd((float)red * 0.30 + (float)green * 0.55 +
            (float)blue * 0.15));
}


ColorToBW(buf, bufsize, colors, ncolors)
register byte  *buf;
unsigned  bufsize;
XColor colors[];
int *ncolors;
{
    register unsigned  i;
    byte  tval[256];

    /* determine b/w intensity level and place in pixel */
    if (debug_flag)
        fprintf(stderr,"making grey pixmap ...\n");
    for (i=0; i < *ncolors; i++) {
        tval[i] = GreyValue(colors[i].red, colors[i].green,
                colors[i].blue) / 257;
        if (debug_flag)
            fprintf(stderr,
            "color[%3d] pix: %3u  r: %5u  g: %5u  b: %5u  new: %3u\n",
            i, colors[i].pixel, colors[i].red, colors[i].green,
            colors[i].blue, tval[i]);
    }
    for (i=0; i < bufsize; i++)
        buf[i] = tval[buf[i]];
    *ncolors = 256;
    for (i=0; i < *ncolors; i++) {
        colors[i].pixel = (u_long)i;
        colors[i].red = colors[i].green = colors[i].blue =
                (u_short)(i * 257);
        colors[i].flags = DoRed | DoGreen | DoBlue;
    }
}

/* VARARGS1 */
error(s1, s2)           /*  A most tragic and fatal error.  */
char *s1, *s2;
{
    extern int errno, sys_nerr;
    extern char *sys_errlist[];

    fprintf(stderr,"%c%s: Error =>\n%c", 7, progName, 7);
    fprintf(stderr, s1, s2);
    if ((errno > 0) && (errno < sys_nerr))
        fprintf(stderr, " (%s)", sys_errlist[errno]);
    fprintf(stderr, "\n");
    exit(1);
}


/*
 * Error - Fatal program error.
 */
Error(string)
	char *string;	/* Error description string. */
{
	fprintf(stderr, "%s: Error => %s\n",progName,string);

	if (errno != 0) {
		perror(progName);
		fprintf(stderr, "\n");
	}

	exit(1);
}

_swapshort (bp, n)
    register char *bp;
    register unsigned n;
{
    register char c;
    register char *ep = bp + n;

    while (bp < ep) {
      c = *bp;
      *bp = *(bp + 1);
      bp++;
      *bp++ = c;
    }
}

_swaplong (bp, n)
    register char *bp;
    register unsigned n;
{
    register char c;
    register char *ep = bp + n;
    register char *sp;

    while (bp < ep) {
        sp = bp + 3;
        c = *sp;
        *sp = *bp;
        *bp++ = c;
        sp = bp + 1;
        c = *sp;
        *sp = *bp;
        *bp++ = c;
        bp += 2;
    }
}

/* End of xmono.c */
