CGI Perl Tutorial

Web based School

Appendix D

The ncSA imagemap.c Program


An imagemap is usually made up of regions, or hotspots, defined by polygons, circles, rectangles, and points. The imagemap program is responsible for matching the x,y coordinates of the mouse-click sent to it by the client, with the URI intended for those x,y coordinates.


Listing D.1. The imagemap.c program.

/*
** mapper 1.2
*/

#include <stdio.h>
#include <string.h>
#if !defined(pyr) && !defined(NO_STDLIB_H)
#include <stdlib.h>
#else
#include <sys/types.h>
#include <ctype.h>
char *getenv();
#endif
#include <sys/types.h>
#include <sys/stat.h>

#define CONF_FILE "/usr/local/etc/httpd/conf/imagemap.conf"

#define MAXLINE 500
#define MAXVERTS 100
#define X 0
#define Y 1
#define LF 10
#define CR 13

int isname(char);

int main(int argc, char **argv)
{
    char input[MAXLINE], *mapname, def[MAXLINE], conf[MAXLINE], errstr[MAXLINE];
    double testpoint[2], pointarray[MAXVERTS][2];
    int i, j, k;
    FILE *fp;
    char *t;
    double dist, mindist;
    int sawpoint = 0;
    
    if (argc != 2)
        servererr("Wrong number of arguments, client may not support ISMAP.");
    mapname=getenv("PATH_INFO");

    if((!mapname) || (!mapname[0]))
        servererr("No map name given. Please read the <A HREF=\"http://
 hoohoo.ncsa.uiuc.edu/docs/setup/admin/Imagemap.asp\">instructions</ A>.<P>"); mapname++; if(!(t = strchr(argv[1],','))) servererr("Your client doesn't support image mapping properly."); *t++ = '\0'; testpoint[X] = (double) atoi(argv[1]); testpoint[Y] = (double) atoi(t); /* * if the mapname contains a '/', it represents a unix path - * we get the translated path, and skip reading the configuration file. */ if (strchr(mapname,'/')) { strcpy(conf,getenv("PATH_TRANSLATED")); goto openconf; } if ((fp = fopen(CONF_FILE, "r")) == NULL){ sprintf(errstr, "Couldn't open configuration file: %s", CONF_FILE); servererr(errstr); } while(!(getline(input,MAXLINE,fp))) { char confname[MAXLINE]; if((input[0] == '#') || (!input[0])) continue; for(i=0;isname(input[i]) && (input[i] != ':');i++) confname[i] = input[i]; confname[i] = '\0'; if(!strcmp(confname,mapname)) goto found; } /* * if mapname was not found in the configuration file, it still * might represent a file in the server root directory - * we get the translated path, and check to see if a file of that * name exists, jumping to the opening of the map file if it does. */ if(feof(fp)) { struct stat sbuf; strcpy(conf,getenv("PATH_TRANSLATED")); if (!stat(conf,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG)) goto openconf; else servererr("Map not found in configuration file."); } found: fclose(fp); while(isspace(input[i]) || input[i] == ':') ++i; for(j=0;input[i] && isname(input[i]);++i,++j) conf[j] = input[i]; conf[j] = '\0'; openconf: if(!(fp=fopen(conf,"r"))){ sprintf(errstr, "Couldn't open configuration file: %s", conf); servererr(errstr); } while(!(getline(input,MAXLINE,fp))) { char type[MAXLINE]; char url[MAXLINE]; char num[10]; if((input[0] == '#') || (!input[0])) continue; type[0] = '\0';url[0] = '\0'; for(i=0;isname(input[i]) && (input[i]);i++) type[i] = input[i]; type[i] = '\0'; while(isspace(input[i])) ++i; for(j=0;input[i] && isname(input[i]);++i,++j) url[j] = input[i]; url[j] = '\0'; if(!strcmp(type,"default") && !sawpoint) { strcpy(def,url); continue; } k=0; while (input[i]) { while (isspace(input[i]) || input[i] == ',') i++; j = 0; while (isdigit(input[i])) num[j++] = input[i++]; num[j] = '\0'; if (num[0] != '\0') pointarray[k][X] = (double) atoi(num); else break; while (isspace(input[i]) || input[i] == ',') i++; j = 0; while (isdigit(input[i])) num[j++] = input[i++]; num[j] = '\0'; if (num[0] != '\0') pointarray[k++][Y] = (double) atoi(num); else { fclose(fp); servererr("Missing y value."); } } pointarray[k][X] = -1; if(!strcmp(type,"poly")) if(pointinpoly(testpoint,pointarray)) sendmesg(url); if(!strcmp(type,"circle")) if(pointincircle(testpoint,pointarray)) sendmesg(url); if(!strcmp(type,"rect")) if(pointinrect(testpoint,pointarray)) sendmesg(url); if(!strcmp(type,"point")) { /* Don't need to take square root. */ dist = ((testpoint[X] - pointarray[0][X]) * (testpoint[X] - pointarray[0][X])) + ((testpoint[Y] - pointarray[0][Y]) * (testpoint[Y] - pointarray[0][Y])); /* If this is the first point, or the nearest, set the default. */ if ((! sawpoint) || (dist < mindist)) { mindist = dist; strcpy(def,url); } sawpoint++; } } if(def[0]) sendmesg(def); servererr("No default specified."); } sendmesg(char *url) { if (strchr(url, ':')) /*** It is a full URL ***/ printf("Location: "); else /*** It is a virtual URL ***/ printf("Location: http://%s:%s", getenv("SERVER_NAME"), getenv("SERVER_PORT")); printf("%s%c%c",url,10,10); printf("This document has moved <A HREF=\"%s\">here</A>%c",url,10); exit(1); } int pointinrect(double point[2], double coords[MAXVERTS][2]) { return ((point[X] >= coords[0][X] && point[X] <= coords[1][X]) && (point[Y] >= coords[0][Y] && point[Y] <= coords[1][Y])); } int pointincircle(double point[2], double coords[MAXVERTS][2]) { int radius1, radius2; radius1 = ((coords[0][Y] - coords[1][Y]) * (coords[0][Y] - coords[1][Y])) + ((coords[0][X] - coords[1][X]) * (coords[0][X] - coords[1][X])); radius2 = ((coords[0][Y] - point[Y]) * (coords[0][Y] - point[Y])) + ((coords[0][X] - point[X]) * (coords[0][X] - point[X])); return (radius2 <= radius1); } int pointinpoly(double point[2], double pgon[MAXVERTS][2]) { int i, numverts, inside_flag, xflag0; int crossings; double *p, *stop; double tx, ty, y; for (i = 0; pgon[i][X] != -1 && i < MAXVERTS; i++) ; numverts = i; crossings = 0; tx = point[X]; ty = point[Y]; y = pgon[numverts - 1][Y]; p = (double *) pgon + 1; if ((y >= ty) != (*p >= ty)) { if ((xflag0 = (pgon[numverts - 1][X] >= tx)) == (*(double *) pgon >= tx)) { if (xflag0) crossings++; } else { crossings += (pgon[numverts - 1][X] - (y - ty) * (*(double *) pgon - pgon[numverts - 1][X]) / (*p - y)) >= tx; } } stop = pgon[numverts]; for (y = *p, p += 2; p < stop; y = *p, p += 2) { if (y >= ty) { while ((p < stop) && (*p >= ty)) p += 2; if (p >= stop) break; if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) { if (xflag0) crossings++; } else { crossings += (*(p - 3) - (*(p - 2) - ty) * (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx; } } else { while ((p < stop) && (*p < ty)) p += 2; if (p >= stop) break; if ((xflag0 = (*(p - 3) >= tx)) == (*(p - 1) >= tx)) { if (xflag0) crossings++; } else { crossings += (*(p - 3) - (*(p - 2) - ty) * (*(p - 1) - *(p - 3)) / (*p - *(p - 2))) >= tx; } } } inside_flag = crossings & 0x01; return (inside_flag); } servererr(char *msg) { printf("Content-type: text/html%c%c",10,10); printf("<title>Mapping Server Error</title>"); printf("<h1>Mapping Server Error</h1>"); printf("This server encountered an error:<p>"); printf("%s", msg); exit(-1); } int isname(char c) { return (!isspace); } int getline(char *s, int n, FILE *f) { register int i=0; while(1) { s[i] = (char)fgetc(f); if(s[i] == CR) s[i] = fgetc(f); if((s[i] == 0x4) || (s[i] == LF) || (i == (n-1))) { s[i] = '\0'; return (feof(f) ? 1: 0); } ++i; } }