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;
       }