| /* |
| * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of version 2 of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| * |
| * Further, this software is distributed without any warranty that it is |
| * free of the rightful claim of any third person regarding infringement |
| * or the like. Any license provided herein, whether implied or |
| * otherwise, applies only to this software file. Patent licenses, if |
| * any, provided herein do not apply to combinations of this program with |
| * other software, or any other product whatsoever. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, |
| * Mountain View, CA 94043, or: |
| * |
| * http://www.sgi.com |
| * |
| * For further information regarding this notice, see: |
| * |
| * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ |
| * |
| */ |
| /* $Id: reporter.c,v 1.1 2000/09/21 21:35:06 alaffin Exp $ */ |
| /* |
| * This is the report generator half of the scanner program. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| #include <unistd.h> |
| #include "reporter.h" |
| #include "symbol.h" |
| #include "tag_report.h" |
| #include "splitstr.h" |
| |
| /************************************************************************ |
| * Report Generation * |
| ************************************************************************/ |
| |
| static int scanner_reporter(SYM); |
| static int iscanner_reporter(SYM); |
| static int scanner_test_end(SYM, SYM, SYM); |
| static int iscanner_test_end(SYM, SYM, SYM); |
| |
| static int (*reporter_func) (SYM) = scanner_reporter; |
| static int (*test_end_func) (SYM, SYM, SYM) = scanner_test_end; |
| |
| /* |
| * Do the report generation. |
| * |
| * A problem: I really need multiple cursors. I'd rather not look into |
| * the depths of the current symbol table implimentation (there are the |
| * cursors there that I could use) so that a different (faster!) symbol |
| * table can be used in the future. |
| * |
| * I could get a key (tag), get it's sub-keys (TCIDs), then get the key |
| * again to reset to the top level, _then_ get the next key. That would |
| * be very inefficient. |
| * |
| * The solution I chose is to extract all tags into a list (char array), |
| * then go thru that list with the cursor free for other levels to use. |
| * |
| * (1) make a list (2d char array) of all Tags |
| * (2) search for the first tag that has a "stime" record, and use that as |
| * the date (MMDDYY) that the tests were run. |
| * (3) print the report header |
| * (4) go thru all tags and report each as described at the beginning of |
| * this file |
| */ |
| static int scanner_reporter(tags) |
| SYM tags; |
| { |
| DBT Key, Data; |
| SYM Tag, Keys; |
| |
| time_t clock; |
| struct tm *tm; |
| |
| /* a list of tags, a count of the number of tags allocated to the list, |
| and a pointer to go thru the list */ |
| char **taglist, **tl; |
| int ntags; |
| int tagcount; /* how many tags used */ |
| |
| char key_get[KEYSIZE]; |
| char *info; |
| |
| /* |
| * extract tag names from data |
| */ |
| ntags = NTAGS_START; |
| taglist = (char **)malloc(sizeof(char *) * ntags); |
| tagcount = 0; |
| |
| tl = taglist; |
| sym_seq(tags, &Key, &Data, R_FIRST); |
| do { |
| if (tagcount == ntags) { |
| /* exceeded tag array size -- realloc */ |
| ntags += NTAGS_START; |
| taglist = |
| (char **)realloc(taglist, sizeof(char *) * ntags); |
| tl = taglist + tagcount; |
| } |
| |
| *tl++ = Key.data; |
| tagcount++; |
| } while (sym_seq(tags, &Key, &Data, R_NEXT) == 0); |
| |
| if (tagcount == ntags) { |
| /* exceeded tag array size -- realloc */ |
| ntags += NTAGS_START; |
| taglist = (char **)realloc(taglist, sizeof(char *) * ntags); |
| tl = taglist + tagcount; |
| } |
| |
| *tl++ = NULL; |
| ntags = tagcount; |
| /* Retrieve one "stime" to get the date. */ |
| for (tl = taglist; *tl != NULL; tl++) { |
| strcpy(key_get, *tl); |
| strcat(key_get, ",_keys,stime"); |
| if ((info = (char *)sym_get(tags, key_get)) != NULL) { |
| clock = atoi(info); |
| tm = gmtime(&clock); |
| strftime(key_get, KEYSIZE, "%x", tm); |
| sym_put(tags, strdup("_RTS,date"), strdup(key_get), 0); |
| break; |
| } |
| } |
| |
| print_header(tags); |
| |
| /* |
| * The way that I am using 'Keys' and 'Tag' makes assumptions about the |
| * internals of the sym_* data structure. |
| */ |
| /* dump 'em all */ |
| for (tl = taglist; *tl != NULL; tl++) { |
| if (!strcmp(*tl, "_RTS")) |
| continue; |
| |
| strcpy(key_get, *tl); |
| strcat(key_get, ",_keys"); |
| if ((Keys = sym_get(tags, key_get)) == NULL) { |
| return 0; |
| } |
| |
| strcpy(key_get, *tl); |
| if ((Tag = sym_get(tags, key_get)) != NULL) { |
| tag_report(NULL, Tag, Keys); |
| } |
| } |
| free(taglist); |
| |
| return 0; |
| } |
| |
| /* |
| * End-Of-Test seen, insert this tag into the global tag data. |
| * (1) Get the test's tag |
| * (2) insert the keywords in the "_keys" tag |
| * (3) insert it into the global data under this tag, replacing any existing |
| * data. |
| * |
| * a "feature" of the key implimentation: I can insert a key tree |
| * under another key tree with almost zero brainwork because a SYM |
| * is what the DATA area points to. |
| */ |
| static int scanner_test_end(alltags, ctag, keys) |
| SYM alltags, ctag, keys; |
| { |
| static int notag = 0; /* counter for records with no tag (error) */ |
| char tagname[KEYSIZE]; /* used when creating name (see above) */ |
| char *tag; /* tag name to look things up in */ |
| char *status; /* initiation status of old tag */ |
| SYM rm; /* pointer to old tag -- to remove it */ |
| |
| if (alltags == NULL || keys == NULL || ctag == NULL) |
| return -1; /* for really messed up test output */ |
| |
| /* insert keys into tag */ |
| sym_put(ctag, "_keys", (void *)keys, 0); |
| |
| /* get the tag, or build a new one */ |
| if ((tag = (char *)sym_get(keys, "tag")) == NULL) { |
| /* this is an "impossible" situation: test_output checks for this |
| * and creates a dummy tag. */ |
| sprintf(tagname, "no_tag_%d", notag++); |
| fprintf(stderr, "No TAG key! Using %s\n", tagname); |
| sym_put(keys, "tag", strdup(tagname), 0); |
| tag = strdup(tagname); |
| } |
| |
| /* |
| * Special case: duplicate tag that has an initiation_status failure |
| * is thrown away. |
| */ |
| if ((rm = (SYM) sym_get(alltags, tag)) != NULL) { |
| if ((status = |
| (char *)sym_get(keys, "initiation_status")) != NULL) { |
| if (strcmp(status, "ok")) { |
| /* do not take new data. remove new data */ |
| sym_rm(ctag, RM_KEY | RM_DATA); |
| return 1; |
| } else { |
| /* remove old data in alltags */ |
| sym_rm(rm, RM_KEY | RM_DATA); |
| } |
| } else { |
| /* new data does not have an initiation_status -- throw it away */ |
| sym_rm(ctag, RM_KEY | RM_DATA); |
| return 1; |
| } |
| } |
| |
| /* put new data.. replaces existing "tag" key if it exists |
| * (it's data should have been removed above) */ |
| sym_put(alltags, tag, ctag, PUT_REPLACE); |
| |
| return 0; |
| } |
| |
| static int iscanner_reporter(tags) |
| SYM tags; |
| { |
| return 0; |
| } |
| |
| static int iscanner_test_end(alltags, ctag, keys) |
| SYM alltags, ctag, keys; |
| { |
| if (alltags == NULL || keys == NULL || ctag == NULL) |
| return -1; /* for really messed up test output */ |
| |
| /* insert keys into tag */ |
| sym_put(ctag, "_keys", (void *)keys, 0); |
| |
| return tag_report(alltags, ctag, keys); |
| } |
| |
| int reporter(SYM s) |
| { |
| return reporter_func(s); |
| } |
| |
| int test_end(SYM a, SYM b, SYM c) |
| { |
| return test_end_func(a, b, c); |
| } |
| |
| void set_scanner(void) |
| { |
| reporter_func = scanner_reporter; |
| test_end_func = scanner_test_end; |
| } |
| |
| void set_iscanner(void) |
| { |
| reporter_func = iscanner_reporter; |
| test_end_func = iscanner_test_end; |
| } |