Пример #1
0
/* remove tags from start and end of a string, for innerHTML */
static void tagStrip(char *line)
{
	char *s = line;
	if (*s != '<') {
/* this shouldn't happen, don't know what to do. */
		return;
	}

	s = strchr(line, '>');
	if (!s)
		return;
	++s;
	skipWhite2(&s);
	strmove(line, s);
	trimWhite(line);
	s = line + strlen(line);
	if (s == line || s[-1] != '>')
		return;
/* back up over </foo> */
	--s;
	while (s >= line) {
		if (*s == '<') {
			*s = 0;
			return;
		}
		--s;
	}
}				/* tagStrip */
Пример #2
0
void stripWhite(char *s)
{
	const char *t = s;
	skipWhite(&t);
	if (t > s)
		strmove(s, t);
trimWhite(s);
}				/* stripWhite */
//find repeated spaces and trim them down to only 
//one space in a row.
void trimWhite(char* beginning) {
	char *to = beginning;
	char *from;
	bool lastIsSpace = false;
	
	while(*to != '\0') {
		if(isspace(*to)) {
			if(lastIsSpace) {
				from = to;
				char* begin = to + 1;
				while(isspace(*from)) from++;
				while(*to) *to++ = *from++;
				trimWhite(begin);
				return;
			}
			else lastIsSpace = true;
			if(*to == '\r') *to = '\n';
		}
		else lastIsSpace = false;
		to++;
	}
}
Пример #4
0
int nm2tsv(Options* inOptions)
/*
**  Read all input.
**  Output tab seperated value data.
**
**  We expect our data to be in a particular format.
**  nm --format=bsd --size-sort --print-file-name --demangle
*/
{
    int retval = 0;
    char lineBuffer[4096];  /* yes, the are some very large symbols */
    char* module = NULL;
    char* size = NULL;
    char* type = NULL;
    char* symbol = NULL;

    /*
    **  Read in the nm file.
    */
    while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
    {
        trimWhite(lineBuffer);

        /*
        ** Find the various pieces of information we'll be looking for.
        */
        size = strchr(lineBuffer, ':');
        if(NULL != size)
        {
            *size = '\0';
            size++;

            module = strrchr(lineBuffer, '/');
            if(NULL == module)
            {
                module = lineBuffer;
            }
            else
            {
                *module = '\0';
                module++;
            }

            type = scanWhite(size);
            *type = '\0';
            type++;

            symbol = type + 1;
            *symbol = '\0';
            symbol++;

            /*
            **  Skip certain types.
            */
            switch(*type)
            {
                case '-':
                    continue;
                    break;
                default:
                    break;
            }

            /*
            **  Simply output the data with a little more interpretation.
            **  First is size.
            */
            fprintf(inOptions->mOutput, "%s\t", size);

            /*
            **  Type, CODE or DATA
            */
            switch(toupper(*type))
            {
                case 'T': /* text (code) */
                case 'W': /* weak symbol ??? */
                    fprintf(inOptions->mOutput, "CODE\t");
                    break;
                default:
                    fprintf(inOptions->mOutput, "DATA\t");
                    break;
            }

            /*
            **  Scope, PUBLIC, STATIC, or UNDEF
            */
            if(islower(*type))
            {
                fprintf(inOptions->mOutput, "STATIC\t");
            }
            else
            {
                switch(*type)
                {
                    case '?':
                        fprintf(inOptions->mOutput, "UNDEF\t");
                        break;
                    default:
                        fprintf(inOptions->mOutput, "PUBLIC\t");
                        break;
                }
            }

            /*
            **  Module name, segment.
            */
            fprintf(inOptions->mOutput, "%s\t", module);
            fprintf(inOptions->mOutput, "%c\t", toupper(*type));

            /*
            **  Origin
            */
            fprintf(inOptions->mOutput, "UNDEF:%s:%c\t", module, toupper(*type));

            /*
            **  Symbol is last.
            */
            fprintf(inOptions->mOutput, "%s\n", symbol);
        }
        else
        {
            retval = __LINE__;
            ERROR_REPORT(retval, lineBuffer, "Malformed input line.");
        }
    }

    if(0 == retval && 0 != ferror(inOptions->mInput))
    {
        retval = __LINE__;
        ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
    }

    return retval;
}
Пример #5
0
int codesighs(Options* inOptions)
/*
**  Output a simplistic report based on our options.
*/
{
    int retval = 0;
    char lineBuffer[0x1000];
    int scanRes = 0;
    unsigned long size;
    #define SEGCLASS_CHARS 15
    char segClass[SEGCLASS_CHARS + 1];
    #define SCOPE_CHARS 15
    char scope[SCOPE_CHARS + 1];
    #define MODULE_CHARS 255
    char module[MODULE_CHARS + 1];
    #define SEGMENT_CHARS 63
    char segment[SEGMENT_CHARS + 1];
    #define OBJECT_CHARS 255
    char object[OBJECT_CHARS + 1];
    char* symbol;
    SizeStats overall;
    ModuleStats* modules = NULL;
    unsigned moduleCount = 0;

    memset(&overall, 0, sizeof(overall));

    /*
    **  Read the file line by line, regardless of number of fields.
    **  We assume tab separated value formatting, at least 7 lead values:
    **      size class scope module segment object symbol ....
    */
    while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
    {
        trimWhite(lineBuffer);

#define STRINGIFY(s_) STRINGIFY2(s_)
#define STRINGIFY2(s_) #s_

        scanRes = sscanf(lineBuffer,
            "%x\t%" STRINGIFY(SEGCLASS_CHARS) "s\t%"
            STRINGIFY(SCOPE_CHARS) "s\t%" STRINGIFY(MODULE_CHARS)
            "s\t%" STRINGIFY(SEGMENT_CHARS) "s\t%"
            STRINGIFY(OBJECT_CHARS) "s\t",
            (unsigned*)&size,
            segClass,
            scope,
            module,
            segment,
            object);

        if(6 == scanRes)
        {
            SegmentClass segmentClass = CODE;

            symbol = strchr(lineBuffer, '\t') + 1;

            /*
            **  Qualify the segment class.
            */
            if(0 == strcmp(segClass, "DATA"))
            {
                segmentClass = DATA;
            }
            else if(0 == strcmp(segClass, "CODE"))
            {
                segmentClass = CODE;
            }
            else
            {
                retval = __LINE__;
                ERROR_REPORT(retval, segClass, "Unable to determine segment class.");
            }

            if(0 == retval)
            {
                /*
                **  Match any options required before continuing.
                **  This is where you would want to add more restrictive totalling.
                */

                /*
                **  Match size.
                */
                if(size < inOptions->mMinSize)
                {
                    continue;
                }
                if(size > inOptions->mMaxSize)
                {
                    continue;
                }

                /*
                **  Match class.
                */
                if(0 != inOptions->mMatchClassCount)
                {
                    unsigned loop = 0;

                    for(loop = 0; loop < inOptions->mMatchClassCount; loop++)
                    {
                        if(NULL != strstr(segClass, inOptions->mMatchClasses[loop]))
                        {
                            break;
                        }
                    }

                    /*
                    **  If there was no match, we skip the line.
                    */
                    if(loop == inOptions->mMatchClassCount)
                    {
                        continue;
                    }
                }

                /*
                **  Match scope.
                */
                if(0 != inOptions->mMatchScopeCount)
                {
                    unsigned loop = 0;

                    for(loop = 0; loop < inOptions->mMatchScopeCount; loop++)
                    {
                        if(NULL != strstr(scope, inOptions->mMatchScopes[loop]))
                        {
                            break;
                        }
                    }

                    /*
                    **  If there was no match, we skip the line.
                    */
                    if(loop == inOptions->mMatchScopeCount)
                    {
                        continue;
                    }
                }

                /*
                **  Match modules.
                */
                if(0 != inOptions->mMatchModuleCount)
                {
                    unsigned loop = 0;

                    for(loop = 0; loop < inOptions->mMatchModuleCount; loop++)
                    {
                        if(NULL != strstr(module, inOptions->mMatchModules[loop]))
                        {
                            break;
                        }
                    }

                    /*
                    **  If there was no match, we skip the line.
                    */
                    if(loop == inOptions->mMatchModuleCount)
                    {
                        continue;
                    }
                }

                /*
                **  Match sections.
                */
                if(0 != inOptions->mMatchSectionCount)
                {
                    unsigned loop = 0;

                    for(loop = 0; loop < inOptions->mMatchSectionCount; loop++)
                    {
                        if(NULL != strstr(segment, inOptions->mMatchSections[loop]))
                        {
                            break;
                        }
                    }

                    /*
                    **  If there was no match, we skip the line.
                    */
                    if(loop == inOptions->mMatchSectionCount)
                    {
                        continue;
                    }
                }

                /*
                **  Match object.
                */
                if(0 != inOptions->mMatchObjectCount)
                {
                    unsigned loop = 0;

                    for(loop = 0; loop < inOptions->mMatchObjectCount; loop++)
                    {
                        if(NULL != strstr(object, inOptions->mMatchObjects[loop]))
                        {
                            break;
                        }
                    }

                    /*
                    **  If there was no match, we skip the line.
                    */
                    if(loop == inOptions->mMatchObjectCount)
                    {
                        continue;
                    }
                }

                /*
                **  Match symbols.
                */
                if(0 != inOptions->mMatchSymbolCount)
                {
                    unsigned loop = 0;

                    for(loop = 0; loop < inOptions->mMatchSymbolCount; loop++)
                    {
                        if(NULL != strstr(symbol, inOptions->mMatchSymbols[loop]))
                        {
                            break;
                        }
                    }

                    /*
                    **  If there was no match, we skip the line.
                    */
                    if(loop == inOptions->mMatchSymbolCount)
                    {
                        continue;
                    }
                }

                /*
                **  Update overall totals.
                */
                if(CODE == segmentClass)
                {
                    overall.mCode += size;
                }
                else if(DATA == segmentClass)
                {
                    overall.mData += size;
                }

                /*
                **  See what else we should be tracking.
                */
                if(0 == inOptions->mTotalOnly)
                {
                    if(inOptions->mModules)
                    {
                        unsigned index = 0;
                        
                        /*
                        **  Find the module to modify.
                        */
                        for(index = 0; index < moduleCount; index++)
                        {
                            if(0 == strcmp(modules[index].mModule, module))
                            {
                                break;
                            }
                        }
                        
                        /*
                        **  If the index is the same as the count, we need to
                        **      add a new module.
                        */
                        if(index == moduleCount)
                        {
                            void* moved = NULL;
                            
                            moved = realloc(modules, sizeof(ModuleStats) * (moduleCount + 1));
                            if(NULL != moved)
                            {
                                modules = (ModuleStats*)moved;
                                moduleCount++;
                                
                                memset(modules + index, 0, sizeof(ModuleStats));
                                modules[index].mModule = strdup(module);
                                if(NULL == modules[index].mModule)
                                {
                                    retval = __LINE__;
                                    ERROR_REPORT(retval, module, "Unable to duplicate string.");
                                }
                            }
                            else
                            {
                                retval = __LINE__;
                                ERROR_REPORT(retval, inOptions->mProgramName, "Unable to allocate module memory.");
                            }
                        }
                        
                        if(0 == retval)
                        {
                            if(CODE == segmentClass)
                            {
                                modules[index].mSize.mCode += size;
                            }
                            else if(DATA == segmentClass)
                            {
                                modules[index].mSize.mData += size;
                            }
                        }
                    }
                }
            }
        }
        else
        {
            retval = __LINE__;
            ERROR_REPORT(retval, inOptions->mInputName, "Problem extracting values from file.");
        }
    }

    if(0 == retval && 0 != ferror(inOptions->mInput))
    {
        retval = __LINE__;
        ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
    }

    /*
    **  If all went well, time to report.
    */
    if(0 == retval)
    {
        if(inOptions->mTotalOnly)
        {
            fprintf(inOptions->mOutput, "%u\n", (unsigned)(overall.mCode + overall.mData));
        }
        else
        {
            fprintf(inOptions->mOutput, "Overall Size\n");
            fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", (unsigned)(overall.mCode + overall.mData));
            fprintf(inOptions->mOutput, "\tCode:\t%10u\n", (unsigned)overall.mCode);
            fprintf(inOptions->mOutput, "\tData:\t%10u\n", (unsigned)overall.mData);
        }

        /*
        **  Check options to see what else we should output.
        */
        if(inOptions->mModules && moduleCount)
        {
            unsigned loop = 0;

            /*
            **  Sort the modules by their size.
            */
            qsort(modules, (size_t)moduleCount, sizeof(ModuleStats), moduleCompare);

            /*
            **  Output each one.
            **  Might as well clean up while we go too.
            */
            for(loop = 0; loop < moduleCount; loop++)
            {
                fprintf(inOptions->mOutput, "\n");
                fprintf(inOptions->mOutput, "%s\n", modules[loop].mModule);
                fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", (unsigned)(modules[loop].mSize.mCode + modules[loop].mSize.mData));
                fprintf(inOptions->mOutput, "\tCode:\t%10u\n", (unsigned)modules[loop].mSize.mCode);
                fprintf(inOptions->mOutput, "\tData:\t%10u\n", (unsigned)modules[loop].mSize.mData);

                CLEANUP(modules[loop].mModule);
            }

            /*
            **  Done with modules.
            */
            CLEANUP(modules);
            moduleCount = 0;
        }
    }

    return retval;
}
Пример #6
0
int processChar(char *p_filename, int p_toestand, int p_lastchar, int p_thischar, int p_nextchar) {

	int toestand = p_toestand;

	/* entering comment area */
	if (p_thischar == '/' && p_nextchar == '*') {
		insideComment = 1;
	}
	if (!insideComment && p_thischar == '@') {
		insideAt = 1;
		toestand = AT;
	}
	/* if inside at area and not inside comment area */
	if (insideAt && !insideComment) {
		switch(p_thischar) {
		default:	/* token not ready yet */
			*tokenPtr++ = p_thischar;
			break;
		case ' ':
			*tokenPtr = '\0';
			tokenPtr = trimWhite(tokenArea);
			if (strcmp(tokenPtr,"@import") == 0) {
				tokenPtr = tokenArea;
				toestand = IMPORT;
			}
			break;
		case '"':	/* filename @import */
			switch (toestand) {
			default:
				fprintf(stderr,"atQuote: Unknown toestand %d near %c%c%c in file %s\n",toestand,p_lastchar,p_thischar,p_nextchar,p_filename);
				exit(1);
			case IMPORT:	/* start of filename */
				*tokenPtr = '\0';
				tokenPtr = trimWhite(tokenArea);
				tokenPtr = tokenArea;
				toestand = FILENAME;
				break;
			case FILENAME:	/* end of filename */
				*tokenPtr = '\0';
				tokenPtr = trimWhite(tokenArea);
				fprintf(stderr,"Found FILENAME=%s\n",tokenPtr);
				tokenPtr = tokenArea;
				toestand = ATDONE;
				break;
			}
			break;
		case ';':
			switch (toestand) {
			default:
				fprintf(stderr,"atSemiColon: Unknown toestand %d near %c%c%c in file %s\n",toestand,p_lastchar,p_thischar,p_nextchar,p_filename);
				exit(1);
			case ATDONE:
				*tokenPtr = '\0';
				tokenPtr = trimWhite(tokenArea);
				tokenPtr = tokenArea;
				break;
			}
			break;
		}
	}

	/* if not inside comment or at area */
	if (!insideComment && !insideAt) {
		switch(p_thischar) {
		default:	/* token not ready yet */
			*tokenPtr++ = p_thischar;
			break;
		case ',':	/* next selector or next value */
			switch (toestand) {
			default:
				fprintf(stderr,"Comma Unknown toestand %d near %c%c%c in file %s\n",toestand,p_lastchar,p_thischar,p_nextchar,p_filename);
				exit(1);
			case SELECTOR:
				*tokenPtr = '\0';
				tokenPtr = trimWhite(tokenArea);
				add2SelectorList(tokenPtr);
				tokenPtr = tokenArea;
				break;
			case VALUE:
				*tokenPtr++ = p_thischar;
				break;
			} 
			break;
		case '{':	/* selector done, property starts here */
			switch(toestand) {
			default:
				fprintf(stderr,"AccoladeOpen Unknown toestand %d near %c%c%c in file %s\n",toestand,p_lastchar,p_thischar,p_nextchar,p_filename);
				exit(1);
			case SELECTOR:
				*tokenPtr = '\0';
				tokenPtr = trimWhite(tokenArea);
				add2SelectorList(tokenPtr);
				tokenPtr = tokenArea;
				toestand = PROPERTY;
				break;
			}
			break;
		case ':':	/* colon can occur in selector. if not then property done, value starts here */
			switch(toestand) {
			default:
				fprintf(stderr,"Colon Unknown toestand %d near %c%c%c in file %s\n",toestand,p_lastchar,p_thischar,p_nextchar,p_filename);
				exit(1);
			case SELECTOR:
				*tokenPtr++ = p_thischar;
				break;
			case PROPERTY:
				*tokenPtr = '\0';
				tokenPtr = trimWhite(tokenArea);
				strcpy(currentPropertyName, tokenPtr);
				tokenPtr = tokenArea;
				toestand = VALUE;
				break;
			}
			break;
		case ';':	/* values done */
			switch(toestand) {
			default:
				fprintf(stderr,"SemiColon Unknown toestand %d near %c%c%c in file %s\n",toestand,p_lastchar,p_thischar,p_nextchar,p_filename);
				exit(1);
			case VALUE:
				*tokenPtr = '\0';
				tokenPtr = trimWhite(tokenArea);
				if (*tokenPtr) {
					int i;
					for (i = 0; i < nSelectors; i++) {
						addValue(addProperty(selectorList[i],currentPropertyName),tokenPtr);
					}
				}
				tokenPtr = tokenArea;
				toestand = PROPERTY;
				break;
			}
			break;
		case '}':	/* selectors done */
			switch(toestand) {
			default:
				fprintf(stderr,"AccoladeClose Unknown toestand %d near %c%c%c in file %s\n",toestand,p_lastchar,p_thischar,p_nextchar,p_filename);
				exit(1);
			case VALUE:
/*fprintf(stderr,"%s: Syntax error found ... missing ;\n",p_filename);*/
{ /* repair */
	/* thischar should have been a semicolon but it is a closing accolade - pretend it's there */
	processChar(p_filename, p_toestand, p_lastchar, ';', p_thischar);
} /* done repair */
				toestand = PROPERTY;	/* fall through */
			case PROPERTY:
				*tokenPtr = '\0';
				tokenPtr = trimWhite(tokenArea);
				if (*tokenPtr) {
					int i;
					for (i = 0; i < nSelectors; i++) {
						addValue(addProperty(selectorList[i],currentPropertyName),tokenPtr);
					}
				}
				tokenPtr = tokenArea;
				resetSelectorList();
				toestand = SELECTOR;
				break;
			}
			break;
		}
	}

	/* exiting comment area */
	if (insideComment && p_lastchar == '*' && p_thischar == '/') {
		insideComment = 0;
	} 
	/* exiting at area */
	if (!insideComment && insideAt && toestand == ATDONE && p_lastchar == ';') {
		insideAt = 0;
		toestand = SELECTOR;
	}

	/* return nieuwe toestand */
	return toestand;
}
bool AutoBan::printTable( TcpSocket *s , HttpRequest *r ) {
	SafeBuf sb(512 * 512,"autobbuf");
	//read in all of the possible cgi parms off the bat:
	//long  user     = g_pages.getUserType( s , r );
	char *username = g_users.getUsername(r);
	//char *pwd  = r->getString ("pwd");

	char *coll = r->getString ("c");

	long banIpsLen;
	char *banIps = r->getString ("banIps" , &banIpsLen , NULL);

	long allowIpsLen;
	char *allowIps = r->getString ("allowIps" , &allowIpsLen , NULL);

 	long clearLen;
 	char *clear = r->getString ("clear" , &clearLen , NULL);

	bool changed = false;

 	long validCodesLen;
 	char *validCodes = r->getString ("validCodes", &validCodesLen, NULL);

	long showAllIps = r->getLong("showAllIps", 0);
	long showLongView = r->getLong("longview", 0);

	// do it all from parm now
	//long banRegexLen;
	//char *banRegex = r->getString("banRegex", &banRegexLen, NULL);
	

// 	char *ss = sb.getBuf();
// 	char *ssend = sb.getBufEnd();
	g_pages.printAdminTop ( &sb, PAGE_AUTOBAN, username,
				coll , NULL , s->m_ip );
	//sb.incrementLength(sss - ss);

	// MDW: moved to here

	long now = getTime();
	
	long days;
	long hours;
	long minutes;
	long secs;
	long msecs;

	if(r->getLong("resetcodes", 0)) {
		setCodesFromConf();
	}

	sb.safePrintf("\n<br><br><table width=100%% bgcolor=#%s "
		      "cellpadding=4 border=1>\n", 
		      BABY_BLUE);
	getCalendarFromMs((now - m_codeResetTime) * 1000,
			  &days, 
			  &hours, 
			  &minutes, 
			  &secs,
			  &msecs);
	sb.safePrintf("<tr><td colspan=18 bgcolor=#%s>"
		      "<center><b>Code Usage "
		      "(<a href=\"/master/"
		      "autoban?c=%s&resetcodes=1\">reset</a> "
		      "%li days %li hours %li "
		      "minutes %li sec ago)"
		      "</b></center></td></tr>", 
		      DARK_BLUE,
		      coll,
		      days, 
		      hours, 
		      minutes, 
		      secs);
	sb.safePrintf("<tr bgcolor=#%s>"
		      "<td><center><b>Code</b></center></td>"
		      "<td><center><b>IP</b></center></td>"
		      "<td><center><b>Query Count</b></center></td>"

		      "<td><center><b>Bytes Read</b></center></td>"
		      "<td><center><b>Bytes Sent</b></center></td>"
		      
		      "<td><center><b>Outstanding Count</b></center></td>"
		      "<td><center><b>Most Ever Outstanding</b></center></td>"
		      "<td><center><b>Max Outstanding</b></center></td>"
		      "</tr>", 
		      LIGHT_BLUE);


	for(long i = 0; i < m_ht.getNumSlots(); i++) {
		if ( m_ht.getKey ( i ) == 0 ) continue;
		CodeVal *cv = m_ht.getValuePointerFromSlot ( i );
		if ( ! cv ) continue;
		
		sb.safePrintf("<tr>");
		sb.safePrintf("<td>");
		sb.copyToken(cv->m_code);//m_codeVals[i].m_code);
		sb.safePrintf("</td>");
		sb.safePrintf("<td><center>%s</center> </td>",
			      iptoa(cv->m_ip));
		sb.safePrintf("<td><center>%lli</center></td>", 
			      cv->m_count);

		sb.safePrintf("<td><center>%lli</center></td>", 
			      cv->m_bytesRead);
		sb.safePrintf("<td><center>%lli</center></td>", 
			      cv->m_bytesSent);

		sb.safePrintf("<td><center>%li</center></td>", 
			      cv->m_outstanding);
		sb.safePrintf("<td><center>%li</center></td>", 
			      cv->m_maxEver);
		if ( cv->m_maxOutstanding != 50 )
			sb.safePrintf("<td><center><b>%li</b></center></td>", 
				      cv->m_maxOutstanding);
		else
			sb.safePrintf("<td><center>%li</center></td>", 
				      cv->m_maxOutstanding);

		sb.safePrintf("</tr>");
		
	}
	sb.safePrintf ("</table><br><br>\n" );


 	if(clear && clearLen < 64) {
 		long ip = atoip(clear, clearLen);
 		if(ip) {
			removeIp(ip);
			char *beginning;
			char ipbuf[64];//gotta NULL terminate for strstr
			memcpy(ipbuf, clear, clearLen);
			ipbuf[clearLen] = '\0';
			beginning = findToken(g_conf.m_banIps, ipbuf, 
					      clearLen);
			if(beginning) {
				char *to = beginning;
				char *from = beginning + clearLen;
				while(*to) *to++ = *from++;
			}
			beginning = findToken(g_conf.m_allowIps, ipbuf,
					      clearLen);
			if(beginning) {
				char *to = beginning;
				char *from = beginning + clearLen;
				while(*to) *to++ = *from++;
			}
			changed = true;
 		}
 	}

 	long allowLen;
 	char *allow = r->getString ( "allow" , &allowLen , NULL );
 	if(allow && allowLen < 64) {
 		long ip = atoip(allow, allowLen);
		
 		if(ip) {
			char *beginning;
			char ipbuf[64];//gotta NULL terminate for strstr
			memcpy(ipbuf, allow, allowLen);
			ipbuf[allowLen] = '\0';
			beginning = findToken(g_conf.m_allowIps, ipbuf, 
					      allowLen);
			if(!beginning) {
				//its not present, so add it.
				char *p = g_conf.m_allowIps;
				while(*p) p++;
				if(p - g_conf.m_allowIps + allowLen + 2 
				   < AUTOBAN_TEXT_SIZE) {
					*p++ = '\n';
					memcpy(p, ipbuf,allowLen);
					*(p + allowLen) = '\0';
				}
				else {
					sb.safePrintf("<font color=red>"
						      "Not enough stack space "
						      "to fit allowIps.  "
						      "Increase "
						      "AUTOBAN_TEXT_SIZE in "
						      "Conf.h. "
						      "Had %i need %li."
						      "</font>", 
						      AUTOBAN_TEXT_SIZE,
						      p - g_conf.m_allowIps + 
						      allowLen + 2);
					goto dontRemove1;
				}
			}
			beginning = findToken(g_conf.m_banIps, ipbuf, 
					      allowLen);
			if(beginning) {
				//remove it from banned if present.
				char *to = beginning;
				char *from = beginning + allowLen;
				while(*to) *to++ = *from++;
			}

			changed = true;
 		}
 	}
 dontRemove1:
 	long denyLen;
 	char *deny = r->getString ( "deny" , &denyLen , NULL );
 	if(deny && denyLen < 64) {
 		long ip = atoip(deny, denyLen);
		
 		if(ip) {
			char *beginning;
			char ipbuf[64];//gotta NULL terminate for strstr
			memcpy(ipbuf, deny, denyLen);
			ipbuf[denyLen] = '\0';
			beginning = findToken(g_conf.m_banIps, ipbuf, denyLen);
			if(!beginning) {
				//its not present, so add it.
				char *p =g_conf.m_banIps;
				while(*p) p++;
				if(p - g_conf.m_banIps + denyLen + 2 < 
				   AUTOBAN_TEXT_SIZE) {
					*p++ = '\n';
					memcpy(p, ipbuf,denyLen);
					*(p + denyLen) = '\0';
				}
				else {
					sb.safePrintf("<font color=red>Not "
						      "enough stack space "
						      "to fit bannedIPs.  "
						      "Increase "
						      "AUTOBAN_TEXT_SIZE in "
						      "Conf.h. "
						      "Had %i need %li."
						      "</font>", 
						      AUTOBAN_TEXT_SIZE,
						      p - g_conf.m_banIps +
						      denyLen + 2);
					goto dontRemove2;
				}
			}
			beginning = findToken(g_conf.m_allowIps, ipbuf,
					      denyLen);
			if(beginning) {
				//remove it from allowed list if present.
				char *to = beginning;
				char *from = beginning + denyLen;
				while(*to) *to++ = *from++;
			}
			changed = true;
 		}
 	}
 dontRemove2:

	if(!g_conf.m_doAutoBan) {
		sb.safePrintf("<center><font color=red><b>Autoban is disabled, "
			      "turn it on in Master Controls.</b></font></center><br>");
	}

 	if(validCodes) {
		if(validCodesLen >= AUTOBAN_TEXT_SIZE) {
			sb.safePrintf("<font color=red>Not enough stack space "
				      "to fit codes.  "
				      "Increase AUTOBAN_TEXT_SIZE in Conf.h. "
				      "Had %i need %li.</font>", 
				      AUTOBAN_TEXT_SIZE,
				      validCodesLen);
			validCodes = NULL;
			validCodesLen = 0;
		}
		else {
			memcpy(g_conf.m_validCodes, validCodes, validCodesLen);
			g_conf.m_validCodes[validCodesLen] = '\0';
			trimWhite(g_conf.m_validCodes);
			setCodesFromConf();
		}
	}



	//first remove all of the ips in the conf, then add the passed in 
	//  ones to the conf parm; 
	if (banIps) {
		//ack, the browser puts in crlf when this comes back, so
		//we will have a longer string here than the one we sent 
		//out. trim back all extrainious whitespace before we do
		//bounds checking.
		trimWhite(banIps);
		banIpsLen = gbstrlen(banIps);
		if(banIpsLen >= AUTOBAN_TEXT_SIZE) {
			sb.safePrintf("<font color=red>Not enough stack space "
				      "to fit bannedIps.  "
				      "Increase AUTOBAN_TEXT_SIZE in Conf.h. "
				      "Had %i need %li.</font>", 
				      AUTOBAN_TEXT_SIZE,
				      banIpsLen);
			banIpsLen = AUTOBAN_TEXT_SIZE - 1;
		}
		for(long i = 0; i < m_tableSize; i++) {
			if(m_detectKeys[i] == 0) continue;
			//check the 'set from conf' bit, and clear those.
			if(m_detectVals[i].m_flags & FROMCONF) {
				removeIp(m_detectKeys[i]);
			}
		}
		memcpy(g_conf.m_banIps, banIps, banIpsLen);
		g_conf.m_banIps[banIpsLen] = '\0';
		changed = true;
	}
	if (allowIps) {
		trimWhite(allowIps);
		allowIpsLen = gbstrlen(allowIps);

		if(allowIpsLen >= AUTOBAN_TEXT_SIZE) {
			sb.safePrintf("<font color=red>Not enough stack space "
				      "to fit allowIps.  "
				      "Increase AUTOBAN_TEXT_SIZE in Conf.h. "
				      "Had %i need %li.</font>", 
				      AUTOBAN_TEXT_SIZE,
				      allowIpsLen);
			allowIpsLen = AUTOBAN_TEXT_SIZE - 1;
		}
		for(long i = 0; i < m_tableSize; i++) {
			if(m_detectKeys[i] == 0) continue;
			//check the 'set from conf' bit, and clear those.
			if(m_detectVals[i].m_flags & FROMCONF) {
				removeIp(m_detectKeys[i]);
			}
		}
		memcpy(g_conf.m_allowIps, allowIps, allowIpsLen);
		g_conf.m_allowIps[allowIpsLen] = '\0';
		changed = true;
	}
	if(changed) {
		trimWhite(g_conf.m_allowIps);
		trimWhite(g_conf.m_banIps);
		setFromConf();
	}



	sb.safePrintf("\n<table width=100%% bgcolor=#%s "
		      "cellpadding=4 border=1>\n", 
		      BABY_BLUE);
	sb.safePrintf("<tr><td colspan=2 bgcolor=#%s>"
		      "<center><b>Add IPs</b></center></td></tr>", 
		      DARK_BLUE);

// 	ss = sb.getBuf();
// 	ssend = sb.getBufEnd();
	g_parms.printParms (&sb, s, r);
	//	sb.incrementLength(sss - ss);



	sb.safePrintf ("<tr><td>"
		       "<center>" 
		       "<input type=submit value=\"Update\" "
		       "method=\"POST\" border=0>"
		       "</center></td></tr>");

	sb.safePrintf ("</table><br><br>\n" );



	if(!showLongView) {
		sb.safePrintf("<b><a href=\"autoban"
			      "?c=%s"
			      "&showAllIps=%li"
			      "&longview=1\">Show watched ips table...</a></b>",
			      coll,
			      showAllIps);
		return g_httpServer.sendDynamicPage ( s , 
						      sb.getBufStart() , 
						      sb.length() , 
						      -1 , 
						      false);
	}

	/////////////////////////////////////////////////////////////////////

	sb.safePrintf("\n<table width=100%% bgcolor=#%s "
		      "cellpadding=4 border=1>\n", 
		      BABY_BLUE);

	sb.safePrintf("<tr><td colspan=3 bgcolor=#%s>"
		      "<center><b>Watched Ips</b></center></td></tr>", 
		      DARK_BLUE);

	sb.safePrintf("<tr bgcolor=#%s>"
		      "<td><center><b>IP</b></center></td>"
		      "<td><center><b>Description</b></center></td>"
		      //		      "<td><center><b>Time Added</b></center></td>"
		      "<td><center><b>Allow/Deny/Clear</b></center></td>"
		      "</tr>", 
		      LIGHT_BLUE);




	long *sortedIndices = (long*)mmalloc(m_tableSize * sizeof(long), 
					     "AutoBanH");

	if(!sortedIndices) {
		return g_httpServer.sendErrorReply(s,500,mstrerror(ENOMEM));
	}

	long numEntries = 0;
	for(long i = 0; i < m_tableSize; i++) {
		if(m_detectKeys[i] == 0) continue;
		sortedIndices[numEntries++] = i;
	}
	SorterTable = m_detectKeys;

        gbsort(sortedIndices, numEntries, sizeof(long), ip_cmp);


	//lets put each class of watched ip in its own safebuf then cat 
	//them together at the end.
	
	SafeBuf allowed;
	SafeBuf banned; 
	SafeBuf feedLeachers; 
	SafeBuf cowBots; 
	SafeBuf *e;

	for(long j = 0; j < numEntries; j++) {
		long i = sortedIndices[j];
		if(m_detectKeys[i] == 0) continue;
		//if(!(m_detectVals[i].m_flags & FROMCONF)) continue;
		bool allow =  m_detectVals[i].m_flags & ALLOW && 
			m_detectVals[i].m_flags & FROMCONF;
		bool deny  =  m_detectVals[i].m_flags & DENY && 
			m_detectVals[i].m_flags & FROMCONF;
		bool explicitban = deny && m_detectVals[i].m_flags & FROMCONF;
		unsigned short dayCount = m_detectVals[i].m_dayCount;
		unsigned char minuteCount = m_detectVals[i].m_minuteCount;

		bool day =    dayCount >= g_conf.m_numFreeQueriesPerDay;
		bool minute = minuteCount >= g_conf.m_numFreeQueriesPerMinute;

		char *description;
		char *color;

		if(allow) {
			color = GREEN;
			description = "Allowed";
			e = &allowed;
		} 
		else if(explicitban) {
			color = RED;
			description = "Banned";
			e = &banned;
		}
		else if(minute) {
			color = RED;
			description = "Cow Bot";
			e = &cowBots;
		}
		else if(day) {
			color = RED;
			description = "Feed Leacher";
			e = &feedLeachers;
		}
		else {
			//this can happen when someone was banned due to 
			//exceeding the quota, then the quota was lowered.
			
			m_detectVals[i].m_flags &= ~DENY;
			//log("autoban: ohshit-banning %s",iptoa(s->m_ip));
			continue;
		}

		
		e->safePrintf("<tr>");

		e->safePrintf("<td bgcolor=#%s><center>%s</center></td><td>"
			      "<center>%s</center></td>"

// 			      "<td><center>"
// 			      "%li days %li hrs %li min ago"
// 			      "</center></td>"

			      "<td><center><a href=\"/master/"
			      "autoban?c=%s&allow=%s&showAllIps=%li\">" 
			      "allow/</a>"

			      "<a href=\"/master/"
			      "autoban?c=%s&deny=%s&showAllIps=%li\">" 
			      "deny/</a>"

			      "<a href=\"/master/"
			      "autoban?c=%s&clear=%s&showAllIps=%li\">"
			      "clear</a></center>"
			      "</td>",color, 
			      iptoa(m_detectKeys[i]),
			      description,

			      //      days,hours,minutes,

			      coll,
			      iptoa(m_detectKeys[i]),
			      showAllIps,
			      coll,
			      iptoa(m_detectKeys[i]),
			      showAllIps,
			      coll,
			      iptoa(m_detectKeys[i]),
			      showAllIps);
		e->safePrintf("</tr>");
	}

	sb.cat(allowed);
	sb.cat(banned); 
	sb.cat(feedLeachers); 
	sb.cat(cowBots); 

	sb.safePrintf ("</table><br><br>\n" );


	// MDW moved from here

	sb.safePrintf("\n<br><br><table width=100%% bgcolor=#%s "
		      "cellpadding=4 border=1>\n", 
		      BABY_BLUE);

	sb.safePrintf("<tr><td colspan=5 bgcolor=#%s>"
		      "<center><b>Control Panel</b></center></td></tr>", 
		      DARK_BLUE);

	sb.safePrintf("<tr>"
		      "<td bgcolor=#%s><center><b>Show Ips by Number of Queries"
		      "</b></center></td>",
		      LIGHT_BLUE);
	sb.safePrintf("<td><center><font color=red><b><a href=\"/master/"
		      "autoban?c=%s&showAllIps=0\">"
		      "0 Queries</a></b>"
		      "</font></center></td>",
		      coll);
	sb.safePrintf("<td><center><font color=red><b><a href=\"/master/"
		      "autoban?c=%s&showAllIps=1\">"
		      "1 Query</a></b>"
		      "</font></center></td>",
		      coll);
	sb.safePrintf("<td><center><font color=red><b><a href=\"/master/"
		      "autoban?c=%s&showAllIps=10\">"
		      "10 Queries</a></b>"
		      "</font></center></td>",
		      coll);
	sb.safePrintf("<td><center><font color=red><b><a href=\"/master/"
		      "autoban?c=%s&showAllIps=100\">"
		      "100 Queries</a></b>"
		      "</font></center></td></tr>",
		      coll);

	sb.safePrintf ("</table><br><br>\n");



	if(!showAllIps) {

		char* ss = (char*) sb.getBufStart();
		long sslen = sb.length();
		mfree(sortedIndices, m_tableSize * sizeof(long),"AutoBanH");

		return g_httpServer.sendDynamicPage ( s , ss , sslen , -1 , false);
	}
	

	sb.safePrintf("\n<br><br><table width=100%% bgcolor=#%s "
		      "cellpadding=4 border=1>\n", 
		      BABY_BLUE);

	sb.safePrintf("<tr><td colspan=6 bgcolor=#%s>"
		      "<center><b>Queries Today</b></center></td></tr>", 
		      DARK_BLUE);

	sb.safePrintf("<tr bgcolor=#%s>"
		      "<td><center><b>IP</b></center></td>"
		      "<td><center><b>Minute count</b></center></td>"
		      "<td><center><b>Day count</b></center></td>"
		      "<td><center><b>Time Until Reset</b></center></td>"
		      "<td><center><b>Times Banned</b></center></td>"
		      "<td><center><b>Allow/Deny</b></center></td>"
		      "</tr>", 
		      LIGHT_BLUE);


	char minBuf[128];
	char dayBuf[128];
	unsigned long lastIpGroup = 0;
	for(long j = 0; j < numEntries; j++) {
		long i = sortedIndices[j];
		long  dayCount = m_detectVals[i].m_dayCount;
		unsigned char minuteCount = m_detectVals[i].m_minuteCount;

		if(!(m_detectVals[i].m_flags & FROMCONF)) {
			if(m_detectVals[i].m_minuteExpires < now) 
				minuteCount = 0;
			if(!(m_detectVals[i].m_flags & DENY) && 
			   m_detectVals[i].m_dayExpires < now) 
				dayCount = 0;
		}
		//a hack:
		if( dayCount < showAllIps) continue;

		char *color = YELLOW;
		
		if(m_detectVals[i].m_flags & ALLOW) {
			color = GREEN;
			snprintf(minBuf, 128, "--");
			snprintf(dayBuf, 128, "%li", dayCount);
		}
		else if(m_detectVals[i].m_flags & DENY) {
			color = RED;
			snprintf(minBuf, 128, "--");
			snprintf(dayBuf, 128, "%li", dayCount);
		} 
		else {
			snprintf(minBuf, 128, "%li", (long)minuteCount);
			snprintf(dayBuf, 128, "%li", (long)dayCount);
		}

		unsigned long thisIpGroup = (unsigned long)m_detectKeys[i] & 
			0x00ffffff;

		sb.safePrintf("<tr><center>");

		if(m_detectVals[i].m_flags & FROMCONF) {
			sb.safePrintf("<td bgcolor=#%s><center>%s%s%s</center></td>"
				      "<td><center>%s</center> </td>"
				      "<td><center>%s</center></td>" 
				      "<td><center><font color=red>"
				      "<b>NEVER</b>"
				      "</font></center></td>"
				      "<td><center>--</center></td>",
				      color, 
				      (thisIpGroup == lastIpGroup)?"<b>":"",
				      iptoa(m_detectKeys[i]),
				      (thisIpGroup == lastIpGroup)?"</b>":"",
				      minBuf,
				      dayBuf);
		}
		else {
			//they haven't done a query since being unbanned,
			//unban them now so we don't get negative resets displayed.
			/*
			  no, don't unban the bots!!! MDW yippy project
			if(m_detectVals[i].m_dayExpires < now) {
				m_detectVals[i].m_flags &= ~DENY; 
				//log("autoban: dayexpire-unbanning %s",
				//    iptoa(ip));
				m_detectVals[i].m_dayExpires = now + ONE_DAY;
				m_detectVals[i].m_minuteExpires = now + 60;
				m_detectVals[i].m_dayCount = 0;
				m_detectVals[i].m_minuteCount = 0;
				sb.safePrintf("</center></tr>");
				continue;
			}
			*/

			getCalendarFromMs((m_detectVals[i].m_dayExpires - now)* 1000,
					  &days, 
					  &hours, 
					  &minutes, 
					  &secs,
					  &msecs);

			sb.safePrintf("<td bgcolor=#%s><center>%s%s%s</center></td>"
				      "<td><center>%s</center> </td>"
				      "<td><center>%s</center></td>" 
				      "<td><center><font color=red>"
				      "<b>%li days %li hrs %li min %li sec</b>"
				      "</font></center></td>"
				      "<td><center>%i</center></td>",
				      color, 
				      (thisIpGroup == lastIpGroup)?"<b>":"",
				      iptoa(m_detectKeys[i]),
				      (thisIpGroup == lastIpGroup)?"</b>":"",
				      minBuf,
				      dayBuf,
				      days, hours, minutes, secs,
				      m_detectVals[i].m_timesBanned);
		}
		sb.safePrintf("<td><center>"
			      "<a href=\"/master/"
			      "autoban?c=%s&allow=%s&showAllIps=%li\">" 
			      "allow/</a>"
			      "<a href=\"/master/"
			      "autoban?c=%s&deny=%s&showAllIps=%li\">" 
			      "deny</a></center>"
			      "</td>",
			      coll,
			      iptoa(m_detectKeys[i]),
			      showAllIps,
			      coll,
			      iptoa(m_detectKeys[i]),
			      showAllIps);

		sb.safePrintf("</center></tr>");
		lastIpGroup = thisIpGroup;
	}


	sb.safePrintf ("</table><br><br>\n" );


	char* ss = (char*) sb.getBufStart();
	long sslen = sb.length();

	mfree(sortedIndices, m_tableSize * sizeof(long),"AutoBanH");

	return g_httpServer.sendDynamicPage ( s , ss , sslen , -1 , false);
}
bool sendPageThesaurus( TcpSocket *s, HttpRequest *r ) {
	SafeBuf p;
	char getBuf[64]; // holds extra values for GET method
	char formBuf[256]; // holds extra values for forms
	snprintf(getBuf, 64, "c=%s", 
		 r->getString("c", 0, ""));
	snprintf(formBuf, 256, 
		 "<input type=hidden name=\"c\" value=\"%s\">",
		 //"<input type=hidden name=\"pwd\" value=\"%s\">",
		 r->getString("c", 0, ""));
	g_pages.printAdminTop( &p, s, r);
	
	if (r->getLong("cancel", 0) != 0) {
		g_thesaurus.cancelRebuild();
		p.safePrintf("<br><br>\n");
		p.safePrintf(
		  "<center><b><font color=#ff0000>"
		  "rebuild canceled"
		  "</font></b></center>");
	}

	if (r->getLong("rebuild", 0) != 0) {
		bool full = r->getLong("full", 0);
		p.safePrintf("<br><br>\n");
		if (g_thesaurus.rebuild(0, full)) {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "error starting rebuild, check log for details"
			  "</font></b></center>");
		} else {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "rebuild started"
			  "</font></b></center>");
		}
	}
	
	if (r->getLong("rebuildaff", 0) != 0) {
		bool full = r->getLong("full", 0);
		p.safePrintf("<br><br>\n");
		if (g_thesaurus.rebuildAffinity(0, full)) {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "error starting rebuild, check log for details"
			  "</font></b></center>");
		} else {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "rebuild started"
			  "</font></b></center>");
		}
	}

	if (r->getLong("distribute", 0) != 0) {
		char cmd[1024];
		p.safePrintf("<br><br>\n");
		if (g_thesaurus.m_affinityState) {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "cannot distribute during rebuild"
			  "</font></b></center>");
		} else {
			for ( long i = 0; i < g_hostdb.getNumHosts() ; i++ ) {
				Host *h = g_hostdb.getHost(i);
				snprintf(cmd, 512,
					"rcp -r "
					"./dict/thesaurus.* "
					"%s:%s/dict/ &",
					iptoa(h->m_ip),
					h->m_dir);
				log(LOG_INFO, "admin: %s", cmd);
				system( cmd );
			}
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "data distributed"
			  "</font></b></center>");
		}	
	}

	if (r->getLong("reload", 0) != 0) {
		p.safePrintf("<br><br>\n");
		if (r->getLong("cast", 0) != 0) {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "reload command broadcast"
			  "</font></b></center>");
		} else if (g_thesaurus.init()) {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "thesaurus data reloaded"
			  "</font></b></center>");
		} else {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "error reloading thesaurus data"
			  "</font></b></center>");
		}
	}

	long manualAddLen = 0;
	char *manualAdd = NULL;
	SafeBuf manualAddBuf;
	if ((manualAdd = r->getString("manualadd", &manualAddLen))) {
		trimWhite(manualAdd);
		manualAddLen = gbstrlen(manualAdd);
		File manualFile;
		manualFile.set(g_hostdb.m_dir, "dict/thesaurus-manual.txt");
		if (manualFile.open(O_WRONLY | O_CREAT | O_TRUNC) &&
			(manualFile.write(manualAdd, manualAddLen, 0) ==
			 manualAddLen)) {
			char newl = '\n'; // for write()
			if (manualAdd[manualAddLen-1] != '\n')
				manualFile.write(&newl, 1, manualAddLen);
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "updated manual add file sucessfully"
			  "</font></b></center>");
		} else {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "error writing manual add file"
			  "</font></b></center>");
		}
	} else {
		char ff[PATH_MAX];
		snprintf(ff, PATH_MAX, "%sdict/thesaurus-manual.txt",
			g_hostdb.m_dir);
		if (manualAddBuf.fillFromFile(ff)) {
			if (*(manualAddBuf.getBuf()-1) != '\n')
				manualAddBuf.pushChar('\n');
			manualAdd = manualAddBuf.getBufStart();
			manualAddLen = manualAddBuf.length();
		}
	}

	long affinityAddLen = 0;
	char *affinityAdd = NULL;
	SafeBuf affinityAddBuf;
	if ((affinityAdd = r->getString("affinityadd", &affinityAddLen))) {
		trimWhite(affinityAdd);
		affinityAddLen = gbstrlen(affinityAdd);
		File affinityFile;
		affinityFile.set(g_hostdb.m_dir, 
			"dict/thesaurus-affinity.txt");
		if (affinityFile.open(O_WRONLY | O_CREAT | O_TRUNC) &&
			(affinityFile.write(affinityAdd, affinityAddLen, 0) ==
			 affinityAddLen)) {
			char newl = '\n'; // for write()
			if (affinityAdd[affinityAddLen-1] != '\n')
				affinityFile.write(&newl, 1, affinityAddLen);
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "updated affinity add file sucessfully"
			  "</font></b></center>");
		} else {
			p.safePrintf(
			  "<center><b><font color=#ff0000>"
			  "error writing affinity add file"
			  "</font></b></center>");
		}
	} else {
		char ff[PATH_MAX];
		snprintf(ff, PATH_MAX, "%sdict/thesaurus-affinity.txt",
			g_hostdb.m_dir);
		if (affinityAddBuf.fillFromFile(ff)) {
			if (*(affinityAddBuf.getBuf()-1) != '\n')
				affinityAddBuf.pushChar('\n');
			affinityAdd = affinityAddBuf.getBufStart();
			affinityAddLen = affinityAddBuf.length();
		}
	}
	

	char *syn = r->getString("synonym");
	long len = 0;
	if (syn) len = gbstrlen(syn);

	if (len) {
		SynonymInfo info;
		bool r = g_thesaurus.getAllInfo(syn, &info, len, SYNBIT_ALL);
		p.safePrintf("<br><br>\n");
		p.safePrintf ( 
		  "<table cellpadding=4 width=100%% bgcolor=#%s border=1>"
		  "<tr>"
		  "<td colspan=2 bgcolor=#%s>"
		  "<center><b>Synonym List (%ld)</b></center>"
		  "</td>"
		  "</tr>\n",
		  LIGHT_BLUE, DARK_BLUE, info.m_numSyns);
		if (r) {
			p.safePrintf("<tr>"
			  "<td align=right><tt>%s</tt></td>"
			  "<td align=left>"
			  "<tt>1.000/%08lX (1.000/%08lX)</tt>"
			  "</td>"
			  "</tr>\n", syn, MAX_AFFINITY, MAX_AFFINITY);
			for (long i = 0; i < info.m_numSyns; i++) {
				// get the reverse affinity as well
				long aff = g_thesaurus.getAffinity(
					info.m_syn[i], syn,
					info.m_len[i], len);
				p.safePrintf( 
				  "<tr>"
				  "<td width=40%% align=right>"
				  "<tt>");
				p.safeMemcpy(info.m_syn[i], info.m_len[i]);
				p.safePrintf("</tt>"
				  "</td>"
				  "<td width=60%% align=left>"
				  "<tt>");
				if (info.m_affinity[i] >= 0) {
					p.safePrintf("%0.3f/%08lX ",
				  	  (float)info.m_affinity[i] 
					  	/ MAX_AFFINITY,
					  info.m_affinity[i]);
				} else {
					p.safePrintf("u ");
				}
				if (aff >= 0) {
					p.safePrintf("(%0.3f/%08lX) ",
					  (float)aff / MAX_AFFINITY, 
					  aff);
				} else {
					p.safePrintf("(u) ");
				}
				p.safePrintf("(%ld) (%ld) (%ld) (%ld) "
					     "(%lld) (%lld)",
				  (long)info.m_type[i], (long)info.m_sort[i],
				  info.m_firstId[i], info.m_lastId[i],
				  info.m_leftSynHash[i], 
				  info.m_rightSynHash[i]);
				for (int j = info.m_firstId[i]; 
					j <= info.m_lastId[i];
					j++) {
					p.safePrintf(" (%lld)",
						info.m_termId[j]);
				}
				p.safePrintf(
				  "</tt>"
				  "</td>"
				  "</tr>\n");
			}
			p.safePrintf("</table>");
		} else {
			p.safePrintf("<tr>"
			  "<td align=center><font color=#FF0000>"
			  "synonym not found: %s"
			  "</font></td>"
			  "</tr>\n",
			  syn);
		}
	}

	p.safePrintf ( "<br><br>\n" );

	p.safePrintf ( 
		  "<table cellpadding=4 width=100%% bgcolor=#%s border=1>"
		  "<tr>"
		  "<td colspan=2 bgcolor=#%s>"
		  "<center><b>Thesaurus Controls"
		  "</b></center></td>"
		  "</tr>\n",
		  LIGHT_BLUE, DARK_BLUE);
	
	p.safePrintf (
		  "<tr>"
		  "<td width=37%%><b>rebuild all data</b><br>"
		  "<font size=1>"
		  "rebuilds synonyms and then begins the rebuild process for "
		  "affinity data; this should only be run on one host, as the "
		  "data is copied when the process is finished; full rebuild "
		  "does not use existing affinity data"
		  "</font>"
		  "</td>"
		  "<td width=12%% bgcolor=#0000ff>"
		  "<center><b><a href=\"/master/thesaurus?rebuild=1&%s\">"
		  "rebuild all data</a> <a href=\"/master/thesaurus?"
		  "rebuild=1&full=1&%s\">(full)</a></b></center>"
		  "</td>"
		  "</tr>\n", getBuf, getBuf);

	p.safePrintf (
		  "<tr>"
		  "<td width=37%%><b>distribute data</b><br>"
		  "<font size=1>"
		  "distributes all thesaurus data to all hosts, this is "
		  "normally done automatically but if there was a problem "
		  "with the copy, this lets you do it manually"
		  "</font>"
		  "</td>"
		  "<td width=12%% bgcolor=#0000ff>"
		  "<center><b><a href=\"/master/thesaurus?distribute=1&%s\">"
		  "distribute data</a></b></center>"
		  "</td>"
		  "</tr>\n", getBuf);

	p.safePrintf (
		  "<tr>"
		  "<td width=37%%><b>reload data</b><br>"
		  "<font size=1>"
		  "reloads the synonyms and affinity table on this host only"
		  "</font>"
		  "</td>"
		  "<td width=12%% bgcolor=#0000ff>"
		  "<center><b>"
		  "<a href=\"/master/thesaurus?reload=1&cast=0&%s\">"
		  "reload data</a></b></center>"
		  "</td>"
		  "</tr>\n", getBuf);

	p.safePrintf (
		  "<tr>"
		  "<td width=37%%><b>reload data (all hosts)</b><br>"
		  "<font size=1>"
		  "reloads the synonyms and affinity table on all hosts"
		  "</font>"
		  "</td>"
		  "<td width=12%% bgcolor=#0000ff>"
		  "<center><b>"
		  "<a href=\"/master/thesaurus?reload=1&cast=1&%s\">"
		  "reload data (all hosts)</a></b></center>"
		  "</td>"
		  "</tr>\n", getBuf);

	p.safePrintf (
		  "<tr>"
		  "<td width=37%%><b>list synonyms</b><br>"
		  "<font size=1>"
		  "enter a word here to list all synonym entries and their "
		  "affinities"
		  "</font>"
		  "</td>"
		  "<td width=12%%>"
		  "<form action=\"/master/thesaurus>\">"
		  "<input type=text name=synonym size=20>"
		  "<input type=submit value=Submit>"
		  "%s"
		  "</form></td>"
		  "</tr>\n", formBuf);
		
	p.safePrintf (
		  "<tr>"
		  "<td colspan=2 bgcolor=#%s>"
		  "<center><b>Affinity Controls"
		  "</b></center></td>"
		  "</tr>\n",
		  DARK_BLUE);

	p.safePrintf (
		  "<tr>"
		  "<td width=37%%><b>cancel running rebuild</b><br>"
		  "<font size=1>"
		  "cancels the rebuild and throws all intermediate data away"
		  "</font>"
		  "</td>"
		  "<td width=12%% bgcolor=#0000ff>"
		  "<center><b><a href=\"/master/thesaurus?cancel=1&%s\">"
		  "cancel running rebuild</a></b></center>"
		  "</td>"
		  "</tr>\n", getBuf);
	
	p.safePrintf (
		  "<tr>"
		  "<td width=37%%><b>rebuild affinity only</b><br>"
		  "<font size=1>"
		  "begins the rebuild process for affinity data, has no "
		  "effect if a rebuild is already in progress; full rebuild "
		  "does not reuse existing affinity data"
		  "</font>"
		  "</td>"
		  "<td width=12%% bgcolor=#0000ff>"
		  "<center><b><a href=\"/master/thesaurus?rebuildaff=1&%s\">"
		  "rebuild affinity</a> <a href=\"/master/thesaurus?"
		  "rebuildaff=1&full=1&%s\">(full)</a></b></center>"
		  "</td>"
		  "</tr>\n", getBuf, getBuf);
	
	p.safePrintf (
		  "<tr>"
		  "<td colspan=2 bgcolor=#%s>"
		  "<center><b>Manual File Controls"
		  "</b></td>"
		  "</tr>\n",
		  DARK_BLUE);

	p.safePrintf (
		  "<tr>"
		  "<td align=center colspan=2>");
	
	p.safePrintf(
		  "<b>manually added pairs</b><br>\n"
		  "<font size=1>place word pairs here that should be linked "
		  "as synonyms, one pair per line, seperated by a pipe '|' "
		  "character, optionally followed by another pipe and a type "
		  "designation; any badly formatted lines will be silently "
		  "ignored</font><br>\n"
		  "<form action=\"/master/thesaurus\" method=post>"
		  "<textarea name=\"manualadd\" rows=20 cols=80>");

	if (manualAdd && manualAddLen) {
		p.htmlEncode(manualAdd, manualAddLen, true);
	}
	
	p.safePrintf (
		  "</textarea><br>"
		  "<input type=submit value=Submit>"
		  "<input type=reset value=Reset>"
		  "%s"
		  "</form></td>"
		  "</tr>\n",
		  formBuf);

	
	p.safePrintf (
		  "<tr>"
		  "<td align=center colspan=2>"
		  "<b>affinity value overrides</b><br>\n"
		  "<font size=1>place word/phrase pairs here that should have "
		  "there affinity values overridden, format is "
		  "\"word1|word2|value\", where value is a floating point, "
		  "integer (either decimal or hex), or the word \"max\"; "
		  "any badly formatted lines will be silently ignored; note "
		  "that these pairs will only work if the thesaurus otherwise "
		  "has an entry for them, so add them to the manual add file "
		  "above if need be</font><br>\n"
		  "<form action=\"/master/thesaurus\" method=post>"
		  "<textarea name=\"affinityadd\" rows=20 cols=80>");

	if (affinityAdd && affinityAddLen) {
		p.htmlEncode(affinityAdd, affinityAddLen, true);
	}
	
	p.safePrintf (
		  "</textarea><br>"
		  "<input type=submit value=Submit>"
		  "<input type=reset value=Reset>"
		  "%s"
		  "</form></td>"
		  "</tr>\n", 
		  formBuf);


	p.safePrintf ( "</table>\n" );
	p.safePrintf ( "<br><br>\n" );

	p.safePrintf (
		  "<table cellpadding=4 width=100%% bgcolor=#%s border=1>"
		  "<tr>"
		  "<td colspan=2 bgcolor=#%s>"
		  "<center><b>Affinity Builder Status"
		  "</b></td>"
		  "</tr>\n",
		  LIGHT_BLUE, DARK_BLUE);

	long long a, b, c, d, e, f, g, h, i, j, k;
	StateAffinity *aff = g_thesaurus.m_affinityState;
	if (!aff) {
		p.safePrintf (
		  "<tr><td colspan=2>"
		  "<center><b>Not running</b></center>"
		  "</td></tr>\n");
		a = b = c = d = e = f = g = h = i = j = k = 0;
	} else {
		a = aff->m_oldTable->getNumSlotsUsed();
		b = aff->m_oldTable->getNumSlotsUsed() - aff->m_n;
		c = aff->m_n;
		d = (gettimeofdayInMilliseconds() - aff->m_time) / 1000;
		if (!d || !(c / d)) { 
			e = 0;
		} else {
			e = b / (c / d);
		}
		f = aff->m_sent;
		g = aff->m_recv;
		h = aff->m_errors;
		i = aff->m_old;
		j = aff->m_cache;
		k = aff->m_hitsTable.getNumSlotsUsed();
	}
	p.safePrintf (
		  "<tr><td><b># of total pairs</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b># of pairs remaining</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b># of pairs processed</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b>elapsed time in seconds</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b>estimated remaining time in seconds</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b># of requests sent</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b># of requests received</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b># of request errors</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b># of old values reused</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b># of cache hits</b></td>"
		  "<td>%lli</td></tr>\n"
		  "<tr><td><b>cache size</b></td>"
		  "<td>%lli</td></tr>\n",
		  a, b, c, d, e, f, g, h, i, j, k);
	p.safePrintf ( "</table>\n" );

	return g_httpServer.sendDynamicPage ( s, p.getBufStart(), p.length() );
}
Пример #9
0
int difftool(Options* inOptions)
/*
**  Read a diff file and spit out relevant information.
*/
{
    int retval = 0;
    char lineBuffer[0x500];
    SizeStats overall;
    ModuleStats* modules = NULL;
    unsigned moduleCount = 0;
    unsigned moduleLoop = 0;
    ModuleStats* theModule = NULL;
    unsigned segmentLoop = 0;
    SegmentStats* theSegment = NULL;
    unsigned objectLoop = 0;
    ObjectStats* theObject = NULL;
    unsigned symbolLoop = 0;
    SymbolStats* theSymbol = NULL;
    unsigned allSymbolCount = 0;

    memset(&overall, 0, sizeof(overall));

    /*
    **  Read the entire diff file.
    **  We're only interested in lines beginning with < or >
    */
    while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
    {
        trimWhite(lineBuffer);

        if(('<' == lineBuffer[0] || '>' == lineBuffer[0]) && ' ' == lineBuffer[1])
        {
            int additive = 0;
            char* theLine = &lineBuffer[2];
            int scanRes = 0;
            int size;
            #define SEGCLASS_CHARS 15
            char segClass[SEGCLASS_CHARS + 1];
            #define SCOPE_CHARS 15
            char scope[SCOPE_CHARS + 1];
            #define MODULE_CHARS 255
            char module[MODULE_CHARS + 1];
            #define SEGMENT_CHARS 63
            char segment[SEGMENT_CHARS + 1];
            #define OBJECT_CHARS 255
            char object[OBJECT_CHARS + 1];
            char* symbol = NULL;

            /*
            **  Figure out if the line adds or subtracts from something.
            */
            if('>' == lineBuffer[0])
            {
                additive = __LINE__;
            }


            /*
            **  Scan the line for information.
            */

#define STRINGIFY(s_) STRINGIFY2(s_)
#define STRINGIFY2(s_) #s_

            scanRes = sscanf(theLine,
                "%x\t%" STRINGIFY(SEGCLASS_CHARS) "s\t%"
                STRINGIFY(SCOPE_CHARS) "s\t%" STRINGIFY(MODULE_CHARS)
                "s\t%" STRINGIFY(SEGMENT_CHARS) "s\t%"
                STRINGIFY(OBJECT_CHARS) "s\t",
                (unsigned*)&size,
                segClass,
                scope,
                module,
                segment,
                object);

            if(6 == scanRes)
            {
                SegmentClass segmentClass = DATA;

                symbol = strrchr(theLine, '\t') + 1;

                if(0 == strcmp(segClass, "CODE"))
                {
                    segmentClass = CODE;
                }
                else if(0 == strcmp(segClass, "DATA"))
                {
                    segmentClass = DATA;
                }
                else
                {
                    retval = __LINE__;
                    ERROR_REPORT(retval, segClass, "Unable to determine segment class.");
                }

                if(0 == retval)
                {
                    unsigned moduleIndex = 0;

                    /*
                    **  Find, in succession, the following things:
                    **      the module
                    **      the segment
                    **      the object
                    **      the symbol
                    **  Failure to find any one of these means to create it.
                    */
                    
                    for(moduleIndex = 0; moduleIndex < moduleCount; moduleIndex++)
                    {
                        if(0 == strcmp(modules[moduleIndex].mModule, module))
                        {
                            break;
                        }
                    }
                    
                    if(moduleIndex == moduleCount)
                    {
                        void* moved = NULL;
                        
                        moved = realloc(modules, sizeof(ModuleStats) * (1 + moduleCount));
                        if(NULL != moved)
                        {
                            modules = (ModuleStats*)moved;
                            moduleCount++;
                            memset(modules + moduleIndex, 0, sizeof(ModuleStats));
                            
                            modules[moduleIndex].mModule = strdup(module);
                            if(NULL == modules[moduleIndex].mModule)
                            {
                                retval = __LINE__;
                                ERROR_REPORT(retval, module, "Unable to duplicate string.");
                            }
                        }
                        else
                        {
                            retval = __LINE__;
                            ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase module array.");
                        }
                    }
                    
                    if(0 == retval)
                    {
                        unsigned segmentIndex = 0;
                        theModule = (modules + moduleIndex);
                        
                        for(segmentIndex = 0; segmentIndex < theModule->mSegmentCount; segmentIndex++)
                        {
                            if(0 == strcmp(segment, theModule->mSegments[segmentIndex].mSegment))
                            {
                                break;
                            }
                        }
                        
                        if(segmentIndex == theModule->mSegmentCount)
                        {
                            void* moved = NULL;
                            
                            moved = realloc(theModule->mSegments, sizeof(SegmentStats) * (theModule->mSegmentCount + 1));
                            if(NULL != moved)
                            {
                                theModule->mSegments = (SegmentStats*)moved;
                                theModule->mSegmentCount++;
                                memset(theModule->mSegments + segmentIndex, 0, sizeof(SegmentStats));
                                
                                theModule->mSegments[segmentIndex].mClass = segmentClass;
                                theModule->mSegments[segmentIndex].mSegment = strdup(segment);
                                if(NULL == theModule->mSegments[segmentIndex].mSegment)
                                {
                                    retval = __LINE__;
                                    ERROR_REPORT(retval, segment, "Unable to duplicate string.");
                                }
                            }
                            else
                            {
                                retval = __LINE__;
                                ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase segment array.");
                            }
                        }
                        
                        if(0 == retval)
                        {
                            unsigned objectIndex = 0;
                            theSegment = (theModule->mSegments + segmentIndex);
                            
                            for(objectIndex = 0; objectIndex < theSegment->mObjectCount; objectIndex++)
                            {
                                if(0 == strcmp(object, theSegment->mObjects[objectIndex].mObject))
                                {
                                    break;
                                }
                            }
                            
                            if(objectIndex == theSegment->mObjectCount)
                            {
                                void* moved = NULL;
                                
                                moved = realloc(theSegment->mObjects, sizeof(ObjectStats) * (1 + theSegment->mObjectCount));
                                if(NULL != moved)
                                {
                                    theSegment->mObjects = (ObjectStats*)moved;
                                    theSegment->mObjectCount++;
                                    memset(theSegment->mObjects + objectIndex, 0, sizeof(ObjectStats));
                                    
                                    theSegment->mObjects[objectIndex].mObject = strdup(object);
                                    if(NULL == theSegment->mObjects[objectIndex].mObject)
                                    {
                                        retval = __LINE__;
                                        ERROR_REPORT(retval, object, "Unable to duplicate string.");
                                    }
                                }
                                else
                                {
                                    retval = __LINE__;
                                    ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase object array.");
                                }
                            }
                            
                            if(0 == retval)
                            {
                                unsigned symbolIndex = 0;
                                theObject = (theSegment->mObjects + objectIndex);
                                
                                for(symbolIndex = 0; symbolIndex < theObject->mSymbolCount; symbolIndex++)
                                {
                                    if(0 == strcmp(symbol, theObject->mSymbols[symbolIndex].mSymbol))
                                    {
                                        break;
                                    }
                                }
                                
                                if(symbolIndex == theObject->mSymbolCount)
                                {
                                    void* moved = NULL;
                                    
                                    moved = realloc(theObject->mSymbols, sizeof(SymbolStats) * (1 + theObject->mSymbolCount));
                                    if(NULL != moved)
                                    {
                                        theObject->mSymbols = (SymbolStats*)moved;
                                        theObject->mSymbolCount++;
                                        allSymbolCount++;
                                        memset(theObject->mSymbols + symbolIndex, 0, sizeof(SymbolStats));
                                        
                                        theObject->mSymbols[symbolIndex].mSymbol = strdup(symbol);
                                        if(NULL == theObject->mSymbols[symbolIndex].mSymbol)
                                        {
                                            retval = __LINE__;
                                            ERROR_REPORT(retval, symbol, "Unable to duplicate string.");
                                        }
                                    }
                                    else
                                    {
                                        retval = __LINE__;
                                        ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase symbol array.");
                                    }
                                }
                                
                                if(0 == retval)
                                {
                                    theSymbol = (theObject->mSymbols + symbolIndex);

                                    /*
                                    **  Update our various totals.
                                    */
                                    if(additive)
                                    {
                                        if(CODE == segmentClass)
                                        {
                                            overall.mCode += size;
                                            theModule->mSize.mCode += size;
                                        }
                                        else if(DATA == segmentClass)
                                        {
                                            overall.mData += size;
                                            theModule->mSize.mData += size;
                                        }

                                        theSegment->mSize += size;
                                        theObject->mSize += size;
                                        theSymbol->mSize += size;
                                    }
                                    else
                                    {
                                        if(CODE == segmentClass)
                                        {
                                            overall.mCode -= size;
                                            theModule->mSize.mCode -= size;
                                        }
                                        else if(DATA == segmentClass)
                                        {
                                            overall.mData -= size;
                                            theModule->mSize.mData -= size;
                                        }

                                        theSegment->mSize -= size;
                                        theObject->mSize -= size;
                                        theSymbol->mSize -= size;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                retval = __LINE__;
                ERROR_REPORT(retval, inOptions->mInputName, "Unable to scan line data.");
            }
        }
    }

    if(0 == retval && 0 != ferror(inOptions->mInput))
    {
        retval = __LINE__;
        ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
    }

    /*
    **  Next, it is time to perform revisionist history of sorts.
    **  If the negation switch is in play, we perfrom the following
    **      aggressive steps:
    **
    **  For each section, find size changes which have an equal and
    **      opposite change, and set them both to zero.
    **  However, you can only do this if the number of negating changes
    **      is even, as if it is odd, then any one of the many could be
    **      at fault for the actual change.
    **
    **  This originally exists to make the win32 codesighs reports more
    **      readable/meaningful.
    */
    if(0 == retval && 0 != inOptions->mNegation)
    {
        ObjectStats** objArray = NULL;
        SymbolStats** symArray = NULL;

        /*
        **  Create arrays big enough to hold all symbols.
        **  As well as an array to keep the owning object at the same index.
        **  We will keep the object around as we may need to modify the size.
        */
        objArray = (ObjectStats**)malloc(allSymbolCount * sizeof(ObjectStats*));
        symArray = (SymbolStats**)malloc(allSymbolCount * sizeof(SymbolStats*));
        if(NULL == objArray || NULL == symArray)
        {
            retval = __LINE__;
            ERROR_REPORT(retval, inOptions->mProgramName, "Unable to allocate negation array memory.");
        }
        else
        {
            unsigned arrayCount = 0;
            unsigned arrayLoop = 0;

            /*
            **  Go through and perform the steps on each section/segment.
            */
            for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
            {
                theModule = modules + moduleLoop;

                for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
                {
                    theSegment = theModule->mSegments + segmentLoop;

                    /*
                    **  Collect all symbols under this section.
                    **  The symbols are spread out between all the objects,
                    **      so keep track of both independently at the
                    **      same index.
                    */
                    arrayCount = 0;

                    for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
                    {
                        theObject = theSegment->mObjects + objectLoop;

                        for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
                        {
                            theSymbol = theObject->mSymbols + symbolLoop;

                            objArray[arrayCount] = theObject;
                            symArray[arrayCount] = theSymbol;
                            arrayCount++;
                        }
                    }

                    /*
                    **  Now that we have a list of symbols, go through each
                    **      and see if there is a chance of negation.
                    */
                    for(arrayLoop = 0; arrayLoop < arrayCount; arrayLoop++)
                    {
                        /*
                        **  If the item is NULL, it was already negated.
                        **  Don't do this for items with a zero size.
                        */
                        if(NULL != symArray[arrayLoop] && 0 != symArray[arrayLoop]->mSize)
                        {
                            unsigned identicalValues = 0;
                            unsigned oppositeValues = 0;
                            unsigned lookLoop = 0;
                            const int lookingFor = symArray[arrayLoop]->mSize;

                            /*
                            **  Count the number of items with this value.
                            **  Count the number of items with the opposite equal value.
                            **  If they are equal, go through and negate all sizes.
                            */
                            for(lookLoop = arrayLoop; lookLoop < arrayCount; lookLoop++)
                            {
                                /*
                                **  Skip negated items.
                                **  Skip zero length items.
                                */
                                if(NULL == symArray[lookLoop] || 0 == symArray[lookLoop]->mSize)
                                {
                                    continue;
                                }

                                if(lookingFor == symArray[lookLoop]->mSize)
                                {
                                    identicalValues++;
                                }
                                else if((-1 * lookingFor) == symArray[lookLoop]->mSize)
                                {
                                    oppositeValues++;
                                }
                            }
                            
                            if(0 != identicalValues && identicalValues == oppositeValues)
                            {
                                unsigned negationLoop = 0;

                                for(negationLoop = arrayLoop; 0 != identicalValues || 0 != oppositeValues; negationLoop++)
                                {
                                    /*
                                    **  Skip negated items.
                                    **  Skip zero length items.
                                    */
                                    if(NULL == symArray[negationLoop] || 0 == symArray[negationLoop]->mSize)
                                    {
                                        continue;
                                    }

                                    /*
                                    **  Negate any size matches.
                                    **  Reflect the change in the object as well.
                                    **  Clear the symbol.
                                    */
                                    if(lookingFor == symArray[negationLoop]->mSize)
                                    {
                                        objArray[negationLoop]->mSize -= lookingFor;
                                        symArray[negationLoop]->mSize = 0;
                                        symArray[negationLoop] = NULL;

                                        identicalValues--;
                                    }
                                    else if((-1 * lookingFor) == symArray[negationLoop]->mSize)
                                    {
                                        objArray[negationLoop]->mSize += lookingFor;
                                        symArray[negationLoop]->mSize = 0;
                                        symArray[negationLoop] = NULL;

                                        oppositeValues--;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        CLEANUP(objArray);
        CLEANUP(symArray);
    }


    /*
    **  If all went well, time to report.
    */
    if(0 == retval)
    {
        /*
        **  Loop through our data once more, so that the symbols can
        **      propigate their changes upwards in a positive/negative
        **      fashion.
        **  This will help give the composite change more meaning.
        */
        for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
        {
            theModule = modules + moduleLoop;
            
            /*
            **  Skip if there is zero drift, or no net change.
            */
            if(0 == inOptions->mZeroDrift && 0 == (theModule->mSize.mCode + theModule->mSize.mData))
            {
                continue;
            }

            for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
            {
                theSegment = theModule->mSegments + segmentLoop;
                
                /*
                **  Skip if there is zero drift, or no net change.
                */
                if(0 == inOptions->mZeroDrift && 0 == theSegment->mSize)
                {
                    continue;
                }
                
                for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
                {
                    theObject = theSegment->mObjects + objectLoop;
                    
                    /*
                    **  Skip if there is zero drift, or no net change.
                    */
                    if(0 == inOptions->mZeroDrift && 0 == theObject->mSize)
                    {
                        continue;
                    }

                    for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
                    {
                        theSymbol = theObject->mSymbols + symbolLoop;
                        
                        /*
                        **  Propagate the composition all the way to the top.
                        **  Sizes of zero change are skipped.
                        */
                        if(0 < theSymbol->mSize)
                        {
                            theObject->mComposition.mPositive += theSymbol->mSize;
                            theSegment->mComposition.mPositive += theSymbol->mSize;
                            if(CODE == theSegment->mClass)
                            {
                                overall.mCodeComposition.mPositive += theSymbol->mSize;
                                theModule->mSize.mCodeComposition.mPositive += theSymbol->mSize;
                            }
                            else if(DATA == theSegment->mClass)
                            {
                                overall.mDataComposition.mPositive += theSymbol->mSize;
                                theModule->mSize.mDataComposition.mPositive += theSymbol->mSize;
                            }
                        }
                        else if(0 > theSymbol->mSize)
                        {
                            theObject->mComposition.mNegative += theSymbol->mSize;
                            theSegment->mComposition.mNegative += theSymbol->mSize;
                            if(CODE == theSegment->mClass)
                            {
                                overall.mCodeComposition.mNegative += theSymbol->mSize;
                                theModule->mSize.mCodeComposition.mNegative += theSymbol->mSize;
                            }
                            else if(DATA == theSegment->mClass)
                            {
                                overall.mDataComposition.mNegative += theSymbol->mSize;
                                theModule->mSize.mDataComposition.mNegative += theSymbol->mSize;
                            }
                        }
                    }
                }
            }
        }


        if(inOptions->mSummaryOnly)
        {
            fprintf(inOptions->mOutput, "%+d (%+d/%+d)\n", overall.mCode + overall.mData, overall.mCodeComposition.mPositive + overall.mDataComposition.mPositive, overall.mCodeComposition.mNegative + overall.mDataComposition.mNegative);
        }
        else
        {
            fprintf(inOptions->mOutput, "Overall Change in Size\n");
            fprintf(inOptions->mOutput, "\tTotal:\t%+11d (%+d/%+d)\n", overall.mCode + overall.mData, overall.mCodeComposition.mPositive + overall.mDataComposition.mPositive, overall.mCodeComposition.mNegative + overall.mDataComposition.mNegative);
            fprintf(inOptions->mOutput, "\tCode:\t%+11d (%+d/%+d)\n", overall.mCode, overall.mCodeComposition.mPositive, overall.mCodeComposition.mNegative);
            fprintf(inOptions->mOutput, "\tData:\t%+11d (%+d/%+d)\n", overall.mData, overall.mDataComposition.mPositive, overall.mDataComposition.mNegative);
        }

        /*
        **  Check what else we should output.
        */
        if(0 == inOptions->mSummaryOnly && NULL != modules && moduleCount)
        {
            const char* segmentType = NULL;

            /*
            **  We're going to sort everything.
            */
            qsort(modules, moduleCount, sizeof(ModuleStats), moduleCompare);
            for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
            {
                theModule = modules + moduleLoop;

                qsort(theModule->mSegments, theModule->mSegmentCount, sizeof(SegmentStats), segmentCompare);

                for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
                {
                    theSegment = theModule->mSegments + segmentLoop;

                    qsort(theSegment->mObjects, theSegment->mObjectCount, sizeof(ObjectStats), objectCompare);

                    for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
                    {
                        theObject = theSegment->mObjects + objectLoop;

                        qsort(theObject->mSymbols, theObject->mSymbolCount, sizeof(SymbolStats), symbolCompare);
                    }
                }
            }

            /*
            **  Loop through for output.
            */
            for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
            {
                theModule = modules + moduleLoop;

                /*
                **  Skip if there is zero drift, or no net change.
                */
                if(0 == inOptions->mZeroDrift && 0 == (theModule->mSize.mCode + theModule->mSize.mData))
                {
                    continue;
                }

                fprintf(inOptions->mOutput, "\n");
                fprintf(inOptions->mOutput, "%s\n", theModule->mModule);
                fprintf(inOptions->mOutput, "\tTotal:\t%+11d (%+d/%+d)\n", theModule->mSize.mCode + theModule->mSize.mData, theModule->mSize.mCodeComposition.mPositive + theModule->mSize.mDataComposition.mPositive, theModule->mSize.mCodeComposition.mNegative + theModule->mSize.mDataComposition.mNegative);
                fprintf(inOptions->mOutput, "\tCode:\t%+11d (%+d/%+d)\n", theModule->mSize.mCode, theModule->mSize.mCodeComposition.mPositive, theModule->mSize.mCodeComposition.mNegative);
                fprintf(inOptions->mOutput, "\tData:\t%+11d (%+d/%+d)\n", theModule->mSize.mData, theModule->mSize.mDataComposition.mPositive, theModule->mSize.mDataComposition.mNegative);

                for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
                {
                    theSegment = theModule->mSegments + segmentLoop;

                    /*
                    **  Skip if there is zero drift, or no net change.
                    */
                    if(0 == inOptions->mZeroDrift && 0 == theSegment->mSize)
                    {
                        continue;
                    }

                    if(CODE == theSegment->mClass)
                    {
                        segmentType = "CODE";
                    }
                    else if(DATA == theSegment->mClass)
                    {
                        segmentType = "DATA";
                    }

                    fprintf(inOptions->mOutput, "\t%+11d (%+d/%+d)\t%s (%s)\n", theSegment->mSize, theSegment->mComposition.mPositive, theSegment->mComposition.mNegative, theSegment->mSegment, segmentType);

                    for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
                    {
                        theObject = theSegment->mObjects + objectLoop;

                        /*
                        **  Skip if there is zero drift, or no net change.
                        */
                        if(0 == inOptions->mZeroDrift && 0 == theObject->mSize)
                        {
                            continue;
                        }

                        fprintf(inOptions->mOutput, "\t\t%+11d (%+d/%+d)\t%s\n", theObject->mSize, theObject->mComposition.mPositive, theObject->mComposition.mNegative, theObject->mObject);
                        
                        for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
                        {
                            theSymbol = theObject->mSymbols + symbolLoop;

                            /*
                            **  Skip if there is zero drift, or no net change.
                            */
                            if(0 == inOptions->mZeroDrift && 0 == theSymbol->mSize)
                            {
                                continue;
                            }

                            fprintf(inOptions->mOutput, "\t\t\t%+11d\t%s\n", theSymbol->mSize, theSymbol->mSymbol);
                        }
                    }
                }
            }
        }
    }

    /*
    **  Cleanup time.
    */
    for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
    {
        theModule = modules + moduleLoop;
        
        for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
        {
            theSegment = theModule->mSegments + segmentLoop;
            
            for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
            {
                theObject = theSegment->mObjects + objectLoop;
                
                for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
                {
                    theSymbol = theObject->mSymbols + symbolLoop;
                    
                    CLEANUP(theSymbol->mSymbol);
                }
                
                CLEANUP(theObject->mSymbols);
                CLEANUP(theObject->mObject);
            }
            
            CLEANUP(theSegment->mObjects);
            CLEANUP(theSegment->mSegment);
        }
        
        CLEANUP(theModule->mSegments);
        CLEANUP(theModule->mModule);
    }
    CLEANUP(modules);
    
    return retval;
}