"Fossies" - the Fresh Open Source Software Archive

Member "sarg-2.4.0/grepday.c" (24 Dec 2019, 24006 Bytes) of package /linux/privat/sarg-2.4.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "grepday.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.3.11_vs_2.4.0.

    1 /*
    2  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
    3  *                                                            1998, 2015
    4  *
    5  * SARG donations:
    6  *      please look at http://sarg.sourceforge.net/donations.php
    7  * Support:
    8  *     http://sourceforge.net/projects/sarg/forums/forum/363374
    9  * ---------------------------------------------------------------------
   10  *
   11  *  This program is free software; you can redistribute it and/or modify
   12  *  it under the terms of the GNU General Public License as published by
   13  *  the Free Software Foundation; either version 2 of the License, or
   14  *  (at your option) any later version.
   15  *
   16  *  This program is distributed in the hope that it will be useful,
   17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19  *  GNU General Public License for more details.
   20  *
   21  *  You should have received a copy of the GNU General Public License
   22  *  along with this program; if not, write to the Free Software
   23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   24  *
   25  */
   26 
   27 #include "include/conf.h"
   28 #include "include/defs.h"
   29 
   30 #if defined(HAVE_GD)
   31 
   32 #if defined(HAVE_ICONV_H) && defined(gdFTEX_Unicode)
   33 #include <iconv.h>
   34 #define USE_ICONV 1
   35 #endif
   36 
   37 struct GraphDataStruct
   38 {
   39     int lavender;
   40     int darkblue;
   41     int dimgray;
   42     int goldenrod;
   43     int goldenrod2;
   44     int gray;
   45     int silver;
   46     int black;
   47     //! The color of the top side of a graph bar.
   48     int color1;
   49     //! The color of the right side of a graph bar.
   50     int color2;
   51     //! The color of the front side of a graph bar.
   52     int color3;
   53     //! The libgd image we are drawing on.
   54     gdImage *im;
   55     //! An allocated buffer to convert the string into UTF-8.
   56     char *string;
   57     //! The number of bytes allocated for the string buffer.
   58     size_t string_size;
   59     //! The bottom border of the graph.
   60     int BottomGraph;
   61     //! The top border of the graph.
   62     int TopGraph;
   63     //! The left border of the graph.
   64     int LeftGraph;
   65     //! The right border of the graph.
   66     int RightGraph;
   67     //! The height at which the bottom depth border of the graph extends.
   68     int BottomDepth;
   69     //! The distance between two ticks on the horizontal axis.
   70     double XScale;
   71     //! The distance between two ticks on the vertical axis.
   72     double YScale;
   73     //! The exterior length of a tick on the scales.
   74     int TickLength;
   75     //! The distance, in pixels, between two ticks along the Y axis.
   76     int YTickSpace;
   77 };
   78 
   79 enum PlotType
   80 {
   81     PTG_LinBin,
   82     PTG_LogBin,
   83     PTG_Time,
   84 };
   85 
   86 struct PlotStruct
   87 {
   88     //! The data points to plot.
   89     long long int *datapoints;
   90     //! The number of points to plot.
   91     int npoints;
   92     //! The minimum data to plot along the Y axis.
   93     long long int ymin;
   94     //! The maximum data to plot along the Y axis.
   95     long long int ymax;
   96     //! The type of Y axis to draw.
   97     enum PlotType ytype;
   98     //! The label to write on the X axis.
   99     const char *XLabel;
  100     //! The label to write on the Y axis.
  101     const char *YLabel;
  102     //! The name of the output PNG file.
  103     const char *pngfile;
  104 };
  105 
  106 enum TextRefPos
  107 {
  108     TRP_TopLeft,
  109     TRP_TopCenter,
  110     TRP_TopRight,
  111     TRP_BottomLeft,
  112     TRP_BottomCenter,
  113     TRP_BottomRight,
  114     TRP_CenterLeft,
  115     TRP_Center,
  116     TRP_CenterRight,
  117 };
  118 
  119 #ifdef USE_ICONV
  120 //! The iconv object to convert the text from the locale character set to UTF-8.
  121 iconv_t localtoutf=(iconv_t)-1;
  122 #endif
  123 
  124 extern char GraphConfigFile[MAXLEN];
  125 
  126 static void Sarg_gdImageStringFT (struct GraphDataStruct *gdata, int fg, char *fontlist,
  127          double ptsize, double angle, int x, int y, const char *string,enum TextRefPos RefPos)
  128 {
  129     char *sstring;
  130     char *retval;
  131     int brect[8];
  132     int minx,miny,maxx,maxy;
  133     int i;
  134 
  135 #ifdef USE_ICONV
  136     if (localtoutf!=(iconv_t)-1) {
  137         const char *str;
  138         char *sstr;
  139         size_t slen, sslen;
  140 
  141         slen = strlen(string) + 1; // We must include string termination character
  142         sslen = slen * 3;          // We assume that the UTF8 string will not be bigger than 3 times the original size.
  143         if (sslen>gdata->string_size) {
  144             sstring = (char *)realloc(gdata->string,sslen);
  145             if (!sstring) {
  146                 debuga(__FILE__,__LINE__,_("realloc error (%"PRIu64" bytes required)\n"),(uint64_t)sslen);
  147                 exit(EXIT_FAILURE);
  148             }
  149             gdata->string=(char *)sstring;
  150             gdata->string_size=sslen;
  151         } else {
  152             sstring=gdata->string;
  153             sslen=gdata->string_size;
  154         }
  155 
  156         str = string;
  157         sstr = sstring;
  158         if (iconv (localtoutf, (ICONV_CONST char **)&str, &slen, &sstr, &sslen)==-1) {
  159             debuga(__FILE__,__LINE__,_("iconv failed to convert string \"%s\" from %s to UTF-8: %s\n"),string,CharSet,strerror(errno));
  160             sstring=(char *)string; //show something sensible on the graph
  161         }
  162     } else {
  163         sstring=(char *)string; //show something sensible on the graph
  164     }
  165 #else
  166     sstring=(char *)string;
  167 #endif
  168 
  169     if (RefPos!=TRP_BottomLeft) {
  170         retval = gdImageStringFTEx (NULL, brect, fg, fontlist, ptsize, angle, 0, 0, sstring, gdFTEX_Unicode);
  171         if (retval) {
  172             debuga(__FILE__,__LINE__,_("libgd failed to calculate the bounding box of the text \"%s\": %s\n"),sstring,retval);
  173             exit(EXIT_FAILURE);
  174         }
  175         /*
  176         From libgd documentation, brect contains this without taking into account the angle:
  177         0  lower left corner, X position
  178         1  lower left corner, Y position
  179         2  lower right corner, X position
  180         3  lower right corner, Y position
  181         4  upper right corner, X position
  182         5  upper right corner, Y position
  183         6  upper left corner, X position
  184         7  upper left corner, Y position
  185         */
  186         minx=maxx=brect[0];
  187         miny=maxy=brect[1];
  188         for (i=2 ; i<7 ; i+=2) {
  189             if (minx>brect[i]) minx=brect[i];
  190             if (maxx<brect[i]) maxx=brect[i];
  191             if (miny>brect[i+1]) miny=brect[i+1];
  192             if (maxy<brect[i+1]) maxy=brect[i+1];
  193         }
  194     }
  195 
  196     switch (RefPos)
  197     {
  198         case TRP_TopLeft:
  199             y-=miny;
  200             break;
  201 
  202         case TRP_TopCenter:
  203             x-=(maxx-minx)/2;
  204             y-=miny;
  205             break;
  206 
  207         case TRP_TopRight:
  208             x-=maxx;
  209             y-=miny;
  210             break;
  211 
  212         case TRP_BottomLeft:
  213             break;
  214 
  215         case TRP_BottomCenter:
  216             x-=(maxx-minx)/2;
  217             break;
  218 
  219         case TRP_BottomRight:
  220             x-=maxx;
  221             break;
  222 
  223         case TRP_Center:
  224             x-=(maxx-minx)/2;
  225             y+=(maxy-miny)/2;
  226             break;
  227 
  228         case TRP_CenterLeft:
  229             y+=(maxy-miny)/2;
  230             break;
  231 
  232         case TRP_CenterRight:
  233             x-=maxx;
  234             y+=(maxy-miny)/2;
  235             break;
  236     }
  237     retval = gdImageStringFTEx (gdata->im, brect, fg, fontlist, ptsize, angle, x, y, sstring, gdFTEX_Unicode);
  238     if (retval) {
  239         debuga(__FILE__,__LINE__,_("libgd failed to render the text \"%s\": %s\n"),sstring,retval);
  240         exit(EXIT_FAILURE);
  241     }
  242 }
  243 
  244 static void bar(struct GraphDataStruct *gdata,int x1,double y,const char *label)
  245 {
  246     gdPoint points[4];
  247     int val=0;
  248     int width2;
  249 
  250     val=gdata->BottomGraph+5-(int)(y*gdata->YScale+0.5);
  251     width2=(int)(gdata->XScale/4.);
  252 
  253     // front side of the bar
  254     if (val<gdata->BottomDepth)
  255         gdImageFilledRectangle(gdata->im, x1-width2, val, x1+width2, gdata->BottomDepth, gdata->color3);
  256 
  257     // top side of the bar
  258     points[0].x = x1-width2+5;
  259     points[0].y = val-5;
  260     points[1].x = x1-width2;
  261     points[1].y = val;
  262     points[2].x = x1+width2;
  263     points[2].y = val;
  264     points[3].x = x1+width2+5;
  265     points[3].y = val-5;
  266     gdImageFilledPolygon(gdata->im, points, 4, gdata->color1);
  267 
  268     gdImageLine(gdata->im, x1+2, val-2, x1+2, val-10, gdata->dimgray);
  269     gdImageFilledRectangle(gdata->im, x1-8, val-20, x1+12, val-10, gdata->goldenrod);
  270     gdImageRectangle(gdata->im, x1-8, val-20, x1+12, val-10, gdata->goldenrod2);
  271 
  272     Sarg_gdImageStringFT(gdata,gdata->black,GraphFont,6,0.0,x1+2,val-12,label,TRP_BottomCenter);
  273 
  274     // lateral side of the bar
  275     if (val<gdata->BottomDepth) {
  276         points[0].x = x1+width2+5;
  277         points[0].y = val-5;
  278         points[1].x = x1+width2;
  279         points[1].y = val;
  280         points[2].x = x1+width2;
  281         points[2].y = gdata->BottomDepth;
  282         points[3].x = x1+width2+5;
  283         points[3].y = gdata->BottomGraph;
  284         gdImageFilledPolygon(gdata->im, points, 4, gdata->color2);
  285     }
  286 
  287     return;
  288 }
  289 
  290 static int greport_compute_yaxis(struct PlotStruct *pdata,struct GraphDataStruct *gdata)
  291 {
  292     double symin,symax;
  293     double range;
  294     double yscale;
  295 
  296     if (pdata->ymin<0.) {
  297         debuga(__FILE__,__LINE__,_("Minimum for Y scale of the graph is out of range: %"PRId64"\n"),(int64_t)pdata->ymin);
  298         return(-1);
  299     }
  300     if (pdata->ymax<=0.) {
  301         debuga(__FILE__,__LINE__,_("Maximum for Y scale of the graph is out of range: %"PRId64"\n"),(int64_t)pdata->ymax);
  302         return(-1);
  303     }
  304 
  305     switch(pdata->ytype)
  306     {
  307         case PTG_LinBin:
  308             symin=(double)pdata->ymin;
  309             symax=(double)pdata->ymax;
  310             break;
  311 
  312         case PTG_LogBin:
  313             if (pdata->ymin>0.)
  314                 symin=log(pdata->ymin);
  315             else
  316                 symin=0.;
  317             symax=log(pdata->ymax);
  318             break;
  319 
  320         case PTG_Time:
  321             symin=(double)pdata->ymin;
  322             symax=(double)pdata->ymax;
  323             break;
  324 
  325         default:
  326             debuga(__FILE__,__LINE__,_("Unknown type %d for Y axis scale\n"),pdata->ytype);
  327             return(-1);
  328     }
  329     gdata->YTickSpace=10;
  330 
  331     range=symax-symin;
  332     yscale=(double)(gdata->BottomGraph-gdata->TopGraph)/range;
  333     gdata->YScale=yscale;
  334     return(0);
  335 }
  336 
  337 static void greport_formatbin(double yval,int maxdigits,char *string,int slen)
  338 {
  339     int len;
  340     char schar[]={'\0','k','M','G','T','P'};
  341     int scount;
  342     int i;
  343     int ndigits;
  344 
  345     for (scount=0 ; scount<sizeof(schar)/sizeof(*schar) && yval>=1000. ; scount++)
  346         yval/=1000.;
  347     if (yval<2.)
  348         ndigits=2;
  349     else if (yval<3.)
  350         ndigits=1;
  351     else
  352         ndigits=0;
  353     if (ndigits>maxdigits) ndigits=maxdigits;
  354     len=snprintf(string,slen,"%.*f",ndigits,(float)yval);
  355     if (UseComma)
  356         for (i=0 ; i<len ; i++)
  357             if (string[i]=='.') string[i]=',';
  358     if (schar[scount] && len<slen) {
  359         string[len++]=schar[scount];
  360         string[len]='\0';
  361     }
  362 }
  363 
  364 static void greport_draw_yaxis(struct PlotStruct *pdata,struct GraphDataStruct *gdata)
  365 {
  366     double yval;
  367     int y0;
  368     int y;
  369     int yt;
  370     char YLabel[50];
  371     int xexterior;
  372     int xinterior;
  373     int xtick;
  374 
  375     y0=gdata->BottomGraph;
  376     yt=gdata->BottomDepth-gdata->BottomGraph;
  377     xexterior=gdata->LeftGraph-10;
  378     xinterior=gdata->LeftGraph;
  379     xtick=gdata->LeftGraph-10-gdata->TickLength;
  380     for (y=y0-gdata->YTickSpace ; y>=gdata->TopGraph ; y-=gdata->YTickSpace) {
  381         gdImageLine(gdata->im, xtick, y+yt, xexterior, y+yt, gdata->dimgray);
  382         gdImageLine(gdata->im, xexterior, y+yt, xinterior, y, gdata->dimgray);
  383         gdImageLine(gdata->im, xinterior, y, gdata->RightGraph, y, gdata->dimgray);
  384         switch (pdata->ytype)
  385         {
  386             case PTG_LinBin:
  387                 yval=(double)(y0-y)/gdata->YScale+(double)pdata->ymin;
  388                 greport_formatbin(yval,2,YLabel,sizeof(YLabel));
  389                 break;
  390 
  391             case PTG_LogBin:
  392                 yval=exp((double)(y0-y)/gdata->YScale+log(pdata->ymin));
  393                 greport_formatbin(yval,2,YLabel,sizeof(YLabel));
  394                 break;
  395 
  396             case PTG_Time:
  397             {
  398                 int t;
  399 
  400                 yval=(double)(y0-y)/gdata->YScale+(double)pdata->ymin;
  401                 t=(int)(yval/60000.+0.5);
  402                 snprintf(YLabel,sizeof(YLabel),"%02d:%02d",t/60,t%60);
  403                 break;
  404             }
  405         }
  406         Sarg_gdImageStringFT(gdata,gdata->dimgray,GraphFont,7,0.0,xtick,y+yt,YLabel,TRP_CenterRight);
  407     }
  408 }
  409 
  410 static void greport_plot(const struct userinfostruct *uinfo,struct PlotStruct *pdata)
  411 {
  412     FILE *pngout;
  413     int x, y;
  414     int day;
  415     int x1;
  416     char graph[MAXLEN];
  417     char s[15];
  418     char ftime[128];
  419     time_t t;
  420     struct tm *local;
  421     gdPoint points[4];
  422     struct GraphDataStruct gdata;
  423     const int ImgXSize=720;
  424     const int ImgYSize=480;
  425     const int LeftMargin=60;
  426     const int RightMargin=20;
  427     const int TopMargin=60;
  428     const int BottomMargin=60;
  429     const int TickLength=3;
  430     const int ZTickLength=5;
  431     double yval;
  432     char blabel[50];
  433     double logpmin;
  434 
  435     memset(&gdata,0,sizeof(gdata));
  436 
  437     gdata.im = gdImageCreate(ImgXSize, ImgYSize);
  438     gdata.BottomGraph=ImgYSize-BottomMargin;
  439     gdata.LeftGraph=LeftMargin;
  440     gdata.RightGraph=ImgXSize-RightMargin;
  441     gdata.TopGraph=TopMargin;
  442     gdata.BottomDepth=gdata.BottomGraph+5;
  443     gdata.XScale=(double)(gdata.RightGraph-gdata.LeftGraph)/(pdata->npoints+1);
  444     if (greport_compute_yaxis(pdata,&gdata)<0) return;
  445     gdata.TickLength=TickLength;
  446 
  447     // first allocated color is the background
  448     gdata.lavender = gdImageColorAllocate(gdata.im, 230, 230, 250);
  449     gdata.gray = gdImageColorAllocate(gdata.im, 192, 192, 192);
  450     gdata.silver = gdImageColorAllocate(gdata.im, 211, 211, 211);
  451     gdata.black = gdImageColorAllocate(gdata.im, 0, 0, 0);
  452     gdata.dimgray = gdImageColorAllocate(gdata.im, 105, 105, 105);
  453     gdata.darkblue = gdImageColorAllocate(gdata.im, 0, 0, 139);
  454     gdata.goldenrod = gdImageColorAllocate(gdata.im, 234, 234, 174);
  455     gdata.goldenrod2 = gdImageColorAllocate(gdata.im, 207, 181, 59);
  456 
  457     if (strcmp(GraphDaysBytesBarColor,"orange") == 0) {
  458         gdata.color1 = gdImageColorAllocate(gdata.im, 255, 233, 142);
  459         gdata.color2 = gdImageColorAllocate(gdata.im, 220, 163, 72);
  460         gdata.color3 = gdImageColorAllocate(gdata.im, 255, 198, 107);
  461     }
  462     else if (strcmp(GraphDaysBytesBarColor,"blue") == 0) {
  463         gdata.color1 = gdImageColorAllocate(gdata.im, 62, 80, 167);
  464         gdata.color2 = gdImageColorAllocate(gdata.im, 40, 51, 101);
  465         gdata.color3 = gdImageColorAllocate(gdata.im, 57, 73, 150);
  466     }
  467     else if (strcmp(GraphDaysBytesBarColor,"green") == 0) {
  468         gdata.color1 = gdImageColorAllocate(gdata.im,120,166,129);
  469         gdata.color2 = gdImageColorAllocate(gdata.im,84,113,82);
  470         gdata.color3 = gdImageColorAllocate(gdata.im,158,223,167);
  471     }
  472     else if (strcmp(GraphDaysBytesBarColor,"yellow") == 0) {
  473         gdata.color1 = gdImageColorAllocate(gdata.im,185,185,10);
  474         gdata.color2 = gdImageColorAllocate(gdata.im,111,111,10);
  475         gdata.color3 = gdImageColorAllocate(gdata.im,166,166,10);
  476     }
  477     else if (strcmp(GraphDaysBytesBarColor,"brown") == 0) {
  478         gdata.color1 = gdImageColorAllocate(gdata.im,97,45,27);
  479         gdata.color2 = gdImageColorAllocate(gdata.im,60,30,20);
  480         gdata.color3 = gdImageColorAllocate(gdata.im,88,41,26);
  481     }
  482     else if (strcmp(GraphDaysBytesBarColor,"red")  == 0){
  483         gdata.color1 = gdImageColorAllocate(gdata.im,185,10,10);
  484         gdata.color2 = gdImageColorAllocate(gdata.im,111,10,10);
  485         gdata.color3 = gdImageColorAllocate(gdata.im,166,10,10);
  486     } else {
  487         debuga(__FILE__,__LINE__,_("Unknown color \"%s\" requested for the graph. Using orange instead\n"),GraphDaysBytesBarColor);
  488         gdata.color1 = gdImageColorAllocate(gdata.im, 255, 233, 142);
  489         gdata.color2 = gdImageColorAllocate(gdata.im, 220, 163, 72);
  490         gdata.color3 = gdImageColorAllocate(gdata.im, 255, 198, 107);
  491     }
  492 
  493     // rectangle around the image
  494     gdImageRectangle(gdata.im, 0, 0, ImgXSize-1, ImgYSize-1, gdata.dimgray);
  495     // backtround of the graph
  496     gdImageFilledRectangle(gdata.im, LeftMargin, gdata.TopGraph, gdata.RightGraph, gdata.BottomGraph, gdata.silver);
  497 
  498     // depth of the left Y axis
  499     points[0].x = gdata.LeftGraph-10;
  500     points[0].y = gdata.TopGraph+5;
  501     points[1].x = gdata.LeftGraph-10;
  502     points[1].y = gdata.BottomDepth;
  503     points[2].x = gdata.LeftGraph;
  504     points[2].y = gdata.BottomGraph;
  505     points[3].x = gdata.LeftGraph;
  506     points[3].y = gdata.TopGraph;
  507     gdImageFilledPolygon(gdata.im, points, 4, gdata.gray);
  508 
  509     // depth of the bottom X axis
  510     points[0].x = gdata.LeftGraph;
  511     points[0].y = gdata.BottomGraph;
  512     points[1].x = gdata.LeftGraph-10;
  513     points[1].y = gdata.BottomDepth;
  514     points[2].x = gdata.RightGraph-10;
  515     points[2].y = gdata.BottomDepth;
  516     points[3].x = gdata.RightGraph;
  517     points[3].y = gdata.BottomGraph;
  518     gdImageFilledPolygon(gdata.im, points, 4, gdata.gray);
  519 
  520     // vertical exterior line of the depth
  521     gdImageLine(gdata.im, LeftMargin-10, TopMargin+5, LeftMargin-10, gdata.BottomDepth+ZTickLength, gdata.black);
  522     // horizontal exterior line of the depth
  523     gdImageLine(gdata.im, LeftMargin-10-ZTickLength, gdata.BottomDepth, gdata.RightGraph-10, gdata.BottomDepth, gdata.black);
  524     // diagonal line between the two depths
  525     gdImageLine(gdata.im, LeftMargin-10, gdata.BottomDepth, LeftMargin, gdata.BottomGraph, gdata.black);
  526     // vertical left line of the graph
  527     gdImageLine(gdata.im, LeftMargin, gdata.BottomGraph, LeftMargin, gdata.TopGraph, gdata.black);
  528     // horizontal bottom line of the graph
  529     gdImageLine(gdata.im, LeftMargin, gdata.BottomGraph, gdata.RightGraph, gdata.BottomGraph, gdata.black);
  530     // vertical right line of the graph
  531     gdImageLine(gdata.im, gdata.RightGraph, gdata.TopGraph, gdata.RightGraph, gdata.BottomGraph, gdata.black);
  532     // diagonal line to close the right of the bottom depth
  533     gdImageLine(gdata.im, gdata.RightGraph-10, gdata.BottomDepth, gdata.RightGraph, gdata.BottomGraph, gdata.black);
  534 
  535     // Y axis ticks
  536     greport_draw_yaxis(pdata,&gdata);
  537 
  538     // X axis ticks and labels
  539     for (y=1; y<=pdata->npoints; y++) {
  540         x=gdata.LeftGraph-10+(int)((double)y*gdata.XScale+0.5);
  541         gdImageLine(gdata.im, x, gdata.BottomDepth, x, gdata.BottomDepth+TickLength, gdata.dimgray);
  542         sprintf(s,"%02d",y);
  543         Sarg_gdImageStringFT(&gdata,gdata.dimgray,GraphFont,7,0.0,x,gdata.BottomDepth+TickLength+1,s,TRP_TopCenter);
  544     }
  545 
  546     t = time(NULL);
  547     local = localtime(&t);
  548     if (df=='u')
  549         strftime(ftime, sizeof(ftime), "%b/%d/%Y %H:%M", local);
  550     if (df=='e')
  551         strftime(ftime, sizeof(ftime), "%d/%b/%Y-%H:%M", local);
  552 
  553     x=ImgXSize*5/12;
  554     Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,7,0.0,ImgXSize-10,ImgYSize-10,ftime,TRP_BottomRight);
  555     if (ShowSargInfo) Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,10,0.0,x,15,_("SARG, "),TRP_BottomRight);
  556     Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,10,0.0,x,15,Title,TRP_BottomLeft);
  557     sprintf(warea,_("Period: %s"),period.text);
  558     Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,9,0.0,x,27,warea,TRP_BottomLeft);
  559     sprintf(warea,_("User: %s"),uinfo->label);
  560     Sarg_gdImageStringFT(&gdata,gdata.darkblue,GraphFont,9,0.0,x,38,warea,TRP_BottomLeft);
  561 
  562     Sarg_gdImageStringFT(&gdata,gdata.black,GraphFont,10,3.141592/2,15,ImgYSize/2,pdata->YLabel,TRP_CenterLeft);
  563     Sarg_gdImageStringFT(&gdata,gdata.black,GraphFont,10,0.0,ImgXSize/2,ImgYSize-20,pdata->XLabel,TRP_BottomCenter);
  564 
  565     logpmin=(pdata->ytype==PTG_LogBin && pdata->ymin>0.) ? log(pdata->ymin) : 0.;
  566     for (day=0 ; day<pdata->npoints ; day++) {
  567         if (pdata->datapoints[day]>0) {
  568             x1=gdata.LeftGraph-10+(int)((double)(day+1)*gdata.XScale+0.5);
  569             switch (pdata->ytype)
  570             {
  571                 case PTG_LinBin:
  572                     yval=(double)pdata->datapoints[day];
  573                     if (yval<pdata->ymin)
  574                         yval=0.;
  575                     else if (yval>pdata->ymax)
  576                         yval=pdata->ymax;
  577                     else
  578                         yval-=pdata->ymin;
  579                     greport_formatbin(pdata->datapoints[day],1,blabel,sizeof(blabel));
  580                     break;
  581                 case PTG_LogBin:
  582                     yval=(double)pdata->datapoints[day];
  583                     if (yval<=pdata->ymin)
  584                         yval=0.;
  585                     else if (yval>pdata->ymax)
  586                         yval=log(pdata->ymax)-logpmin;
  587                     else
  588                         yval=log(yval)-logpmin;
  589                     greport_formatbin(pdata->datapoints[day],1,blabel,sizeof(blabel));
  590                     break;
  591                 case PTG_Time:
  592                 {
  593                     int t;
  594 
  595                     yval=(double)pdata->datapoints[day];
  596                     if (yval<pdata->ymin)
  597                         yval=0.;
  598                     else if (yval>pdata->ymax)
  599                         yval=pdata->ymax;
  600                     else
  601                         yval-=pdata->ymin;
  602                     t=(int)(pdata->datapoints[day]/60000.);
  603                     snprintf(blabel,sizeof(blabel),"%d:%02d",t/60,t%60);
  604                     break;
  605                 }
  606                 default:
  607                     yval=-1.;
  608                     break;
  609             }
  610             if (yval>=0.) bar(&gdata,x1,yval,blabel);
  611         }
  612     }
  613 
  614     if (snprintf(graph,sizeof(graph),"%s/%s/%s",outdirname,uinfo->filename,pdata->pngfile)>=sizeof(graph)) {
  615         /* TRANSLATORS: The message is followed by the path that is too long. */
  616         debuga(__FILE__,__LINE__,_("User name too long to manufacture file name "));
  617         debuga_more("%s/%s/%s\n",outdirname,uinfo->filename,pdata->pngfile);
  618         exit(EXIT_FAILURE);
  619     }
  620     if ((pngout=fopen(graph,"wb"))==NULL) {
  621         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),graph,strerror(errno));
  622         exit(EXIT_FAILURE);
  623     }
  624     gdImagePng(gdata.im, pngout);
  625     if (fclose(pngout)==EOF) {
  626         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),graph,strerror(errno));
  627     }
  628     gdImageDestroy(gdata.im);
  629 
  630     if (gdata.string) free(gdata.string);
  631 }
  632 
  633 #endif //HAVE_GD
  634 
  635 void greport_prepare(void)
  636 {
  637 #ifdef HAVE_GD
  638     if (!Graphs) {
  639         if (debugz>=LogLevel_Process)
  640             debugaz(__FILE__,__LINE__,_("Graphs disabled as requested in \"%s\"\n"),GraphConfigFile);
  641         return;
  642     }
  643     if (GraphFont[0]=='\0') {
  644         if (debugz>=LogLevel_Process) {
  645             const char *File=(GraphConfigFile[0]) ? GraphConfigFile : ConfigFile;
  646             debugaz(__FILE__,__LINE__,_("Graphs disabled as no font names were provided in \"%s\"\n"),File);
  647         }
  648         return;
  649     }
  650 
  651     if (access(GraphFont, R_OK) != 0) {
  652         debuga(__FILE__,__LINE__,_("Font name \"%s\" not found\n"),GraphFont);
  653         exit(EXIT_FAILURE);
  654     }
  655 
  656 #ifdef USE_ICONV
  657     localtoutf = iconv_open ("UTF-8", CharSet);
  658     if (localtoutf==(iconv_t)-1) {
  659         debuga(__FILE__,__LINE__,_("iconv cannot convert from %s to UTF-8: %s\n"),CharSet,strerror(errno));
  660     }
  661 #endif
  662 
  663 #endif //HAVE_GD
  664 }
  665 
  666 void greport_day(const struct userinfostruct *uinfo)
  667 {
  668 #ifdef HAVE_GD
  669     FILE *fp_in, *fp_ou;
  670     char wdirname[MAXLEN];
  671     char buf[MAXLEN];
  672     int day;
  673     long long int llday;
  674     long long int bytes;
  675     long long int elap;
  676     long long int bytespoints[31];
  677     long long int elappoints[31];
  678     struct getwordstruct gwarea;
  679     struct PlotStruct pdata;
  680 
  681     if (datetimeby==0) return;
  682     if (!Graphs || GraphFont[0]=='\0') return;
  683     if (snprintf(wdirname,sizeof(wdirname),"%s/%s.day",tmp,uinfo->filename)>=sizeof(wdirname)) {
  684         debuga(__FILE__,__LINE__,_("User name too long to manufacture file name "));
  685         debuga_more("%s/%s.day\n",tmp,uinfo->filename);
  686         exit(EXIT_FAILURE);
  687     }
  688     if (access(wdirname, R_OK) != 0) {
  689         return;
  690     }
  691 
  692     if ((fp_in=fopen(wdirname,"r"))==NULL) {
  693         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wdirname,strerror(errno));
  694         exit(EXIT_FAILURE);
  695     }
  696 
  697     memset(bytespoints,0,sizeof(bytespoints));
  698     memset(elappoints,0,sizeof(elappoints));
  699     while(fgets(buf,sizeof(buf),fp_in)!=NULL) {
  700         fixendofline(buf);
  701         getword_start(&gwarea,buf);
  702         if (getword_atoll(&llday,&gwarea,'/')<0) {
  703             debuga(__FILE__,__LINE__,_("Invalid date in file \"%s\"\n"),wdirname);
  704             exit(EXIT_FAILURE);
  705         }
  706         day=(int)llday;
  707         if (day<1 || day>31) continue;
  708         if (getword_skip(20,&gwarea,'\t')<0 || getword_skip(20,&gwarea,'\t')<0) {
  709             debuga(__FILE__,__LINE__,_("Invalid entry in file \"%s\"\n"),wdirname);
  710             exit(EXIT_FAILURE);
  711         }
  712         if ((datetimeby & DATETIME_BYTE)!=0) {
  713             if (getword_atoll(&bytes,&gwarea,'\t')<0) {
  714                 debuga(__FILE__,__LINE__,_("Invalid number of bytes in file \"%s\"\n"),wdirname);
  715                 exit(EXIT_FAILURE);
  716             }
  717             bytespoints[day-1]+=bytes;
  718         }
  719         if ((datetimeby & DATETIME_ELAP)!=0) {
  720             if (getword_atoll(&elap,&gwarea,'\0')<0) {
  721                 debuga(__FILE__,__LINE__,_("Invalid elapsed time in file \"%s\"\n"),wdirname);
  722                 exit(EXIT_FAILURE);
  723             }
  724             elappoints[day-1]+=elap;
  725         }
  726     }
  727     if (fclose(fp_in)==EOF) {
  728         debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wdirname,strerror(errno));
  729         exit(EXIT_FAILURE);
  730     }
  731 
  732     if (snprintf(wdirname,sizeof(wdirname),"%s/%s/graph.html",outdirname,uinfo->filename)>=sizeof(wdirname)) {
  733         debuga(__FILE__,__LINE__,_("User name too long to manufacture file name "));
  734         debuga_more("%s/%s/%s\n",outdirname,uinfo->filename,"graph.html");
  735         exit(EXIT_FAILURE);
  736     }
  737     if ((fp_ou=fopen(wdirname,"wt"))==NULL) {
  738         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wdirname,strerror(errno));
  739         exit(EXIT_FAILURE);
  740     }
  741     write_html_head(fp_ou,(IndexTree == INDEX_TREE_DATE) ? 4 : 2,_("Graph report"),HTML_JS_NONE);
  742 
  743     fputs("<table class=\"report\" cellpadding=\"0\" cellspacing=\"2\">\n", fp_ou);
  744     if ((datetimeby & DATETIME_BYTE)!=0) {
  745         memset(&pdata,0,sizeof(pdata));
  746         pdata.datapoints=bytespoints;
  747         pdata.npoints=31;
  748         pdata.XLabel=_("DAYS");
  749         pdata.ymin=50LL*1000LL;
  750         pdata.ymax=5LL*1000LL*1000LL*1000LL;
  751         pdata.ytype=PTG_LogBin;
  752         pdata.YLabel=_("BYTES");
  753         pdata.pngfile="graph_day_byte.png";
  754         greport_plot(uinfo,&pdata);
  755         fprintf(fp_ou,"<tr><td><img src=\"%s\" alt=\"B\"></td></tr>\n",pdata.pngfile);
  756     }
  757     if ((datetimeby & DATETIME_ELAP)!=0) {
  758         memset(&pdata,0,sizeof(pdata));
  759         pdata.datapoints=elappoints;
  760         pdata.npoints=31;
  761         pdata.XLabel=_("DAYS");
  762         pdata.ymin=0;
  763         pdata.ymax=86400000;
  764         pdata.ytype=PTG_Time;
  765         pdata.YLabel=_("ELAPSED TIME");
  766         pdata.pngfile="graph_day_elap.png";
  767         greport_plot(uinfo,&pdata);
  768         fprintf(fp_ou,"<tr><td><img src=\"%s\" alt=\"E\"></td></tr>\n",pdata.pngfile);
  769     }
  770     fputs("</table>\n",fp_ou);
  771 
  772     write_html_trailer(fp_ou);
  773     if (fclose(fp_ou)==EOF) {
  774         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),wdirname,strerror(errno));
  775         exit(EXIT_FAILURE);
  776     }
  777 #endif //HAVE_GD
  778 
  779     return;
  780 }
  781 
  782 void greport_cleanup(void)
  783 {
  784 #ifdef HAVE_GD
  785     gdFontCacheShutdown();
  786 
  787 #ifdef USE_ICONV
  788     if (localtoutf!=(iconv_t)-1)
  789         iconv_close (localtoutf);
  790 #endif
  791 #endif //HAVE_GD
  792 }