const char * UsageLines [] = { "Usage: p6paint (default r) (default g) (default b)", "Reads input text from standard input and writes ppm image to standard", "output. All input lines should be the same length and will be the", "image width.", "The letter indicates the color for that pixel. The default", "color specified on the command line will be used for", "any letter not in the list.", "", "May 20, 2020. For latest, see gopher://sdf.org/1/users/julianbr", "(For the opposite of 'p6paint' see 'p6show').", "", "Compiled for the following colors (use lowercase letter):" "", }; const int NumUsageLines = sizeof (UsageLines) / sizeof (UsageLines [0] ); const struct { char * name; char letter; int r; int g; int b; } Colors [] = { {"rED", 'r', 255, 0, 0 }, {"PiNK", 'i', 255, 192, 203 }, {"oRANGE", 'o', 255, 127, 0 }, {"yELLOW", 'y', 255, 255, 0 }, {"gREEN", 'g', 0, 255, 0 }, {"bLUE", 'b', 0, 0, 255 }, {"pURPLE", 'p', 128, 0, 128 }, {"wHITE", 'w', 255, 255, 255 }, {"GRaY", 'a', 128, 128, 128 }, {"tAN", 't', 210, 180, 140 }, {"BROWn", 'n', 150, 75, 0 }, {"BLACk", 'k', 0, 0, 0 }, }; const int NumColors = sizeof (Colors) / sizeof (Colors [0] ); #include #include int ReadInputLine (int * EndOfInputPtr, char * * InputLinePtr) { struct Letter { char letter; struct Letter * next; } * Letters, * Letter, * nextLetter, * * LetterPtr; int MemoryOk, length, c, i; MemoryOk = 1; EndOfInputPtr [0] = 0; Letters = NULL; LetterPtr = & Letters; c = getchar (); while (c != EOF && c != '\n' && MemoryOk) { LetterPtr [0] = malloc (sizeof (LetterPtr [0] [0] ) ); if (LetterPtr [0] == NULL) { fprintf (stderr, "***p6paint: Not enough memory.\n"); MemoryOk = 0; } else { LetterPtr [0]->letter = c; LetterPtr [0]->next = NULL; LetterPtr = & LetterPtr [0]->next; } c = getchar (); } length = 0; Letter = Letters; while (Letter != NULL) { length++; Letter = Letter->next; } if (c == EOF) EndOfInputPtr [0] = 1; InputLinePtr [0] = NULL; if (MemoryOk) { InputLinePtr [0] = malloc (length + 1); if (InputLinePtr [0] == NULL) { fprintf (stderr, "***p6paint: Not enough memory.\n"); MemoryOk = 0; } else { i = 0; Letter = Letters; while (i < length && Letter != NULL) { InputLinePtr [0] [i] = Letter->letter; Letter = Letter->next; i++; } InputLinePtr [0] [length] = '\0'; } } Letter = Letters; while (Letter != NULL) { nextLetter = Letter->next; free (Letter); Letter = nextLetter; } return MemoryOk; } int ReadInputLines (int * NumInputLinesPtr, char * * * InputLinesPtr) { struct Line { char * line; struct Line * next; } * Line, * Lines, * nextLine, * * LinePtr; char * InputLine; int MemoryOk, EndOfInput, length, i; MemoryOk = 1; EndOfInput = 0; NumInputLinesPtr [0] = 0; Lines = NULL; LinePtr = & Lines; while (MemoryOk && !EndOfInput) { if (ReadInputLine (& EndOfInput, & InputLine) ) { LinePtr [0] = malloc (sizeof (LinePtr [0] [0] ) ); if (LinePtr [0] == NULL) { fprintf (stderr, "***p6paint: Not enough memory.\n"); MemoryOk = 0; } else { LinePtr [0]->line = InputLine; LinePtr [0]->next = NULL; LinePtr = & LinePtr [0]->next; } } else MemoryOk = 0; } length = 0; Line = Lines; while (Line != NULL) { length++; Line = Line->next; } InputLinesPtr [0] = NULL; if (MemoryOk && length > 0) { InputLinesPtr [0] = malloc (length*sizeof (InputLinesPtr [0] [0] ) ); if (InputLinesPtr [0] == NULL) { fprintf (stderr, "***p6paint: Not enough memory.\n"); MemoryOk = 0; } else { i = 0; Line = Lines; while (i < length && Line != NULL) { InputLinesPtr [0] [i] = Line->line; Line->line = NULL; i++; Line = Line->next; } } } Line = Lines; while (Line != NULL) { if (Line->line != NULL) free (Line->line); nextLine = Line->next; free (Line); Line = nextLine; } NumInputLinesPtr [0] = length; return MemoryOk; } #include int WidthOk (int NumInputLines, char * * InputLines) { int i, width, MinWidth, MaxWidth; if (NumInputLines < 1) { fprintf (stderr, "***p6paint: Empty input.\n"); return 0; } width = strlen (InputLines [0] ); MinWidth = width; MaxWidth = width; for (i = 0; i < NumInputLines; i++) { width = strlen (InputLines [i] ); if (MinWidth > width) MinWidth = width; if (MaxWidth < width) MaxWidth = width; } if (MinWidth == MaxWidth) { fprintf (stderr, "p6paint: Writing %d x %d.\n", MinWidth, NumInputLines); return 1; } fprintf (stderr, "***p6paint: Input lines must be same length,"); fprintf (stderr, " found %d to %d.\n", MinWidth, MaxWidth); return 0; } void WriteImage ( int NumInputLines, char * * InputLines, int r, int g, int b) { int i, j, k, KeyFound; char c; printf ("P6\n"); printf ("%d %d\n", (int) strlen (InputLines [0] ), NumInputLines); printf ("255\n"); for (i = 0; i < NumInputLines; i++) { j = 0; c = InputLines [i] [j]; while (c != '\0') { KeyFound = 0; k = 0; while (!KeyFound && k < NumColors) { if (c == Colors [k].letter) KeyFound = 1; else k++; } if (KeyFound) { putchar (Colors [k].r); putchar (Colors [k].g); putchar (Colors [k].b); } else { putchar (r); putchar (g); putchar (b); } j++; c = InputLines [i] [j]; } } } int main (int argc, char * * argv) { char * * InputLines; int NumInputLines, i, r, g, b, ok; char c; ok = 0; if (argc != 4) { for (i = 0; i < NumUsageLines; i++) printf ("%s\n", UsageLines [i] ); for (i = 0; i < NumColors; i++) printf ("%s ", Colors [i].name); printf ("\n"); } else { ok = 1; if (sscanf (argv [1], "%d%c", & r, & c) != 1 || r < 0 || r > 255) { fprintf (stderr, "***p6paint: Improper r \"%s\"", argv [1] ); fprintf (stderr, " - must be integer from 0 to 255\n"); ok = 0; } if (sscanf (argv [2], "%d%c", & g, & c) != 1 || g < 0 || g > 255) { fprintf (stderr, "***p6paint: Improper g \"%s\"", argv [2] ); fprintf (stderr, " - must be integer from 0 to 255\n"); ok = 0; } if (sscanf (argv [3], "%d%c", & b, & c) != 1 || b < 0 || b > 255) { fprintf (stderr, "***p6paint: Improper b \"%s\"", argv [3] ); fprintf (stderr, " - must be integer from 0 to 255\n"); ok = 0; } } if (ok) { if (ReadInputLines (& NumInputLines, & InputLines) && WidthOk (NumInputLines - 1, InputLines) ) WriteImage ( NumInputLines - 1, InputLines, r, g, b ); for (i = 0; i < NumInputLines; i++) free (InputLines [i] ); if (NumInputLines > 0) free (InputLines); } return 0; }