1 /***             analog 6.0             http://www.analog.cx/             ***/
2 /*** This program is copyright (c) Stephen R. E. Turner 1995 - 2004 except as
3  *** stated otherwise.
4  ***
5  *** This program is free software. You can redistribute it and/or modify it
6  *** under the terms of version 2 of the GNU General Public License, which you
7  *** should have received with it.
8  ***
9  *** This program is distributed in the hope that it will be useful, but
10  *** without any warranty, expressed or implied.   ***/
11 
12 /*** outxhtml.c; XHTML output ***/
13 
14 #include "anlghea3.h"
15 
16 /* Page width */
xhtml_pagewidth(Outchoices * od)17 unsigned int xhtml_pagewidth(Outchoices *od) {
18   return od->htmlpagewidth;  /* only used to guide the bar chart width */
19 }
20 
21 /* The top of the output if we are in CGI mode */
xhtml_cgihead(FILE * outf,Outchoices * od)22 void xhtml_cgihead(FILE *outf, Outchoices *od) {
23   fprintf(outf, "Content-Type: application/xhtml+xml; charset=%s\n\n",
24 	  od->lngstr[charset_]);
25 }
26 
27 /* Stuff this output style needs in the page header */
xhtml_stylehead(FILE * outf,Outchoices * od)28 void xhtml_stylehead(FILE *outf, Outchoices *od) {
29   fprintf(outf, "<?xml version=\"1.0\" encoding=\"%s\"?>\n",
30 	  od->lngstr[charset_]);
31   if (strcaseeq(od->stylesheet, "none"))
32     fputs("<?xml-stylesheet href=\"#internalStyle\" type=\"text/css\"?>\n",
33 	  outf);
34   else {
35     fputs("<?xml-stylesheet href=\"", outf);
36     xhtmlputs(outf, od, od->stylesheet, IN_HREF);
37     fputs("\" type=\"text/css\"?>\n", outf);
38   }
39   fputs("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n", outf);
40   fputs("\t\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n", outf);
41   fputs("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n", outf);
42   fputs("<head>\n", outf);
43   fprintf(outf, "<title>%s ", od->lngstr[webstatsfor_]);
44   xhtmlputs(outf, od, od->hostname, FROM_CFG);
45   fputs("</title>\n", outf);
46   fprintf(outf, "<meta http-equiv=\"Content-Type\" "
47 	  "content=\"text/html; charset=%s\" />\n", od->lngstr[charset_]);
48   if (od->norobots)
49     fputs("<meta name=\"robots\" content=\"noindex,nofollow\" />\n", outf);
50   fprintf(outf, "<meta name=\"generator\" content=\"analog %s\" />\n",
51 	  VERSION);
52   if (!strcaseeq(od->stylesheet, "none")) {
53     fputs("<link href=\"", outf);
54     xhtmlputs(outf, od, od->stylesheet, IN_HREF);
55     fputs("\" rel=\"stylesheet\" />\n", outf);
56   }
57   else { /* default style sheet inline if no external style sheet specified */
58     fprintf(outf, "<style type=\"text/css\" id=\"internalStyle\">\n");
59     fprintf(outf, "h2 {\n\tbackground-color: #A0C0F0;\n\twidth: 98%%;\n\t"
60 	  "padding: 3px 6px;\n}\n");
61     fprintf(outf, "table {\n\ttext-align: right;\n\tmargin-left: 30px;\n\t"
62 	    "background-color: #D0E0F0;\n\tborder-collapse: collapse;\n}\n");
63     fprintf(outf, "th {\n\tborder-bottom: 1px solid #404050;\n\t"
64 	  "border-right: 1px dotted #606070;\n\tborder-top: none;\n\t"
65 	  "border-left: none;\n\tpadding: 0px 5px 1px 5px;\n\t"
66 	  "font-weight: bold;\n\tbackground-color: #A0C0F0;\n}\n");
67     fprintf(outf, "td {\n\tpadding: 0px 5px 1px 5px;\n\t"
68 	  "border-right: 1px dotted #606070;\n\tborder-left: none;\n\t"
69 	  "border-bottom: none;\n\tborder-top:none;\n}\n");
70     fprintf(outf,
71 	    "td.%sx {\n\tfont-family: monospace;\n\twhite-space: pre;\n}\n",
72 	    od->cssprefix);
73     fprintf(outf, ".%sxl {\n\ttext-align: left;\n\tborder-right: none;\n}\n",
74 	    od->cssprefix);
75     fprintf(outf, ".%sxr {\n\ttext-align: right;\n\tborder-right: none;\n}\n",
76 	    od->cssprefix);
77     fprintf(outf, ".%sbar {\n\ttext-align: left;\n\tborder-right: none;\n}\n",
78 	    od->cssprefix);
79     fprintf(outf,
80 	    "tr.%ssub {background-color: #C0C0FF;\n\tfont-style: italic;\n}\n",
81 	    od->cssprefix);
82     fprintf(outf, ".%srepdesc {\n\tfont-style: italic;\n}\n", od->cssprefix);
83     fprintf(outf, ".%srepspan {\n\tfont-style: italic;\n}\n", od->cssprefix);
84     fprintf(outf, ".%sgoto {\n\tfont-size: small;\n}\n", od->cssprefix);
85     fprintf(outf, ".%sgensumtitle {\n\tfont-weight: bold;\n}\n",
86 	    od->cssprefix);
87     fprintf(outf, ".%sgototitle {\n\tfont-weight: bold;\n}\n", od->cssprefix);
88     fprintf(outf, ".%sruntimetitle {\n\tfont-weight: bold;\n}\n",
89 	    od->cssprefix);
90     fprintf(outf, "img {\n\tborder-style: none;\n}\n");
91     fprintf(outf, "a:link {\n\tcolor: blue;\n\ttext-decoration: none;\n}\n");
92     fprintf(outf,
93 	    "a:visited {\n\tcolor: purple;\n\ttext-decoration: none;\n}\n");
94     fprintf(outf, "a:link:hover {\n\ttext-decoration: underline;\n}\n");
95     fprintf(outf, "a:visited:hover {\n\ttext-decoration: underline;\n}\n");
96     fprintf(outf, "a:link:active {\n\tcolor: red;\n\t"
97 	    "text-decoration: underline;\n}\n");
98     fprintf(outf, "a:visited:active {\n\tcolor: red;\n\t"
99 	  "text-decoration: underline;\n}\n");
100     fprintf(outf, "</style>\n");
101   }  /* end of style sheet */
102   fputs("</head>\n", outf);
103   fputs("<body>\n", outf);
104 }
105 
106 /* The title of the page, plus the user's HEADERFILE */
xhtml_pagetitle(FILE * outf,Outchoices * od)107 void xhtml_pagetitle(FILE *outf, Outchoices *od) {
108   fprintf(outf, "<div class=\"%sheader\">", od->cssprefix);
109   fputs("<h1><a name=\"Top\" id=\"Top\"", outf);
110   if (!strcaseeq(od->logourl, "none")) {
111     fputs(" href=\"", outf);
112     xhtmlputs(outf, od, od->logourl, IN_HREF);
113     fputs("\"", outf);
114   }
115   fputs(">", outf);
116 
117   if (!strcaseeq(od->logo, "none")) {
118     fputs("<img src=\"", outf);
119     if (od->logo[0] != '/' && strstr(od->logo, "://") == NULL)
120       xhtmlputs(outf, od, od->imagedir, IN_HREF);
121     xhtmlputs(outf, od, od->logo, IN_HREF);
122     if (STREQ(od->logo, "analogo"))
123       fprintf(outf, ".%s", od->pngimages?"png":"gif");
124     /* Above: '.' not EXTSEP even on RISC OS */
125     fputs("\" alt=\"\" /></a> ", outf);  /* close <a> here if logo */
126   }
127   if (strcaseeq(od->hosturl, "none")) {
128     fprintf(outf, "%s ", od->lngstr[webstatsfor_]);
129     xhtmlputs(outf, od, od->hostname, FROM_CFG);
130     if (strcaseeq(od->logo, "none"))
131       fputs("</a>", outf);  /* close <a> here if no logo */
132   }
133   else {
134     fputs(od->lngstr[webstatsfor_], outf);
135     if (strcaseeq(od->logo, "none"))
136       fputs("</a>", outf);  /* close <a> here if no logo */
137     fputs(" <a href=\"", outf);
138     xhtmlputs(outf, od, od->hosturl, IN_HREF);
139     fputs("\">", outf);
140     xhtmlputs(outf, od, od->hostname, FROM_CFG);
141     fputs("</a>", outf);
142   }
143   fputs("</h1>\n\n", outf);
144 
145   if (!strcaseeq(od->headerfile, "none"))
146     xhtml_includefile(outf, od, od->headerfile, 'h');
147 }
148 
149 /* Program start time, and logfile start and end times */
xhtml_timings(FILE * outf,Outchoices * od,Dateman * dman)150 void xhtml_timings(FILE *outf, Outchoices *od, Dateman *dman) {
151   extern timecode_t starttimec;
152 
153   char **lngstr = od->lngstr;
154 
155   double t0;
156   int t1, t2;
157 
158   if (!od->runtime && dman->firsttime > dman->lasttime)
159     return; /* Nothing to show, avoid printing <p></p> */
160 
161   fprintf(outf, "<p class=\"%sanalysisspan\">", od->cssprefix);
162   if (od->runtime)
163     fprintf(outf, "%s %s.", lngstr[progstart_],
164 	    timesprintf(od, lngstr[datefmt2_], starttimec, UNSET));
165 
166   if (dman->firsttime <= dman->lasttime) {
167     if (od->runtime)
168       fputs("\n<br />", outf);
169     fprintf(outf, "%s %s ", lngstr[reqstart_],
170 	    timesprintf(od, lngstr[datefmt2_], dman->firsttime, UNSET));
171     fprintf(outf, "%s %s", lngstr[to_],
172 	    timesprintf(od, lngstr[datefmt2_], dman->lasttime, UNSET));
173     t0 = (dman->lasttime - dman->firsttime) / 1440.0 + 0.005;
174     t1 = (int)t0;
175     t2 = (int)(100 * (t0 - (double)t1));
176     fprintf(outf, " (%d", t1);
177     xhtml_putch(outf, od->decpt);
178     fprintf(outf, "%02d %s).</p>\n", t2, lngstr[days_]);
179   }
180   else
181     fputs("</p>\n", outf);
182 }
183 
184 /* Finishing the top of the page */
xhtml_closehead(FILE * outf,Outchoices * od)185 void xhtml_closehead(FILE *outf, Outchoices *od) {
186   fputs("</div>\n", outf);
187   if (od->gotos == FEW)
188     xhtml_gotos(outf, od, -1);
189 }
190 
191 /* Starting the bottom of the page */
xhtml_pagebotstart(FILE * outf,Outchoices * od)192 void xhtml_pagebotstart(FILE *outf, Outchoices *od) {
193   fprintf(outf, "<div class=\"%sfooter\">", od->cssprefix);
194 }
195 
196 /* The credit line at the bottom of the page */
xhtml_credit(FILE * outf,Outchoices * od)197 void xhtml_credit(FILE *outf, Outchoices *od) {
198   fprintf(outf, "<p class=\"%scredit\">%s <a href=\"%s\">analog %s</a>.\n",
199 	  od->cssprefix, od->lngstr[credit_], ANALOGURL, VNUMBER);
200 }
201 
202 /* The program run time */
xhtml_runtime(FILE * outf,Outchoices * od,long secs)203 void xhtml_runtime(FILE *outf, Outchoices *od, long secs) {
204   char **lngstr = od->lngstr;
205 
206   fprintf(outf, "<br /><span class=\"%sruntimetitle\">%s:</span> ",
207 	  od->cssprefix, lngstr[runtime_]);
208 
209   if (secs == 0)
210     fprintf(outf, "%s %s.\n", lngstr[lessone_], lngstr[second_]);
211   else if (secs < 60)
212     fprintf(outf, "%ld %s.\n", secs,
213 	    (secs == 1)?lngstr[second_]:lngstr[seconds_]);
214   else
215     fprintf(outf, "%ld %s, %ld %s.\n", secs / 60,
216 	    (secs < 120)?lngstr[minute_]:lngstr[minutes_], secs % 60,
217 	    (secs % 60 == 1)?lngstr[second_]:lngstr[seconds_]);
218 }
219 
220 /* The page footer, including the user's FOOTERFILE */
xhtml_pagefoot(FILE * outf,Outchoices * od)221 void xhtml_pagefoot(FILE *outf, Outchoices *od) {
222   fputs("</p>\n", outf);
223   if (od->gotos != FALSE)
224     xhtml_gotos(outf, od, -1);
225   fputs("</div>\n", outf);
226 
227   if (!strcaseeq(od->footerfile, "none"))
228     xhtml_includefile(outf, od, od->footerfile, 'f');
229 }
230 
231 /* Footer material for this output style */
xhtml_stylefoot(FILE * outf,Outchoices * od)232 void xhtml_stylefoot(FILE *outf, Outchoices *od) {
233   fputs("</body>\n</html>\n", outf);
234 }
235 
236 /* Report title */
xhtml_reporttitle(FILE * outf,Outchoices * od,choice rep)237 void xhtml_reporttitle(FILE *outf, Outchoices *od, choice rep) {
238   extern char *anchorname[];
239   extern unsigned int *rep2lng;
240 
241   fprintf(outf, "<div class=\"%s%s\">", od->cssprefix, anchorname[rep]);
242   fprintf(outf, "<h2><a name=\"%s\" id=\"%s\">%s</a></h2>\n", anchorname[rep],
243 	  anchorname[rep], od->lngstr[rep2lng[rep]]);
244   if (od->gotos == TRUE)
245     xhtml_gotos(outf, od, rep);
246 }
247 
248 /* Report footer */
xhtml_reportfooter(FILE * outf,Outchoices * od,choice rep)249 void xhtml_reportfooter(FILE *outf, Outchoices *od, choice rep) {
250   fputs("</div>", outf);
251 }
252 
253 /* Report description */
xhtml_reportdesc(FILE * outf,Outchoices * od,choice rep)254 void xhtml_reportdesc(FILE *outf, Outchoices *od, choice rep) {
255   fprintf(outf, "<p class=\"%srepdesc\">%s</p>\n", od->cssprefix,
256 	  od->descstr[rep]);
257 }
258 
259 /* The time period spanned by the report */
xhtml_reportspan(FILE * outf,Outchoices * od,choice rep,timecode_t maxd,timecode_t mind)260 void xhtml_reportspan(FILE *outf, Outchoices *od, choice rep, timecode_t maxd,
261 		     timecode_t mind) {
262   /* NB Can't combine next two lines because timesprintf uses static buffer. */
263   fprintf(outf, "<p class=\"%srepspan\">%s %s ", od->cssprefix,
264 	  od->lngstr[repspan_],
265 	  timesprintf(od, od->lngstr[datefmt2_], mind, UNSET));
266   fprintf(outf, "%s %s.</p>\n", od->lngstr[to_],
267 	  timesprintf(od, od->lngstr[datefmt2_], maxd, UNSET));
268 }
269 
270 /* General Summary header */
xhtml_gensumhead(FILE * outf,Outchoices * od)271 void xhtml_gensumhead(FILE *outf, Outchoices *od) {
272 }
273 
274 /* General Summary footer */
xhtml_gensumfoot(FILE * outf,Outchoices * od)275 void xhtml_gensumfoot(FILE *outf, Outchoices *od) {
276   fputs("</p>\n", outf);
277 }
278 
279 /* Single General Summary line, long data */
xhtml_gensumline(FILE * outf,Outchoices * od,int namecode,unsigned long x,unsigned long x7,logical isaverage)280 void xhtml_gensumline(FILE *outf, Outchoices *od, int namecode,
281 		      unsigned long x, unsigned long x7, logical isaverage) {
282 
283   /* If this is the first Gen Sum line, open the paragraph.
284      (succreqs_ is always printed, and is always first). */
285   if (namecode == succreqs_)
286     fprintf(outf, "<p class=\"%sgensumlines\">\n", od->cssprefix);
287   /* If it isn't, then put a line break. */
288   else
289     fputs("<br />", outf);
290   fprintf(outf, "<span class=\"%sgensumtitle\">%s%s</span> ", od->cssprefix,
291 	  od->lngstr[namecode], od->lngstr[colon_]);
292 
293   f3printf(outf, od, (double)x, 0, od->sepchar);
294 
295   if (x7 != (unsigned long)UNSET) {
296     fputs(" (", outf);
297     f3printf(outf, od, (double)x7, 0, od->sepchar);
298     putc(')', outf);
299   }
300   putc('\n', outf);
301 }
302 
303 /* Single General Summary line, bytes data */
xhtml_gensumlineb(FILE * outf,Outchoices * od,int namecode,double x,double x7,logical isaverage)304 void xhtml_gensumlineb(FILE *outf, Outchoices *od, int namecode, double x,
305 		      double x7, logical isaverage) {
306   char **lngstr = od->lngstr;
307 
308   unsigned int bm;
309   char *c;
310 
311   fprintf(outf, "<br /><span class=\"%sgensumtitle\">%s%s</span> ",
312 	  od->cssprefix, lngstr[namecode], lngstr[colon_]);
313 
314   bm = (od->rawbytes)?0:findbmult(x, od->bytesdp);
315   printbytes(outf, od, x, bm, 0, od->sepchar);
316 
317   if (bm > 0) {
318     c = strchr(lngstr[xbytes_], '?');
319     *c = '\0';
320     fprintf(outf, " %s%s%s", lngstr[xbytes_], lngstr[byteprefix_ + bm], c + 1);
321     *c = '?';
322   }
323   else
324     fprintf(outf, " %s", lngstr[bytes_]);
325 
326   if (x7 != UNSET) {
327     fputs(" (", outf);
328     bm = (od->rawbytes)?0:findbmult(x7, od->bytesdp);
329     printbytes(outf, od, x7, bm, 0, od->sepchar);
330     if (bm > 0) {
331       c = strchr(lngstr[xbytes_], '?');
332       *c = '\0';
333       fprintf(outf, " %s%s%s)", lngstr[xbytes_], lngstr[byteprefix_ + bm],
334 	      c + 1);
335       *c = '?';
336     }
337     else
338       fprintf(outf, " %s)", lngstr[bytes_]);
339   }
340 
341   putc('\n', outf);
342 }
343 
344 /* "Last seven" explanation line */
xhtml_lastseven(FILE * outf,Outchoices * od,timecode_t last7to)345 void xhtml_lastseven(FILE *outf, Outchoices *od, timecode_t last7to) {
346   fprintf(outf, "<p class=\"%slastseven\">", od->cssprefix);
347   fprintf(outf, "%s %s %s.</p>\n", od->lngstr[brackets_],
348 	  od->lngstr[sevendaysto_],
349 	  timesprintf(od, od->lngstr[datefmt1_], last7to, UNSET));
350 }
351 
352 /* Start of a <pre> section */
xhtml_prestart(FILE * outf,Outchoices * od)353 void xhtml_prestart(FILE *outf, Outchoices *od) {
354   fputs("<table>\n", outf);
355 }
356 
357 /* End of a <pre> section */
xhtml_preend(FILE * outf,Outchoices * od)358 void xhtml_preend(FILE *outf, Outchoices *od) {
359   fputs("</tbody></table>\n", outf);
360 }
361 
362 /* A horizontal rule */
xhtml_hrule(FILE * outf,Outchoices * od)363 void xhtml_hrule(FILE *outf, Outchoices *od) {
364 }
365 
366 /* An en dash */
xhtml_endash(void)367 char *xhtml_endash(void) {
368   return "&ndash;";
369 }
370 
371 /* putc with special characters escaped */
xhtml_putch(FILE * outf,char c)372 void xhtml_putch(FILE *outf, char c) {
373   if (c == '<')
374     fputs("&lt;", outf);
375   else if (c == '>')
376     fputs("&gt;", outf);
377   else if (c == '&')
378     fputs("&amp;", outf);
379   else if (c == '"')
380     fputs("&quot;", outf);
381   else
382     putc(c, outf);
383 }
384 
385 /* strlen for XHTML strings. Assume string contains no &'s except as markup.
386    May be switched to html_strlength_utf8 or html_strlength_jis in outhtml.c,
387    depending on the output character set. */
xhtml_strlength(const char * s)388 size_t xhtml_strlength(const char *s) {
389   const char *t;
390   logical f;
391   size_t i;
392 
393   for (t = s, f = TRUE, i = 0; *t != '\0'; t++) {
394     if (*t == '&')
395       f = FALSE;
396     else if (*t == ';')
397       f = TRUE;
398     if (f)
399       i++;
400   }
401   return(f?i:strlen(s));
402   /* If !f, something went wrong (eg multibyte). Maybe the & wasn't markup. */
403 }
404 
405 /* Allow month in dates? DO NOT enable for human-readable text because of
406    i18n problems. */
xhtml_allowmonth(void)407 logical xhtml_allowmonth(void) {
408   return FALSE;
409 }
410 
411 /* Calculate column widths */
xhtml_calcwidths(Outchoices * od,choice rep,unsigned int width[],unsigned int * bmult,unsigned int * bmult7,double * unit,unsigned long maxr,unsigned long maxr7,unsigned long maxp,unsigned long maxp7,double maxb,double maxb7,unsigned long howmany)412 void xhtml_calcwidths(Outchoices *od, choice rep, unsigned int width[],
413 		      unsigned int *bmult, unsigned int *bmult7, double *unit,
414 		      unsigned long maxr, unsigned long maxr7,
415 		      unsigned long maxp, unsigned long maxp7, double maxb,
416 		      double maxb7, unsigned long howmany) {
417   /* widths don't really have much meaning, but they will still be used for the
418      bar charts, and it's easier just to call the existing function. */
419   calcwidths(od, rep, width, bmult, bmult7, unit, maxr, maxr7, maxp, maxp7,
420 	     maxb, maxb7, howmany);
421 }
422 
423 /* "Each unit represents" line */
xhtml_declareunit(FILE * outf,Outchoices * od,char graphby,double unit,unsigned int bmult)424 void xhtml_declareunit(FILE *outf, Outchoices *od, char graphby, double unit,
425 		       unsigned int bmult) {
426   char **lngstr = od->lngstr;
427 
428   char *s;
429 
430   fprintf(outf, "<p class=\"%seachunit\">", od->cssprefix);
431   fprintf(outf, "%s (", lngstr[eachunit_]);
432   if (ISLOWER(graphby))
433     fprintf(outf, "%c", od->markchar);
434   else {
435     fprintf(outf, "<img src=\"");
436     xhtmlputs(outf, od, od->imagedir, IN_HREF);
437     fprintf(outf, "bar%c1.%s\" alt=\"%c\" />", od->barstyle,
438 	    od->pngimages?"png":"gif", od->markchar);
439     /* Above: '.' not EXTSEP even on RISC OS */
440   }
441   fprintf(outf, ") %s ", lngstr[represents_]);
442 
443   if (graphby == 'R' || graphby == 'r') {
444     f3printf(outf, od, unit, 0, od->sepchar);
445     if (unit == 1.)
446       fprintf(outf, " %s.", lngstr[request_]);
447     else
448       fprintf(outf, " %s %s.", lngstr[requests_], lngstr[partof_]);
449   }
450   else if (graphby == 'P' || graphby == 'p') {
451     f3printf(outf, od, unit, 0, od->sepchar);
452     if (unit == 1.)
453       fprintf(outf, " %s.", lngstr[pagereq_]);
454     else
455       fprintf(outf, " %s %s.", lngstr[pagereqs_], lngstr[partof_]);
456   }
457   else {
458     if (bmult > 0) {
459       xhtml_printdouble(outf, od, unit);
460       s = strchr(lngstr[xbytes_], '?');  /* checked in initialisation */
461       *s = '\0';
462       fprintf(outf, " %s%s%s %s.", lngstr[xbytes_],
463 	      lngstr[byteprefix_ + bmult], s + 1, lngstr[partof_]);
464       *s = '?';
465     }
466     else {
467       f3printf(outf, od, unit, 0, od->sepchar);
468       fprintf(outf, " %s %s.", lngstr[bytes_], lngstr[partof_]);
469     }
470   }
471   fputs("</p>\n", outf);
472 }
473 
474 /* Start of column header line */
xhtml_colheadstart(FILE * outf,Outchoices * od,choice rep)475 void xhtml_colheadstart(FILE *outf, Outchoices *od, choice rep) {
476   fputs("<thead><tr>", outf);
477 }
478 
479 /* Column header line: individual column */
xhtml_colheadcol(FILE * outf,Outchoices * od,choice rep,choice col,unsigned int width,char * colname,logical unterminated)480 void xhtml_colheadcol(FILE *outf, Outchoices *od, choice rep, choice col,
481 		     unsigned int width, char *colname, logical unterminated) {
482   extern char colcodes[];
483 
484   char code[3];
485 
486   code[0] = colcodes[col];
487   if (unterminated) {
488     code[1] = 'l';  /* i.e. "xl" */
489     code[2] = '\0';
490   }
491   else
492     code[1] = '\0';
493 
494   fprintf(outf, "<th class=\"%s%s\">%s</th>", od->cssprefix, code, colname);
495 }
496 
497 /* End of column header line */
xhtml_colheadend(FILE * outf,Outchoices * od,choice rep)498 void xhtml_colheadend(FILE *outf, Outchoices *od, choice rep) {
499 
500   if (rep < DATEREP_NUMBER)  /* time report: extra col for bar chart */
501     fprintf(outf, "<th class=\"%sbar\">&nbsp;</th>", od->cssprefix);
502 
503   fputs("</tr></thead>\n", outf);
504 }
505 
506 /* Start of column header underlining line */
xhtml_colheadustart(FILE * outf,Outchoices * od,choice rep)507 void xhtml_colheadustart(FILE *outf, Outchoices *od, choice rep) {
508 }
509 
510 /* Underlining of one column header. */
xhtml_colheadunderline(FILE * outf,Outchoices * od,choice rep,choice col,unsigned int width,char * name)511 void xhtml_colheadunderline(FILE *outf, Outchoices *od, choice rep, choice col,
512 			   unsigned int width, char *name) {
513 }
514 
515 /* End of column header underlining line */
xhtml_colheaduend(FILE * outf,Outchoices * od,choice rep)516 void xhtml_colheaduend(FILE *outf, Outchoices *od, choice rep) {
517   fputs("<tbody>", outf);
518 }
519 
520 /* Start of a table row */
xhtml_rowstart(FILE * outf,Outchoices * od,choice rep,choice * cols,int level,char * name,char * datefmt,char * timefmt)521 void xhtml_rowstart(FILE *outf, Outchoices *od, choice rep, choice *cols,
522 		   int level, char *name, char *datefmt, char *timefmt) {
523   if (level >= 2)
524     fprintf(outf, "<tr class=\"%ssub %slevel%d\">",
525 	    od->cssprefix, od->cssprefix, level);
526   else
527     fprintf(outf, "<tr>");
528 }
529 
530 /* Print level in hierarchy represented by this row */
xhtml_levelcell(FILE * outf,Outchoices * od,choice rep,int level)531 void xhtml_levelcell(FILE *outf, Outchoices *od, choice rep, int level) {
532 }
533 
534 /* Name column */
xhtml_namecell(FILE * outf,Outchoices * od,choice rep,char * name,choice source,unsigned int width,logical name1st,logical isfirst,logical rightalign,Alias * aliashead,Include * linkhead,logical ispage,unsigned int spaces,char * baseurl)535 void xhtml_namecell(FILE *outf, Outchoices *od, choice rep, char *name,
536 		    choice source, unsigned int width, logical name1st,
537 		    logical isfirst, logical rightalign, Alias *aliashead,
538 		    Include *linkhead, logical ispage, unsigned int spaces,
539 		    char *baseurl) {
540   extern char *workspace;
541 
542   choice savemultibyte;
543   logical linked;
544   int i;
545 
546   if (name1st != isfirst)
547     return;
548 
549   savemultibyte = od->multibyte;
550   if (rep == REP_SIZE || rep == REP_PROCTIME)
551     /* Kludge: for these two reports, we know the texts are things like
552        "< 1" and we want to convert > and < */
553     od->multibyte = FALSE;
554 
555   if (isfirst)
556     fprintf(outf, "<td class=\"%sx\">", od->cssprefix);
557   else if (rightalign)
558     fprintf(outf, "<td class=\"%sxr\">", od->cssprefix);
559   else
560     fprintf(outf, "<td class=\"%sxl\">", od->cssprefix);
561 
562   strcpy(workspace, name);
563   do_aliasx(workspace, aliashead);
564 
565   if (!isfirst && !rightalign) {
566     for (i = 0; i < spaces; i++)
567       fputs("&nbsp;", outf);
568   }
569 
570   linked = (linkhead != NULL && included(name, ispage, linkhead));
571   if (linked) {
572     /* We link to the unaliased name, because the OUTPUTALIAS is usually in
573        the nature of an annotation. */
574     fputs("<a href=\"", outf);
575     if (baseurl != NULL)
576       xhtmlputs(outf, od, baseurl, IN_HREF);
577     xhtml_escfprintf(outf, name);
578     fputs("\">", outf);
579   }
580 
581   xhtmlputs(outf, od, workspace, source);
582 
583   if (linked)
584     fputs("</a>", outf);
585 
586   if (!isfirst && rightalign) {
587     for (i = 0; i < spaces; i++)
588       fputs("&nbsp;", outf);
589   }
590 
591   fputs("</td>", outf);
592 
593   od->multibyte = savemultibyte;  /* restore multibyte */
594 }
595 
596 /* Single cell, unsigned long argument */
xhtml_ulcell(FILE * outf,Outchoices * od,choice rep,choice col,unsigned long x,unsigned int width)597 void xhtml_ulcell(FILE *outf, Outchoices *od, choice rep, choice col,
598 		  unsigned long x, unsigned int width) {
599   extern char colcodes[];
600 
601   fprintf(outf, "<td class=\"%s%c\">", od->cssprefix, colcodes[col]);
602   f3printf(outf, od, (double)x, 0, od->repsepchar);
603   fprintf(outf, "</td>");
604 }
605 
606 /* Single cell, TRUSTED string argument */
xhtml_strcell(FILE * outf,Outchoices * od,choice rep,choice col,char * s,unsigned int width)607 void xhtml_strcell(FILE *outf, Outchoices *od, choice rep, choice col,
608 		   char *s, unsigned int width) {
609   extern char colcodes[];
610 
611   fprintf(outf, "<td class=\"%s%c\">", od->cssprefix, colcodes[col]);
612   xhtmlputs(outf, od, s, TRUSTED);
613   fprintf(outf, "</td>");
614 }
615 
616 /* Single cell, listing bytes */
xhtml_bytescell(FILE * outf,Outchoices * od,choice rep,choice col,double b,double bmult,unsigned int width)617 void xhtml_bytescell(FILE *outf, Outchoices *od, choice rep, choice col,
618 		     double b, double bmult, unsigned int width) {
619   extern char colcodes[];
620 
621   fprintf(outf, "<td class=\"%s%c\">", od->cssprefix, colcodes[col]);
622   printbytes(outf, od, b, bmult, 0, od->repsepchar);
623   fprintf(outf, "</td>");
624 }
625 
626 /* Single cell, listing percentage */
xhtml_pccell(FILE * outf,Outchoices * od,choice rep,choice col,double n,double tot,unsigned int width)627 void xhtml_pccell(FILE *outf, Outchoices *od, choice rep, choice col, double n,
628 		  double tot, unsigned int width) {
629   double pc;
630   unsigned int pc1, pc2;
631 
632   extern char colcodes[];
633 
634   fprintf(outf, "<td class=\"%s%c\">", od->cssprefix, colcodes[col]);
635   if (tot == 0)
636     pc = 0.0;
637   else
638     pc = n * 10000.0 / tot;
639   if (pc >= 9999.5)
640     fputs("100%", outf);
641   else if (pc < 0.5)
642     fputs("&nbsp;", outf);
643   else {
644     pc1 = ((int)(pc + 0.5)) / 100;
645     pc2 = ((int)(pc + 0.5)) % 100;
646     fprintf(outf, "%2d", pc1);
647     xhtml_putch(outf, od->decpt);
648     fprintf(outf, "%02d%%", pc2);
649   }
650   fputs("</td>", outf);
651 }
652 
653 /* Single cell, index */
xhtml_indexcell(FILE * outf,Outchoices * od,choice rep,choice col,long index,unsigned int width)654 void xhtml_indexcell(FILE *outf, Outchoices *od, choice rep, choice col,
655 		     long index, unsigned int width) {
656   extern char colcodes[];
657 
658   fprintf(outf, "<td class=\"%s%c\">", od->cssprefix, colcodes[col]);
659 
660   /* If index is 0 (i.e. sub-item), just print space */
661   if (index <= 0)
662     fputs("&nbsp;", outf);
663   else
664     f3printf(outf, od, (double)index, 0, od->repsepchar);
665   fputs("</td>", outf);
666 }
667 
668 /* End of a table row */
xhtml_rowend(FILE * outf,Outchoices * od,choice rep)669 void xhtml_rowend(FILE *outf, Outchoices *od, choice rep) {
670   fputs("</tr>\n", outf);
671 }
672 
673 /* Blank line in time reports */
xhtml_blankline(FILE * outf,Outchoices * od,choice * cols)674 void xhtml_blankline(FILE *outf, Outchoices *od, choice *cols) {
675   extern char colcodes[];
676   unsigned int c;
677 
678   fputs("<tr>", outf);
679   fprintf(outf, "<td class=\"%sx\">&nbsp;</td>", od->cssprefix);
680   for (c = 0; cols[c] != COL_NUMBER; c++)
681     fprintf(outf, "<td class=\"%s%c\">&nbsp;</td>", od->cssprefix,
682 	    colcodes[cols[c]]);
683   fprintf(outf, "<td class=\"%sbar\">&nbsp;</td>", od->cssprefix);
684   fputs("</tr>\n", outf);
685 }
686 
687 /* Barchart in time reports */
xhtml_barchart(FILE * outf,Outchoices * od,int y,char graphby)688 void xhtml_barchart(FILE *outf, Outchoices *od, int y, char graphby) {
689   int i, j;
690   logical first = TRUE;
691 
692   fprintf(outf, "<td class=\"%sbar\">", od->cssprefix);
693 
694   if (ISLOWER(graphby)) {
695     for (i = 0; i < y; i++)
696       xhtml_putch(outf, od->markchar);
697   }
698   else {
699     for (j = 32; j >= 1; j /= 2) {
700       while (y >= j) {
701 	fputs("<img src=\"", outf);
702 	xhtmlputs(outf, od, od->imagedir, IN_HREF);
703 	fprintf(outf, "bar%c%d.%s\" alt=\"", od->barstyle, j,
704 		od->pngimages?"png":"gif");/* '.' not EXTSEP even on RISC OS */
705 	if (first) {
706 	  for (i = 0; i < y; i++)
707 	    xhtml_putch(outf, od->markchar);
708 	  first = FALSE;
709 	}
710 	fputs("\" />", outf);
711 	y -= j;
712       }
713     }
714   }
715 
716   fputs("</td>", outf);
717 }
718 
719 /* "Busiest time period" line */
xhtml_busyprintf(FILE * outf,Outchoices * od,choice rep,char * datefmt,unsigned long reqs,unsigned long pages,double bys,datecode_t date,unsigned int hr,unsigned int min,datecode_t newdate,unsigned int newhr,unsigned int newmin,char graphby)720 void xhtml_busyprintf(FILE *outf, Outchoices *od, choice rep, char *datefmt,
721 		     unsigned long reqs, unsigned long pages, double bys,
722 		     datecode_t date, unsigned int hr, unsigned int min,
723 		     datecode_t newdate, unsigned int newhr,
724 		     unsigned int newmin, char graphby) {
725   extern unsigned int *rep2busystr;
726 
727   char **lngstr = od->lngstr;
728   char sepchar = od->sepchar;
729 
730   unsigned int bmult;
731   char *s;
732 
733   fprintf(outf, "<p class=\"%sbusiesttime\">%s %s (", od->cssprefix,
734 	  lngstr[rep2busystr[rep]],
735 	  datesprintf(od, datefmt, date, hr, min, newdate, newhr, newmin,
736 		      TRUE, UNSET));
737   if (TOLOWER(graphby) == 'r') {
738     f3printf(outf, od, (double)reqs, 0, sepchar);
739     fprintf(outf, " %s", (reqs == 1)?lngstr[request_]:lngstr[requests_]);
740   }
741   else if (TOLOWER(graphby) == 'p') {
742     f3printf(outf, od, (double)pages, 0, sepchar);
743     fprintf(outf, " %s",
744 	    (pages == 1)?lngstr[pagereq_]:lngstr[pagereqs_]);
745   }
746   else /* TOLOWER(graphby) == 'b' */ {
747     if (od->rawbytes)
748       bmult = 0;
749     else
750       bmult = findbmult(bys, od->bytesdp);
751     printbytes(outf, od, bys, bmult, 0, sepchar);
752     putc(' ', outf);
753     if (bmult >= 1) {
754       s = strchr(lngstr[xbytes_], '?');  /* checked in initialisation */
755       *s = '\0';
756       fprintf(outf, "%s%s%s", lngstr[xbytes_],
757 	      lngstr[byteprefix_ + bmult], s + 1);
758       *s = '?';
759     }
760     else
761       fprintf(outf, "%s", lngstr[bytes_]);
762   }
763   fputs(").</p>\n", outf);
764 }
765 
766 /* End of "Not listed" line. */
xhtml_notlistedstr(FILE * outf,Outchoices * od,choice rep,unsigned long badn)767 void xhtml_notlistedstr(FILE *outf, Outchoices *od, choice rep,
768 			unsigned long badn) {
769   extern unsigned int *rep2lng, *rep2colhead;
770 
771   char **lngstr = od->lngstr;
772   char *colhead = lngstr[rep2colhead[rep]];
773   char *colheadp = lngstr[rep2colhead[rep] + 1];
774   char gender = lngstr[rep2lng[rep] + 3][0];
775 
776   char *notlistedstr;
777 
778   if (gender == 'm')
779     notlistedstr = lngstr[notlistedm_];
780   else if (gender == 'f')
781     notlistedstr = lngstr[notlistedf_];
782   else
783     notlistedstr = lngstr[notlistedn_];
784 
785   fprintf(outf, "<td class=\"%sxl\">[%s: ", od->cssprefix, notlistedstr);
786   f3printf(outf, od, (double)badn, 0, od->sepchar);
787   fprintf(outf, " %s]</td>", (badn == 1)?colhead:colheadp);
788 }
789 
790 /* The line declaring the floor and sort for a report */
xhtml_whatincluded(FILE * outf,Outchoices * od,choice rep,unsigned long n,Dateman * dman)791 void xhtml_whatincluded(FILE *outf, Outchoices *od, choice rep,
792 			unsigned long n, Dateman *dman) {
793   whatincluded(outf, od, rep, n, dman);
794 }
795 
796 /* Spacing at the start of the whatincluded line */
xhtml_whatinchead(FILE * outf,Outchoices * od)797 void xhtml_whatinchead(FILE *outf, Outchoices *od) {
798   fprintf(outf, "<p class=\"%swhatinc\">\n", od->cssprefix);
799 }
800 
801 /* Finishing the whatincluded line */
xhtml_whatincfoot(FILE * outf,Outchoices * od)802 void xhtml_whatincfoot(FILE *outf, Outchoices *od) {
803   fputs("</p>\n", outf);
804 }
805 
806 /* Printing part of the whatincluded line */
xhtml_whatincprintstr(FILE * outf,Outchoices * od,char * s)807 void xhtml_whatincprintstr(FILE *outf, Outchoices *od, char *s) {
808   xhtmlputs(outf, od, s, TRUSTED);
809 }
810 
811 /* Print a double to a nice number of decimal places */
xhtml_printdouble(FILE * outf,Outchoices * od,double x)812 void xhtml_printdouble(FILE *outf, Outchoices *od, double x) {
813   unsigned int prec;
814   double d;
815 
816   /* first calculate how many decimal places we need */
817 
818   for (prec = 0, d = x - (double)((int)(x));
819        d - (double)((int)(d + 0.000005)) > 0.00001; d *= 10)
820     prec++;
821 
822   /* now print it */
823 
824   if (prec > 0) {
825     fprintf(outf, "%d", (int)x);
826     xhtml_putch(outf, od->decpt);
827     fprintf(outf, "%0*d", prec, (int)(d + EPSILON));
828   }
829   else
830     fprintf(outf, "%d", (int)(x + EPSILON));
831 }
832 
833 /* Include a header file or footer file */
xhtml_includefile(FILE * outf,Outchoices * od,char * name,char type)834 void xhtml_includefile(FILE *outf, Outchoices *od, char *name, char type) {
835   FILE *inf;
836   char buffer[BLOCKSIZE];
837   size_t n;
838 
839   if ((inf = my_fopen(name, (type == 'h')?"header file":"footer file")) !=
840       NULL) {
841     while ((n = fread(buffer, 1, BLOCKSIZE, inf)))  /* single equals */
842       fwrite((void *)buffer, 1, n, outf);
843     (void)my_fclose(inf, name, (type == 'h')?"header file":"footer file");
844   }
845 }
846 
847 /* Filetype for RISC OS */
xhtml_riscosfiletype(void)848 unsigned int xhtml_riscosfiletype(void) {
849   return 0xfaf;
850 }
851 
852 /* ======================================================================= */
853 /* Supporting functions for XHTML */
854 
855 /* Print "goto"s. Assume we've checked that we want gotos here. */
xhtml_gotos(FILE * outf,Outchoices * od,choice rep)856 void xhtml_gotos(FILE *outf, Outchoices *od, choice rep) {
857   extern unsigned int *rep2lng;
858   extern char *anchorname[];
859 
860   choice *reporder = od->reporder;
861   char **lngstr = od->lngstr;
862   int i;
863 
864   fprintf(outf, "<p class=\"%sgoto\">(<span class=\"%sgototitle\">%s</span>",
865 	  od->cssprefix, od->cssprefix, lngstr[goto_]);
866   fprintf(outf, "%s <a href=\"#Top\">%s</a>", lngstr[colon_], lngstr[top_]);
867   for (i = 0; reporder[i] != -1; i++) {
868     if (reporder[i] == rep)
869       fprintf(outf, " | %s", lngstr[rep2lng[reporder[i]]]);
870     else if (od->repq[reporder[i]])
871       fprintf(outf, " | <a href=\"#%s\">%s</a>", anchorname[reporder[i]],
872 	      lngstr[rep2lng[reporder[i]]]);
873   }
874   fputs(")</p>\n", outf);
875 }
876 
877 /* Escape names for use in hyperlinks. */
xhtml_escfprintf(FILE * outf,char * name)878 void xhtml_escfprintf(FILE *outf, char *name) {
879   html_escfprintf(outf, name);
880 }
881 
882 /* Print a string with an appropriate amount of HTML encoding. */
xhtmlputs(FILE * outf,Outchoices * od,char * s,choice source)883 void xhtmlputs(FILE *outf, Outchoices *od, char *s, choice source) {
884   htmlputs(outf, od, s, source);
885 }
886