/* Define DETAIL if you want detail listings to be kept, this can
* double the pointer memory required and slow things down. If you NEVER
* want to do DETAIL listings then undefine it. On fast machines it really
* doesn't matter, but on my Amiga I can notice the difference. You need
* about 1.5 times the size of you log file in memory.
*/
#define DETAIL
/*** glog 3.0 ***/
/*** glog.c -- analysis tool for Unix gopherd logs ***/
/*** Version 3.0
*** by: Andy Wick -
[email protected]
*** This version is an almost TOTAL rewrite of glog. It now reads all
*** the information into memory before it does ANYTHING. It then goes
*** through the arguments one at a time. So inorder to effect something
*** you must change it before the report. ie. Argument order matters now.
***
*** Version 2.2
*** by: Chuck Shotton -
[email protected]
***
*** Version 2.1
*** by: Michael Mealling - Georgia Institute of Technology
*** Office of Information Technology
***
[email protected]
*** 12/29/92
***
*** Versions 1.0
*** by: Chuck Shotton - U of Texas Health Science Center - Houston,
*** Office of Academic Computing
***
[email protected]
*** 6/17/92
***/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef THINK_C
#include <console.h>
#endif
#define GLOG_VERSION "Gopher Log Analyzer v.3.0"
/* GENERAL STUFF */
typedef unsigned char byte;
/* Error log link list */
typedef struct enode_list {
char *data;
struct enode_list *next;
} ELIST_REC, *ELIST_PTR;
/* GOPHER LINE STUFF */
/* These are the different types of data that are currenly reconized*/
#define FILETYPE ' '
#define DIRTYPE 'D'
#define MAILDIRTYPE 'M'
#define FTPTYPE 'F'
#define RANGETYPE 'R'
/* One line of the gopher log is stored in here */
typedef struct gopher_line {
byte day;
byte month;
short date;
char *hostname;
char *path;
char type;
} GOPHER_REC, *GOPHER_PTR;
/* A Linked list of gopher lines */
typedef struct node_list {
GOPHER_PTR data;
short hits;
struct node_list *next;
} LIST_REC, *LIST_PTR;
/* Main tree */
typedef struct node_rec {
GOPHER_PTR data;
#ifdef DETAIL
LIST_REC *llist;
#endif
short hits;
struct node_rec *left, *right;
} NODE_REC, *NODE_PTR;
/***
*** The cruft list is a general list for things that aren't parse-able by
*** ProcessLine(). "cruft" kept for historical reasons.
***/
ELIST_PTR cruft = NULL;
/***
*** The following lists are maintained.
***/
NODE_PTR hosts = NULL;
NODE_PTR docs = NULL;
NODE_PTR days = NULL;
NODE_PTR dates = NULL;
NODE_PTR types = NULL;
/***
*** The following macro is used to insert things into the above lists
*** If you add a new sorting type, don't forget to add it here.
***/
#define ADDDATA(data) hosts = Insert(hosts, data, HostsCmp); \
docs = Insert(docs, data, DocsCmp); \
dates = Insert(dates, data, DatesCmp); \
types = Insert(types, data, TypesCmp); \
days = Insert(days, data, DaysCmp);
/***
*** Self-Documenting vars, that save memory
***/
char *ROOTNAME = "Root Connections";
char *Days[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
char *Months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
/* The base file name for gnuplot reports */
char BASE[7] = "gopher";
char *base = BASE;
/* Plot Output */
#define REPORTOUT 0
#define GNUOUT 1
#define HISTOUT 2
/* Type of plot to do */
char OutPlot=GNUOUT;
/* Used to tell the Plot routines that you are starting and stoping */
#define PLOTSTART (GOPHER_PTR)0
#define PLOTDONE (GOPHER_PTR)1
/* Width of reports */
byte Width = 62; /* 80 - WIDTHSUB */
#define WIDTHSUB 18 /* The width of the standard print stuff */
/* Information */
/* Internal */
#define NOINFO 0
#define DETAILINFO 1
/* Error log requested, but not a valid SORT TYPE */
#define ERRORINFO 'E'
/* SORT TYPES */
/* Changing these will change the options also */
#define DATAINFO 'D'
#define HOSTINFO 'H'
#define WEEKDAYINFO 'W'
#define MONTHDATEINFO 'M'
#define TYPEINFO 'T'
/* The only forward decleration needed, since I wrote this the pascal way,
the way all programs should be written. You don't need all the stupid
forward declerations, or prototypes. */
void PrintInfo(NODE_PTR tree, void print(GOPHER_PTR), int cmp(GOPHER_PTR a, GOPHER_PTR b), byte DetailType);
/*******************************/
/* Add item to error log */
ELIST_PTR InsertErrorLog(ELIST_PTR list, char *data)
{
ELIST_PTR temp, temp2;
if (NULL == (temp = (ELIST_PTR)malloc(sizeof(ELIST_REC))))
{
fprintf(stderr, "Not enough memory to add to ErrorLog\n");
exit(1);
}
if (NULL == (temp->data = (char *)malloc(sizeof(char) * (strlen(data) +1))))
{
fprintf(stderr, "Not enough memory to add to ErrorLog\n");
exit(1);
}
strcpy(temp->data, data);
temp->next = NULL;
if (list == NULL)
return (temp);
for (temp2 = list; temp2->next != NULL ; temp2 = temp2->next);
temp2->next = temp;
return(list);
}
#ifdef DETAIL
/*******************************/
LIST_PTR InsertDetail(LIST_PTR list, GOPHER_PTR data)
{
LIST_PTR temp;
if (NULL == (temp = (LIST_PTR)malloc(sizeof(LIST_REC))))
{
fprintf(stderr, "Not enough memory to add to DetailList\n");
exit(1);
}
temp->data = data;
temp->next = list;
temp->hits = 1;
return(temp);
}
#endif
/*******************************/
/* Insert tree_element into the appropriate symbol table. Increment the */
/* number of hits if that element is already present. */
/* Insert list_element into linked list contained in the node that */
/* tree_element was put in. */
NODE_PTR Insert(NODE_PTR tree, GOPHER_PTR data, int cmp(GOPHER_PTR a, GOPHER_PTR b))
{
int i;
if (tree == NULL)
{
if (NULL == (tree = (NODE_PTR) malloc(sizeof(NODE_REC))))
{
fprintf(stderr, "No memory for InsertHost\n");
exit(1);
}
tree->data = data;
tree->left = tree->right = NULL;
#ifdef DETAIL
tree->llist = InsertDetail(NULL, data);
#endif
tree->hits = 1;
return(tree);
}
i=cmp(data, tree->data);
if (i > 0)
tree->right = Insert(tree->right, data, cmp);
else if (i<0)
tree->left = Insert(tree->left, data, cmp);
else
{
tree->hits += 1;
#ifdef DETAIL
tree->llist = InsertDetail(tree->llist, data);
#endif
}
return(tree);
}
/*******************************/
NODE_PTR Find(NODE_PTR tree, GOPHER_PTR data, int cmp(GOPHER_PTR a, GOPHER_PTR b))
{
int i;
if (tree == NULL)
{
return (NULL);
}
i=cmp(data, tree->data);
if (i > 0)
return(Find(tree->right, data, cmp));
if (i<0)
return(Find(tree->left, data, cmp));
return(tree);
}
/*******************************/
/* Get a single field from temp, and return the new spot */
char *getf(char *temp, char *field)
{
while(*temp == ' ')
temp++;
*field = '\0';
if (*temp == '\n')
return(temp);
while ((*temp != ' ') && (*temp != '\0'))
*field++ = *temp++;
*field = '\0';
return(temp);
}
/*******************************/
int TypesCmp(GOPHER_PTR a, GOPHER_PTR b)
{
return(a->type - b->type);
}
/*******************************/
int HostsCmp(GOPHER_PTR a, GOPHER_PTR b)
{
return(strcmp(a->hostname, b->hostname));
}
/*******************************/
int DocsCmp(GOPHER_PTR a, GOPHER_PTR b)
{
return(strcmp(a->path, b->path));
}
/*******************************/
int DaysCmp(GOPHER_PTR a, GOPHER_PTR b)
{
return(a->day - b->day);
}
/*******************************/
int DatesCmp(GOPHER_PTR a, GOPHER_PTR b)
{
int i = a->month - b->month;
if (i == 0)
return(a->date - b->date);
else
return(i);
}
/*******************************/
byte MonthStr2Num(char *str)
{
static char lastmonth[4] = "Jan"; /* Who knows if saving the last month */
static int lastmonthnum = 1; /* really makes it faster */
int i;
if (strcmp(lastmonth, str) == 0)
return(lastmonthnum);
for(i=0;i<12;i++)
if (strcmp(Months[i], str) == 0)
{
strcpy(lastmonth, Months[i]);
lastmonthnum = i+1;
return(lastmonthnum);
}
return(13);
}
/*******************************/
byte DayStr2Num(char *str)
{
static char lastday[4] = "Sun"; /* Same here. Is there a better way? */
static int lastdaynum = 1;
int i;
if (strcmp(lastday, str) == 0)
return(lastdaynum);
for(i=0;i<7;i++)
if (strcmp(Days[i], str) == 0)
{
strcpy(lastday, Days[i]);
lastdaynum = i+1;
return(lastdaynum);
}
return(8);
}
/*******************************/
/* Read a line from the log file, parse it up, and insert the */
/* info into the appropriate tables. */
void ProcessLine(char *line)
{
GOPHER_PTR data;
short len;
char *temp; /* Used to save line, incase it is needed for cruft */
char junk[1025];
char message1[128];
char message2[128];
if (NULL == (data = (GOPHER_PTR)malloc(sizeof(GOPHER_REC))))
{
fprintf(stderr, "Not enough memory. Sorry\n");
exit(1);
}
temp = line;
temp = getf(temp, junk); /* Day */
if (8 == (data->day = DayStr2Num(junk)))
{ /* Not a real day of week */
free(data);
cruft = InsertErrorLog(cruft, line);
return;
}
temp = getf(temp, junk); /* Month */
if (13 == (data->month = MonthStr2Num(junk)))
{ /* Not a real month */
free(data);
cruft = InsertErrorLog(cruft, line);
return;
}
temp = getf(temp, junk); /* Date */
data->date = atoi(junk);
temp = getf(temp, junk);
temp = getf(temp, junk);
temp = getf(temp, junk);
temp = getf(temp ,junk); /* hostname */
if (junk[0] == ':')
{ /* A colon in the hostfield */
free(data);
cruft = InsertErrorLog(cruft, line);
return;
}
if (NULL == (data->hostname = (char *)malloc(sizeof(char) * (strlen(junk)+1))))
{
fprintf(stderr, "Not enough memory. Sorry\n");
exit(1);
}
strcpy(data->hostname, junk);
temp = getf(temp, junk); /* : COLON */
if (junk[0] != ':')
{ /* Now we don't have a colon */
free(data->hostname);
free(data);
cruft = InsertErrorLog(cruft, line);
return;
}
temp = getf(temp, message1);
temp = getf(temp, message2);
while((*temp == ' ') && (*temp != '\0'))
temp++;
data->path = (char *)malloc(sizeof(char)*(strlen(temp)+1));
strcpy(data->path, temp);
data->path[strlen(temp)] = '\0';
if (0 != (len = strlen(data->path)))
{
if (data->path[len-1] == '\n')
data->path[len-1] = '\0';
}
/***
*** This one is for that annoying 0.0.0.* IP address then gets stuck
*** in the log when someone is trying to access something you ain't got
***/
if (strncmp(data->hostname,"0.0.0", 5) == 0)
{
free(data->path);
free(data->hostname);
free(data);
cruft = InsertErrorLog(cruft, line);
return;
}
if (strcmp(message1, "Root") == 0)
{
data->type = DIRTYPE;
free(data->path);
data->path = ROOTNAME;
ADDDATA(data);
}
else if ((strcmp(message1, "retrieved") == 0) && (strcmp(data->path, "/") == 0))
{
data->type = DIRTYPE;
free(data->path);
data->path = ROOTNAME;
ADDDATA(data);
}
else if (strncmp(message2, "ftp:", 4) == 0)
{
strcpy(junk, data->path); /* Incase there was a space in the path */
free(data->path); /* Then we have to save off path, since it contains it*/
data->path = (char *)malloc(sizeof(char)*(strlen(message2)+strlen(junk)));
strcpy(data->path, message2+4);
strcat(data->path, junk);
data->type = FTPTYPE;
ADDDATA(data);
}
else if (strcmp(message1, "retrieved") == 0)
{
if (data->path[0] == '\0')
{ /* We some how retrieved nothing */
free(data->path);
free(data->hostname);
free(data);
cruft = InsertErrorLog(cruft, line);
return;
}
if (strcmp(message2, "directory") == 0)
data->type = DIRTYPE;
else if (strcmp(message2, "maildir") == 0)
data->type = MAILDIRTYPE;
else if (strcmp(message2, "file") == 0)
data->type = FILETYPE;
else if (strcmp(message2, "range") == 0)
data->type = RANGETYPE;
else
{
free(data->path);
free(data->hostname);
free(data);
cruft = InsertErrorLog(cruft, line);
return;
}
ADDDATA(data);
}
else /* wasn't anything we know about, g+ maybe?*/
{
free(data->path);
free(data->hostname);
free(data);
cruft = InsertErrorLog(cruft, line);
return;
}
return;
}
/*******************************/
void GatherInfo(void)
{
char line[1025];
while(!feof(stdin))
{
fgets(line, 1024, stdin);
if (feof(stdin))
break;
ProcessLine(line);
}
}
/*******************************/
/* These vars are only valid right after a call to TreeTo?List. I could have
* done some fancy var passing, but why bother. :) */
LIST_PTR GByNum;
int GByNumHits;
int GByNumMin; /* These two will be used for histograms in the future */
int GByNumMax;
/*******************************/
void InsertSByNum(GOPHER_PTR data, short hits)
{
LIST_PTR temp, temp2;
if (NULL == (temp = (LIST_PTR)malloc(sizeof(LIST_REC))))
{
fprintf(stderr, "Not enough memory in InsertByNum\n");
exit(1);
}
temp->data = data;
temp->next = NULL;
temp->hits = hits;
/* Figure out some vars */
if (hits < GByNumMin)
GByNumMin = hits;
if (hits > GByNumMax)
GByNumMax = hits;
GByNumHits += temp->hits;
if (GByNum == NULL)
GByNum = temp;
else if (GByNum->hits < hits)
{
temp->next = GByNum;
GByNum = temp;
}
else
{
temp2 = GByNum;
while (temp2->next != NULL)
{
if (temp2->next->hits < hits)
{
temp->next = temp2->next;
temp2->next = temp;
return;
}
temp2 = temp2->next;
}
temp2->next = temp;
}
}
/*******************************/
void InsertUByNum(GOPHER_PTR data, short hits)
{
LIST_PTR temp;
if (NULL == (temp = (LIST_PTR)malloc(sizeof(LIST_REC))))
{
fprintf(stderr, "Not enough memory in InsertByNum\n");
exit(1);
}
temp->data = data;
temp->next = NULL;
temp->hits = hits;
/* Figure out some vars */
if (hits < GByNumMin)
GByNumMin = hits;
if (hits > GByNumMax)
GByNumMax = hits;
GByNumHits += temp->hits;
if (GByNum == NULL)
GByNum = temp;
else
{
temp->next = GByNum;
GByNum = temp;
}
}
/*******************************/
/* I did two different routines so it would be faster :). I know this
* doesn't follow the logic of the rest of the program, but oh well.
* Do Inorder so that they remain in order, if two have the same
* num of hits
*/
void TreeToSList(NODE_PTR tree)
{
if (tree == NULL)
return;
TreeToSList(tree->left);
InsertSByNum(tree->data, tree->hits);
TreeToSList(tree->right);
}
/*******************************/
void TreeToUList(NODE_PTR tree)
{
/* I did two different routines so it would be faster :). I know this
* doesn't follow the logic of the rest of the program, but oh well.
* Do reverse inorder, so the insert just basicly sticks it at the
* beginning. Someone should rewrite this, maybe later :)
*/
if (tree == NULL)
return;
TreeToUList(tree->right);
InsertUByNum(tree->data, tree->hits);
TreeToUList(tree->left);
}
/*******************************/
NODE_PTR ListToTree(LIST_PTR list, int cmp(GOPHER_PTR, GOPHER_PTR))
{
NODE_PTR temptree = NULL;
for(;list != NULL; list = list->next)
temptree = Insert(temptree, list->data, cmp);
return(temptree);
}
/*******************************/
void FreeList(LIST_PTR list)
{
LIST_PTR temp;
while (list != NULL)
{
temp = list;
list = list->next;
free(temp);
}
}
/*******************************/
void FreeTree(NODE_PTR tree)
{
if (tree == NULL)
return;
FreeTree(tree->left);
FreeTree(tree->right);
#ifdef DETAIL
FreeList(tree->llist);
#endif
free(tree);
return;
}
/*******************************/
/* Given a string and and len, left justify and fill with spaces */
void printl(char *str, int len)
{
while (len > 0)
{
if (*str == '\n')
str++;
if (*str == '\0')
putc(' ', stdout);
else
putc(*str++, stdout);
len--;
}
}
/*******************************/
void PrintData(GOPHER_PTR data)
{
if (data == NULL)
{
printf("Data:\n");
}
else
{
printf("%c ",data->type);
printl(data->path, Width - 2);
}
}
/*******************************/
void PrintType(GOPHER_PTR data)
{
char *temp;
if (data == NULL)
{
printf("Types:\n");
}
else
{
switch(data->type)
{
case FILETYPE:
temp = "File";
break;
case DIRTYPE:
temp = "Directory";
break;
case MAILDIRTYPE:
temp = "Mail Directory";
break;
case FTPTYPE:
temp = "FTP";
break;
case RANGETYPE:
temp = "Range";
break;
}
printl(temp, Width);
}
}
/*******************************/
void PrintHost(GOPHER_PTR data)
{
if (data == NULL)
{
printf("Hosts:\n");
}
else
{
printl(data->hostname, Width);
}
}
/*******************************/
void PrintDay(GOPHER_PTR data)
{
if (data == NULL)
{
printf("Days:\n");
}
else
{
printl(Days[data->day-1], Width);
}
}
/*******************************/
void PrintDate(GOPHER_PTR data)
{
if (data == NULL)
{
printf("Dates:\n");
}
else
{
printf("%3s %3s %2d", Days[data->day-1], Months[data->month-1], data->date);
printl("\0", Width - 10);
}
}
/*******************************/
void PlotData(FILE *rfp, int num, GOPHER_PTR data)
{
if (data == PLOTSTART)
{
fprintf(stderr, "Plot of Data is not currently supported, since I am not quite sure what it is suppose to do. Mail me ideas:
[email protected]\n");
}
}
/*******************************/
void PlotType(FILE *rfp, int num, GOPHER_PTR data)
{
char *temp;
if (data == PLOTSTART)
{
fprintf(rfp,"set xtics (");
}
else if (data == PLOTDONE)
{
fprintf(rfp,"\"\" %d)\n", num);
fprintf(rfp,"set data style linespoints\n");
fprintf(rfp,"set tics out\n");
fprintf(rfp,"set grid\n");
fprintf(rfp,"set title \"Gopher Usage\"\n");
fprintf(rfp,"plot \"%s.dat\"\n", base);
}
else
{
switch(data->type)
{
case FILETYPE:
temp = "File";
break;
case DIRTYPE:
temp = "Directory";
break;
case MAILDIRTYPE:
temp = "Mail Directory";
break;
case FTPTYPE:
temp = "FTP";
break;
case RANGETYPE:
temp = "Range";
break;
}
fprintf(rfp,"\"%s\" %d,", temp, num);
}
}
/*******************************/
void PlotHost(FILE *rfp, int num, GOPHER_PTR data)
{
if (data == PLOTSTART)
{
fprintf(stderr, "Plot of Hosts is not currently supported, since I am not quite sure what it is suppose to do. Mail me ideas:
[email protected]\n");
}
}
/*******************************/
void PlotDay(FILE *rfp, int num, GOPHER_PTR data)
{
if (data == PLOTSTART)
{
fprintf(rfp,"set xtics (");
}
else if (data == PLOTDONE)
{
fprintf(rfp,"\"\" %d)\n", num);
fprintf(rfp,"set data style linespoints\n");
fprintf(rfp,"set tics out\n");
fprintf(rfp,"set grid\n");
fprintf(rfp,"set title \"Gopher Usage\"\n");
fprintf(rfp,"plot \"%s.dat\"\n", base);
}
else
{
fprintf(rfp,"\"%s\" %d,",Days[data->day-1], num);
}
}
/*******************************/
void PlotDate(FILE *rfp, int num, GOPHER_PTR data)
{
if (data == PLOTSTART)
{
fprintf(rfp,"set xtics (");
}
else if (data == PLOTDONE)
{
fprintf(rfp,"\"\" %d)\n", num);
fprintf(rfp,"set data style linespoints\n");
fprintf(rfp,"set tics out\n");
fprintf(rfp,"set grid\n");
fprintf(rfp,"set title \"Gopher Usage\"\n");
fprintf(rfp,"plot \"%s.dat\"\n", base);
}
else
{
if ((data->date == 1) || (data->date == 15) || (num == 1))
fprintf(rfp,"\"%s/%d\" %d,",Months[data->month-1], data->date, num);
}
}
#ifdef DETAIL
/*******************************/
void DoDetail(NODE_PTR tree, byte DetailType)
{
NODE_PTR newtree;
switch(DetailType)
{
case DATAINFO:
newtree = ListToTree(tree->llist, DocsCmp);
PrintInfo(newtree, PrintData, DocsCmp, DETAILINFO);
break;
case HOSTINFO:
newtree = ListToTree(tree->llist, HostsCmp);
PrintInfo(newtree, PrintHost, HostsCmp, DETAILINFO);
break;
case WEEKDAYINFO:
newtree = ListToTree(tree->llist, DaysCmp);
PrintInfo(newtree, PrintDay, DaysCmp, DETAILINFO);
break;
case MONTHDATEINFO:
newtree = ListToTree(tree->llist, DatesCmp);
PrintInfo(newtree, PrintDate, DatesCmp, DETAILINFO);
break;
case TYPEINFO:
newtree = ListToTree(tree->llist, TypesCmp);
PrintInfo(newtree, PrintType, TypesCmp, DETAILINFO);
break;
}
FreeTree(newtree);
}
#endif
/*******************************/
void PrintInfo(NODE_PTR tree, void print(GOPHER_PTR), int cmp(GOPHER_PTR a, GOPHER_PTR b), byte DetailType)
{
LIST_PTR temp;
LIST_PTR ByNum;
int ByNumHits;
if (DetailType != DETAILINFO)/*We are printing Detail info now,so no headers*/
{
print(NULL);
printf("=========================================================\n");
}
GByNum = NULL; /* Init the vars for the TreeToList function */
GByNumHits = 0;
TreeToSList(tree);
ByNum = GByNum; /* Save off and clear the globals vars, since this */
ByNumHits = GByNumHits; /* function can be called recurisively */
GByNum = NULL;
temp = ByNum;
while (temp != NULL)
{
#ifdef DETAIL
if (DetailType == DETAILINFO)
printf(" ");
#endif
print(temp->data);
printf(" %4d (%2.2f%%)\n", temp->hits, (float)temp->hits*100.0/ByNumHits);
#ifdef DETAIL
if ((DetailType != NOINFO) && (DetailType != DETAILINFO))
DoDetail(Find(tree, temp->data, cmp), DetailType);
/* Don't generate Detail for NOINFO or if we are already doing detail */
#endif
temp = temp->next;
}
printf("\n");
FreeList(ByNum);
}
/*******************************/
void PlotInfo(NODE_PTR tree, void plot(FILE *, int, GOPHER_PTR))
{
LIST_PTR temp;
FILE *rfp, *dfp;
char *fn;
int points = 1;
if (OutPlot == GNUOUT)
{
fn = (char *)malloc(strlen(base) + 5);
sprintf(fn,"%s.run", base);
if (NULL == (rfp = fopen(fn, "w")))
{
fprintf(stderr, "Could not open file \"%s\" for plot run\n", fn);
free(fn);
return;
}
sprintf(fn,"%s.dat", base);
if (NULL == (dfp = fopen(fn, "w")))
{
fprintf(stderr, "Could not open file \"%s\" for plot data\n", fn);
free(fn);
return;
}
free(fn);
}
else
{
rfp = stdout;
dfp = stdout;
}
plot(rfp, 0, PLOTSTART);
GByNum = NULL; /* Init the vars for the TreeToList function */
GByNumHits = 0;
GByNumMax = 0;
GByNumMin = 36000;
TreeToUList(tree);
temp = GByNum;
while (temp != NULL)
{
plot(rfp, points, temp->data);
fprintf(dfp, "%d %d\n", points++, temp->hits);
temp = temp->next;
}
plot(rfp, points, PLOTDONE);
printf("\n");
FreeList(GByNum);
}
/*******************************/
void PrintErrorInfo()
{
ELIST_PTR temp = cruft;
printf("=========================================================\n");
printf("Exception/Problem Report\n");
printf("NOTE: THESE ENTRIES MAY DENOTE A SERVER PROBLEM. THEY SHOULD BE LOOKED OVER!\n");
while (temp != NULL)
{
printf(temp->data);
temp = temp->next;
}
printf("\n");
}
/*******************************/
void PrintHelp()
{
#ifdef DETAIL
fprintf(stderr,"Usage: glog [-%ch] [-<SORTTYPE>[<SORTTYPE>]] [-p<SORTTYPE>]\n", ERRORINFO);
#else
fprintf(stderr,"Usage: glog [-%ch] [-<SORTTYPE>] [-p<SORTTYPE>]\n", ERRORINFO);
#endif
fprintf(stderr, " [-w <width>] [-o <outputtype>] [-f <basefilename>]\n");
fprintf(stderr, " -%c = Error log -h = this help\n", ERRORINFO);
fprintf(stderr, "\n");
fprintf(stderr, "SORTTYPE is one of the following\n");
fprintf(stderr, " %c = Host Names %c = Day of Week \n",
HOSTINFO, WEEKDAYINFO);
fprintf(stderr, " %c = Document Names %c = Month/Day\n",
DATAINFO, MONTHDATEINFO);
fprintf(stderr, " %c = Type\n", TYPEINFO);
fprintf(stderr, "\n");
}
/*******************************/
int main(argc, argv)
int argc;
char **argv;
{
int i = 1;
#ifdef THINK_C
argc = ccommand(&argv);
#endif
#ifdef DETAIL
printf("%s with DETAIL\n", GLOG_VERSION);
#else
printf("%s\n", GLOG_VERSION);
#endif
fflush(stdout);
if (1 == argc)
{
PrintHelp(); /* Clueless */
exit(-1);
}
GatherInfo();
fflush(stdout);
fflush(stderr);
while (i<argc)
{
switch (argv[i][1])
{
case ERRORINFO:
PrintErrorInfo();
break;
case DATAINFO:
PrintInfo(docs, PrintData, DocsCmp, argv[i][2]);
break;
case TYPEINFO:
PrintInfo(types, PrintType, TypesCmp, argv[i][2]);
break;
case WEEKDAYINFO:
PrintInfo(days, PrintDay, DaysCmp, argv[i][2]);
break;
case MONTHDATEINFO:
PrintInfo(dates, PrintDate, DatesCmp, argv[i][2]);
break;
case HOSTINFO:
PrintInfo(hosts, PrintHost, HostsCmp, argv[i][2]);
break;
case 'p': /*custom plots*/
switch (argv[i][2])
{
case DATAINFO:
PlotInfo(docs, PlotData);
break;
case TYPEINFO:
PlotInfo(types, PlotType);
break;
case WEEKDAYINFO:
PlotInfo(days, PlotDay);
break;
case MONTHDATEINFO:
PlotInfo(dates, PlotDate);
break;
case HOSTINFO:
PlotInfo(hosts, PlotHost);
break;
}
break;
case 'w':
if (i<argc-1)
Width = atoi(argv[++i]) - WIDTHSUB;
break;
case 'o':
if (i<argc-1)
OutPlot = atoi(argv[++i]);
break;
case 'f':
if (i<argc-1)
base = argv[++i];
break;
case '?':
case 'h':
PrintHelp();
break;
default:
fprintf(stderr, "Unknown option \"%c\" . -h for help\n", argv[i][1]);
break;
} /*switch*/
i++; /*next arg...*/
} /*while*/
exit(0);
}
/*******************************/