const char * UsageLines [] = {
       "Usage: linetopbm (width) (height)",
       "Reads space-separated points, from standard input, in the form",
       "\tacross,down",
       "\twhere across and down are positive or negative integers.",
       "Writes, to standard output, a P4 PBM image.",
       "A line one pixel wide will join the points on each input line",
       "\t(that has at least two points).",
       "On each input line, everything after # is treated as a comment.",
       "The leftmost column of pixels is considered - (width)/2 across.",
       "The topmost row of pixels is considered - (height)/2 down.",
       "August 26, 2011.  Newest is at gopher -p users/julianbr sdf.org",
       };
const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] );


struct Segment {
       int across1;
       int down1;
       int across2;
       int down2;
       struct Segment * next;
       };

#include <stdlib.h>
#include <stdio.h>


int ReadSegments (struct Segment * * SegmentsPtr)
       {
       struct Segment * * SegmentPtr;
       unsigned int LineNum;
       int IsNegative, FoundAcross, across, FoundDown, down;
       int PreviousAcross, PreviousDown, PreviousPoint;
       int c, ok;

       ok = 1;
       LineNum = 0;
       SegmentsPtr [0] = NULL;
       SegmentPtr = SegmentsPtr;
       c = getchar ();
       while (c != EOF) {
               LineNum++;
               PreviousPoint = 0;
               while (c != EOF && c != '\n') {
                       while (c == ' ')
                               c = getchar ();
                       /* read across */
                       IsNegative = 0;
                       if (c == '+')
                               c = getchar ();
                       else if (c == '-') {
                               IsNegative = 1;
                               c = getchar ();
                               }
                       FoundAcross = 0;
                       across = 0;
                       while (c >= '0' && c <= '9') {
                               FoundAcross = 1;
                               across = 10*across + (c - '0');
                               c = getchar ();
                               }
                       if (IsNegative)
                               across = - across;
                       if (c == ',')
                               c = getchar ();
                       else
                               FoundAcross = 0;

                       /* read down */
                       IsNegative = 0;
                       if (c == '+')
                               c = getchar ();
                       else if (c == '-') {
                               IsNegative = 1;
                               c = getchar ();
                               }
                       FoundDown = 0;
                       down = 0;
                       while (c >= '0' && c <= '9') {
                               FoundDown = 1;
                               down = 10*down + (c - '0');
                               c = getchar ();
                               }
                       if (IsNegative)
                               down = - down;

                       if (c != EOF && c != '\n' && c != ' ' && c != '#') {
                               fprintf (stderr, "***linetopbm: Improper");
                               fprintf (stderr, " '%c'", c);
                               fprintf (stderr, " in line #%u.\n", LineNum);
                               while (c != EOF && c != '\n' && c != ' '
                                                       && c != '#')
                                       c = getchar ();
                               ok = 0;
                               }
                       else if (FoundAcross && !FoundDown) {
                               fprintf (stderr, "***linetopbm: Incomplete");

                               fprintf (stderr, " across,down");
                               fprintf (stderr, " in line #%u.\n", LineNum);
                               ok = 0;
                               }
                       else if (FoundAcross && FoundDown) {
                               if (PreviousPoint) {
                                       /* Add segment */;
                                       SegmentPtr [0] = malloc (
                                               sizeof (SegmentPtr [0] [0] ) );
                                       if (SegmentPtr [0] == NULL) {
                                               fprintf (stderr, "***");
                                               fprintf (stderr, "linetopbm:");
                                               fprintf (stderr, " Not enough");
                                               fprintf (stderr, " memory.\n");
                                               ok = 0;
                                               }
                                       else {
                                               SegmentPtr [0]->across1
                                                       = PreviousAcross;
                                               SegmentPtr [0]->down1
                                                       = PreviousDown;
                                               SegmentPtr [0]->across2
                                                       = across;
                                               SegmentPtr [0]->down2
                                                       = down;
                                               SegmentPtr [0]->next
                                                       = NULL;
                                               SegmentPtr
                                               = & SegmentPtr [0]->next;
                                               }
                                       }
                               PreviousPoint = 1;
                               PreviousAcross = across;
                               PreviousDown = down;
                               }
                       if (c == '#') {
                               while (c != EOF && c != '\n')
                                       c = getchar ();
                               }
                       }
               if (c != EOF)
                       c = getchar ();
               }
       return ok;
       }


int IsOnSegment (int across, int down, struct Segment * Segments)
       {
       struct Segment * Segment;
       int m, n, x, y, temp;

       Segment = Segments;
       while (Segment != NULL) {
               if (Segment->across1 > Segment->across2) {
                       m = Segment->across1 - Segment->across2 + 1;
                       y = Segment->across1 - across;
                       }
               else {
                       m = Segment->across2 - Segment->across1 + 1;
                       y = across - Segment->across1;
                       }
               if (Segment->down1 > Segment->down2) {
                       n = Segment->down1 - Segment->down2 + 1;
                       x = Segment->down1 - down;
                       }
               else {
                       n = Segment->down2 - Segment->down1 + 1;
                       x = down - Segment->down1;
                       }
               if (m > n) {
                       temp = n;
                       n = m;
                       m = temp;
                       temp = y;
                       y = x;
                       x = temp;
                       }
               if (x >= 0 && x < n) {
                       if (y == (m/2 + m*x)/n)
                               return 1;
                       }
               Segment = Segment->next;
               }
       return 0;
       }


void WriteSegments (
               struct Segment * Segments,
               int width,
               int height)
       {
       /* int i, j, k, m, LineSize, OutputBuffer, pixel; */
       int across, down, OutputWeight, OutputValue;

       printf ("P4\n%d %d\n", width, height);
       for (down = - height/2; down < height - height/2; down++) {
               OutputWeight = 128;
               OutputValue = 0;
               for (across = - width/2; across < width - width/2; across++) {
                       if (IsOnSegment (across, down, Segments) )
                               OutputValue += OutputWeight;
                       OutputWeight /= 2;
                       if (OutputWeight == 0) {
                               putchar (OutputValue);
                               OutputWeight = 128;
                               OutputValue = 0;
                               }
                       }
               if (OutputWeight < 128)
                       putchar (OutputValue);
               }
       }


void CloseSegments (struct Segment * Segments)
       {
       struct Segment * Segment, * NextSegment;

       Segment = Segments;
       while (Segment != NULL) {
               NextSegment = Segment->next;
               free (Segment);
               Segment = NextSegment;
               }
       }


int main (int argc, char * argv [] )
       {
       struct Segment * Segments;
       int width, height, i;
       char c;

       if (argc < 2) {
               for (i = 0; i < NumUsageLines; i++)
                       printf ("%s\n", UsageLines [i] );
               }
       else if (argc == 3
                       && sscanf (argv [1], "%d%c", & width, & c) == 1
                       && width > 0
                       && sscanf (argv [2], "%d%c", & height, & c) == 1
                       && height > 0) {
               if (ReadSegments (& Segments) )
                       WriteSegments (Segments, width, height);
               CloseSegments (Segments);
               }
       else {
               fprintf (stderr, "Usage: linetopbm");
               fprintf (stderr, " (width) (height)\n");
               }
       return 0;
       }