{
From: remcos@htsa.aha.nl (Remco Schellekens)
}

{$R-}    {Range checking off}
{$B-}    {Boolean complete evaluation off}
{$S-}    {Stack checking off}
{$I+}    {I/O checking on}
{$N-}    {No numeric coprocessor}

PROGRAM show_pcx;

{****************************************************************************}
{                                                                            }
{ SHOW_PCX is an example program written in Borland's Turbo Pascal(R) 5.0.   }
{ (Turbo Pascal is a registered trademark of Borland International, Inc.)    }
{ SHOW_PCX doesn't use any of the graphics routines built into Turbo Pascal, }
{ since many programmers won't be using Pascal for their final program.      }
{                                                                            }
{                            PERMISSION TO COPY:                             }
{                                                                            }
{          SHOW_PCX -- (C) Copyright 1989 ZSoft, Corporation.                }
{                                                                            }
{ You are licensed to freely copy SHOW_PCX and incorporate it into your      }
{ own programs, provided that:                                               }
{                                                                            }
{  IF YOU COPY SHOW_PCX WITHOUT CHANGING IT:                                 }
{  (1) You must retain this "Permission to Copy" notice, and                 }
{  (2) You must not charge for the SHOW_PCX software or                      }
{      documentation; however, you may charge a service fee for              }
{      disk duplication and distribution, so long as such fee is             }
{      not more than $5.00.                                                  }
{                                                                            }
{  IF YOU MODIFY SHOW_PCX AND/OR INCORPORATE SHOW_PCX INTO YOUR OWN PROGRAMS }
{  (1) You must include the following acknowledgment notice in the           }
{      appropriate places:                                                   }
{                                                                            }
{      Includes portions of SHOW_PCX.                                        }
{      Used by permission of ZSoft Corporation.                              }
{                                                                            }
{                                                                            }
{ ZSoft Corporation reserves all rights to SHOW_PCX except as stated herein. }
{                                                                            }
{                                                                            }
{                  [END OF "PERMISSION TO COPY" NOTICE]                      }
{                                                                            }
{ This program reads a PC Paintbrush PCX file and shows it on the screen.    }
{ The picture must be a 2 color CGA, 4 color CGA, or a 16 color EGA picture. }
{ The picture will be displayed until a key is pressed.                      }
{                                                                            }
{ This program can be run at the DOS prompt - 'SHOW_PCX SAMPLE.PCX'.         }
{                                                                            }
{****************************************************************************}
{                                                                            }
{ Since this program is provided as a service, you are on your own when      }
{ when you modify it to work with your own programs.                         }
{                                                                            }
{ We strive to make every program bug-free. If you find any bugs in this     }
{ program, please contact us on Compuserve (76702,1207)                      }
{ However, this program is provided AS IS and we are not responsible for any }
{ problems you might discover.                                               }
{                                                                            }
{****************************************************************************}
{                                                                            }
{ Remember, some computers and video adapters are NOT 100% compatible, no    }
{ matter what their marketing department may say. This shows up when your    }
{ program runs on everyone's computer EXCEPT a particular clone.             }
{ Unfortunately, there is not much you can do to correct it.                 }
{                                                                            }
{ For example, some early VGA cards do not support the BIOS calls to set up  }
{ a VGA palette - so the PCX image may come up all black, or with the wrong  }
{ colors.                                                                    }
{                                                                            }
{ Also, if you use code that attempts to determine what kind of video card   }
{ is attached to the computer it may lock-up...                              }
{                                                                            }
{****************************************************************************}
{                                                                            }
{ The PCX file format was originally developed in 1982, when there were only }
{ three video addapters: CGA, Hercules, and the Tecmar Graphics Master. Over }
{ the years, as new hardware became available (EGA, VGA, etc.), we had to    }
{ modify the format. Wherever posible, we insure downward compatiblity. This }
{ means, if you follow the suggestions in this program, your own program     }
{ should be able to read 'new' PCX files in the future.                      }
{                                                                            }
{****************************************************************************}

{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
{
  NEEDED ADDITIONS:
  CGA palette - read old and new palette - set screen palette
}
{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}


USES
	Crt, Dos;

CONST
	MAX_WIDTH = 4000;    { arbitrary - maximum width (in bytes) of a PCX image }
	COMPRESS_NUM = $C0;  { this is the upper two bits that indicate a count }
	MAX_BLOCK = 4096;

	RED = 0;
	GREEN = 1;
	BLUE = 2;

	CGA4 = $04;          { video modes }
	CGA2 = $06;
	EGA  = $10;
	VGA  = $12;
	MCGA = $13;

type
	Str80 = STRING [80];
	FILE_buffer = ARRAY [0..127] OF Byte;
	block_ARRAY = ARRAY [0..MAX_BLOCK] OF Byte;
	pal_ARRAY = ARRAY [0..255, RED..BLUE] OF Byte;
	ega_ARRAY = ARRAY [0..16] OF Byte;
	line_ARRAY = ARRAY [0..MAX_WIDTH] OF Byte;

	pcx_header = RECORD
	Manufacturer: Byte;     { Always 10 for PCX file }

	Version: Byte;          { 2 - old PCX - no palette (NOT used anymore),
									  3 - no palette,
									  4 - Microsoft Windows - no palette (only in
									  old files, New Windows version USES 3),
									  5 - WITH palette }

	Encoding: Byte;         { 1 is PCX, it is possible that we may add
									  additional encoding methods IN the future }

	Bits_per_pixel: Byte;   { Number of bits to represent a pixel
									  (per plane) - 1, 2, 4, or 8 }

	Xmin: INTEGER;          { Image window dimensions (inclusive) }
	Ymin: INTEGER;          { Xmin, Ymin are usually zero (not always) }
	Xmax: INTEGER;
	Ymax: INTEGER;

	Hdpi: INTEGER;          { Resolution of image (dots per inch) }
	Vdpi: INTEGER;          { Set to scanner resolution - 300 is default }

	ColorMap: ARRAY [0..15, RED..BLUE] OF Byte;
									{ RGB palette data (16 colors or less)
									  256 color palette is appended to END OF FILE }

	Reserved: Byte;         { (used to contain video mode)
									  now it is ignored - just set to zero }

	Nplanes: Byte;          { Number of planes }

	Bytes_per_line_per_plane: INTEGER;   { Number of bytes to allocate
														for a scanline plane.
														MUST be an an EVEN number!
														DO NOT calculate from Xmax-Xmin! }

	PaletteInfo: INTEGER;   { 1 = black & white or color image,
									  2 = grayscale image - ignored IN PB4, PB4+
									  palette must also be set to shades of gray! }

	HscreenSize: INTEGER;   { added for PC Paintbrush IV Plus ver 1.0,  }
	VscreenSize: INTEGER;   { PC Paintbrush IV ver 1.02 (and later)     }
									{ I know it is tempting to use these fields
									  to determine what video mode should be used
									  to display the image - but it is not
									  recommended since the fields will probably
									  just contain garbage. It is better to have
									  the user install for the graphics mode he
									  wants to use... }

	Filler: ARRAY [74..127] OF Byte;     { Just set to zeros }
	END;

VAR
	Name: Str80;                        { Name of PCX file to load }
	ImageName: Str80;                   { Name of PCX file - used by ReadError }
	BlockFile: FILE;                    { file for reading block data }
	BlockData: block_ARRAY;             { 4k data buffer }

	Header: pcx_header;                 { PCX file header }
	Palette256: pal_ARRAY;              { place to put 256 color palette }
	PaletteEGA: ega_ARRAY;              { place to put 17 EGA palette values }
	PCXline: line_ARRAY;                { place to put uncompressed data }

	Ymax: INTEGER;                      { maximum Y value on screen }
	NextByte: INTEGER;                  { index into file buffer in ReadByte }
	Index: INTEGER;                     { PCXline index - where to put Data }
	Data: Byte;                         { PCX compressed data byte }

	PictureMode: INTEGER;               { Graphics mode number }
	Reg: Registers;                     { Register set - used for int 10 calls }


{ ================================= Error ================================== }

PROCEDURE Error (s: Str80 );

{ Print out the error message and wait, then halt }

VAR c: CHAR;
	i: INTEGER;

BEGIN
	TextMode (C80);
	WriteLn ('ERROR');
	WriteLn (s);
	Halt;
END;   { Error }


{ =============================== ReadError =============================== }

PROCEDURE ReadError (msg: INTEGER);

{ Check for an i/o error }

BEGIN
	IF IOResult <> 0 THEN
	CASE msg OF
		1: Error ('Can''t open file - ' + ImageName);
		2: Error ('Error closing file - ' + ImageName + ' - disk may be full');
		3: Error ('Error reading file - ' + ImageName);

		ELSE
		Error ('Error doing file I/O - ' + ImageName);
	END;   { case }
END;   { ReadError }


{ =========================== VideoMode =============================== }

PROCEDURE VideoMode (n: INTEGER);

{ Do a BIOS call to set the video mode }
{ In Turbo Pascal, a '$' means the number is hexadeximal. }

BEGIN
	Reg.ah := $00;
	Reg.al := n;                         { mode number }
	intr ($10, Reg);                     { call interrupt }
END;  { VideoMode }


{ =========================== EGApalette =============================== }

PROCEDURE EGApalette (n, R, G, B: INTEGER);

{ Set a single EGA's palette register.
  n is the index of the palette register.
  R, G, and B are 0..255. }

{ This code is never called - it is here as an example }

{ In Turbo Pascal, a '$' means the number is hexadeximal. }

VAR i: INTEGER;

BEGIN
	R := R SHR 6;                        { R, G, and B are now 0..3 }
	G := G SHR 6;
	B := B SHR 6;
	i := (R SHL 4) + (G SHL 2) + B;

	Reg.ah := $10;
	Reg.al := 0;                         { set individual palette register }
	Reg.bh := i;                         { value }
	Reg.bl := n;                         { palette register number }
	intr ($10, Reg);                     { call interrupt }
END;  { EGApalette }


{ =========================== VGApalette =============================== }

PROCEDURE VGApalette (n, R, G, B: INTEGER);

{ Set a single VGA palette and DAC register pair.
  n is the index of the palette register.
  R, G, and B are 0..255. }

{ This code is never called - it is here as an example }

{ In Turbo Pascal, a '$' means the number is hexadeximal. }

BEGIN
	R := R SHR 2;                        { R, G, and B are now 0..63 }
	G := G SHR 2;
	B := B SHR 2;

	Reg.ah := $10;                       { Set Palette Call }
	Reg.al := $0;                        { set individual palette register }
	Reg.bl := n;                         { palette register number 0..15, 0..255 }
	Reg.bh := n;                         { palette register value }
	intr ($10, Reg);                     { call interrupt }

	Reg.ah := $10;                       { Set DAC Call }
	Reg.al := $10;                       { set individual DAC register }
	Reg.bx := n;                         { DAC register number 0..15, 0..255 }
	Reg.dh := R;                         { red value 0..63 }
	Reg.ch := G;                         { green value 0..63 }
	Reg.cl := B;                         { blue value 0..63 }
	intr ($10, Reg);                     { call interrupt }
END;  { VGApalette }


{ =========================== EGA16palette =============================== }

PROCEDURE EGA16palette;

{ Set the EGA's entire 16 color palette. }
{ In Turbo Pascal, a '$' means the number is hexadeximal. }

VAR
	i, r, g, b: INTEGER;

BEGIN
	FOR i := 0 TO 15 DO
	BEGIN
		r := Header.ColorMap [i, RED]   SHR 6;       { r, g, and b are now 0..3 }
		g := Header.ColorMap [i, GREEN] SHR 6;
		b := Header.ColorMap [i, BLUE]  SHR 6;
		PaletteEGA [i] := (r SHL 4) + (g SHL 2) + b;
	END;
	PaletteEGA [16] := 0;                { border color }

	Reg.ah := $10;                       { Set Palette Call }
	Reg.al := $02;                       { set a block of palette registers }
	Reg.dx := ofs (PaletteEGA);          { offset of block }
	Reg.es := seg (PaletteEGA);          { segment of block }
	intr ($10, Reg);                     { call interrupt }

END;  { EGA16palette }


{ =========================== VGA16palette =============================== }

PROCEDURE VGA16palette;

{ Set the VGA's entire 16 color palette. }
{ In Turbo Pascal, a '$' means the number is hexadeximal. }

VAR
	i: INTEGER;

BEGIN
	FOR i := 0 TO 15 DO
	PaletteEGA [i] := i;
	PaletteEGA [16] := 0;                { border color }

	Reg.ah := $10;                       { Set Palette Call }
	Reg.al := $02;                       { set a block of palette registers }
	Reg.dx := ofs (PaletteEGA);          { offset of block }
	Reg.es := seg (PaletteEGA);          { segment of block }
	intr ($10, Reg);                     { call interrupt }

	FOR i := 0 TO 15 DO
	BEGIN                                          { R, G, and B must be 0..63 }
		Palette256 [i, RED]   := Header.ColorMap [i, RED]   SHR 2;
		Palette256 [i, GREEN] := Header.ColorMap [i, GREEN] SHR 2;
		Palette256 [i, BLUE]  := Header.ColorMap [i, BLUE]  SHR 2;
	END;

	Reg.ah := $10;                       { Set DAC Call }
	Reg.al := $12;                       { set a block of DAC registers }
	Reg.bx := 0;                         { first DAC register number }
	Reg.cx := 255;                       { number of registers to update }
	Reg.dx := ofs (Palette256);          { offset of block }
	Reg.es := seg (Palette256);          { segment of block }
	intr ($10, Reg);                     { call interrupt }

END;  { VGA16palette }


{ =========================== EntireVGApalette =============================== }

PROCEDURE EntireVGApalette;

{ Set the VGA's entire 256 color palette. }
{ In Turbo Pascal, a '$' means the number is hexadeximal. }

VAR
	i: INTEGER;

BEGIN
	FOR i := 0 TO 255 DO
	BEGIN                                          { R, G, and B must be 0..63 }
		Palette256 [i, RED]   := Palette256 [i, RED]   SHR 2;
		Palette256 [i, GREEN] := Palette256 [i, GREEN] SHR 2;
		Palette256 [i, BLUE]  := Palette256 [i, BLUE]  SHR 2;
	END;

	Reg.ah := $10;                       { Set DAC Call }
	Reg.al := $12;                       { set a block of DAC registers }
	Reg.bx := 0;                         { first DAC register number }
	Reg.cx := 255;                       { number of registers to update }
	Reg.dx := ofs (Palette256);          { offset of block }
	Reg.es := seg (Palette256);          { segment of block }
	intr ($10, Reg);                     { call interrupt }

END;  { EntireVGApalette }


{ =========================== SetPalette =============================== }

PROCEDURE SetPalette;

{ Set up the entire graphics palette }

VAR i: INTEGER;

BEGIN
	IF PictureMode = MCGA THEN
		EntireVGApalette
	ELSE IF PictureMode = VGA THEN
		VGA16palette
	ELSE
		EGA16palette;
END;  { SetPalette }


{ =========================== ShowCGA =============================== }

PROCEDURE ShowCGA (Y: INTEGER);

{ Put a line of CGA data on the screen }
{ In Turbo Pascal, a '$' means the number is hexadeximal. }

VAR
	i, j, l, m, t: INTEGER;
	Yoffset: INTEGER;
	CGAScreen: ARRAY [0..32000] OF Byte ABSOLUTE $B800:$0000;

BEGIN
	i := 8 DIV Header.Bits_per_pixel;        { i is pixels per byte }

	IF (i = 8) THEN                          { 1 bit per pixel }
		j := 7
	ELSE                                     { 2 bits per pixel }
		j := 3;

	t := (Header.Xmax - Header.Xmin + 1);    { width in pixels }
	m := t AND j;                            { left over bits }

	l := (t + j) DIV i;                      { compute number of bytes to display }
	IF l > 80 THEN
	BEGIN
		l := 80;                              { don't overrun screen width }
		m := 0;
	END;

	IF (m <> 0) THEN                         { we need to mask unseen pixels }
	BEGIN
		m := $FF SHL (8 - (m * Header.Bits_per_pixel));   { m = mask }
		t := l - 1;
		PCXline [t] := PCXline [t] AND m;     { mask off unseen pixels }
	END;

	Yoffset := 8192 * (Y AND 1);
	Move (PCXline [0], CGAScreen [((Y SHR 1) * 80) + Yoffset], l);

END;   { ShowCGA }


{ =========================== ShowEGA =============================== }

PROCEDURE ShowEGA (Y: INTEGER);

{ Put a line of EGA (or VGA) data on the screen }
{ In Turbo Pascal, a '$' means the number is hexadeximal. }

VAR
	i, j, l, m, t: INTEGER;
	EGAplane: INTEGER;
	EGAscreen: ARRAY [0..32000] OF Byte ABSOLUTE $A000:$0000;

BEGIN
	EGAplane := $0100;                       { the first plane to update }
	PortW [$3CE] := $0005;                   { use write mode 0 }

{ PortW [$3CE] := $0005;      does port I/O by words. It is the same as:

  Out 03CEh,05h
  Out 03CFh,00h
}

	t := (Header.Xmax - Header.Xmin + 1);    { width in pixels }
	m := t AND 7;                            { left over bits }

	l := (t + 7) SHR 3;                      { compute number of bytes to display }
	IF (l >= 80) THEN
	BEGIN
		l := 80;                              { don't overrun screen width }
		m := 0;
	END;

	IF (m <> 0) THEN
	m := $FF SHL (8 - m)                  { m = mask for unseen pixels }
	ELSE
	m := $FF;

	FOR i := 0 TO Header.Nplanes-1 DO
	BEGIN
		j := i * Header.Bytes_per_line_per_plane;
		t := j + l - 1;
		PCXline [t] := PCXline [t] AND m;           { mask off unseen pixels }

		PortW [$3C4] := EGAplane + 2;               { set plane number }
		Move (PCXline [j], EGAscreen [Y * 80], l);
		EGAplane := EGAplane SHL 1;
	END;

	PortW [$3C4] := $0F02;                         { default plane mask }
END;   { ShowEGA }


{ =========================== ShowMCGA =============================== }

PROCEDURE ShowMCGA (Y: INTEGER);

{ Put a line of MCGA data on the screen }
{ In Turbo Pascal, a '$' means the number is hexadeximal. }

VAR
	l: INTEGER;
	MCGAscreen: ARRAY [0..64000] OF Byte ABSOLUTE $A000:$0000;

BEGIN
	l := Header.XMax - Header.Xmin;            { compute number of bytes to display }
	IF l > 320 THEN
		l := 320;                               { don't overrun screen width }

	Move (PCXline [0], MCGAScreen [Y * 320], l);

END;   { ShowMCGA }


{ =========================== Read256palette =============================== }

PROCEDURE Read256palette;

{ Read in a 256 color palette at end of PCX file }

VAR
	i: INTEGER;
	b: Byte;

BEGIN
	Seek (BlockFile, FileSize (BlockFile) - 769);
	BlockRead (BlockFile, b, 1);           { read indicator byte }
	ReadError (3);

	IF b <> 12 THEN                        { no palette here... }
	Exit;

	BlockRead (BlockFile, Palette256, 3*256);
	ReadError (3);

	Seek (BlockFile, 128);                 { go back to start of PCX data }

END;  { Read256palette }


{ =========================== ReadHeader =============================== }

PROCEDURE ReadHeader;

{ Load a picture header from a PC Paintbrush PCX file }

LABEL WrongFormat;

BEGIN
{$I-}
	BlockRead (BlockFile, Header, 128);         { read 128 byte PCX header }
	ReadError (3);

	{ Is it a PCX file? }
	IF (Header.Manufacturer <> 10) OR (Header.Encoding <> 1) THEN
	BEGIN
		Close (BlockFile);
		Error ('This is not a valid PCX image file.');
	END;

	IF (Header.Nplanes = 4) AND (Header.Bits_per_pixel = 1) THEN
	BEGIN
		IF (Header.Ymax - Header.Ymin) <= 349 THEN
		begin
			PictureMode := EGA;
			Ymax := 349;
		end
		ELSE
		begin
			PictureMode := VGA;
			Ymax := 479;
		END;
	END
	ELSE IF (Header.Nplanes = 1) THEN
	BEGIN
		Ymax := 199;

		IF (Header.Bits_per_pixel = 1) THEN
		PictureMode := CGA2
		ELSE IF (Header.Bits_per_pixel = 2) THEN
		PictureMode := CGA4
		ELSE IF (Header.Bits_per_pixel = 8) THEN
		begin
			PictureMode := MCGA;
			IF Header.Version = 5 then
			Read256palette;
		end
		ELSE
		GOTO WrongFormat;
	END
	ELSE
	BEGIN
		WrongFormat:
		Close (BlockFile);
		Error ('PCX file is in wrong format - It must be a CGA, EGA, VGA, or MCGA image');
	END;

	Index := 0;
	NextByte := MAX_BLOCK;          { indicates no data read in yet... }

END;  { ReadHeader }


{ =========================== ReadByte =============================== }

PROCEDURE ReadByte;

{ read a single byte of data - use BlockRead because it is FAST! }

VAR
	NumBlocksRead: INTEGER;

BEGIN
	IF NextByte = MAX_BLOCK THEN
	BEGIN
		BlockRead (BlockFile, BlockData, MAX_BLOCK, NumBlocksRead);
		NextByte := 0;
	END;

	data := BlockData [NextByte];
	Inc (NextByte);                         { NextByte++; }
END;  { ReadByte }


{ =========================== Read_PCX_Line =============================== }

PROCEDURE Read_PCX_Line;

{ Read a line from a PC Paintbrush PCX file }

VAR
	count: INTEGER;
	bytes_per_line: INTEGER;

BEGIN
{$I-}

	bytes_per_line := Header.Bytes_per_line_per_plane * Header.Nplanes;

	{ bring in any data that wrapped from previous line }
	{ usually none  -  this is just to be safe          }
	IF Index <> 0 THEN
	FillChar (PCXline [0], Index, data);    { fills a contiguous block of data }

	WHILE (Index < bytes_per_line) DO          { read 1 line of data (all planes) }
	BEGIN
		ReadByte;

		IF (data AND $C0) = compress_num THEN
		begin
			count := data AND $3F;
			ReadByte;
			FillChar (PCXline [Index], count, data);  { fills a contiguous block }
			Inc (Index, count);                       { Index += count; }
		end
		ELSE
		begin
			PCXline [Index] := data;
			Inc (Index);                              { Index++; }
		END;
	END;

	ReadError (3);

	Index := Index - bytes_per_line;

{$I+}
END;  { Read_PCX_Line }


{ =========================== Read_PCX =============================== }

PROCEDURE Read_PCX (name: Str80);

{ Read PC Paintbrush PCX file and put it on the screen }

VAR
	k, kmax: INTEGER;

BEGIN
{$I-}
	ImageName := name;                     { used by ReadError }

	Assign (BlockFile, name);
	Reset (BlockFile, 1);                  { use 1 byte blocks }
	ReadError (1);

	ReadHeader;                            { read the PCX header }

{ >>>>> No checking is done to see if the user has the correct hardware <<<<<
  >>>>> to load the image. Your program sure verify the video mode is   <<<<<
  >>>>> supported. Otherwise, the computer may lock-up.                 <<<<< }

	VideoMode (PictureMode);               { switch to graphics mode }
	IF Header.Version = 5 THEN
	SetPalette;                         { set the screen palette, if available }

{ >>>>> Note: You should compute the height of the image as follows. <<<<<
  >>>>> Do NOT just read until End-Of-File!                          <<<<< }

	kmax := Header.Ymin + Ymax;
	IF Header.Ymax < kmax THEN        { don't show more than the screen can display }
	kmax := Header.ymax;

	IF (PictureMode = EGA) OR (PictureMode = VGA) THEN
	BEGIN
		FOR k := Header.Ymin TO kmax DO          { each loop is separate for speed }
		begin
			Read_PCX_Line;
			ShowEGA (k);
		END;
	END
	ELSE IF (PictureMode = MCGA) THEN
	BEGIN
		FOR k := Header.Ymin TO kmax DO
		begin
			Read_PCX_Line;
			ShowMCGA (k);
		END;
	END
	ELSE                                         { it's a CGA picture }
	BEGIN
		FOR k := Header.Ymin TO kmax DO
		begin
			Read_PCX_Line;
			ShowCGA (k);
		END;
	END;

	Close (BlockFile);
	ReadError (2);
{$I+}
END;  { Read_PCX }


{ =========================== DISPLAY_PCX =============================== }

PROCEDURE display_pcx (name: Str80);

{ Display a PCX picture }

VAR
	c: CHAR;

BEGIN
	Read_PCX (name);              { read and display the file }

	WHILE (NOT KeyPressed) DO     { wait for any key to be pressed }
	;{ nothing }

	c := ReadKey;                 { now get rid of the key that was pressed }
	IF c = #0 THEN                { handle function keys }
	c := ReadKey;

END;   { display_pcx }


{ *************************** MAIN ******************************* }

BEGIN
	ClrScr;
	writeln ('         SHOW_PCX - read and display a PC Paintbrush (R) picture');
	WriteLn;
	WriteLn ('                            PERMISSION TO COPY:');
	writeln ('            SHOW_PCX -- (C) Copyright 1989 ZSoft, Corporation.');
	WriteLn;
	writeln ('You are licensed to freely copy SHOW_PCX and incorporate it into your');
	WriteLn ('own programs, provided that:');
	WriteLn ('  IF YOU COPY SHOW_PCX WITHOUT CHANGING IT:');
	writeln ('  (1) You must retain this "Permission to Copy" notice, and');
	writeln ('  (2) You must not charge for the SHOW_PCX software or documentaion;');
	writeln ('      however, you may charge a service fee for disk duplication and');
	writeln ('      distribution, so long as such fee is not more than $5.00');
	writeln ('  IF YOU MODIFY SHOW_PCX AND/OR INCORPORATE SHOW_PCX INTO YOUR OWN PROGRAMS');
	writeln ('  (1) You must include the following notice in the appropriate places:');
	writeln ('      Includes portions of SHOW_PCX. Used by permission of ZSoft Corporation.');
	WriteLn;
	writeln (' ZSoft Corporation reserves all rights to SHOW_PCX except as stated herein.');
	writeln (' ZSoft Corporation,  450 Franklin Road, Suite 100,  Marietta, GA 30067');
	WriteLn (' (404) 428-0008');
	writeln ('                  [END OF "PERMISSION TO COPY" NOTICE]');
	WriteLn;

	IF (ParamCount = 0) THEN           { no DOS command line parameters }
	BEGIN
		writeln ('The image must be a 2 or 4 color CGA, 16 color EGA or VGA,');
		WriteLn ('or a 256 color MCGA picture');
		WriteLn;

		Write ('Enter name of picture file to display: ');
		ReadLn (name);
		WriteLn;
	END
	ELSE
	Name := ParamStr (1);           { get filename from DOS command line }

	IF (Pos ('.', Name) = 0) THEN      { make sure the filename has PCX extension }
	Name := Concat (Name, '.pcx');

	display_pcx (Name);

	TextMode (co80);                   { back to text mode }

END.  { Show_PCX }

