const char * UsageLines [] = {
       "Usage: llfind (latitude) (longitude)... < (input file)"
       "",
       "Finds points inside a perimeter containing straight line segments",
       "oriented E-W which are specified by latitude, and straight line",
       "segments oriented N-S which are specified by longitude.",
       "Input must contain lines beginning with:",
       "\t(latitude),(longitude)",
       "",
       "Outputs points that are inside (or on) the borders specified.",
       "Rounds input and borders to and displays output at 4 decimal places.",
       "Displays area in \"GeoAres\": a GeoAre is a rectangle whose",
       "sides are .0001 degree latitude, and .0001 degree longitude apart.",
       "(1 sq km = 8100 GeoAres at the equator,",
       " 1 sq km = 12600 GeoAres at 50 degrees latitude.)",
       "",
       "March 10, 2013",
       "Latest version can be found at:",
       " gopher -p users/julianbr sdf.org",
       "or: gopher://sdf.org/1/users/julianbr",
       };
const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] );

#include <stdlib.h>
#include <stdio.h>
#define NumDecimalPlaces 4


int ReadLocation (
               long int * northPtr,
               long int * eastPtr,
               int * endOfInputLinePtr,
               int * endOfInputPtr)
       {
       char sign;
       int decimalPosition, LatitudeAndLongitudeOk, c;

       LatitudeAndLongitudeOk = 0;
       endOfInputLinePtr [0] = 0;
       c = getchar ();
       sign = '+';
       if (c == '-' || c == '+') {
               sign = c;
               c = getchar ();
               }
       northPtr [0] = 0;
       while (c >= '0' && c <= '9') {
               northPtr [0] = 10*northPtr [0] + (c - '0');
               c = getchar ();
               }
       decimalPosition = 0;
       if (c == '.') {
               c = getchar ();
               while (c >= '0' && c <= '9') {
                       if (decimalPosition == NumDecimalPlaces) {
                               if (c > '4')
                                       northPtr [0]++;
                               }
                       else if (decimalPosition < NumDecimalPlaces)
                               northPtr [0]
                                       = 10*northPtr [0] + (c - '0');
                       decimalPosition++;
                       c = getchar ();
                       }
               }
       while (decimalPosition < NumDecimalPlaces) {
               northPtr [0] = 10*northPtr [0];
               decimalPosition++;
               }
       if (sign == '-')
               northPtr [0] = - northPtr [0];
       if (c == ',') {
               c = getchar ();
               sign = '+';
               if (c == '-' || c == '+') {
                       sign = c;
                       c = getchar ();
                       }
               eastPtr [0] = 0;
               while (c >= '0' && c <= '9') {
                       eastPtr [0] = 10*eastPtr [0] + (c - '0');
                       c = getchar ();
                       }
               decimalPosition = 0;
               if (c == '.') {
                       c = getchar ();
                       while (c >= '0' && c <= '9') {
                               if (decimalPosition == NumDecimalPlaces) {
                                       if (c > '4')
                                               eastPtr [0]++;
                                       }
                               else if (decimalPosition < NumDecimalPlaces)
                                       eastPtr [0]
                                               = 10*eastPtr [0]
                                               + (c - '0');
                               decimalPosition++;
                               c = getchar ();
                               }
                       }
               while (decimalPosition < NumDecimalPlaces) {
                       eastPtr [0] = 10*eastPtr [0];
                       decimalPosition++;
                       }
               if (sign == '-')
                       eastPtr [0] = - eastPtr [0];
               LatitudeAndLongitudeOk = 1;
               }
       if (c != EOF && c != '\n' && c != ' ') {
               fprintf (stderr, "***llfind: Improper '%c'", c);
               LatitudeAndLongitudeOk = 0;
               }
       else if (c != EOF && !LatitudeAndLongitudeOk)
               fprintf (stderr, "***llfind: Comma not found");
       if (c == EOF) {
               endOfInputLinePtr [0] = 1;
               endOfInputPtr [0] = 1;
               }
       if (c == '\n')
               endOfInputLinePtr [0] = 1;
       return LatitudeAndLongitudeOk;
       }


