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 "–";
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("<", outf);
375 else if (c == '>')
376 fputs(">", outf);
377 else if (c == '&')
378 fputs("&", outf);
379 else if (c == '"')
380 fputs(""", 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\"> </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(" ", 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(" ", 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(" ", 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(" ", 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\"> </td>", od->cssprefix);
680 for (c = 0; cols[c] != COL_NUMBER; c++)
681 fprintf(outf, "<td class=\"%s%c\"> </td>", od->cssprefix,
682 colcodes[cols[c]]);
683 fprintf(outf, "<td class=\"%sbar\"> </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