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