long int ReadBoundary (char * Boundary)
       {
       long int boundaryValue;
       int decimalPosition;
       char sign, * ptr;

       ptr = Boundary;
       sign = '+';
       if (ptr [0] == '-' || ptr [0] == '+') {
               sign = ptr [0];
               ptr++;
               }
       boundaryValue = 0;
       while (ptr [0] >= '0' && ptr [0] <= '9') {
               boundaryValue = 10*boundaryValue + (ptr [0] - '0');
               ptr++;
               }
       decimalPosition = 0;
       if (ptr [0] == '.') {
               ptr++;
               while (ptr [0] >= '0' && ptr [0] <= '9') {
                       if (decimalPosition == NumDecimalPlaces) {
                               if (ptr [0] > '4')
                                       boundaryValue++;
                               }
                       else if (decimalPosition < NumDecimalPlaces)
                               boundaryValue
                                       = 10*boundaryValue
                                       + (ptr [0] - '0');
                       decimalPosition++;
                       ptr++;
                       }
               }
       while (decimalPosition < NumDecimalPlaces) {
               boundaryValue = 10*boundaryValue;
               decimalPosition++;
               }
       if (sign == '-')
               boundaryValue = - boundaryValue;
       return boundaryValue;
       }


void FindAreaInsideBoundaries (
               int numBoundaries,
               char * * Boundaries)
       {
       long int cwArea, east;
       int i;

       cwArea = 0;
       east = 0;
       for (i = 1; i < numBoundaries; i += 2) {
               east += ReadBoundary (Boundaries [i] );
               }
       east /= numBoundaries/2;
       for (i = 1; i < numBoundaries; i += 2) {
               cwArea += (ReadBoundary (Boundaries [(i + 1)%numBoundaries] )
                               - ReadBoundary (Boundaries [i - 1] ) )
                       *(east - ReadBoundary (Boundaries [i] ) );
               }
       if (cwArea < 0)
               cwArea = - cwArea;
       fprintf (stderr, "llfind: %ld GeoAres", cwArea);
       fprintf (stderr, " inside specified boundaries.\n");
       }


int IsInsideOrOnBoundaries (
               long int north,
               long int east,
               int numBoundaries,
               char * * Boundaries)
       {
       long int north1, east2, north3, east4;
       int numCrossings, i;

       numCrossings = 0;
       for (i = 0; i < numBoundaries/2; i++) {
               north1 = ReadBoundary (
                               Boundaries [(i + i + 0)%numBoundaries] );
               east2 = ReadBoundary (
                               Boundaries [(i + i + 1)%numBoundaries] );
               north3 = ReadBoundary (
                               Boundaries [(i + i + 2)%numBoundaries] );
               east4 = ReadBoundary (
                               Boundaries [(i + i + 3)%numBoundaries] );
               if (east == east2
                               && !(north < north1 && north < north3)
                               && !(north > north1 && north > north3) )
                       return 1;
               else if (north == north3
                               && !(east < east2 && east < east4)
                               && !(east > east2 && east > east4) )
                       return 1;
               else if (north >= north1 && north < north3) {
                       if (east >= east2)
                               numCrossings++;
                       }
               else if (north >= north3 && north < north1) {
                       if (east >= east2)
                               numCrossings--;
                       }
               }
       if (numCrossings == 0)
               return 0;
       return 1;
       }


int BoundaryOk (char * Boundary)
       {
       char * ptr;

       ptr = Boundary;
       if (ptr [0] == '-' || ptr [0] == '+')
               ptr++;
       while (ptr [0] >= '0' && ptr [0] <= '9')
               ptr++;
       if (ptr [0] == '.')
               ptr++;
       while (ptr [0] >= '0' && ptr [0] <= '9')
               ptr++;
       if (ptr [0] == '\0')
               return 1;
       return 0;
       }


