4 * This file holds the reverse engineering algorithm common for
5 * dump-cm.c and dump-svg.c.
7 * Copyright (c) 2000 A. Mueller, Technical University of Braunschweig.
8 * Copyright (c) 2005 K. Sperner, Technical University of Braunschweig.
10 * See the file "COPYING" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * @(#) $Id: rea.c 7823 2008-03-01 13:53:12Z schoenw $
35 * Constants used by the reverse engineering algorithm.
38 static char *pointer[] = {
42 static char *suffix[] = {
46 static char *supportObjs[] = {
47 "RowStatus", "StorageType", NULL
50 static char *baseTypes[] = {
51 "Integer32", "OctetString", "Unsigned32", "Integer64",
52 "Unsigned64", "Float32", "Float64", "Float128",
53 "Enumeration", "Counter32", "Counter64","Bits",
54 "Gauge", "Gauge32", "Integer", "TimeTicks",
55 "IpAddress", "Opaque", "ObjectIdentifier",
62 * driver output control
66 * variables for svg-output
68 * When you change CANVASHEIGHT, CANVASWIDTH values here, you should
69 * also change them in initSvg() and the cgi-script.
72 int CANVASHEIGHT = 700; /* height of the svg */
73 int CANVASWIDTH = 1100; /* width of the svg */
74 int SHOW_DEPRECATED = 0; /* false, show deprecated objects */
75 int SHOW_DEPR_OBSOLETE = 0; /* false, show deprecated and
77 int STATIC_OUTPUT = 0; /* false, enable interactivity */
78 /* variables for cm-driver */
79 int XPLAIN = 0; /* false, generates ASCII output */
80 int XPLAIN_DEBUG = 0; /* false, generates additional
81 output in xplain-mode */
82 int SUPPRESS_DEPRECATED = 1; /* true, suppresses deprecated
84 /* common variables */
85 int PRINT_DETAILED_ATTR = 1; /* true, prints all column
87 int IGNORE_IMPORTED_NODES = 1; /* true, ignores nodes which are
88 imported from other MIBs*/
93 Graph *graph = NULL; /* the graph */
99 /* ------ Misc. ----------------- */
108 * Compares two SmiNode and returns 1 if they are equal and 0 otherwise.
110 int cmpSmiNodes(SmiNode *node1, SmiNode *node2)
112 SmiModule *module1, *module2;
114 module1 = smiGetNodeModule(node1);
115 module2 = smiGetNodeModule(node2);
117 if (!node1 || !node2 || !module1 || !module2) return 0;
119 return (strcmp(node1->name, node2->name) == 0 &&
120 strcmp(module1->name, module2->name) == 0);
126 * Returns the number of identical characters at the beginning of s1 and s2.
128 static int strpfxlen(const char *s1, const char *s2)
132 for (i = 0; s1[i] && s2[i]; i++) {
133 if (s1[i] != s2[i]) {
145 /* ------ Graph primitives ------ */
154 * Inserts a new node into an existing graph.
156 * Result : pointer to the new node
158 GraphNode *graphInsertNode(Graph *graph, SmiNode *smiNode)
164 newNode = xmalloc(sizeof(GraphNode));
165 memset(newNode, 0, sizeof(GraphNode));
166 newNode->smiNode = smiNode;
168 if (graph->nodes == NULL) {
169 graph->nodes = newNode;
174 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
178 lastNode->nextPtr = newNode;
184 * graphInsertComponent
186 * Inserts a new component into an existing graph.
188 * Result : pointer to the new component
190 GraphComponent *graphInsertComponent(Graph *graph)
192 GraphComponent *newComponent;
193 GraphComponent *tComponent;
194 GraphComponent *lastComponent;
196 newComponent = xmalloc(sizeof(GraphComponent));
197 memset(newComponent, 0, sizeof(GraphComponent));
199 if (graph->components == NULL) {
200 graph->components = newComponent;
204 lastComponent = NULL;
205 for (tComponent = graph->components; tComponent;
206 tComponent = tComponent->nextPtr) {
207 lastComponent = tComponent;
210 lastComponent->nextPtr = newComponent;
218 * Inserts a new edge into an existing list of edges.
220 * Input : graph = pointer to an edge structure
221 * startNode = pointer to the starting node of the edge
222 * endNode = pointer to the ending node of the edge
223 * indexkind = type of relationship between the two nodes
225 * Result : pointer to the new edge
227 static GraphEdge *graphInsertEdge(Graph *graph, GraphNode *startNode,
229 SmiIndexkind indexkind,
230 GraphEnhIndex enhancedindex)
236 newEdge = xmalloc(sizeof(GraphEdge));
237 memset(newEdge, 0, sizeof(GraphEdge));
238 newEdge->startNode = startNode;
239 newEdge->endNode = endNode;
240 newEdge->indexkind = indexkind;
241 newEdge->connection = GRAPH_CON_ASSOCIATION;
242 newEdge->enhancedindex = enhancedindex;
244 switch (newEdge->indexkind) {
245 case SMI_INDEX_AUGMENT :
246 newEdge->cardinality = GRAPH_CARD_ONE_TO_ONE;
248 case SMI_INDEX_SPARSE :
249 newEdge->cardinality = GRAPH_CARD_ONE_TO_ZERO_OR_ONE;
251 case SMI_INDEX_EXPAND :
252 newEdge->cardinality = GRAPH_CARD_UNKNOWN;
254 case SMI_INDEX_REORDER :
255 newEdge->cardinality = GRAPH_CARD_ONE_TO_ONE;
257 case SMI_INDEX_INDEX :
258 newEdge->cardinality = GRAPH_CARD_UNKNOWN;
260 case SMI_INDEX_UNKNOWN :
261 newEdge->cardinality = GRAPH_CARD_UNKNOWN;
265 if (graph->edges == NULL) {
266 graph->edges = newEdge;
271 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
275 lastEdge->nextPtr = newEdge;
283 * Frees all memory allocated by the graph.
285 void graphExit(Graph *graph)
287 GraphEdge *tEdge, *dummyEdge;
288 GraphNode *tNode, *dummyNode;
289 GraphComponent *tComponent, *dummyComponent;
294 tNode = graph->nodes;
295 while (tNode != NULL) {
297 tNode = tNode->nextPtr;
303 tEdge = graph->edges;
304 while (tEdge != NULL) {
306 tEdge = tEdge->nextPtr;
311 dummyComponent = NULL;
312 tComponent = graph->components;
313 while (tComponent != NULL) {
314 dummyComponent = tComponent;
315 tComponent = tComponent->nextPtr;
317 xfree(dummyComponent);
325 * graphGetFirstEdgeByNode
327 * Returns the first edge adjacent to the given node (as startNode or EndNode).
329 GraphEdge *graphGetFirstEdgeByNode(Graph *graph, GraphNode *node)
333 if (!graph || !node) {
337 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
338 /*if (tEdge->startNode->smiNode->name == node->smiNode->name ||
339 tEdge->endNode->smiNode->name == node->smiNode->name) break;*/
340 if (cmpSmiNodes(tEdge->startNode->smiNode, node->smiNode) ||
341 cmpSmiNodes(tEdge->endNode->smiNode, node->smiNode)) break;
348 * graphGetNextEdgeByNode
350 * Returns the next edge adjacent to the given node (as startNode or EndNode)
351 * after the given edge.
353 GraphEdge *graphGetNextEdgeByNode(Graph *graph,
359 if (!graph || !node) {
363 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
364 /*if (tEdge->startNode->smiNode->name ==
365 edge->startNode->smiNode->name &&
366 tEdge->endNode->smiNode->name ==
367 edge->endNode->smiNode->name) break;*/
368 if (cmpSmiNodes(tEdge->startNode->smiNode,edge->startNode->smiNode) &&
369 cmpSmiNodes(tEdge->endNode->smiNode,edge->endNode->smiNode))
373 for (tEdge = tEdge->nextPtr; tEdge; tEdge = tEdge->nextPtr) {
374 /*if (tEdge->startNode->smiNode->name == node->smiNode->name ||
375 tEdge->endNode->smiNode->name == node->smiNode->name) break;*/
376 if (cmpSmiNodes(tEdge->startNode->smiNode, node->smiNode) ||
377 cmpSmiNodes(tEdge->endNode->smiNode, node->smiNode)) break;
384 * graphCheckForRedundantEdge
386 * Finds redundant edges and returns 1 if one is found and 0 otherwise.
388 static int graphCheckForRedundantEdge(Graph *graph,
389 GraphNode *startNode,
394 if (!graph || !startNode || !endNode) {
398 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
399 /*if (tEdge->startNode->smiNode->name == startNode->smiNode->name &&
400 tEdge->endNode->smiNode->name == endNode->smiNode->name) {*/
401 if (cmpSmiNodes(tEdge->startNode->smiNode, startNode->smiNode) &&
402 cmpSmiNodes(tEdge->endNode->smiNode, endNode->smiNode)) {
414 * Returns the graph node containing smiNode.
416 static GraphNode *graphGetNode(Graph *graph, SmiNode *smiNode)
420 if (!smiNode || !graph) {
424 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
425 if (tNode->smiNode->name == smiNode->name) {
436 * Prints the nodes of the graph.
438 void graphShowNodes(Graph *graph)
443 printf("No nodes!\n");
447 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
448 if (tNode->smiNode->nodekind == SMI_NODEKIND_TABLE)
450 else printf("[SCALAR]");
451 printf("%40s [%s]\n", tNode->smiNode->name,
452 smiGetNodeModule(tNode->smiNode)->name);
459 * Prints the edges with their attributes in the following order :
461 * - reason for the link
462 * - connection type in UML
464 * - index relationship derived from the row-objects of the tables
467 static void graphShowEdges(Graph *graph)
472 printf("No edges!\n");
476 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
479 switch (tEdge->enhancedindex) {
480 case GRAPH_ENHINDEX_UNKNOWN :
481 printf("[UNKNOWN] ");
483 case GRAPH_ENHINDEX_NOTIFICATION :
485 case GRAPH_ENHINDEX_NAMES :
488 case GRAPH_ENHINDEX_TYPES :
491 case GRAPH_ENHINDEX_INDEX :
494 case GRAPH_ENHINDEX_REROUTE :
495 printf("[REROUTE] ");
497 case GRAPH_ENHINDEX_POINTER :
498 printf("[POINTER] ");
503 switch (tEdge->connection) {
504 case GRAPH_CON_AGGREGATION:
507 case GRAPH_CON_DEPENDENCY:
510 case GRAPH_CON_ASSOCIATION:
513 case GRAPH_CON_UNKNOWN:
517 switch (tEdge->cardinality) {
518 case GRAPH_CARD_UNKNOWN :
521 case GRAPH_CARD_ONE_TO_ONE :
524 case GRAPH_CARD_ONE_TO_MANY :
527 case GRAPH_CARD_ZERO_TO_ONE :
530 case GRAPH_CARD_ZERO_TO_MANY :
533 case GRAPH_CARD_ONE_TO_ZERO_OR_ONE :
538 switch (tEdge->indexkind) {
539 case SMI_INDEX_UNKNOWN :
542 case SMI_INDEX_INDEX :
545 case SMI_INDEX_AUGMENT :
548 case SMI_INDEX_SPARSE :
551 case SMI_INDEX_EXPAND :
554 case SMI_INDEX_REORDER :
558 printf("%29s - ",tEdge->startNode->smiNode->name);
559 printf("%s\n",tEdge->endNode->smiNode->name);
567 /* ------ algorithm primitives ------ */
572 * algCountIndexElements
574 * Returns the number of index elements in a given row entry.
577 static int algCountIndexElements(SmiNode *smiNode)
580 SmiElement *smiElement;
582 if (smiNode->nodekind != SMI_NODEKIND_ROW) {
587 for (smiElement = smiGetFirstElement(smiNode);
589 smiElement = smiGetNextElement(smiElement)) {
599 * Inserts an edge in a given graph. The edge is adjacent to snode
601 * The type of edge is given in indexkind and the enhanced index as
602 * an additional information in enhancedindex.
603 * Nodes which are not loaded yet into the node list of the graph
604 * are added (nodes from imported MIBs).
606 static void algInsertEdge(SmiNode *snode, SmiNode *enode,
607 SmiIndexkind indexkind,
608 GraphEnhIndex enhancedindex)
610 GraphNode *startNode;
615 startNode = graphGetNode(graph, snode);
616 endNode = graphGetNode(graph, enode);
618 /* insert imported nodes into graph if needed */
619 if (startNode == NULL) {
620 if (IGNORE_IMPORTED_NODES) return;
622 startNode = graphInsertNode(graph, snode);
624 if (endNode == NULL) {
625 if (IGNORE_IMPORTED_NODES) return;
627 endNode = graphInsertNode(graph, enode);
630 if (graphCheckForRedundantEdge(graph, startNode, endNode) == 0 &&
631 graphCheckForRedundantEdge(graph, endNode, startNode) == 0) {
632 graphInsertEdge(graph, startNode, endNode, indexkind, enhancedindex);
637 * algGetGroupByFatherNode
639 * Returns the group number associated with the father node of the
640 * given node. If there is no group the result is 0 for no
643 static int algGetGroupByFatherNode(SmiNode *smiNode)
647 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
648 if (tNode->smiNode->nodekind == SMI_NODEKIND_SCALAR &&
649 !graphGetFirstEdgeByNode(graph, tNode)) {
650 if (cmpSmiNodes(smiGetParentNode(smiNode),
651 smiGetParentNode(tNode->smiNode))) {
661 * algGetNumberOfGroups
663 * Returns the number of groups.
665 int algGetNumberOfGroups()
672 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
673 maxGroup = max(maxGroup, tNode->group);
682 * Prints the group with the number group.
684 static void algPrintGroup(int group)
688 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
689 if (tNode->group == group) {
690 printf("%2d - %35s\n", group, tNode->smiNode->name);
696 * algGetTypeDescription
698 * Returns the description of the data type used in smiNode.
700 char *algGetTypeDescription(SmiNode *smiNode)
702 SmiType *smiType, *parentType;
704 smiType = smiGetNodeType(smiNode);
706 if (!smiType || smiNode->nodekind == SMI_NODEKIND_TABLE)
709 if (smiType->decl == SMI_DECL_IMPLICIT_TYPE) {
710 parentType = smiGetParentType(smiType);
711 smiType = parentType;
714 return smiType->description;
720 * Returns the name of the data type used in smiNode.
722 char *algGetTypeName(SmiNode *smiNode)
724 SmiType *smiType, *parentType;
726 smiType = smiGetNodeType(smiNode);
728 if (!smiType || smiNode->nodekind == SMI_NODEKIND_TABLE)
731 if (smiType->decl == SMI_DECL_IMPLICIT_TYPE) {
732 parentType = smiGetParentType(smiType);
733 smiType = parentType;
736 return smiType->name;
742 * Returns the module which defines the data type used in smiNode.
744 SmiModule *algGetTypeModule(SmiNode *smiNode)
746 SmiType *smiType, *parentType;
747 SmiModule *smiModule;
749 smiType = smiGetNodeType(smiNode);
751 if (!smiType || smiNode->nodekind == SMI_NODEKIND_TABLE)
754 if (smiType->decl == SMI_DECL_IMPLICIT_TYPE) {
755 parentType = smiGetParentType(smiType);
756 smiType = parentType;
759 smiModule = smiGetTypeModule(smiType);
765 * algCountElementsFromOtherTables
767 * Returns the number of index objects derived from other tables than
770 static int algCountElementsFromOtherTables(SmiNode *smiNode)
772 SmiElement *smiElement;
776 for (smiElement = smiGetFirstElement(smiNode);
778 smiElement = smiGetNextElement(smiElement)) {
780 tNode = smiGetElementNode(smiElement);
782 if (cmpSmiNodes(smiGetParentNode(smiGetParentNode(tNode)),
783 smiGetParentNode(smiNode)) != 1) {
794 * Returns the number of rows =
795 * number of elements in smiNode - number of rows
796 * + RowStatus-Objects + StorageType-Objects
798 * If the number is > 0 it is only a supporting table (like entLPMappingTable)
799 * and if the number is < 0 it is a "full" table (like ifTable).
801 * Subroutine for algCheckForDependency.
803 static int algGetNumberOfRows(SmiNode *smiNode)
811 tSmiNode = smiGetFirstChildNode(table);
813 elemCount = algCountIndexElements(tSmiNode) -
814 algCountElementsFromOtherTables(tSmiNode);
816 for (tSmiNode = smiGetNextNode(tSmiNode, SMI_NODEKIND_COLUMN);
818 tSmiNode = smiGetNextNode(tSmiNode, SMI_NODEKIND_COLUMN)) {
820 if (cmpSmiNodes(table, smiGetParentNode(smiGetParentNode(tSmiNode)))
825 for (i = 0; supportObjs[i]; i++) {
826 char *typeName = algGetTypeName(tSmiNode);
827 if (typeName && (strcasecmp(typeName, supportObjs[i]) == 0)) {
832 if (!supportObjs[i]) elemCount--;
841 * returns 1 if smiElement is a basetype used in SMIv2/SMIng. Otherwise
844 int isBaseType(SmiNode *node)
848 for (i = 0; baseTypes[i]; i++) {
849 if (strcasecmp(algGetTypeName(node), baseTypes[i]) == 0) {
860 * Looks in all tables indices for an equal type to the type used in typeNode.
861 * It returns the first table found which is different to startTable.
863 * Subroutine for algCheckForDependency.
865 static SmiNode *algFindEqualType(SmiNode *startTable, SmiNode *typeNode)
867 SmiElement *smiElement;
872 typeName = algGetTypeName(typeNode);
873 /* if (isBaseType(typeNode)) return NULL; */
875 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
876 if (tNode->smiNode->nodekind == SMI_NODEKIND_TABLE) {
878 tSmiNode = tNode->smiNode;
879 if (cmpSmiNodes(tSmiNode, startTable) == 1) break;
881 for (smiElement = smiGetFirstElement(
882 smiGetFirstChildNode(tSmiNode));
884 smiElement = smiGetNextElement(smiElement)) {
885 /* found type matching ? */
887 algGetTypeName(smiGetElementNode
888 (smiElement))) == 0) {
900 * 0 = totaly equal (order and objects)
901 * 1 = equal objects but different order
905 static int equalElements(SmiNode *firstRow, SmiNode *secondRow)
907 int i,j,number1, number2;
908 SmiElement *elemFirst, *elemSecond;
910 if (!firstRow->nodekind == SMI_NODEKIND_ROW ||
911 !secondRow->nodekind == SMI_NODEKIND_ROW) {
912 /* printf("no row entries\n"); */
916 if (cmpSmiNodes(firstRow, secondRow) == 1) {
917 /* printf("same objects\n"); */
921 number1 = algCountIndexElements(firstRow);
922 number2 = algCountIndexElements(secondRow);
924 if (number1 != number2) {
925 /* printf("Different number of elements\n"); */
930 for (elemFirst = smiGetFirstElement(firstRow);
932 elemFirst = smiGetNextElement(elemFirst)) {
936 for (elemSecond = smiGetFirstElement(secondRow);
938 elemSecond = smiGetNextElement(elemSecond)) {
940 if (i == j && cmpSmiNodes(smiGetElementNode(elemFirst),
941 smiGetElementNode(elemSecond)) == 1) {
946 /* maybe same elements but in different order */
947 if (!elemSecond) break;
950 /* printf("totaly equal\n"); */
954 for (elemFirst = smiGetFirstElement(firstRow);
956 elemFirst = smiGetNextElement(elemFirst)) {
958 for (elemSecond = smiGetFirstElement(secondRow);
960 elemSecond = smiGetNextElement(elemSecond)) {
962 if (cmpSmiNodes(smiGetElementNode(elemFirst),
963 smiGetElementNode(elemSecond)) == 1) {
968 /* maybe same elements but in different order */
969 if (!elemSecond) break;
973 /* printf("Equal\n"); */
977 /* printf("inequal"); */
985 * Tests whether a given node is part of the index of a particular
986 * table. Returns 1 if the node is an index node and 0 otherwise.
989 int algIsIndexElement(SmiNode *table, SmiNode *node)
991 SmiElement *smiElement;
994 if (node->nodekind != SMI_NODEKIND_TABLE) {
998 row = smiGetFirstChildNode(table);
999 if (!row || row->nodekind != SMI_NODEKIND_ROW) {
1003 for (smiElement = smiGetFirstElement(row);
1005 smiElement = smiGetNextElement(smiElement)) {
1006 SmiNode *indexNode = smiGetElementNode(smiElement);
1007 if (cmpSmiNodes(indexNode, node)) {
1015 /* -------------- main functions ------------------------------------------- */
1021 * algCheckForExpandRel
1023 * Checks the given table for an expand relationship to an other table.
1025 * 1. gets the expanded table (father node of smiNode)
1026 * 2. gets the base table by walking through the elements of the smiNode
1027 * starting at the end. The first table found which is different from the
1028 * expanded table is the first candidate for the base table.
1029 * 3. comparing the number of elements in both tables
1030 * if the number in the expanded table is greater -> 5.
1031 * if the number in the base table is greater -> 4.
1032 * 4. getting a second base table candidate :
1033 * It is possible that a table expands an other table which is expanded
1035 * Therefore it is hard to track the base table.
1036 * - scanning all tables which are different from the expanded table
1037 * - the base table must have :
1039 * - the same elementes must occur as in the expanded table
1040 * 5. the elements in both tables are checked for equality
1042 static void algCheckForExpandRel(SmiNode *smiNode)
1047 SmiElement *smiElement;
1048 SmiElement *findElement;
1049 unsigned int refcounter;
1050 unsigned int basecounter;
1052 if (!smiNode) return;
1054 expTable = smiGetParentNode(smiNode);
1056 /* count the elements in the given table <- father of smiNode */
1057 refcounter = algCountIndexElements(smiNode);
1059 /* find the base table <- via the last element which does not refer to
1062 for (smiElement = smiGetFirstElement(smiNode);
1064 smiElement = smiGetNextElement(smiElement)) {
1065 tNode = smiGetElementNode(smiElement);
1066 tNode = smiGetParentNode(tNode);
1067 tNode = smiGetParentNode(tNode);
1069 if (cmpSmiNodes(tNode, expTable) == 1) break;
1074 if (!baseTable) return;
1076 /* count the elements in the basetable */
1077 basecounter = algCountIndexElements(smiGetFirstChildNode(baseTable));
1079 /* are baseTable and expTable identical ? */
1080 if (basecounter >= refcounter) {
1082 /* searching for new base table candidate in order to handle multiple
1084 for (baseTable = smiGetNextNode(baseTable, SMI_NODEKIND_TABLE);
1086 baseTable = smiGetNextNode(baseTable, SMI_NODEKIND_TABLE)) {
1088 basecounter = algCountIndexElements(smiGetFirstChildNode(baseTable));
1090 if (basecounter < refcounter) {
1092 for (smiElement = smiGetFirstElement(
1093 smiGetFirstChildNode(expTable));
1095 smiElement = smiGetNextElement(smiElement)) {
1096 tNode = smiGetElementNode(smiElement);
1098 /*if (smiGetParentNode(smiGetParentNode(tNode))->name ==
1099 expTable->name) break; */
1100 if (cmpSmiNodes(smiGetParentNode(smiGetParentNode(tNode)),
1101 expTable) == 1) break;
1103 for (findElement = smiGetFirstElement(
1104 smiGetFirstChildNode(baseTable));
1106 findElement = smiGetNextElement(findElement)) {
1107 if (cmpSmiNodes(tNode, smiGetElementNode(findElement))
1124 for (smiElement = smiGetFirstElement(smiGetFirstChildNode(baseTable));
1126 smiElement = smiGetNextElement(smiElement)) {
1127 tNode = smiGetElementNode(smiElement);
1129 for (findElement = smiGetFirstElement(smiGetFirstChildNode(expTable));
1131 findElement = smiGetNextElement(findElement)) {
1132 if (cmpSmiNodes(tNode, smiGetElementNode(findElement)) == 1)
1141 algInsertEdge(baseTable, expTable, SMI_INDEX_EXPAND,
1142 GRAPH_ENHINDEX_INDEX);
1146 * algCheckForSparseRel
1148 * Checks the given table for a sparse relationship to an other table.
1150 * Criterias for a sparse relationship :
1151 * - same number of index elements in both tables
1152 * - the same order of this elements
1153 * 1. Getting the basetable via the last element in the index of smiNode.
1154 * 2. comparing the number of elements
1156 static void algCheckForSparseRel(SmiNode *smiNode)
1158 SmiNode *tNode = NULL;
1160 SmiElement *smiElement;
1161 unsigned int basecounter;
1163 if (!smiNode) return;
1165 table = smiGetParentNode(smiNode);
1167 basecounter = algCountIndexElements(smiNode);
1169 /* getting the basetable via the father node of the last element
1170 to handle multiple instanceing */
1171 for (smiElement = smiGetFirstElement(smiNode);
1173 smiElement = smiGetNextElement(smiElement)) {
1174 tNode = smiGetElementNode(smiElement);
1181 tNode = smiGetParentNode(tNode);
1182 if (equalElements(smiNode, tNode) == 0) {
1183 algInsertEdge(smiGetParentNode(tNode), smiGetParentNode(smiNode),
1184 SMI_INDEX_SPARSE, GRAPH_ENHINDEX_INDEX);
1189 * algCheckForReOrderRel
1191 * Checks the given table for a reorder relationship to an other table.
1193 * Criterias for reoder relationships :
1194 * - same number of elements
1195 * - same elements must occur in a different order
1197 static void algCheckForReorderRel(SmiNode *smiNode)
1200 GraphNode *graphNode;
1206 for (graphNode = graph->nodes;
1208 graphNode = graphNode->nextPtr) {
1209 tNode = graphNode->smiNode;
1210 if (tNode->nodekind == SMI_NODEKIND_TABLE) {
1211 if (equalElements(smiNode, smiGetFirstChildNode(tNode)) == 1) {
1212 algInsertEdge(smiGetParentNode(smiNode), tNode,
1213 SMI_INDEX_REORDER, GRAPH_ENHINDEX_INDEX);
1223 * Gets the indexkind of the given table. The row object of the table is
1224 * passed to this function.
1225 * Therefore three subfunctions are called to get the indexkind.
1226 * - algChechForExpandRel
1227 * - algCheckForSparseRel
1228 * - algCheckForReOrderRel
1229 * Look there for further information.
1231 static void algGetIndexkind(SmiNode *row)
1233 algCheckForExpandRel(row);
1234 algCheckForSparseRel(row);
1235 algCheckForReorderRel(row);
1241 * Links the tables of the given module.
1243 * 1. Getting the tables and the scalars from the given module.
1244 * 2. Linking the tables :
1245 * - AUGMENT no work to do just adding the corresponding edge
1246 * - for other relationships the subfunction algGetIndexkind is called
1247 * look there for further information
1249 void algLinkTables()
1251 GraphNode *tGraphNode;
1255 /* linking the tables */
1256 for (tGraphNode = graph->nodes;
1258 tGraphNode = tGraphNode->nextPtr) {
1259 node = tGraphNode->smiNode;
1261 if (node->nodekind == SMI_NODEKIND_TABLE) {
1262 node = smiGetFirstChildNode(node);
1264 if (node->nodekind == SMI_NODEKIND_ROW) {
1266 /* get the relationship between the tables and insert
1268 if (node->indexkind == SMI_INDEX_INDEX) {
1269 algGetIndexkind(node);
1272 node = smiGetRelatedNode(node);
1273 node = smiGetParentNode(node);
1275 smiGetParentNode(tSmiNode),
1276 tSmiNode->indexkind,
1277 GRAPH_ENHINDEX_INDEX);
1284 printf("--- Second Phase - linking the tables\n\n");
1285 graphShowEdges(graph);
1290 * algCheckLinksByName
1292 * Reordering the connections by looking at the names.
1293 * Related objects are linked (if their names are related).
1294 * Every expand relationship is examined. Therefore number of
1295 * identical characters at the beginning of the both table names is
1297 * Then every sparse relationship (only the ending node) is checked if
1298 * there is better connection with more identical characters at the beginning.
1299 * The starting node must be same as in the expand relationship to make sure
1300 * that there are no unrelated tables are linked.
1301 * Only legal overlappings lead to a new edge. A illegal overlap is :
1302 * - when the next character in both strings is a lower case character
1303 * because if something like this is detected the two strings are
1304 * corresponding in the middle of their names and not at defined points
1305 * like suffix or prefix (-> the next character must be upper case or NULL)
1307 void algCheckLinksByName()
1309 GraphEdge *tEdge, *tEdge2, *newEdge;
1310 char *start, *end, *end2;
1311 int overlap, longestOverlap, i;
1313 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
1315 if (tEdge->indexkind == SMI_INDEX_EXPAND) {
1317 start = tEdge->startNode->smiNode->name;
1318 end = tEdge->endNode->smiNode->name;
1320 overlap = strpfxlen(start,end);
1323 * looking for better connection with longer overlap
1324 * maybe better to traverse the edges with graphGetNextEdgeByNode
1325 * using tEdge->startNode
1328 longestOverlap = overlap;
1329 for (tEdge2 = graphGetFirstEdgeByNode(graph,tEdge->startNode);
1331 tEdge2 = graphGetNextEdgeByNode(graph, tEdge2,
1332 tEdge->startNode)) {
1335 * must be a sparse relationship to get a correct new edge
1337 if (tEdge2->indexkind == SMI_INDEX_SPARSE) {
1338 end2 = tEdge2->endNode->smiNode->name;
1341 * new overlap longer and different tables ?
1343 i = strpfxlen(end,end2);
1345 !cmpSmiNodes(tEdge->endNode->smiNode,
1346 tEdge2->endNode->smiNode)) {
1350 if (islower((int)end[i]) && islower((int)end2[i])) {
1360 /* better connection found -> changing the edge */
1362 tEdge->startNode = newEdge->endNode;
1368 printf("\n--- Third Phase - reordering the connections\n\n");
1369 graphShowEdges(graph);
1374 * algLinkObjectsByNames
1376 * Links Scalars to Tables using the prefix
1377 * Links Tables to Tables using the prefix
1379 static void algLinkObjectsByNames()
1381 GraphNode *tNode, *tNode2;
1382 int overlap,minoverlap,new;
1384 /* getting the minimum overlap for all nodes */
1386 tNode2 = graph->nodes;
1388 for (tNode = tNode2->nextPtr; tNode; tNode = tNode->nextPtr) {
1389 minoverlap = min(minoverlap, strpfxlen(tNode->smiNode->name,
1390 tNode2->smiNode->name));
1395 * prefix overlap of one is too short to create any usefull edges
1397 if (minoverlap == 1) return;
1399 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
1400 if (!graphGetFirstEdgeByNode(graph, tNode)) {
1401 overlap = minoverlap;
1403 for (tNode2 = graph->nodes; tNode2; tNode2 = tNode2->nextPtr) {
1404 if (cmpSmiNodes(tNode->smiNode, tNode2->smiNode)) continue;
1406 new = strpfxlen(tNode->smiNode->name, tNode2->smiNode->name);
1408 if (new >= overlap) {
1411 * no scalar - scalar edges
1413 if (tNode->smiNode->nodekind == SMI_NODEKIND_SCALAR &&
1414 tNode2->smiNode->nodekind == SMI_NODEKIND_SCALAR) {
1419 * is it a legal prefix
1420 * (if the next char is NULL || uppercase)
1422 if (tNode->smiNode->name[new] &&
1423 tNode2->smiNode->name[new]) {
1424 if (!isupper((int)tNode->smiNode->name[new]) ||
1425 !isupper((int)tNode2->smiNode->name[new])) continue;
1432 if (overlap == minoverlap) continue;
1435 for (tNode2 = graph->nodes; tNode2; tNode2 = tNode2->nextPtr) {
1436 if (cmpSmiNodes(tNode->smiNode, tNode2->smiNode)) continue;
1438 new = strpfxlen(tNode->smiNode->name, tNode2->smiNode->name);
1440 if (new == overlap && new > minoverlap) {
1443 * a scalar should only be adjacent to one node
1445 if (tNode2->smiNode->nodekind == SMI_NODEKIND_SCALAR &&
1446 graphGetFirstEdgeByNode(graph,tNode2)) continue;
1447 if (tNode->smiNode->nodekind == SMI_NODEKIND_SCALAR &&
1448 graphGetFirstEdgeByNode(graph,tNode)) continue;
1451 * adding only table -> scalar edges
1453 if (tNode->smiNode->nodekind == SMI_NODEKIND_SCALAR &&
1454 tNode2->smiNode->nodekind == SMI_NODEKIND_SCALAR) {
1458 if (tNode->smiNode->nodekind == SMI_NODEKIND_SCALAR) {
1459 algInsertEdge(tNode2->smiNode, tNode->smiNode,
1461 GRAPH_ENHINDEX_NAMES);
1463 algInsertEdge(tNode->smiNode, tNode2->smiNode,
1465 GRAPH_ENHINDEX_NAMES);
1477 * Grouping the scalars using a common fathernode.
1479 static void algGroupScalars()
1482 int actGroup, fGroup;
1485 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
1486 if (!graphGetFirstEdgeByNode(graph, tNode) &&
1487 tNode->smiNode->nodekind == SMI_NODEKIND_SCALAR) {
1488 fGroup = algGetGroupByFatherNode(tNode->smiNode);
1490 tNode->group = ++actGroup;
1493 tNode->group = fGroup;
1499 printf("Scalar Groups : \n");
1501 if (algGetNumberOfGroups() != 0) {
1503 actGroup <= algGetNumberOfGroups();
1505 algPrintGroup(actGroup);
1508 } else printf("No groups!\n");
1514 * algLinkLonelyTables
1516 * Links isolated tables with other tables via the types of the
1518 * If no type is found the types are checked via the suffix if they differ
1519 * only in the range (-OrZero). Therefore the suffix-vector is checked.
1520 * Basetypes used in SMIv1/v2/ng are sorted out.
1522 static void algLinkLonelyTables()
1524 SmiElement *smiElement, *smiElement2 = NULL;
1525 GraphNode *tNode, *tNode2;
1528 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
1529 if (!graphGetFirstEdgeByNode(graph, tNode) &&
1530 tNode->smiNode->nodekind == SMI_NODEKIND_TABLE) {
1532 for (smiElement = smiGetFirstElement(
1533 smiGetFirstChildNode(tNode->smiNode));
1535 smiElement = smiGetNextElement(smiElement)) {
1537 for (tNode2 = graph->nodes;
1539 tNode2 = tNode2->nextPtr) {
1540 if (tNode->smiNode->nodekind == SMI_NODEKIND_TABLE &&
1543 for (smiElement2 = smiGetFirstElement(
1544 smiGetFirstChildNode(tNode2->smiNode));
1546 smiElement2 = smiGetNextElement(smiElement2)) {
1548 if (strcasecmp(algGetTypeName(
1549 smiGetElementNode(smiElement2)),
1551 smiGetElementNode(smiElement)))
1554 if (isBaseType(smiGetElementNode(smiElement))
1559 graphInsertEdge(graph,tNode2, tNode,
1561 GRAPH_ENHINDEX_TYPES);
1565 for (i = 0; suffix[i]; i++) {
1568 smiGetElementNode(smiElement)),
1570 graphInsertEdge(graph,tNode2,
1573 GRAPH_ENHINDEX_TYPES);
1578 if (suffix[i]) break;
1582 if (smiElement2) break;
1592 * algConnectLonelyNodes
1594 * Connect the isolated nodes (scalars and tables)
1596 * 1. Trying to link tables via the type of the index objects
1597 * 2. Trying to link scalars to tables using the names
1598 * 3. Trying to group scalars which have not been adjacent to any edge.
1600 void algConnectLonelyNodes()
1603 printf("\n--- Fourth Phase - connecting isolated nodes\n\n");
1606 algLinkLonelyTables();
1608 algLinkObjectsByNames();
1613 graphShowEdges(graph);
1618 * Subfunction of algCheckForDependencies
1620 * change UML-edges to dependecy if possible
1622 static void createDependencies()
1627 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
1629 if (tEdge->indexkind == SMI_INDEX_UNKNOWN) {
1631 if (tEdge->startNode->smiNode->nodekind == SMI_NODEKIND_TABLE &&
1632 tEdge->endNode->smiNode->nodekind == SMI_NODEKIND_TABLE) {
1634 elemCount = algGetNumberOfRows(tEdge->startNode->smiNode);
1635 if (elemCount >= 0) tEdge->connection = GRAPH_CON_DEPENDENCY;
1637 elemCount = algGetNumberOfRows(tEdge->endNode->smiNode);
1638 if (elemCount >= 0) tEdge->connection = GRAPH_CON_DEPENDENCY;
1645 * returns 1 if a new rerouting edge creates a loop and 0 otherwise
1647 static int isloop(GraphEdge *tEdge, SmiNode *depTable)
1649 GraphEdge *loopEdge;
1651 for (loopEdge = graphGetFirstEdgeByNode(graph, tEdge->endNode);
1653 loopEdge = graphGetNextEdgeByNode(graph,loopEdge,tEdge->endNode)) {
1655 if ((cmpSmiNodes(loopEdge->startNode->smiNode, depTable)) ||
1656 (cmpSmiNodes(loopEdge->endNode->smiNode, depTable) &&
1657 (loopEdge != tEdge))) {
1666 * subfunction of algCheckForDependency
1668 static void rerouteDependencyEdge(GraphEdge *tEdge)
1670 SmiNode *startTable, *endTable, *depTable;
1671 SmiElement *smiElement;
1673 startTable = tEdge->startNode->smiNode;
1674 endTable = tEdge->endNode->smiNode;
1676 for (smiElement = smiGetFirstElement(
1677 smiGetFirstChildNode(endTable));
1679 smiElement = smiGetNextElement(smiElement)) {
1681 /* look only at expanded indices (only present in endTable) */
1682 if (cmpSmiNodes(endTable, smiGetParentNode(
1683 smiGetParentNode(smiGetElementNode(smiElement)))) == 1) {
1684 depTable = algFindEqualType(startTable,
1685 smiGetElementNode(smiElement));
1687 /* depTable different to endTable? */
1688 if (depTable && !cmpSmiNodes(depTable, endTable)) {
1691 if (isloop(tEdge, depTable)) continue;
1693 algInsertEdge(depTable,
1694 startTable, SMI_INDEX_UNKNOWN,
1695 GRAPH_ENHINDEX_REROUTE);
1703 * algCheckForDependency
1705 * Tries to change connection types from association to dependency by
1706 * looking at the types.
1708 * 1. Supporting tables are revealed. Supporting tables consist only
1709 * index objects and RowStatus-Objects and/or Storage-Type/Objects.
1710 * 2. If a supporting table is found the connection type is changed to
1712 * 3. Now the types of the index objects are checked (only in the end-table).
1713 * If the same type is found in an other table the start-table is going to
1714 * be connected with it (inserting a new edge).
1715 * The end-table is still connected to the start-table.
1717 void algCheckForDependency()
1721 createDependencies();
1723 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
1725 if (tEdge->connection == GRAPH_CON_DEPENDENCY) {
1727 rerouteDependencyEdge(tEdge);
1732 printf("\n--- Fifth Phase - checking for dependency relationships\n\n");
1733 graphShowEdges(graph);
1740 static SmiNode *algFindTable(SmiNode *node)
1744 SmiElement *smiElement;
1747 if (!node) return NULL;
1749 toFind = xstrdup(node->name
1750 + strpfxlen(node->name, smiGetParentNode(node)->name));
1752 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
1753 if (tNode->smiNode->nodekind == SMI_NODEKIND_TABLE) {
1754 if (cmpSmiNodes(node, tNode->smiNode)) continue;
1755 smiNode = smiGetFirstChildNode(tNode->smiNode);
1757 for (smiElement = smiGetFirstElement(smiNode);
1759 smiElement = smiGetNextElement(smiElement)) {
1760 smiNode = smiGetElementNode(smiElement);
1761 if (strstr(smiNode->name, toFind)) {
1763 return smiGetParentNode(smiGetParentNode(smiNode));
1775 * Creates edges based on column-objects pointing to other tables.
1776 * Column-objects with a substring "Index" are examined.
1778 void algCheckForPointerRels()
1782 SmiNode *smiNode = NULL;
1783 SmiNode *ppNode, *table;
1786 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
1787 if (tNode->smiNode->nodekind == SMI_NODEKIND_TABLE) {
1789 module = smiGetNodeModule(tNode->smiNode);
1791 for (smiNode = smiGetFirstNode(module, SMI_NODEKIND_COLUMN);
1793 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_COLUMN)) {
1794 ppNode = smiGetParentNode(smiNode);
1795 ppNode = smiGetParentNode(ppNode);
1797 if (!algIsIndexElement(tNode->smiNode, smiNode) &&
1798 cmpSmiNodes(tNode->smiNode, ppNode)) {
1800 for (i = 0; pointer[i]; i++) {
1801 if (strstr(smiNode->name, pointer[i])) {
1802 /* printf("%s \n",smiNode->name); */
1803 table = algFindTable(smiNode);
1805 algInsertEdge(table, tNode->smiNode,
1807 GRAPH_ENHINDEX_POINTER);
1817 printf("\n--- Sixth Phase - checking for pointer relationships\n\n");
1818 graphShowEdges(graph);