1161200Ssam/*-
2174244Ssam * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
3161200Ssam * All rights reserved.
4161200Ssam *
5161200Ssam * Redistribution and use in source and binary forms, with or without
6161200Ssam * modification, are permitted provided that the following conditions
7161200Ssam * are met:
8161200Ssam * 1. Redistributions of source code must retain the above copyright
9161200Ssam *    notice, this list of conditions and the following disclaimer,
10161200Ssam *    without modification.
11161200Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12161200Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13161200Ssam *    redistribution must be conditioned upon including a substantially
14161200Ssam *    similar Disclaimer requirement for further binary redistribution.
15161200Ssam *
16161200Ssam * NO WARRANTY
17161200Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18161200Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19161200Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20161200Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21161200Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22161200Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23161200Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24161200Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25161200Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26161200Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27161200Ssam * THE POSSIBILITY OF SUCH DAMAGES.
28161200Ssam *
29161200Ssam * $FreeBSD$
30161200Ssam */
31161200Ssam
32161200Ssam#include <stdio.h>
33161200Ssam#include <string.h>
34161200Ssam
35161200Ssam#include "statfoo.h"
36161200Ssam
37161200Ssamstatic void
38161200Ssamstatfoo_setfmt(struct statfoo *sf, const char *fmt0)
39161200Ssam{
40161200Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
41161200Ssam	char fmt[4096];
42161200Ssam	char *fp, *tok;
43178699Ssam	int i, j, field;
44161200Ssam
45178699Ssam	j = field = 0;
46161200Ssam	strlcpy(fmt, fmt0, sizeof(fmt));
47161200Ssam	for (fp = fmt; (tok = strsep(&fp, ", ")) != NULL;) {
48161200Ssam		for (i = 0; i < sf->nstats; i++)
49161200Ssam			if (strcasecmp(tok, sf->stats[i].name) == 0)
50161200Ssam				break;
51161200Ssam		if (i >= sf->nstats) {
52161200Ssam			fprintf(stderr, "%s: unknown statistic name \"%s\" "
53161200Ssam				"skipped\n", sf->name, tok);
54161200Ssam			continue;
55161200Ssam		}
56161200Ssam		if (j+3 > sizeof(sf->fmts)) {
57161200Ssam			fprintf(stderr, "%s: not enough room for all stats; "
58161200Ssam				"stopped at %s\n", sf->name, tok);
59161200Ssam			break;
60161200Ssam		}
61178699Ssam		if (field > 127) {
62178699Ssam			fprintf(stderr, "%s: too many fields; "
63178699Ssam				"stopped at %s\n", sf->name, tok);
64178699Ssam			break;
65178699Ssam		}
66161200Ssam		if (j != 0)
67161200Ssam			sf->fmts[j++] = ' ';
68178699Ssam		sf->fmts[j++] = 0x80 | field;
69178699Ssam		sf->fields[field++] = i;
70161200Ssam	}
71161200Ssam	sf->fmts[j] = '\0';
72161200Ssam#undef N
73161200Ssam}
74161200Ssam
75161200Ssamstatic void
76161200Ssamstatfoo_collect(struct statfoo *sf)
77161200Ssam{
78161200Ssam	fprintf(stderr, "%s: don't know how to collect data\n", sf->name);
79161200Ssam}
80161200Ssam
81161200Ssamstatic void
82161200Ssamstatfoo_update_tot(struct statfoo *sf)
83161200Ssam{
84161200Ssam	fprintf(stderr, "%s: don't know how to update total data\n", sf->name);
85161200Ssam}
86161200Ssam
87161200Ssamstatic int
88161200Ssamstatfoo_get(struct statfoo *sf, int s, char b[], size_t bs)
89161200Ssam{
90161200Ssam	fprintf(stderr, "%s: don't know how to get stat #%u\n", sf->name, s);
91161200Ssam	return 0;
92161200Ssam}
93161200Ssam
94161200Ssamstatic void
95161200Ssamstatfoo_print_header(struct statfoo *sf, FILE *fd)
96161200Ssam{
97161200Ssam	const unsigned char *cp;
98161200Ssam
99161200Ssam	for (cp = sf->fmts; *cp != '\0'; cp++) {
100161200Ssam		if (*cp & 0x80) {
101178699Ssam			int six = sf->fields[*cp &~ 0x80];
102178699Ssam			const struct fmt *f = &sf->stats[six];
103161200Ssam			fprintf(fd, "%*s", f->width, f->label);
104161200Ssam		} else
105161200Ssam			putc(*cp, fd);
106161200Ssam	}
107161200Ssam	putc('\n', fd);
108161200Ssam}
109161200Ssam
110161200Ssamstatic void
111161200Ssamstatfoo_print_current(struct statfoo *sf, FILE *fd)
112161200Ssam{
113161200Ssam	char buf[32];
114161200Ssam	const unsigned char *cp;
115161200Ssam
116161200Ssam	for (cp = sf->fmts; *cp != '\0'; cp++) {
117161200Ssam		if (*cp & 0x80) {
118178699Ssam			int six = sf->fields[*cp &~ 0x80];
119178699Ssam			const struct fmt *f = &sf->stats[six];
120178699Ssam			if (sf->get_curstat(sf, six, buf, sizeof(buf)))
121161200Ssam				fprintf(fd, "%*s", f->width, buf);
122161200Ssam		} else
123161200Ssam			putc(*cp, fd);
124161200Ssam	}
125161200Ssam	putc('\n', fd);
126161200Ssam}
127161200Ssam
128161200Ssamstatic void
129161200Ssamstatfoo_print_total(struct statfoo *sf, FILE *fd)
130161200Ssam{
131161200Ssam	char buf[32];
132161200Ssam	const unsigned char *cp;
133161200Ssam
134161200Ssam	for (cp = sf->fmts; *cp != '\0'; cp++) {
135161200Ssam		if (*cp & 0x80) {
136178699Ssam			int six = sf->fields[*cp &~ 0x80];
137178699Ssam			const struct fmt *f = &sf->stats[six];
138178699Ssam			if (sf->get_totstat(sf, six, buf, sizeof(buf)))
139161200Ssam				fprintf(fd, "%*s", f->width, buf);
140161200Ssam		} else
141161200Ssam			putc(*cp, fd);
142161200Ssam	}
143161200Ssam	putc('\n', fd);
144161200Ssam}
145161200Ssam
146161200Ssamstatic void
147161200Ssamstatfoo_print_verbose(struct statfoo *sf, FILE *fd)
148161200Ssam{
149173305Ssam	const struct fmt *f;
150161200Ssam	char s[32];
151173305Ssam	int i, width;
152161200Ssam
153173305Ssam	width = 0;
154161200Ssam	for (i = 0; i < sf->nstats; i++) {
155173305Ssam		f = &sf->stats[i];
156173305Ssam		if (f->width > width)
157173305Ssam			width = f->width;
158173305Ssam	}
159173305Ssam	for (i = 0; i < sf->nstats; i++) {
160173305Ssam		f = &sf->stats[i];
161161200Ssam		if (sf->get_totstat(sf, i, s, sizeof(s)) && strcmp(s, "0"))
162173305Ssam			fprintf(fd, "%-*s %s\n", width, s, f->desc);
163161200Ssam	}
164161200Ssam}
165161200Ssam
166161200Ssamstatic void
167161200Ssamstatfoo_print_fields(struct statfoo *sf, FILE *fd)
168161200Ssam{
169161200Ssam	int i, w, width;
170161200Ssam
171161200Ssam	width = 0;
172161200Ssam	for (i = 0; i < sf->nstats; i++) {
173161200Ssam		w = strlen(sf->stats[i].name);
174161200Ssam		if (w > width)
175161200Ssam			width = w;
176161200Ssam	}
177161200Ssam	for (i = 0; i < sf->nstats; i++) {
178161200Ssam		const struct fmt *f = &sf->stats[i];
179161200Ssam		if (f->width != 0)
180161200Ssam			fprintf(fd, "%-*s %s\n", width, f->name, f->desc);
181161200Ssam	}
182161200Ssam}
183161200Ssam
184161200Ssamvoid
185161200Ssamstatfoo_init(struct statfoo *sf, const char *name, const struct fmt *stats, int nstats)
186161200Ssam{
187161200Ssam	sf->name = name;
188161200Ssam	sf->stats = stats;
189161200Ssam	sf->nstats = nstats;
190161200Ssam	sf->setfmt = statfoo_setfmt;
191161200Ssam	sf->collect_cur = statfoo_collect;
192161200Ssam	sf->collect_tot = statfoo_collect;
193161200Ssam	sf->update_tot = statfoo_update_tot;
194161200Ssam	sf->get_curstat = statfoo_get;
195161200Ssam	sf->get_totstat = statfoo_get;
196161200Ssam	sf->print_header = statfoo_print_header;
197161200Ssam	sf->print_current = statfoo_print_current;
198161200Ssam	sf->print_total = statfoo_print_total;
199161200Ssam	sf->print_verbose = statfoo_print_verbose;
200161200Ssam	sf->print_fields = statfoo_print_fields;
201161200Ssam}
202