int BoundariesOk (int numBoundaries, char * * Boundaries)
       {
       int i, ok;

       ok = 1;
       for (i = 0; i < numBoundaries; i++) {
               if (!BoundaryOk (Boundaries [i] ) ) {
                       fprintf (stderr, "***llfind: Improper boundary:");
                       fprintf (stderr, " \"%s\".\n", Boundaries [i] );
                       ok = 0;
                       }
               }
       return ok;
       }


void WriteLocation (
               long int north,
               long int east,
               int endOfInputLine,
               int * endOfInputPtr)
       {
       unsigned long int value, factor;
       int i, c;

       if (north < 0) {
               putchar ('-');
               value = - north;
               }
       else {
               putchar ('+');
               value = north;
               }
       factor = 1;
       for (i = 0; i < NumDecimalPlaces + 2; i++)
               factor *= 10;
       for (i = 0; i < 2; i++) {
               factor /= 10;
               putchar ('0' +  value/factor%10);
               }
       putchar ('.');
       for (i = 0; i < NumDecimalPlaces; i++) {
               factor /= 10;
               putchar ('0' + value/factor%10);
               }
       putchar (',');
       if (east < 0) {
               putchar ('-');
               value = - east;
               }
       else {
               putchar ('+');
               value = east;
               }
       factor = 1;
       for (i = 0; i < NumDecimalPlaces + 3; i++)
               factor *= 10;
       for (i = 0; i < 3; i++) {
               factor /= 10;
               putchar ('0' + value/factor%10);
               }
       putchar ('.');
       for (i = 0; i < NumDecimalPlaces; i++) {
               factor /= 10;
               putchar ('0' + value/factor%10);
               }
       if (!endOfInputLine) {
               putchar (' ');
               c = getchar ();
               while (c != EOF && c != '\n') {
                       putchar (c);
                       c = getchar ();
                       }
               if (c == EOF)
                       endOfInputPtr [0] = 1;
               }
       putchar ('\n');
       }


void FindLocationsOnOrInsideBoundaries (
               int numBoundaries,
               char * * Boundaries)
       {
       unsigned long int all, inside, lineNum;
       long int north, east;
       int endOfInputLine, endOfInput, ok, c;

       ok = 1;
       all = 0;
       inside = 0;
       lineNum = 0;
       endOfInput = 0;
       while (!endOfInput) {
               lineNum++;
               if (ReadLocation (
                               & north,
                               & east,
                               & endOfInputLine,
                               & endOfInput) ) {
                       all++;
                       if (IsInsideOrOnBoundaries (
                                       north,
                                       east,
                                       numBoundaries,
                                       Boundaries) ) {
                               inside++;
                               WriteLocation (
                                               north,
                                               east,
                                               endOfInputLine,
                                               & endOfInput);
                               }
                       else if (!endOfInputLine) {
                               c = getchar ();
                               while (c != EOF && c != '\n')
                                       c = getchar ();
                               if (c == EOF)
                                       endOfInput = 1;
                               }
                       }
               else if (!endOfInput) {
                       ok = 0;
                       fprintf (stderr, " in line #%lu.\n", lineNum);
                       if (!endOfInputLine) {
                               c = getchar ();
                               while (c != EOF && c != '\n')
                                       c = getchar ();
                               if (c == EOF)
                                       endOfInput = 1;
                               }
                       }
               }
       if (ok) {
               fprintf (stderr, "llfind: Found %lu inside or", inside);
               fprintf (stderr, " on boundaries out of %lu total.\n", all);
               }
       }

int main (int argc, char * argv [] )
       {
       int i;

       if (argc < 2) {
               for (i = 0; i < NumUsageLines; i++)
                       printf ("%s\n", UsageLines [i] );
               }
       else if ((argc - 1)%2 == 1)
               printf ("***llfind: must specify number pairs.\n");
       else if ((argc - 1) > 0 && BoundariesOk (argc - 1, argv + 1) ) {
               FindAreaInsideBoundaries (argc - 1, argv + 1);
               FindLocationsOnOrInsideBoundaries (argc - 1, argv + 1);
               }
       return 0;
       }