home *** CD-ROM | disk | FTP | other *** search
- /*===================================================================
- <M> Module name - imagemap.c
- <A> Abstract - CGI program for parsing image map requests
- <C> Copyright (C) 1996 MicroPlot Systems Co., Stephen F. Bean
- <C> Released for FREE distribution 11/07/96
- <B> Bibliography
- <B> Many of the definitions for this code came from an excellent book
- <B> entitled: "HTML Sourcebook", by Ian S. Graham, 2nd Edition
- <B> ISBN: 0-471-14242-5, 1996, John Wiley & Sons
- <D> October 25, 1996
- <I> Interface - none
- <V> Version 1.00.00 11/07/96 Stephen F. Bean (published on Internet)
- <R> Revision Record
- <R> 1.
- ;==================================================================*/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <malloc.h>
- #include <math.h>
- #include <direct.h>
- //
- // local string tables
- //
- char *ServerErrors[] = { "Bad Path Error",
- "Map File Not Found",
- "Insufficient Arguments",
- "Bad Arguments"};
- //
- // object types recognized
- //
- char *ObjectTypes[] = { "rect",
- "circ",
- "poly",
- "poin",
- "defa"};
- //
- // local structure defs
- // one of these structures is created for each line in the
- // map file.
- //
- typedef struct {
- int MapRecordNumber;
- int MapObjectType;
- int MapXMin;
- int MapXMax;
- int MapYMin;
- int MapYMax;
- char MapObjectUrl[100];
- int NumMapPoints;
- void *MapRecordPoints;
- void *NextMapRecord;
- } MapRecord;
- //
- // sub structure for x,y data points
- // the first one is pointed to by MapRecordPoints
- //
- typedef struct {
- int MapX;
- int MapY;
- void *NextPoint;
- } MapPoint;
- //
- // global variables
- //
- MapRecord *FirstMapRecord = NULL;
- MapRecord *CurrMapRecord = NULL;
- MapRecord *TempMapRecord = NULL;
- MapPoint *FirstPoint = NULL;
- MapPoint *CurrPoint = NULL;
- MapPoint *TempPoint = NULL;
- //
- // local function prototypes
- //
- void main(int argc, char **argv);
- void ParseMapString(char *MapString);
- void ServerError(int ErrorNumber);
- int CompareRectangle(int Xval, int Yval);
- int CompareCircle(int Xval, int Yval);
- int ComparePolygon(int Xval, int Yval);
- int ComparePoint(int Xval, int Yval);
- int IsLetter(char Value);
- int IsNumber(char Value);
- int IsSeparator(char Value);
- int IsUrl(char Value);
- /*===================================================================
- <M> Module name - main
- <A> Abstract - main module CGI program for parsing image map requests
- <C> Copyright (C) 1996 MicroPlot Systems Co., Stephen F. Bean
- <D> October 25, 1996
- <I> Interface - void main(int argc, char **argv);
- <R> Revision Record
- <R> 1.
- ;==================================================================*/
- void main(int argc, char **argv)
- {
- FILE *CgiMap;
- int idx;
- int FoundRecord;
- char *MapFileString;
- char OutString[100];
- char MapFileName[100];
- char *MapPtr;
- char DefaultUrl[100];
- int Xcoord;
- int Ycoord;
- int ServerPort;
- //
- // check that there are enough passed parms
- // in the command line
- // passed x & y are in second argument as "x,y"
- //
- if(argc >= 2)
- {
- //
- // extract x & y from passed values
- //
- strcpy(OutString, argv[1]);
- MapPtr = strstr(OutString, ",");
- if (MapPtr != NULL)
- {
- *MapPtr = '\0';
- MapPtr++;
- Xcoord = atoi(OutString);
- Ycoord = atoi(MapPtr);
- //
- // get server port number for later
- //
- strcpy(OutString, getenv("SERVER_PORT"));
- ServerPort = atoi(OutString);
- //
- // construct file name for map resource
- //
- DefaultUrl[0] = '\0';
- MapFileString = (char *)calloc(257, sizeof(char));
- _getcwd(MapFileName, 100);
- //
- // patch for default location of OmniHTTPd server
- // user files
- //
- strcpy(OutString, getenv("SERVER_SOFTWARE"));
- if (strstr(OutString, "OmniHTTPd") != NULL)
- {
- strcat(MapFileName, "\\htdocs");
- }
- strcat(MapFileName, getenv("PATH_INFO"));
- idx = 0;
- //
- // since this is DOS, change / to \
- //
- while ((unsigned)idx < strlen(MapFileName))
- {
- if (MapFileName[idx] == '/')
- {
- MapFileName[idx] = '\\';
- }
- idx++;
- }
- //
- // open map file and parse it line by line
- // create a structure for each map line
- // a map file has the following syntax:
- // <object type> <URL> <x,y pairs>
- // where object type can be: rectangle, circle, polygon, point, default
- // URL - depends upon the HTTP server but usually is a relative URL to a HTML file
- // x,y pairs separated by spaces or commas
- //
- if ((CgiMap = fopen(MapFileName, "r")) != NULL)
- {
- while (fgets(MapFileString, 255, CgiMap) != NULL)
- {
- ParseMapString(MapFileString);
- }
- fclose(CgiMap);
- //
- // look through parsed map records to see if
- // current position maps to a URL
- //
- FoundRecord = 0;
- CurrMapRecord = FirstMapRecord;
- while (CurrMapRecord != NULL)
- {
- switch(CurrMapRecord->MapObjectType)
- {
- case 0: // rectangle
- if (CompareRectangle(Xcoord, Ycoord) != 0)
- {
- FoundRecord = 1;
- TempMapRecord = CurrMapRecord;
- }
- break;
- case 1: // circle
- if (CompareCircle(Xcoord, Ycoord) != 0)
- {
- FoundRecord = 1;
- TempMapRecord = CurrMapRecord;
- }
- break;
- case 2: // polygon
- if (ComparePolygon(Xcoord, Ycoord) != 0)
- {
- FoundRecord = 1;
- TempMapRecord = CurrMapRecord;
- }
- break;
- case 3: // point
- if (ComparePoint(Xcoord, Ycoord) != 0)
- {
- FoundRecord = 1;
- TempMapRecord = CurrMapRecord;
- }
- break;
- case 4:
- strcpy(DefaultUrl, CurrMapRecord->MapObjectUrl);
- break;
- default: // bad object type
- break;
- }
- CurrMapRecord = CurrMapRecord->NextMapRecord;
- }
- //
- // construct a complete url
- // get chars up to first '.' in server name
- // this may not be right but I had to do it to make it work on my system
- // I am running Microsoft NT & Win 95 network using TCP/IP and NetBEUI and
- // EMWACS reports my server machine whose name is "fileserver" as
- // fileserver.MICROPLOT ?? MicroPlot is the workgroup name on my network
- // but EMWACS appends it to the host name.
- //
- strcpy(OutString, getenv("SERVER_NAME"));
- if ((MapPtr = strstr(OutString, ".")) != NULL)
- {
- *MapPtr = '\0';
- }
- strcpy(MapFileString, "http://");
- strcat(MapFileString, OutString);
- if (ServerPort != 80)
- {
- sprintf(OutString, ":%d", ServerPort);
- strcat(MapFileString, OutString);
- }
- //
- // get user and directory portion of path
- //
- strcpy(OutString, getenv("PATH_INFO"));
- idx = strlen(OutString) -1;
- while ((OutString[idx] != '/') && (idx >= 0))
- {
- idx--;
- }
- OutString[idx] = '\0';
- strcat(MapFileString, OutString);
- //
- // return value to http server
- // using a Location: directive
- // send map object url if found
- //
- if (FoundRecord != 0)
- {
- //
- // need to construct complete url
- //
- if (strstr(TempMapRecord->MapObjectUrl, ":") == NULL)
- {
- printf("Location: %s/%s\n\n",MapFileString, TempMapRecord->MapObjectUrl);
- }
- //
- // url is complete with http://...
- //
- else
- {
- printf("Location: %s\n\n",TempMapRecord->MapObjectUrl);
- }
- }
- //
- // send default url if not found
- //
- else
- {
- if (DefaultUrl[0] == '\0')
- {
- printf("Content-TYPE: text/html\n\n");
- printf("<HEAD><TITLE>MicroPlot IsMap Server</TITLE></HEAD><BODY>No Default URL in Map</BODY><BR>\n");
- }
- else
- {
- if (strstr(DefaultUrl, ":") == NULL)
- {
- printf("Location: %s/%s\n\n",MapFileString, DefaultUrl);
- }
- else
- {
- printf("Location: %s\n\n",DefaultUrl);
- }
- }
- }
- }
- else
- {
- ServerError(1);
- }
- }
- else
- {
- ServerError(3);
- }
- }
- //
- // clean up before exiting
- //
- free(MapFileString);
- CurrMapRecord = FirstMapRecord;
- while (CurrMapRecord != NULL)
- {
- TempMapRecord = CurrMapRecord->NextMapRecord;
- CurrPoint = CurrMapRecord->MapRecordPoints;
- while (CurrPoint != NULL)
- {
- TempPoint = CurrPoint->NextPoint;
- free(CurrPoint);
- CurrPoint = TempPoint;
- }
- free(CurrMapRecord);
- CurrMapRecord = TempMapRecord;
- }
- }
- /*===================================================================
- <M> Module name - ParseMapString
- <A> Abstract - take string data from map file and put in structures
- <C> Copyright (C) 1996 MicroPlot Systems Co., Stephen F. Bean
- <D> October 25, 1996
- <I> Interface - void ParseMapString(char *MapString);
- <R> Revision Record
- <R> 1.
- ;==================================================================*/
- void ParseMapString(char *MapString)
- {
- int idx;
- int ObjType;
- int LeftPtr;
- int RightPtr;
- int NewX;
- int NewY;
- int ParseState;
- int MapPoints;
-
- idx = 0;
- MapPoints = 0;
- FirstPoint = NULL;
- CurrPoint = NULL;
- //
- // passed line has to include at least an object definition and URL
- // # is interpreted as a comment line (this may be an extension)
- //
- if (((RightPtr = strlen(MapString)) < 10) || (MapString[0] == '#'))
- {
- return;
- }
- //
- // create new map object structure
- //
- if ((TempMapRecord = (MapRecord *)calloc(sizeof(MapRecord), sizeof(char))) == NULL)
- {
- return;
- }
- //
- // set up linked list pointers and min/max values
- //
- TempMapRecord->NextMapRecord = NULL;
- TempMapRecord->MapRecordPoints = NULL;
- TempMapRecord->MapXMin = 9999;
- TempMapRecord->MapXMax = 0;
- TempMapRecord->MapYMin = 9999;
- TempMapRecord->MapYMax = 0;
- if (FirstMapRecord == NULL)
- {
- FirstMapRecord = TempMapRecord;
- TempMapRecord->MapRecordNumber = 0;
- }
- else
- {
- CurrMapRecord->NextMapRecord = TempMapRecord;
- TempMapRecord->MapRecordNumber = CurrMapRecord->MapRecordNumber + 1;
- }
- CurrMapRecord = TempMapRecord;
- CurrMapRecord->MapObjectType = -1;
- //
- // state machine
- // extracts object type, URL, and x,y from string
- // until end of string is found.
- //
- ParseState = 0;
- while (idx < RightPtr)
- {
- switch(ParseState)
- {
- //
- // get object type string
- // filter out leading spaces & tabs
- //
- case 0:
- if (IsLetter(MapString[idx]) != 0)
- {
- LeftPtr = idx; // set at first alphabetic
- ParseState++;
- }
- else
- {
- idx++;
- }
- break;
- //
- // get map object type string - mark end of string
- // allowed are: rect(angle), circ(le), poly(gon), poin(t), defa(ult)
- //
- case 1:
- if (IsLetter(MapString[idx]) == 0)
- {
- MapString[idx] = '\0';
- ParseState++;
- }
- else
- {
- idx++;
- }
- break;
- //
- // look up valid object types and
- // save object type in structure
- //
- case 2:
- ObjType = 0;
- for (ObjType = 0; ObjType < 5; ObjType++)
- {
- if (strnicmp(&MapString[LeftPtr], ObjectTypes[ObjType],4) == 0)
- {
- CurrMapRecord->MapObjectType = ObjType;
- break;
- }
- }
- if (CurrMapRecord->MapObjectType >= 0)
- {
- ParseState++;
- }
- else
- {
- idx = RightPtr; // done - error
- }
- break;
- //
- // get URL, skip over white space
- //
- case 3:
- if (IsUrl(MapString[idx]) == 0)
- {
- idx++;
- }
- else
- {
- LeftPtr = idx;
- ParseState++;
- }
- break;
- //
- // find end of URL
- //
- case 4:
- if (IsUrl(MapString[idx]) != 0)
- {
- idx++;
- }
- else
- {
- MapString[idx] = '\0';
- strcpy(CurrMapRecord->MapObjectUrl, &MapString[LeftPtr]);
- ParseState++;
- }
- break;
- //
- // skip over white spaces
- //
- case 5:
- NewX = -1;
- NewY = -1;
- if (IsNumber(MapString[idx]) == 0)
- {
- idx++;
- }
- else
- {
- LeftPtr = idx;
- ParseState++;
- }
- break;
- //
- // get x
- //
- case 6:
- if (IsNumber(MapString[idx]) != 0)
- {
- idx++;
- }
- else
- {
- MapString[idx] = '\0';
- ParseState++;
- }
- break;
- //
- // save newx
- //
- case 7:
- NewX = atoi(&MapString[LeftPtr]);
- if (NewX < CurrMapRecord->MapXMin)
- {
- CurrMapRecord->MapXMin = NewX;
- }
- if (NewX > CurrMapRecord->MapXMax)
- {
- CurrMapRecord->MapXMax = NewX;
- }
- ParseState++;
- break;
- //
- // skip over white space
- //
- case 8:
- if (IsNumber(MapString[idx]) == 0)
- {
- idx++;
- }
- else
- {
- LeftPtr = idx;
- ParseState++;
- }
- break;
- case 9: // get new y
- if (IsNumber(MapString[idx]) != 0)
- {
- idx++;
- }
- else
- {
- MapString[idx] = '\0';
- ParseState++;
- }
- break;
- //
- // save new y
- //
- case 10:
- NewY = atoi(&MapString[LeftPtr]);
- if (NewY < CurrMapRecord->MapYMin)
- {
- CurrMapRecord->MapYMin = NewY;
- }
- if (NewY > CurrMapRecord->MapYMax)
- {
- CurrMapRecord->MapYMax = NewY;
- }
- ParseState++;
- break;
- //
- // create new point record to save x & y
- // x,y points are stored in a second linked list
- // the head of the x,y linked list is stored in
- // MapRecordPoints in each map structure
- //
- case 11:
- if ((TempPoint = (MapPoint *)malloc(sizeof(MapPoint))) == NULL)
- {
- return;
- }
- TempPoint->NextPoint = NULL;
- if (FirstPoint == NULL)
- {
- FirstPoint = TempPoint;
- CurrMapRecord->MapRecordPoints = TempPoint;
- }
- else
- {
- CurrPoint->NextPoint = TempPoint;
- }
- CurrPoint = TempPoint;
- CurrPoint->MapX = NewX;
- CurrPoint->MapY = NewY;
- MapPoints++;
- ParseState = 5; // get more x,y
- break;
- }
- }
- CurrMapRecord->NumMapPoints = MapPoints;
- }
- /*===================================================================
- <M> Module name - CompareRectangle
- <A> Abstract - compare passed x,y with current map record
- <C> Copyright (C) 1996 MicroPlot Systems Co., Stephen F. Bean
- <D> October 27, 1996
- <I> Interface - int CompareRectangle(int Xval, int Yval);
- <R> Revision Record
- <R> 1.
- ;==================================================================*/
- int CompareRectangle(int Xval, int Yval)
- {
- if ((Xval < CurrMapRecord->MapXMin) ||
- (Xval > CurrMapRecord->MapXMax) ||
- (Yval < CurrMapRecord->MapYMin) ||
- (Yval > CurrMapRecord->MapYMax))
- {
- return(0);
- }
- else
- {
- return(1);
- }
- }
- /*===================================================================
- <M> Module name - CompareCircle
- <A> Abstract - compare passed x,y with current map record
- <C> Copyright (C) 1996 MicroPlot Systems Co., Stephen F. Bean
- <D> October 27, 1996
- <I> Interface - int CompareCircle(int Xval, int Yval);
- <R> Revision Record
- <R> 1.
- ;==================================================================*/
- int CompareCircle(int Xval, int Yval)
- {
- int Xp, Yp;
- int Xc, Yc;
- double dist, radius;
- //
- // the 2 x,y points passed are (1) the center of the circle and (2) a point on the
- // circle. I compute the radius of the circle and the distance between the center
- // of the circle and the passed point.
- //
- if (CurrMapRecord->NumMapPoints == 2)
- {
- CurrPoint = CurrMapRecord->MapRecordPoints;
- Xc = CurrPoint->MapX;
- Yc = CurrPoint->MapY;
- CurrPoint = CurrPoint->NextPoint;
- Xp = CurrPoint->MapX;
- Yp = CurrPoint->MapY;
- radius = sqrt((double)((Xc - Xp) * (Xc - Xp)) + (double)((Yc - Yp) * (Yc - Yp)));
- dist = sqrt((double)((Xc - Xval) * (Xc - Xval)) + (double)((Yc - Yval) * (Yc - Yval)));
- if (dist <= radius)
- {
- return(1);
- }
- }
- return(0);
- }
- /*===================================================================
- <M> Module name - ComparePolygon
- <A> Abstract - compare passed x,y with current map record
- <A> I wimped out - only test is the trivially rejected points
- <A> outside the bounding box
- <C> Copyright (C) 1996 MicroPlot Systems Co., Stephen F. Bean
- <D> October 27, 1996
- <I> Interface - int ComparePolygon(int Xval, int Yval);
- <R> Revision Record
- <R> 1.
- ;==================================================================*/
- int ComparePolygon(int Xval, int Yval)
- {
- if ((Xval < CurrMapRecord->MapXMin) ||
- (Xval > CurrMapRecord->MapXMax) ||
- (Yval < CurrMapRecord->MapYMin) ||
- (Yval > CurrMapRecord->MapYMax))
- {
- return(0);
- }
- else
- {
- return(1);
- }
- }
- /*===================================================================
- <M> Module name - ComparePoint
- <A> Abstract - compare passed x,y with current map record
- <C> Copyright (C) 1996 MicroPlot Systems Co., Stephen F. Bean
- <D> October 27, 1996
- <I> Interface - int ComparePoint(int Xval, int Yval);
- <R> Revision Record
- <R> 1.
- ;==================================================================*/
- int ComparePoint(int Xval, int Yval)
- {
- CurrPoint = CurrMapRecord->MapRecordPoints;
- if ((CurrPoint->MapX == Xval) && (CurrPoint->MapY == Yval))
- {
- return(1);
- }
- return(0);
- }
- /*===================================================================
- <M> Module name - ServerError
- <A> Abstract - report error to HTTP server
- <C> Copyright (C) 1996 MicroPlot Systems Co., Stephen F. Bean
- <D> October 25, 1996
- <I> Interface - void ServerError(int ErrorNumber);
- <R> Revision Record
- <R> 1.
- ;==================================================================*/
- void ServerError(int ErrorNumber)
- {
- printf("Content-TYPE: text/html\n\n");
- printf("<TITLE>MicroPlot IsMap Server Error</TITLE>");
- printf("<H1>MicroPlot IsMap Server Error</H1>");
- printf("Error is: %s<BR>",ServerErrors[ErrorNumber]);
- }
- /*===================================================================
- <M> Module name - IsNumber, IsLetter, IsSeparator
- <A> Abstract - filters for character types
- <C> Copyright (C) 1996 MicroPlot Systems Co., Stephen F. Bean
- <D> October 25, 1996
- <I> Interface - short IsLetter(char Value);
- <I> Interface - short IsNumber(char Value);
- <I> Interface - short IsSeparator(char Value);
- <R> Revision Record
- <R> 1.
- ;==================================================================*/
- int IsLetter(char Value)
- {
- if (((Value >= 'A') && (Value <= 'Z')) || ((Value >= 'a') && (Value <= 'z')))
- {
- return(1);
- }
- return(0);
- }
-
- int IsNumber(char Value)
- {
- if ((Value >= '0') && (Value <= '9'))
- {
- return(1);
- }
- return(0);
- }
-
- int IsSeparator(char Value)
- {
- if ((Value == ' ') || (Value == ',') || (Value == '\t'))
- {
- return(1);
- }
- return(0);
- }
-
- int IsUrl(char Value)
- {
- if (((Value >= 0) && (Value <= 0x1f)) ||
- (Value == 0x09) || // tab
- (Value == 0x22) || // double quote
- (Value == '>') ||
- (Value == '<') ||
- (Value == ' ') ||
- (Value == '[') ||
- (Value == ']') ||
- (Value == '\\') ||
- (Value == '^') ||
- (Value == '`') ||
- (Value == '{') ||
- (Value == '}') ||
- (Value == '|') ||
- (Value == '~'))
- {
- return(0);
- }
- return(1);
- }