1 /*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31 *
32 */
33 /* $Id: reporter.c,v 1.1 2000/09/21 21:35:06 alaffin Exp $ */
34 /*
35 * This is the report generator half of the scanner program.
36 */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 #include <unistd.h>
43 #include "reporter.h"
44 #include "symbol.h"
45 #include "tag_report.h"
46 #include "splitstr.h"
47
48 /************************************************************************
49 * Report Generation *
50 ************************************************************************/
51
52 static int scanner_reporter(SYM);
53 static int iscanner_reporter(SYM);
54 static int scanner_test_end(SYM, SYM, SYM);
55 static int iscanner_test_end(SYM, SYM, SYM);
56
57 static int (*reporter_func) (SYM) = scanner_reporter;
58 static int (*test_end_func) (SYM, SYM, SYM) = scanner_test_end;
59
60 /*
61 * Do the report generation.
62 *
63 * A problem: I really need multiple cursors. I'd rather not look into
64 * the depths of the current symbol table implimentation (there are the
65 * cursors there that I could use) so that a different (faster!) symbol
66 * table can be used in the future.
67 *
68 * I could get a key (tag), get it's sub-keys (TCIDs), then get the key
69 * again to reset to the top level, _then_ get the next key. That would
70 * be very inefficient.
71 *
72 * The solution I chose is to extract all tags into a list (char array),
73 * then go thru that list with the cursor free for other levels to use.
74 *
75 * (1) make a list (2d char array) of all Tags
76 * (2) search for the first tag that has a "stime" record, and use that as
77 * the date (MMDDYY) that the tests were run.
78 * (3) print the report header
79 * (4) go thru all tags and report each as described at the beginning of
80 * this file
81 */
scanner_reporter(SYM tags)82 static int scanner_reporter(SYM tags)
83 {
84 DBT Key, Data;
85 SYM Tag, Keys;
86
87 time_t clock;
88 struct tm *tm;
89
90 /* a list of tags, a count of the number of tags allocated to the list,
91 and a pointer to go thru the list */
92 char **taglist, **tl;
93 int ntags;
94 int tagcount; /* how many tags used */
95
96 char key_get[KEYSIZE];
97 char *info;
98
99 /*
100 * extract tag names from data
101 */
102 ntags = NTAGS_START;
103 taglist = malloc(sizeof(char *) * ntags);
104 tagcount = 0;
105
106 tl = taglist;
107 sym_seq(tags, &Key, &Data, R_FIRST);
108 do {
109 if (tagcount == ntags) {
110 /* exceeded tag array size -- realloc */
111 ntags += NTAGS_START;
112 taglist =
113 (char **)realloc(taglist, sizeof(char *) * ntags);
114 tl = taglist + tagcount;
115 }
116
117 *tl++ = Key.data;
118 tagcount++;
119 } while (sym_seq(tags, &Key, &Data, R_NEXT) == 0);
120
121 if (tagcount == ntags) {
122 /* exceeded tag array size -- realloc */
123 ntags += NTAGS_START;
124 taglist = (char **)realloc(taglist, sizeof(char *) * ntags);
125 tl = taglist + tagcount;
126 }
127
128 *tl++ = NULL;
129 ntags = tagcount;
130 /* Retrieve one "stime" to get the date. */
131 for (tl = taglist; *tl != NULL; tl++) {
132 strcpy(key_get, *tl);
133 strcat(key_get, ",_keys,stime");
134 if ((info = (char *)sym_get(tags, key_get)) != NULL) {
135 clock = atoi(info);
136 tm = gmtime(&clock);
137 strftime(key_get, KEYSIZE, "%x", tm);
138 sym_put(tags, strdup("_RTS,date"), strdup(key_get), 0);
139 break;
140 }
141 }
142
143 print_header(tags);
144
145 /*
146 * The way that I am using 'Keys' and 'Tag' makes assumptions about the
147 * internals of the sym_* data structure.
148 */
149 /* dump 'em all */
150 for (tl = taglist; *tl != NULL; tl++) {
151 if (!strcmp(*tl, "_RTS"))
152 continue;
153
154 strcpy(key_get, *tl);
155 strcat(key_get, ",_keys");
156 if ((Keys = sym_get(tags, key_get)) == NULL) {
157 return 0;
158 }
159
160 strcpy(key_get, *tl);
161 if ((Tag = sym_get(tags, key_get)) != NULL) {
162 tag_report(NULL, Tag, Keys);
163 }
164 }
165 free(taglist);
166
167 return 0;
168 }
169
170 /*
171 * End-Of-Test seen, insert this tag into the global tag data.
172 * (1) Get the test's tag
173 * (2) insert the keywords in the "_keys" tag
174 * (3) insert it into the global data under this tag, replacing any existing
175 * data.
176 *
177 * a "feature" of the key implimentation: I can insert a key tree
178 * under another key tree with almost zero brainwork because a SYM
179 * is what the DATA area points to.
180 */
scanner_test_end(SYM alltags,SYM ctag,SYM keys)181 static int scanner_test_end(SYM alltags, SYM ctag, SYM keys)
182 {
183 static int notag = 0; /* counter for records with no tag (error) */
184 char tagname[KEYSIZE]; /* used when creating name (see above) */
185 char *tag; /* tag name to look things up in */
186 char *status; /* initiation status of old tag */
187 SYM rm; /* pointer to old tag -- to remove it */
188
189 if (alltags == NULL || keys == NULL || ctag == NULL)
190 return -1; /* for really messed up test output */
191
192 /* insert keys into tag */
193 sym_put(ctag, "_keys", (void *)keys, 0);
194
195 /* get the tag, or build a new one */
196 if ((tag = (char *)sym_get(keys, "tag")) == NULL) {
197 /* this is an "impossible" situation: test_output checks for this
198 * and creates a dummy tag. */
199 sprintf(tagname, "no_tag_%d", notag++);
200 fprintf(stderr, "No TAG key! Using %s\n", tagname);
201 sym_put(keys, "tag", strdup(tagname), 0);
202 tag = strdup(tagname);
203 }
204
205 /*
206 * Special case: duplicate tag that has an initiation_status failure
207 * is thrown away.
208 */
209 if ((rm = (SYM) sym_get(alltags, tag)) != NULL) {
210 if ((status =
211 (char *)sym_get(keys, "initiation_status")) != NULL) {
212 if (strcmp(status, "ok")) {
213 /* do not take new data. remove new data */
214 sym_rm(ctag, RM_KEY | RM_DATA);
215 return 1;
216 } else {
217 /* remove old data in alltags */
218 sym_rm(rm, RM_KEY | RM_DATA);
219 }
220 } else {
221 /* new data does not have an initiation_status -- throw it away */
222 sym_rm(ctag, RM_KEY | RM_DATA);
223 return 1;
224 }
225 }
226
227 /* put new data.. replaces existing "tag" key if it exists
228 * (it's data should have been removed above) */
229 sym_put(alltags, tag, ctag, PUT_REPLACE);
230
231 return 0;
232 }
233
iscanner_reporter(SYM tags)234 static int iscanner_reporter(SYM tags)
235 {
236 return 0;
237 }
238
iscanner_test_end(SYM alltags,SYM ctag,SYM keys)239 static int iscanner_test_end(SYM alltags, SYM ctag, SYM keys)
240 {
241 if (alltags == NULL || keys == NULL || ctag == NULL)
242 return -1; /* for really messed up test output */
243
244 /* insert keys into tag */
245 sym_put(ctag, "_keys", (void *)keys, 0);
246
247 return tag_report(alltags, ctag, keys);
248 }
249
reporter(SYM s)250 int reporter(SYM s)
251 {
252 return reporter_func(s);
253 }
254
test_end(SYM a,SYM b,SYM c)255 int test_end(SYM a, SYM b, SYM c)
256 {
257 return test_end_func(a, b, c);
258 }
259
set_scanner(void)260 void set_scanner(void)
261 {
262 reporter_func = scanner_reporter;
263 test_end_func = scanner_test_end;
264 }
265
set_iscanner(void)266 void set_iscanner(void)
267 {
268 reporter_func = iscanner_reporter;
269 test_end_func = iscanner_test_end;
270 }
271