home *** CD-ROM | disk | FTP | other *** search
- // tabs = 4
- //------------------------------------------------------------------------
- // TITLE: IMAGEMAP.C
- //
- // FACILITY: Image Mapper
- //
- // ABSTRACT: This program is intended to serve as a "back end" to a
- // world-wide web server. It takes the name of a "map" and
- // a set of coordinates, and returns a URL (document address)
- // specific to the coordinates and the information in the map.
- //
- // The maps themselves are in separate files. The maps are
- // listed in a configuration file called "imagemap.cnf"
- // that is located on the path given by the environment
- // variable HTTPD_CONFDIR, defaulting to "c:/httpd/conf".
- // Each entry in this file must be for the form:
- //
- // <mapname> : <mapfile pathname>
- //
- // Note that this provides a logical to physical mapping facility
- // for the mapfiles. The mapfiles themselves list regions in the
- // target bitmap as follows:
- //
- // <rtype> <URL> <coords>
- //
- // where <rtype> is "rect", "poly", "ellipse" or "circle",
- // <URL> is the URL of the document to return if the testpoint
- // is within that region, and <coords> are the defining x-y
- // coordinates for that type of region.
- //
- // NOTE: The <rtype> can also be "default", in which case the URL
- // is the one to send if the test point is not in any of the
- // regions. In this case, no coordinates are needed.
- //
- //
- // ENVIRONMENT: Microsoft Windows 3.1/3.11 (16-bit)
- // Developed under Borland C++ 4.0
- //
- // AUTHOR: Bob Denny <rdenny@netcom.com>
- //
- // Edit Log:
- //
- // When Who What
- //---------- --- --------------------------------------------------
- // 21-Nov-94 rbd Adapted from Kevin Hughes & Casey Barton version,
- // and the version I made that used doubles.
- // Convert to use ints and the Windows built-in
- // region handling functions.
- // 17-Dec-94 rbd Normalize rects before doing the test so that
- // corners may be given in any order.
- //------------------------------------------------------------------------
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <windows.h>
- #include "util.h"
-
- #define DEFAULT_CONF_DIR "c:\\httpd\\conf"
- #define CONF_FILE_NAME "imagemap.cnf"
-
- #define MAXLINE 500
- #define MAXVERTS 100
- #define X 0
- #define Y 1
- #define END_SIGNAL 0xFFFFFFFF
-
- static char *bad_tgt_msg = "Your client probably doesn't support image maps.";
- static char *ofile;
- static BOOL fDebug = FALSE;
-
- void sendmesg(char *url);
- void servererr(char *msg);
- void debug_wait(void);
- BOOL pointinrect(int point[2], int coords[MAXVERTS][2]);
- BOOL pointincircle(int point[2], int coords[MAXVERTS][2]);
- BOOL pointinpoly(int point[2], int pgon[MAXVERTS][2], int nvert);
- BOOL pointinellipse(int point[2], int coords[MAXVERTS][2]);
- static void NormalizeRect(RECT *rp);
-
- //========================================================================
- // From httpd (windows CGI 1.1):
- //
- // argv[1] CGI .INI file pathname
- // argv[2] Input file (does not exist for Imagemap)
- // argv[3] Output file
- // argv[4] Coordinates
- //
- //========================================================================
- #pragma argsused
- int main(int argc, char *argv[])
- {
- char input[MAXLINE], mapname[MAXLINE], def[MAXLINE], conf[256];
- int testpoint[2], pointarray[MAXVERTS][2];
- int i, j, k;
- FILE *fp;
- char *t, *cp;
- MSG msg;
-
- //
- // Yield to the system for a bit so the server has a chance
- // to synchronize with our exit...
- //
- for(i=0; i<10; i++)
- PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
-
- //
- // Locate the configuration file via this environment variable.
- //
- if((t = getenv("HTTPD_CONFDIR")) != NULL)
- strcpy(conf, t);
- else
- strcpy(conf, DEFAULT_CONF_DIR);
-
- i = strlen(conf) - 1;
- if((conf[i] != '/') && (conf[i] != '\\'))
- strcat(conf, "\\"); // Assure trailing slash
- strcat(conf, CONF_FILE_NAME); // Full path to our config file
-
- //
- // Run according to fDebugging mode
- //
- GetPrivateProfileString("System", "Debug Mode", "No",
- input, MAXLINE, argv[1]);
- if(tolower(input[0]) == 'y')
- {
- printf("Debugging mode set by server.\n");
- fDebug = TRUE;
- }
-
- //
- // If web server wants back-end debugging, install an atexit() handler
- // that holds the console open until a key is pressed
- //
- if(fDebug)
- atexit(debug_wait);
-
- //
- // The "Logical Path" (URL extension) contains the map name.
- //
- GetPrivateProfileString("CGI", "Logical Path", "",
- input, MAXLINE, argv[1]);
- strcpy(mapname, &input[1]); // Skip leading slash
- if(mapname[0] == '\0') // No map name?
- servererr(bad_tgt_msg); // Client doesn't support imagemapping
-
- //
- // argv[3] (and the "Output File") contains the name of the file
- // into which we put the result (a "Location:" document or an error message).
- //
- ofile = argv[3];
-
- //
- // Get target coordinates. The only requirement for syntax is
- // that there be two numeric strings acceptable to strtol()
- // and that they be separated by ONE CHARACTER that is not.
- // Browsers SHOULD send "x,y". Use base=0 so strtol() can
- // deal with decimal, octal and hex values.
- //
- cp = argv[4];
- if(cp == NULL) // Missing arg = access violation
- servererr(bad_tgt_msg); // Bogus URL, no doubt
- testpoint[X] = strtol(cp, &t, 0); // Attempt to convert X
- if(t == cp)
- servererr(bad_tgt_msg);
-
- cp = t + 1;
- testpoint[Y] = strtol(cp, &t, 0); // Attempt to convert y
- if(t == cp)
- servererr(bad_tgt_msg);
-
- if(fDebug)
- printf("Map = %s\nOutput = %s\nCoord = [%d,%d]\n",
- mapname, ofile, testpoint[X], testpoint[Y]);
-
- //
- // Open the config file and find the line that matches the map
- // name given in the URL extension.
- //
- if ((fp = fopen(conf,"r")) == NULL)
- servererr("Couldn't open imagemap config. file.");
-
- while(!(getline(input, MAXLINE, fp))) {
- char buf[MAXLINE];
-
- if((input[0] == '#') || (!input[0])) // # lines are comments
- continue;
-
- for(i=0; !isspace(input[i]) && (input[i] != ':'); i++)
- buf[i] = input[i];
-
- buf[i] = '\0';
-
- if(!strcmp(buf, mapname)) // Preserve mapname case
- break;
- }
-
- if(feof(fp)) {
- char buf[256];
-
- sprintf(buf, "Map \"%s\" not found in configuration file.", mapname);
- fclose(fp);
- servererr(buf);
- }
- fclose(fp);
-
- while(isspace(input[i]) || input[i] == ':') ++i; // Skip past ":" on index line
-
- //
- // Now input[i] -> physical pathname for the mapfile. Collect it and
- // open the mapfile.
- //
- for(j=0;input[i] && !isspace(input[i]);++i,++j)
- conf[j] = input[i];
- conf[j] = '\0';
-
- if((fp=fopen(conf,"r")) == NULL)
- servererr("Couldn't open map file.");
-
- //
- // Here's where we read in the regions, URLs and defining coordinates
- // and for each region, perform the hit test for that region type.
- //
- while(!(getline(input,MAXLINE,fp))) {
- char type[MAXLINE];
- char url[MAXLINE];
-
- if((input[0] == '#') || (!input[0])) // Skip comment lines
- continue;
-
- type[0] = '\0';url[0] = '\0';
-
- for(i=0; !isspace(input[i]) && (input[i]); i++) // Get the type
- type[i] = input[i];
- type[i] = '\0';
-
- while(isspace(input[i])) ++i;
-
- for(j=0; input[i] && !isspace(input[i]); ++i, ++j)// Get the URL
- url[j] = input[i];
- url[j] = '\0';
-
- if(!stricmp(type, "default")) {
- strcpy(def, url);
- continue;
- }
-
- //
- // (rbd) Use the features of strtol() to scan off coordinate pairs
- //
- k = 0; // Indexes coordinate pairs
- cp = &input[i]; // Switch to pointer
- while (*cp != '\0')
- {
- pointarray[k][X] = (int)strtol(cp, &t, 0);
- if(t == cp) // No number converted
- {
- if(*cp != '\0') // If not at end yet
- cp += 1; // Skip past this stopper
- continue; // Try again, stop if end of string
- }
- cp = t + 1; // Skip past stopper (should be ",")
- pointarray[k][Y] = (int)strtol(cp, &t, 0);
- if(t == cp) // If no Y, this is bad.
- {
- char buf[256];
-
- fclose(fp);
- sprintf(buf,
- "Missing Y value in map file %s<P>offending line: %s<P>",
- conf, input);
- servererr(buf);
- }
- if(*t != '\0')
- cp = t + 1;
- else
- cp = t;
- k += 1;
- }
-
- //
- // If sendmesg() is called, it never returns. It exit()s.
- //
- pointarray[k][X] = END_SIGNAL; // Add signal value
-
- if(!strcmpi(type,"poly"))
- if(pointinpoly(testpoint, pointarray, k))
- sendmesg(url);
-
- if(!strcmpi(type,"circle"))
- if(pointincircle(testpoint, pointarray))
- sendmesg(url);
-
- if(!strcmpi(type,"ellipse"))
- if(pointinellipse(testpoint, pointarray))
- sendmesg(url);
-
- if(!strcmpi(type,"rect"))
- if(pointinrect(testpoint, pointarray))
- sendmesg(url);
- }
-
- //
- // If we get here, the testpoint was not in any of the regions.
- // Send the default, unless we didn't get one, in which case,
- // send an error message.
- //
- if(def[0])
- sendmesg(def);
- servererr("No default specified.");
-
- //NOTREACHED
- return(0); // Shut compiler up
- }
-
- //=============================================================================
- //
- // sendmesg() - Return the URL for the selected region.
- //
- //=============================================================================
- void sendmesg(char *url) // Output destination URLs directly to OUTPUT_FILE
- {
- FILE *outfile;
-
- if(fDebug)
- printf("Resolved to:\n %s\n", url);
-
- if ((outfile = fopen(ofile,"w")) == NULL)
- {
- printf("Couldn't open output file."); // This is ugly!
- exit(-1);
- }
- fprintf(outfile,"Location: %s%c%c",url,10, 10);
- fprintf(outfile,
- "This document has moved <A HREF=\"%s\">here</A>%c", url, 10);
- fclose(outfile);
- exit(0);
- }
-
-
- //=============================================================================
- //
- // servererr() - Return an HTTP error message.
- //
- //=============================================================================
- void servererr(char *msg) // Output server errors directly to OUTPUT_FILE
- {
- FILE *outfile;
-
- if(fDebug)
- printf("An error occurred:\n %s\n", msg);
-
- if ((outfile = fopen(ofile,"w")) == NULL)
- {
- printf("Couldn't open output file.");
- exit(-1);
- }
- fprintf(outfile,"Content-type: text/html%c%c",10,10);
- fprintf(outfile,"<title>Mapping Server Error</title>");
- fprintf(outfile,"<h1>Mapping Server Error</h1><HR>");
- fprintf(outfile,"This server encountered an error:<p>");
- fprintf(outfile,"<code>%s</code>", msg);
- fclose(outfile);
- exit(-1);
- }
-
-
- //=============================================================================
- //
- // sendmesg() - Return the URL for the selected region.
- //
- //=============================================================================
- void debug_wait(void)
- {
- char buf[32];
-
- printf("\nPress [enter] to exit...");
- fflush(stdout);
- gets(buf);
- }
-
- //=============================================================================
- //
- // pointinrect() - Return TRUE if point is in rectangle
- //
- // Rectangle is defined as top,left bottom,right
- //
- //=============================================================================
- BOOL pointinrect(int point[2], int coords[MAXVERTS][2])
- {
- RECT r;
- POINT p;
-
- p.x = point[0];
- p.y = point[1];
-
- SetRect(&r, coords[0][X], coords[0][Y], coords[1][X], coords[1][Y]);
- NormalizeRect(&r);
- return(PtInRect(&r, p));
- }
-
- //=============================================================================
- //
- // pointincircle() - Return TRUE if point is in circle
- //
- // For compatibility with old-style maps. Circle is defined as centerpoint,
- // and any point on circumference. For new maps, use ellipse (below).
- //
- //=============================================================================
-
- BOOL pointincircle(int point[2], int coords[MAXVERTS][2])
- {
- unsigned 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);
- }
-
-
- //=============================================================================
- //
- // pointinellipse() - Return TRUE if point is in ellipse
- //
- // Ellipse is given by the bounding rectangle top,left bottom,right.
- //
- //=============================================================================
- BOOL pointinellipse(int point[2], int coords[MAXVERTS][2])
- {
- RECT r;
- HRGN e;
- BOOL f;
-
- SetRect(&r, coords[0][X], coords[0][Y], coords[1][X], coords[1][Y]);
- NormalizeRect(&r);
- e = CreateEllipticRgn(r.left, r.top, r.right, r.bottom);
- f = PtInRegion(e, point[0], point[1]);
- DeleteObject(e);
- return(f);
- }
-
-
- //=============================================================================
- //
- // pointinpoly() - Return TRUE if point is in polygon
- //
- // Polygon is given by a series of vertices (x,y). WARNING: Complex
- // overlapping polygons may not act like you think. See the docs on
- // SetPolyFillMode() for more info. This function is intended to be
- // used on non-overlapping polygons, and will work fine for them.
- //
- //=============================================================================
- int pointinpoly(int point[2], int pgon[MAXVERTS][2], int nvert)
- {
- HRGN p = CreatePolygonRgn((POINT FAR *)pgon, nvert, ALTERNATE);
- BOOL f = PtInRegion(p, point[0], point[1]);
- DeleteObject(p);
- return(f);
- }
-
-
- //=============================================================================
- //
- // NormalizeRect() - Assure topleft is really left and above
- //
- //=============================================================================
- static void NormalizeRect(RECT *rp)
- {
- int i, j;
-
- if(rp->left > rp->right)
- {
- i = rp->left;
- j = rp->top;
- rp->left = rp->right;
- rp->top = rp->bottom;
- rp->right = i;
- rp->bottom = j;
- }
- }
-