const char * UsageLines [] = {
	"Reads text lines from standard input.",
	"Writes P4 PBM image to standard output.",
	"Each input character becomes an output pixel.",
	"Character specified as (key) becomes a '1' output pixel.",
	"All other inputs become a '0' output pixel.",
	"All input lines must be same size = output width.",
	"Number of input lines = output height.",
	"May 20, 2020.  Newest is at gopher -p users/julianbr sdf.org",
	"(See 'p4show' for the opposite of 'p4paint'.)",
	};
const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] );


struct ImageLine {
	unsigned char * data;
	int width;
	struct ImageLine * next;
	};

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WidthIncrement 5


int ReadKey (struct ImageLine * * ImageLinesPtr, char key)
	{
	struct ImageLine * ImageLine, * * ImageLinePtr;
	unsigned char * WiderLine;
	char c;

	ImageLinesPtr [0] = NULL;
	ImageLinePtr = ImageLinesPtr;
	c = getchar ();
	while (c != EOF) {
		ImageLine = malloc (sizeof (ImageLine [0] ) );
		if (ImageLine == NULL) {
			fprintf (stderr, "***p4paint: Not enough memory.\n");
			return 0;
			}
		ImageLinePtr [0] = ImageLine;
		ImageLine->width = 0;
		ImageLine->next = NULL;
		ImageLinePtr = & ImageLine->next;
		while (c != EOF && c != '\n') {
			if (ImageLine->width%(8*WidthIncrement) == 0) {
				WiderLine = malloc (ImageLine->width/8
						+ WidthIncrement);
				if (WiderLine == NULL) {
					fprintf (stderr, "***p4paint: Not");
					fprintf (stderr, " enough memory.\n");
					return 0;
					}
				if (ImageLine->width > 0) {
					memcpy (WiderLine, ImageLine->data,
							ImageLine->width/8);
					free (ImageLine->data);
					}
				ImageLine->data = WiderLine;
				}
			if (ImageLine->width%8 == 0)
				ImageLine->data [ImageLine->width/8] = 0;
			if (c == key)
				ImageLine->data [ImageLine->width/8]
					+= 1<<(7 - ImageLine->width%8);
			ImageLine->width++;
			c = getchar ();
			}
		if (c != EOF)
			c = getchar ();
		}
	if (ImageLinesPtr [0] == NULL) {
		fprintf (stderr, "***p4paint: No input found.\n");
		return 0;
		}
	return 1;
	}


void WriteImage (struct ImageLine * ImageLines)
	{
	struct ImageLine * ImageLine;
	int width, height;

	height = 0;
	ImageLine = ImageLines;
	while (ImageLine != NULL) {
		height++;
		if (ImageLine == ImageLines)
			width = ImageLine->width;
		else if (ImageLine->width != width) {
			fprintf (stderr, "***p4paint: line #%d", height - 1);
			fprintf (stderr, " is %d long,", width);
			fprintf (stderr, " line #%d", height);
			fprintf (stderr, " is %d long.\n", ImageLine->width);
			fprintf (stderr, "***p4paint: All input lines");
			fprintf (stderr, " must be same length.\n");
			return;
			}
		ImageLine = ImageLine->next;
		}
	printf ("P4\n");
	printf ("%d %d\n", width, height);
	ImageLine = ImageLines;
	while (ImageLine != NULL) {
		if (ImageLine->width > 0)
			fwrite (
					ImageLine->data,
					(ImageLine->width + 7)/8,
					1,
					stdout);
		ImageLine = ImageLine->next;
		}
	}


void CloseImage (struct ImageLine * ImageLines)
	{
	struct ImageLine * ImageLine, * NextImageLine;

	ImageLine = ImageLines;
	while (ImageLine != NULL) {
		NextImageLine = ImageLine->next;
		if (ImageLine->width > 0)
			free (ImageLine->data);
		free (ImageLine);
		ImageLine = NextImageLine;
		}
	}


int main (int argc, char * argv [] )
	{
	struct ImageLine * ImageLines;
	char key, c;
	int i;

	if (argc != 2) {
		fprintf (stderr, "Usage: p4paint (key)\n");
		for (i = 0; i < NumUsageLines; i++)
			printf ("%s\n", UsageLines [i] );
		}
	else if (sscanf (argv [1], "%c%c", & key, & c) != 1) {
		fprintf (stderr, "***p4paint: Improper \"%s\":", argv [1] );
		fprintf (stderr, " must be single character.\n");
		}
	else {
		if (ReadKey (& ImageLines, key) )
			WriteImage (ImageLines);
		CloseImage (ImageLines);
		}
	return 0;
	}