4 * Operations to extract a SVG diagram from MIB modules.
5 * This driver is based on the cm-driver by A. Mueller.
6 * Mail comments and suggestions to sperner@ibr.cs.tu-bs.de
8 * Copyright (c) 2004-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: dump-svg.c 8090 2008-04-18 12:56:29Z strauss $
32 #include "dump-svg-script.h"
34 #define URL "http://www.ibr.cs.tu-bs.de/projects/libsmi/svg/mib2svg.cgi?"
38 extern int smiAsprintf(char **strp, const char *format, ...);
43 * Definitions used by the svg output driver (node layout).
46 /* FIXME int or float? */
47 static const float HEADFONTSIZETABLE = (float)7;
48 static const float HEADSPACESIZETABLE = (float)4;
49 static const float ATTRFONTSIZE = (float)7;
50 static const float ATTRSPACESIZE = (float)2;
51 static const float TABLEHEIGHT = (float)20; /*headline of the table*/
52 static const float TABLEELEMHEIGHT = (float)15; /*height of one attribute*/
53 static const float TABLEBOTTOMHEIGHT = (float)5; /*bottom of the table*/
55 static const int MODULE_INFO_WIDTH =150;
56 /* The description of RowStatus is quite long... :-/ */
57 static const int DYN_TEXT =470;
59 /* used by the springembedder */
60 static const int ITERATIONS =100;
63 static const char *linkcolor = "blue";
67 /* ------ Misc. ----------------- */
71 static char *getTimeString(time_t t)
73 static char *s = NULL;
79 if (tm->tm_hour == 0 && tm->tm_min == 0) {
80 smiAsprintf(&s, "%04d-%02d-%02d",
81 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
83 smiAsprintf(&s, "%04d-%02d-%02d %02d:%02d",
84 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
85 tm->tm_hour, tm->tm_min);
92 /* -------------- main functions ------------------------------------------- */
97 * Creates the graph nodes of the given module
99 static void algCreateNodes(SmiModule *module)
104 /* get tables and scalars from the MIB module */
105 for (node = smiGetFirstNode(module, SMI_NODEKIND_TABLE);
107 node = smiGetNextNode(node, SMI_NODEKIND_TABLE)) {
108 if ((node->status == SMI_STATUS_DEPRECATED
109 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
110 || (node->status == SMI_STATUS_OBSOLETE
111 && !SHOW_DEPR_OBSOLETE))
113 newNode = graphInsertNode(graph, node);
114 newNode->smiModule = module;
116 for (node = smiGetFirstNode(module, SMI_NODEKIND_SCALAR);
118 node = smiGetNextNode(node, SMI_NODEKIND_SCALAR)) {
119 if ((node->status == SMI_STATUS_DEPRECATED
120 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
121 || (node->status == SMI_STATUS_OBSOLETE
122 && !SHOW_DEPR_OBSOLETE))
124 newNode = graphInsertNode(graph, node);
125 newNode->smiModule = module;
131 /* ------ XML primitives ------ */
136 * parseTooltip: Parse any input to output to make the text safe for the
137 * ShowTooltipMZ-functin in the ecma-script.
139 static void parseTooltip(char *input, char *output)
143 for (i = j = 0; input[i]; i++) {
154 /* quotes are not allowed in strings. */
155 /* See chapter 3.4.5 in "Understanding SNMP MIBs" */
177 /* It seems, ' doesn't work... */
182 output[j++] = input[i];
188 static int isObjectGroup(SmiNode *groupNode)
191 SmiElement *smiElement;
193 for (smiElement = smiGetFirstElement(groupNode); smiElement;
194 smiElement = smiGetNextElement(smiElement)) {
196 smiNode = smiGetElementNode(smiElement);
198 if (smiNode->nodekind != SMI_NODEKIND_SCALAR
199 && smiNode->nodekind != SMI_NODEKIND_COLUMN) {
207 static int isNotificationGroup(SmiNode *groupNode)
210 SmiElement *smiElement;
212 for (smiElement = smiGetFirstElement(groupNode); smiElement;
213 smiElement = smiGetNextElement(smiElement)) {
215 smiNode = smiGetElementNode(smiElement);
217 if (smiNode->nodekind != SMI_NODEKIND_NOTIFICATION) {
225 static char *printFillColor(SmiStatus status)
228 (status == SMI_STATUS_CURRENT) ? "rgb(0%,0%,0%)" :
229 (status == SMI_STATUS_DEPRECATED) ? "rgb(40%,40%,40%)" :
230 (status == SMI_STATUS_OBSOLETE) ? "rgb(60%,60%,60%)" :
231 (status == SMI_STATUS_MANDATORY) ? "rgb(0%,0%,0%)" :
232 (status == SMI_STATUS_OPTIONAL) ? "rgb(20%,20%,20%)" :
236 static char *getStatusString(SmiStatus status)
239 (status == SMI_STATUS_CURRENT) ? "current" :
240 (status == SMI_STATUS_DEPRECATED) ? "deprecated" :
241 (status == SMI_STATUS_OBSOLETE) ? "obsolete" :
242 (status == SMI_STATUS_MANDATORY) ? "mandatory" :
243 (status == SMI_STATUS_OPTIONAL) ? "optional" :
248 * Prints the footer of the SVG output file.
250 static void printSVGClose(float xMin, float yMin, float xMax, float yMax)
254 scale = max((xMax-xMin)/CANVASWIDTH,(yMax-yMin)/CANVASHEIGHT);
255 /* enclose whole canvas in its bounding box */
257 printf(" <rect x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%.2f\"\n",
258 xMin, yMin, xMax-xMin-1, yMax-yMin-1);
259 printf(" fill=\"none\" stroke=\"blue\" stroke-width=\"1\"/>\n");
261 if (!STATIC_OUTPUT) {
262 printf(" <g transform=\"translate(%.2f,%.2f) scale(%.2f)\">\n",
264 printf(" <g id=\"tooltip\" style=\"visibility: hidden\">\n");
265 printf(" <rect id=\"ttr\" x=\"0\" y=\"0\" rx=\"5\" ry=\"5\"");
266 printf(" width=\"100\" height=\"16\"/>\n");
267 printf(" <line id=\"ttl\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"0\"/>\n");
268 printf(" <text class=\"tooltip\" xml:space=\"preserve\"");
269 printf(" id=\"ttt\" x=\"0\" y=\"0\" style=\"visibility: hidden\">");
270 printf("dyn. Text</text>\n");
271 printf(" <text class=\"tooltip\" xml:space=\"preserve\"");
272 printf(" x=\"-10\" y=\"-10\">dyn. Text</text>\n");
281 * index = 0 -> no index element
282 * index = 1 -> index element -> printed with "+"
284 static void printSVGAttribute(SmiNode *node, SmiNode *tableNode, int index,
285 int modc, SmiModule **modv,
286 float *textYOffset, float *textXOffset)
288 int i, target_exists = 0;
290 char *tooltip, *tooltipDescription, *typeDescription;
291 const char *baseTypeTooltipText = "This is a basetype.";
292 const char *isDefined = " is defined in module ";
294 if ((node->status == SMI_STATUS_DEPRECATED
295 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
296 || (node->status == SMI_STATUS_OBSOLETE
297 && !SHOW_DEPR_OBSOLETE))
302 printf(" id=\"%s\"", node->name);
304 printf(" fill=\"%s\"", printFillColor(node->status));
305 printf(" x=\"%.2f\" y=\"%.2f\">\n",
306 *textXOffset + ATTRSPACESIZE + 4, *textYOffset);
308 *textYOffset += TABLEELEMHEIGHT;
311 rintf(" textLength=\"100\" lengthAdjust=\"spacingAndGlyphs\""); */
314 if (node->access == SMI_ACCESS_NOT_ACCESSIBLE) {
315 printf(" <tspan style=\"text-anchor:middle\">-</tspan>");
317 printf(" <tspan style=\"text-anchor:middle\">+</tspan>");
321 printf("<tspan x=\"%.2f\"", *textXOffset + ATTRSPACESIZE + 8);
322 if (!STATIC_OUTPUT) {
323 if (node->description) {
324 tooltip = (char *)xmalloc(2*strlen(node->description));
325 parseTooltip(node->description, tooltip);
326 printf(" onmousemove=\"ShowTooltipMZ(evt,'%s')\"", tooltip);
327 printf(" onmouseout=\"HideTooltip(evt)\"");
331 for (i=0; i<modc; i++) {
332 if (modv[i] == smiGetNodeModule(node)) {
336 if (!target_exists) {
337 printf(" fill=\"%s\">\n", linkcolor);
338 printf(" <a xlink:href=\"%s", link);
339 for (i=0; i<modc; i++) {
340 printf("&mibs=%s", modv[i]->name);
342 printf("&mibs=%s\">\n", smiGetNodeModule(node)->name);
343 printf(" %s:\n", node->name);
344 printf(" </a></tspan>\n");
346 printf(">%s:</tspan>\n", node->name);
349 printf(">%s:</tspan>\n", node->name);
352 printf(">%s:</tspan>\n", node->name);
356 if (!STATIC_OUTPUT) {
357 if ((typeDescription = algGetTypeDescription(node))) {
358 tooltipDescription = (char *)xmalloc(2*strlen(typeDescription));
359 parseTooltip(typeDescription, tooltipDescription);
360 if (algGetTypeModule(node)) {
361 if ((smiGetNodeModule(node) != smiGetNodeModule(tableNode)) ||
362 (smiGetNodeModule(node) != algGetTypeModule(node))) {
363 length = strlen(tooltipDescription) + 150;
364 tooltip = (char *)xmalloc(length);
365 strcpy(tooltip, algGetTypeName(node));
366 strcat(tooltip, isDefined);
367 strcat(tooltip, algGetTypeModule(node)->name);
368 strcat(tooltip, ":\\n\\n");
369 strcat(tooltip, tooltipDescription);
371 length = strlen(tooltipDescription) + 150;
372 tooltip = (char *)xmalloc(length);
373 strcpy(tooltip, tooltipDescription);
376 length = strlen(tooltipDescription);
377 tooltip = (char *)xmalloc(length);
378 strcpy(tooltip, tooltipDescription);
380 xfree(tooltipDescription);
381 printf(" onmousemove=\"ShowTooltipMZ(evt,'%s')\"", tooltip);
382 printf(" onmouseout=\"HideTooltip(evt)\"");
384 } else if (isBaseType(node)) {
385 length = strlen(baseTypeTooltipText) + 1;
386 tooltip = (char *)xmalloc(length);
387 strcpy(tooltip, baseTypeTooltipText);
388 printf(" onmousemove=\"ShowTooltipMZ(evt,'%s')\"", tooltip);
389 printf(" onmouseout=\"HideTooltip(evt)\"");
393 printf(">%s</tspan>", algGetTypeName(node));
394 switch (node->status) {
395 case SMI_STATUS_DEPRECATED:
396 case SMI_STATUS_OBSOLETE:
397 printf(" (%s)", getStatusString(node->status));
398 case SMI_STATUS_MANDATORY:
399 case SMI_STATUS_OPTIONAL:
400 case SMI_STATUS_CURRENT:
401 case SMI_STATUS_UNKNOWN:
408 * prints the related scalars for a given table
410 static void printSVGRelatedScalars(GraphNode *node, SmiNode *tableNode,
411 int modc, SmiModule **modv,
412 float *textYOffset, float *textXOffset)
416 for (tEdge = graphGetFirstEdgeByNode(graph, node);
418 tEdge = graphGetNextEdgeByNode(graph, tEdge, node)) {
419 if (tEdge->startNode == node &&
420 tEdge->endNode->smiNode->nodekind == SMI_NODEKIND_SCALAR) {
422 printSVGAttribute(tEdge->endNode->smiNode, tableNode, 0,
424 textYOffset, textXOffset);
430 * prints all columns objects of the given node
432 static void printSVGAllColumns(GraphNode *node, SmiNode *tableNode,
433 int modc, SmiModule **modv,
434 float *textYOffset, float *textXOffset)
436 SmiModule *module = NULL;
437 SmiNode *smiNode = NULL;
440 module = smiGetNodeModule(node->smiNode);
442 for (smiNode = smiGetFirstNode(module, SMI_NODEKIND_COLUMN);
444 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_COLUMN)) {
445 ppNode = smiGetParentNode(smiNode);
446 ppNode = smiGetParentNode(ppNode);
448 if (!algIsIndexElement(node->smiNode, smiNode) &&
449 cmpSmiNodes(node->smiNode, ppNode))
450 printSVGAttribute(smiNode, tableNode, 0,
452 textYOffset, textXOffset);
457 * adds the index to an augmenting table (row-element)
459 static void printSVGAugmentIndex(GraphNode *tNode, SmiNode *tableNode,
460 int modc, SmiModule **modv,
461 float *textYOffset, float *textXOffset)
464 SmiElement *smiElement;
466 for (tEdge = graphGetFirstEdgeByNode(graph, tNode);
468 tEdge = graphGetNextEdgeByNode(graph, tEdge, tNode)) {
469 if (tEdge->indexkind == SMI_INDEX_AUGMENT) {
470 for (smiElement = smiGetFirstElement(
471 smiGetFirstChildNode(tEdge->startNode->smiNode));
473 smiElement = smiGetNextElement(smiElement)) {
474 if (!cmpSmiNodes(tNode->smiNode, tEdge->startNode->smiNode)) {
475 printSVGAttribute(smiGetElementNode(smiElement), tableNode,
477 textYOffset, textXOffset);
485 * print "This module doesn't contain any objects"
487 static void printNoObjects()
489 printf(" <rect x=\"10\" y=\"10\" width=\"120\" height=\"40\"");
490 printf(" fill=\"white\" stroke=\"black\"/>\n");
491 printf(" <text x=\"15\" y=\"25\" fill=\"black\">\n");
492 printf(" This module doesn't\n");
493 printf(" </text>\n");
494 printf(" <text x=\"15\" y=\"40\" fill=\"black\">\n");
495 printf(" contain any objects.\n");
496 printf(" </text>\n");
500 * print "This module only contains textual conventions"
502 static void printOnlyTCs()
504 printf(" <rect x=\"10\" y=\"10\" width=\"150\" height=\"40\"");
505 printf(" fill=\"white\" stroke=\"black\"/>\n");
506 printf(" <text x=\"15\" y=\"25\" fill=\"black\">\n");
507 printf(" This module only contains\n");
508 printf(" </text>\n");
509 printf(" <text x=\"15\" y=\"40\" fill=\"black\">\n");
510 printf(" textual conventions.\n");
511 printf(" </text>\n");
515 * create svg-output for the given node
517 static void printSVGObject(GraphNode *node, int *classNr,
518 int modc, SmiModule **modv)
520 SmiElement *smiElement;
521 float textXOffset, textYOffset, xOrigin, yOrigin;
523 char *tooltip, *tooltipTable, *tooltipEntry;
524 const char *blankLine = "\\n-- -- --\\n";
528 xOrigin = node->dia.w/-2;
529 yOrigin = node->dia.h/-2;
530 textYOffset = yOrigin + TABLEHEIGHT + TABLEELEMHEIGHT;
531 textXOffset = xOrigin;
533 printf(" <g transform=\"translate(%.2f,%.2f)\">\n",
534 node->dia.x + node->component->xOffset,
535 node->dia.y + node->component->yOffset);
536 printf(" <rect id=\"%s\"", node->smiNode->name);
537 printf(" x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%.2f\"\n",
538 xOrigin, yOrigin, node->dia.w, node->dia.h);
539 printf(" fill=\"white\" stroke=\"black\"/>\n");
540 if (!STATIC_OUTPUT) {
541 printf(" <rect x=\"%.2f\" y=\"%.2f\" width=\"16\" height=\"16\"",
542 xOrigin + 2, yOrigin + 2);
543 printf(" rx=\"4\" ry=\"4\"");
544 printf(" stroke-width=\"3\" stroke=\"gray\" fill=\"white\"\n");
545 printf(" onmousedown=\"ClickObj(evt)\"");
546 printf(" onclick=\"ClickObj(evt)\"");
547 printf(" onmousemove=\"MoveObj(evt)\"");
548 printf(" onmouseup=\"OutOfObj(evt)\"");
549 printf(" onmouseout=\"OutOfObj(evt)\"/>\n");
551 printf(" <polygon points=\"%.2f %.2f %.2f %.2f\"\n",
552 xOrigin, yOrigin + TABLEHEIGHT,
553 xOrigin + node->dia.w, yOrigin + TABLEHEIGHT);
554 printf(" fill=\"none\" stroke=\"black\"/>\n");
555 printf(" <text x=\"0\" y=\"%.2f\"", yOrigin + 15);
556 printf(" fill=\"%s\"", printFillColor(node->smiNode->status));
557 printf(" style=\"text-anchor:middle; font-weight:bold\"");
559 /* descriptions for the table and the entries */
560 if (!STATIC_OUTPUT) {
561 if (node->smiNode->description) {
562 tooltipTable=(char *)xmalloc(2*strlen(node->smiNode->description));
563 parseTooltip(node->smiNode->description, tooltipTable);
565 if (smiGetFirstChildNode(node->smiNode)->description) {
566 tooltipEntry=(char *)xmalloc(2*strlen(smiGetFirstChildNode(
567 node->smiNode)->description));
568 parseTooltip(smiGetFirstChildNode(node->smiNode)->description,
572 if (node->smiNode->description) {
573 length += strlen(tooltipTable);
575 if (node->smiNode->description
576 && smiGetFirstChildNode(node->smiNode)->description) {
577 length += strlen(blankLine);
579 if (smiGetFirstChildNode(node->smiNode)->description) {
580 length += strlen(tooltipEntry);
582 tooltip = (char *)xmalloc(length);
584 strcpy(tooltip, "\0");
585 if (node->smiNode->description) {
586 strcat(tooltip, tooltipTable);
588 if (node->smiNode->description
589 && smiGetFirstChildNode(node->smiNode)->description) {
590 strcat(tooltip, blankLine);
592 if (smiGetFirstChildNode(node->smiNode)->description) {
593 strcat(tooltip, tooltipEntry);
596 printf(" onmousemove=\"ShowTooltipMZ(evt,'%s')\"", tooltip);
597 printf(" onmouseout=\"HideTooltip(evt)\"");
599 if (node->smiNode->description) {
602 if (smiGetFirstChildNode(node->smiNode)->description) {
609 printf(" %s",smiGetFirstChildNode(node->smiNode)->name);
610 switch (node->smiNode->status) {
611 case SMI_STATUS_DEPRECATED:
612 case SMI_STATUS_OBSOLETE:
613 printf(" (%s)", getStatusString(node->smiNode->status));
614 case SMI_STATUS_MANDATORY:
615 case SMI_STATUS_OPTIONAL:
616 case SMI_STATUS_CURRENT:
617 case SMI_STATUS_UNKNOWN:
624 if (node->smiNode->nodekind == SMI_NODEKIND_TABLE) {
626 if (node->dia.relatedScalars) {
628 printSVGRelatedScalars(node, node->smiNode,
630 &textYOffset, &textXOffset);
632 printf(" <polygon points=\"%.2f %.2f %.2f %.2f\"\n",
634 textYOffset - TABLEELEMHEIGHT + TABLEBOTTOMHEIGHT,
635 xOrigin + node->dia.w,
636 textYOffset - TABLEELEMHEIGHT + TABLEBOTTOMHEIGHT);
637 printf(" fill=\"none\" stroke=\"black\"/>\n");
638 textYOffset += TABLEBOTTOMHEIGHT;
641 if (node->dia.indexObjects) {
643 printSVGAugmentIndex(node, node->smiNode,
645 &textYOffset, &textXOffset);
647 for (smiElement = smiGetFirstElement(
648 smiGetFirstChildNode(node->smiNode));
650 smiElement = smiGetNextElement(smiElement)) {
651 printSVGAttribute(smiGetElementNode(smiElement), node->smiNode,
653 &textYOffset, &textXOffset);
656 printf(" <polygon points=\"%.2f %.2f %.2f %.2f\"\n",
658 textYOffset - TABLEELEMHEIGHT + TABLEBOTTOMHEIGHT,
659 xOrigin + node->dia.w,
660 textYOffset - TABLEELEMHEIGHT + TABLEBOTTOMHEIGHT);
661 printf(" fill=\"none\" stroke=\"black\"/>\n");
662 textYOffset += TABLEBOTTOMHEIGHT;
666 if (PRINT_DETAILED_ATTR) {
667 printSVGAllColumns(node, node->smiNode,
669 &textYOffset, &textXOffset);
677 * prints a group of scalars denoted by group
679 static void printSVGGroup(int group, int *classNr,
680 int modc, SmiModule **modv)
683 float textXOffset, textYOffset, xOrigin, yOrigin;
685 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
686 if (tNode->group == group) break;
691 xOrigin = tNode->dia.w/-2;
692 yOrigin = tNode->dia.h/-2;
693 textYOffset = yOrigin + TABLEHEIGHT + TABLEELEMHEIGHT;
694 textXOffset = xOrigin;
696 printf(" <g transform=\"translate(%.2f,%.2f)\">\n",
697 tNode->dia.x + tNode->component->xOffset,
698 tNode->dia.y + tNode->component->yOffset);
699 printf(" <rect id=\"%s\"",
700 smiGetParentNode(tNode->smiNode)->name);
701 printf(" x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%.2f\"\n",
702 xOrigin, yOrigin, tNode->dia.w, tNode->dia.h);
703 printf(" fill=\"white\" stroke=\"black\"/>\n");
704 if (!STATIC_OUTPUT) {
705 printf(" <rect x=\"%.2f\" y=\"%.2f\" width=\"16\" height=\"16\"",
706 xOrigin + 2, yOrigin + 2);
707 printf(" rx=\"4\" ry=\"4\"");
708 printf(" stroke-width=\"3\" stroke=\"gray\" fill=\"white\"\n");
709 printf(" onmousedown=\"ClickObj(evt)\"");
710 printf(" onclick=\"ClickObj(evt)\"");
711 printf(" onmousemove=\"MoveObj(evt)\"");
712 printf(" onmouseup=\"OutOfObj(evt)\"");
713 printf(" onmouseout=\"OutOfObj(evt)\"/>\n");
715 printf(" <polygon points=\"%.2f %.2f %.2f %.2f\"\n",
716 xOrigin, yOrigin + TABLEHEIGHT,
717 xOrigin + tNode->dia.w, yOrigin + TABLEHEIGHT);
718 printf(" fill=\"none\" stroke=\"black\"/>\n");
719 printf(" <text x=\"0\" y=\"%.2f\"", yOrigin + 15);
720 printf(" fill=\"%s\"",
721 printFillColor(smiGetParentNode(tNode->smiNode)->status));
722 printf(" style=\"text-anchor:middle; font-weight:bold\">\n");
723 /* groups don't seem to have a description. */
724 printf(" %s", smiGetParentNode(tNode->smiNode)->name);
725 switch (smiGetParentNode(tNode->smiNode)->status) {
726 case SMI_STATUS_DEPRECATED:
727 case SMI_STATUS_OBSOLETE:
729 getStatusString(smiGetParentNode(tNode->smiNode)->status));
730 case SMI_STATUS_MANDATORY:
731 case SMI_STATUS_OPTIONAL:
732 case SMI_STATUS_CURRENT:
733 case SMI_STATUS_UNKNOWN:
740 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
741 if (tNode->group == group) {
742 printSVGAttribute(tNode->smiNode, tNode->smiNode, 0,
744 &textYOffset, &textXOffset);
751 static void calculateIntersectionPoints(GraphEdge *tEdge)
754 const float PI = acos(-1);
756 /* calculate intersection of edge and startNode */
757 alpha = atan2(tEdge->startNode->dia.y-tEdge->endNode->dia.y,
758 tEdge->startNode->dia.x-tEdge->endNode->dia.x);
759 beta = atan2(tEdge->startNode->dia.h, tEdge->startNode->dia.w);
763 || (alpha > PI-beta && alpha < PI+beta)
764 || alpha > 2*PI-beta) {
765 /* intersection at left or right border */
766 if (tEdge->startNode->dia.x < tEdge->endNode->dia.x) {
767 tEdge->dia.startX = tEdge->startNode->dia.x +
768 tEdge->startNode->dia.w/2;
770 tEdge->dia.startX = tEdge->startNode->dia.x -
771 tEdge->startNode->dia.w/2;
773 if (tEdge->startNode->dia.y < tEdge->endNode->dia.y) {
774 tEdge->dia.startY = tEdge->startNode->dia.y +
775 fabsf(tEdge->startNode->dia.w*tan(alpha)/2);
777 tEdge->dia.startY = tEdge->startNode->dia.y -
778 fabsf(tEdge->startNode->dia.w*tan(alpha)/2);
781 /* intersection at top or bottom border */
782 if (tEdge->startNode->dia.y < tEdge->endNode->dia.y) {
783 tEdge->dia.startY = tEdge->startNode->dia.y +
784 tEdge->startNode->dia.h/2;
786 tEdge->dia.startY = tEdge->startNode->dia.y -
787 tEdge->startNode->dia.h/2;
789 if (tEdge->startNode->dia.x < tEdge->endNode->dia.x) {
790 tEdge->dia.startX = tEdge->startNode->dia.x +
791 fabsf(tEdge->startNode->dia.h/(2*tan(alpha)));
793 tEdge->dia.startX = tEdge->startNode->dia.x -
794 fabsf(tEdge->startNode->dia.h/(2*tan(alpha)));
798 /* calculate intersection of edge and endNode */
799 alpha = atan2(tEdge->startNode->dia.y-tEdge->endNode->dia.y,
800 tEdge->startNode->dia.x-tEdge->endNode->dia.x);
801 beta = atan2(tEdge->endNode->dia.h, tEdge->endNode->dia.w);
805 || (alpha > PI-beta && alpha < PI+beta)
806 || alpha > 2*PI-beta) {
807 /* intersection at left or right border */
808 if (tEdge->startNode->dia.x > tEdge->endNode->dia.x) {
809 tEdge->dia.endX = tEdge->endNode->dia.x + tEdge->endNode->dia.w/2;
811 tEdge->dia.endX = tEdge->endNode->dia.x - tEdge->endNode->dia.w/2;
813 if (tEdge->startNode->dia.y > tEdge->endNode->dia.y) {
814 tEdge->dia.endY = tEdge->endNode->dia.y +
815 fabsf(tEdge->endNode->dia.w*tan(alpha)/2);
817 tEdge->dia.endY = tEdge->endNode->dia.y -
818 fabsf(tEdge->endNode->dia.w*tan(alpha)/2);
821 /* intersection at top or bottom border */
822 if (tEdge->startNode->dia.y > tEdge->endNode->dia.y) {
823 tEdge->dia.endY = tEdge->endNode->dia.y + tEdge->endNode->dia.h/2;
825 tEdge->dia.endY = tEdge->endNode->dia.y - tEdge->endNode->dia.h/2;
827 if (tEdge->startNode->dia.x > tEdge->endNode->dia.x) {
828 tEdge->dia.endX = tEdge->endNode->dia.x +
829 fabsf(tEdge->endNode->dia.h/(2*tan(alpha)));
831 tEdge->dia.endX = tEdge->endNode->dia.x -
832 fabsf(tEdge->endNode->dia.h/(2*tan(alpha)));
837 static void printSVGDependency(GraphEdge *tEdge)
841 calculateIntersectionPoints(tEdge);
843 /* print text upside down, if angle is between 180° and 360° */
844 if (tEdge->startNode->dia.x > tEdge->endNode->dia.x)
847 printf(" <path id=\"%s-%s\"\n",
848 tEdge->startNode->smiNode->name,
849 tEdge->endNode->smiNode->name);
851 printf(" d=\"M %.2f %.2f %.2f %.2f\"\n",
852 tEdge->dia.startX + tEdge->startNode->component->xOffset,
853 tEdge->dia.startY + tEdge->startNode->component->yOffset,
854 tEdge->dia.endX + tEdge->endNode->component->xOffset,
855 tEdge->dia.endY + tEdge->endNode->component->yOffset);
857 printf(" d=\"M %.2f %.2f %.2f %.2f\"\n",
858 tEdge->dia.endX + tEdge->endNode->component->xOffset,
859 tEdge->dia.endY + tEdge->endNode->component->yOffset,
860 tEdge->dia.startX + tEdge->startNode->component->xOffset,
861 tEdge->dia.startY + tEdge->startNode->component->yOffset);
863 printf(" stroke-dasharray=\"10, 10\" stroke=\"black\"");
865 printf(" marker-end=\"url(#arrowend)\"/>\n");
867 printf(" marker-start=\"url(#arrowstart)\"/>\n");
872 * Aggregation is a special case of the association.
873 * If aggregate = 1 it is an aggregation if 0 it is an association.
875 static void printSVGAssociation(GraphEdge *tEdge, int aggregate)
879 if (aggregate > 1) aggregate = 1;
880 if (aggregate < 0) aggregate = 0;
882 calculateIntersectionPoints(tEdge);
884 /* expands should have cardinalities 1 * */
885 if (tEdge->indexkind==SMI_INDEX_EXPAND)
886 tEdge->cardinality = GRAPH_CARD_ONE_TO_MANY;
888 /* print text upside down, if angle is between 180° and 360° */
889 if (tEdge->startNode->dia.x > tEdge->endNode->dia.x)
893 printf(" <path id=\"%s-%s\"\n",
894 tEdge->startNode->smiNode->name,
895 tEdge->endNode->smiNode->name);
897 printf(" d=\"M %.2f %.2f %.2f %.2f\"\n",
898 tEdge->dia.startX + tEdge->startNode->component->xOffset,
899 tEdge->dia.startY + tEdge->startNode->component->yOffset,
900 tEdge->dia.endX + tEdge->endNode->component->xOffset,
901 tEdge->dia.endY + tEdge->endNode->component->yOffset);
903 printf(" d=\"M %.2f %.2f %.2f %.2f\"\n",
904 tEdge->dia.endX + tEdge->endNode->component->xOffset,
905 tEdge->dia.endY + tEdge->endNode->component->yOffset,
906 tEdge->dia.startX + tEdge->startNode->component->xOffset,
907 tEdge->dia.startY + tEdge->startNode->component->yOffset);
909 printf(" stroke=\"black\"");
910 if (tEdge->indexkind==SMI_INDEX_AUGMENT ||
911 tEdge->indexkind==SMI_INDEX_SPARSE ||
912 tEdge->indexkind==SMI_INDEX_EXPAND) {
914 printf(" marker-start=\"url(#arrowstart)\"");
916 printf(" marker-end=\"url(#arrowend)\"");
918 } else if (tEdge->indexkind==SMI_INDEX_REORDER) {
919 printf(" marker-start=\"url(#arrowstart)\"");
920 printf(" marker-end=\"url(#arrowend)\"");
924 /* edges without labels are finished here */
925 if (tEdge->cardinality==GRAPH_CARD_UNKNOWN)
929 printf(" <text text-anchor=\"middle\">\n");
930 printf(" <textPath xlink:href=\"#%s-%s\"",
931 tEdge->startNode->smiNode->name, tEdge->endNode->smiNode->name);
933 printf(" startOffset=\"10%%\">\n");
935 printf(" startOffset=\"90%%\">\n");
937 switch (tEdge->cardinality) {
938 case GRAPH_CARD_ZERO_TO_ONE:
939 case GRAPH_CARD_ZERO_TO_MANY:
942 case GRAPH_CARD_ONE_TO_ONE:
943 case GRAPH_CARD_ONE_TO_MANY:
944 case GRAPH_CARD_ONE_TO_ZERO_OR_ONE:
947 case GRAPH_CARD_UNKNOWN:
950 printf("</textPath>\n");
951 printf(" </text>\n");
953 if (tEdge->indexkind==SMI_INDEX_AUGMENT ||
954 tEdge->indexkind==SMI_INDEX_SPARSE ||
955 tEdge->indexkind==SMI_INDEX_REORDER ||
956 tEdge->indexkind==SMI_INDEX_EXPAND) {
957 printf(" <text text-anchor=\"middle\">\n");
958 printf(" <textPath xlink:href=\"#%s-%s\" startOffset=\"50%%\">\n",
959 tEdge->startNode->smiNode->name, tEdge->endNode->smiNode->name);
961 switch(tEdge->indexkind) {
962 case SMI_INDEX_AUGMENT:
965 case SMI_INDEX_SPARSE:
966 printf(" sparsly augments");
968 case SMI_INDEX_REORDER:
971 case SMI_INDEX_EXPAND:
974 case SMI_INDEX_UNKNOWN:
975 case SMI_INDEX_INDEX:
978 if (tEdge->indexkind==SMI_INDEX_AUGMENT ||
979 tEdge->indexkind==SMI_INDEX_SPARSE ||
980 tEdge->indexkind==SMI_INDEX_REORDER ||
981 tEdge->indexkind==SMI_INDEX_EXPAND) {
982 printf("</textPath>\n");
983 printf(" </text>\n");
986 printf(" <text text-anchor=\"middle\">\n");
987 printf(" <textPath xlink:href=\"#%s-%s\"",
988 tEdge->startNode->smiNode->name, tEdge->endNode->smiNode->name);
990 printf(" startOffset=\"90%%\">\n");
992 printf(" startOffset=\"10%%\">\n");
994 switch (tEdge->cardinality) {
995 case GRAPH_CARD_ONE_TO_ONE:
996 case GRAPH_CARD_ZERO_TO_ONE:
999 case GRAPH_CARD_ONE_TO_MANY:
1000 case GRAPH_CARD_ZERO_TO_MANY:
1003 case GRAPH_CARD_ONE_TO_ZERO_OR_ONE:
1006 case GRAPH_CARD_UNKNOWN:
1009 printf("</textPath>\n");
1010 printf(" </text>\n");
1013 static void printSVGConnection(GraphEdge *tEdge)
1015 switch (tEdge->connection) {
1016 case GRAPH_CON_UNKNOWN:
1018 case GRAPH_CON_AGGREGATION : /* never used??? */
1019 printSVGAssociation(tEdge,1);
1021 case GRAPH_CON_DEPENDENCY :
1022 printSVGDependency(tEdge);
1024 case GRAPH_CON_ASSOCIATION :
1025 printSVGAssociation(tEdge,0);
1031 * Prints the title of the SVG output file (Modulename and smidump version).
1033 * Print title somewhere into the SVG.
1034 * Make size of SVG configurable.
1036 static void printSVGHeaderAndTitle(int modc, SmiModule **modv,
1037 int miCount, int idCount,
1038 float xMin, float yMin,
1039 float xMax, float yMax)
1044 const char *s11 = "Conceptual model of ";
1045 const char *s12 = "- generated by smidump " SMI_VERSION_STRING;
1048 scale = max((xMax-xMin)/CANVASWIDTH,(yMax-yMin)/CANVASHEIGHT);
1051 * Calculate the length of the string...
1054 length1 = strlen(s11) + strlen(s12) + 1;
1055 for (i = 0; i < modc; i++) {
1056 length1 += strlen(modv[i]->name) + 1;
1060 * ... before allocating a buffer and putting the string together.
1063 note1 = xmalloc(length1);
1065 for (i = 0; i < modc; i++) {
1066 strcat(note1, modv[i]->name);
1071 printf("<?xml version=\"1.0\"?>\n");
1072 printf("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n");
1073 printf(" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
1074 printf("<svg preserveAspectRatio=\"xMinYMin meet\"\n");
1075 printf(" width=\"%i\" height=\"%i\" viewBox=\"%.2f %.2f %.2f %.2f\"\n",
1076 CANVASWIDTH, CANVASHEIGHT, xMin, yMin, xMax-xMin, yMax-yMin);
1077 printf(" version=\"1.1\"\n");
1078 printf(" xmlns=\"http://www.w3.org/2000/svg\"\n");
1079 printf(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"");
1081 printf("\n onload=\"init(evt)\" onzoom=\"ZoomControl()\"");
1084 if (!STATIC_OUTPUT) {
1085 /* css-stylesheet for the tooltip-text */
1086 printf("<style type=\"text/css\">\n<![CDATA[\ntext.tooltip {\n");
1087 printf(" font-family: \"Courier New\", Courier, monospace;\n}\n");
1088 printf("]]>\n</style>\n\n");
1090 /* the ecma-script for the tooltip */
1091 /* and the folding of the module information */
1092 /* and the colorizing of the text */
1093 printf("<script type=\"text/ecmascript\">\n<![CDATA[\n");
1094 /* print the script from the included file */
1095 /* FIXME calculate things dynamically: */
1096 /* * maximal number of lines for the tooltip. */
1097 printf(code, idCount, idCount, idCount, idCount,
1098 scale, xMin, scale, yMin, DYN_TEXT, DYN_TEXT,
1099 miCount, miCount, miCount,
1100 idCount, idCount, idCount, idCount, idCount, idCount);
1101 printf("// ]]>\n</script>\n\n");
1104 printf(" <title>%s</title>\n", note1);
1106 /* definitions for the arrowheads */
1107 printf(" <defs>\n");
1108 printf(" <marker id=\"arrowstart\" markerWidth=\"12\"");
1109 printf(" markerHeight=\"8\" refX=\"0\" refY=\"4\" orient=\"auto\">\n");
1110 printf(" <line x1=\"12\" y1=\"0\" x2=\"0\" y2=\"4\"");
1111 printf(" fill=\"none\" stroke=\"black\"/>\n");
1112 printf(" <line x1=\"0\" y1=\"4\" x2=\"12\" y2=\"8\"");
1113 printf(" fill=\"none\" stroke=\"black\"/>\n");
1114 printf(" </marker>\n");
1115 printf(" <marker id=\"arrowend\" markerWidth=\"12\"");
1116 printf(" markerHeight=\"8\" refX=\"12\" refY=\"4\" orient=\"auto\">\n");
1117 printf(" <line x1=\"0\" y1=\"0\" x2=\"12\" y2=\"4\"");
1118 printf(" fill=\"none\" stroke=\"black\"/>\n");
1119 printf(" <line x1=\"12\" y1=\"4\" x2=\"0\" y2=\"8\"");
1120 printf(" fill=\"none\" stroke=\"black\"/>\n");
1121 printf(" </marker>\n");
1122 printf(" </defs>\n\n");
1128 * Calculates the size of a given node for the UML representation.
1130 * FIXME this algorithm may work good for a monospace-font. we have some
1131 * problems with the proportional-font. :-(
1133 static GraphNode *calcNodeSize(GraphNode *node, int *idCount)
1136 SmiNode *tNode,*ppNode;
1137 SmiElement *smiElement;
1142 if (node->smiNode->nodekind == SMI_NODEKIND_SCALAR) return node;
1145 node->dia.x = (float) rand();
1146 node->dia.y = (float) rand();
1147 node->dia.x /= (float) RAND_MAX;
1148 node->dia.y /= (float) RAND_MAX;
1149 node->dia.w = strlen(node->smiNode->name) * HEADFONTSIZETABLE
1150 + HEADSPACESIZETABLE;
1151 node->dia.h = TABLEHEIGHT + TABLEBOTTOMHEIGHT;
1153 lastHeight = node->dia.h;
1155 for (tEdge = graphGetFirstEdgeByNode(graph,node);
1157 tEdge = graphGetNextEdgeByNode(graph, tEdge, node)) {
1158 if (tEdge->startNode == node &&
1159 tEdge->endNode->smiNode->nodekind == SMI_NODEKIND_SCALAR) {
1161 tNode = tEdge->endNode->smiNode;
1163 if ((tNode->status == SMI_STATUS_DEPRECATED
1164 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
1165 || (tNode->status == SMI_STATUS_OBSOLETE
1166 && !SHOW_DEPR_OBSOLETE))
1169 stringlen = strlen(tNode->name) + strlen(algGetTypeName(tNode)) +2;
1170 switch (tNode->status) {
1171 case SMI_STATUS_DEPRECATED:
1172 case SMI_STATUS_OBSOLETE:
1173 stringlen += strlen(getStatusString(tNode->status)) +3;
1174 case SMI_STATUS_MANDATORY:
1175 case SMI_STATUS_OPTIONAL:
1176 case SMI_STATUS_CURRENT:
1177 case SMI_STATUS_UNKNOWN:
1180 node->dia.w = max(node->dia.w, stringlen
1182 + ATTRSPACESIZE + 5);
1183 node->dia.h += TABLEELEMHEIGHT;
1187 if (node->dia.h > lastHeight) {
1188 node->dia.relatedScalars = 1;
1189 node->dia.h += TABLEBOTTOMHEIGHT;
1192 lastHeight = node->dia.h;
1194 for (tEdge = graphGetFirstEdgeByNode(graph,node);
1196 tEdge = graphGetNextEdgeByNode(graph, tEdge, node)) {
1197 if (tEdge->indexkind == SMI_INDEX_AUGMENT) {
1198 for (smiElement = smiGetFirstElement(
1199 smiGetFirstChildNode(tEdge->startNode->smiNode));
1201 smiElement = smiGetNextElement(smiElement)) {
1202 if (!cmpSmiNodes(node->smiNode, tEdge->startNode->smiNode)) {
1204 tNode = smiGetElementNode(smiElement);
1206 if ((tNode->status == SMI_STATUS_DEPRECATED
1207 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
1208 || (tNode->status == SMI_STATUS_OBSOLETE
1209 && !SHOW_DEPR_OBSOLETE))
1212 stringlen = strlen(tNode->name)
1213 + strlen(algGetTypeName(tNode)) +3;
1214 switch (tNode->status) {
1215 case SMI_STATUS_DEPRECATED:
1216 case SMI_STATUS_OBSOLETE:
1217 stringlen += strlen(getStatusString(tNode->status)) +3;
1218 case SMI_STATUS_MANDATORY:
1219 case SMI_STATUS_OPTIONAL:
1220 case SMI_STATUS_CURRENT:
1221 case SMI_STATUS_UNKNOWN:
1224 node->dia.w = max(node->dia.w, stringlen
1226 + ATTRSPACESIZE + 5);
1227 node->dia.h += TABLEELEMHEIGHT;
1234 for (smiElement = smiGetFirstElement(
1235 smiGetFirstChildNode(node->smiNode));
1237 smiElement = smiGetNextElement(smiElement)) {
1239 tNode = smiGetElementNode(smiElement);
1241 if ((tNode->status == SMI_STATUS_DEPRECATED
1242 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
1243 || (tNode->status == SMI_STATUS_OBSOLETE
1244 && !SHOW_DEPR_OBSOLETE))
1247 stringlen = strlen(tNode->name) + strlen(algGetTypeName(tNode)) +3;
1248 switch (tNode->status) {
1249 case SMI_STATUS_DEPRECATED:
1250 case SMI_STATUS_OBSOLETE:
1251 stringlen += strlen(getStatusString(tNode->status)) +3;
1252 case SMI_STATUS_MANDATORY:
1253 case SMI_STATUS_OPTIONAL:
1254 case SMI_STATUS_CURRENT:
1255 case SMI_STATUS_UNKNOWN:
1258 node->dia.w = max(node->dia.w, stringlen
1260 + ATTRSPACESIZE + 5);
1261 node->dia.h += TABLEELEMHEIGHT;
1263 if (node->dia.h > lastHeight) {
1264 node->dia.indexObjects = 1;
1265 node->dia.h += TABLEBOTTOMHEIGHT;
1269 if (PRINT_DETAILED_ATTR && node->smiNode->nodekind == SMI_NODEKIND_TABLE) {
1270 module = smiGetNodeModule(node->smiNode);
1272 for (tNode = smiGetFirstNode(module, SMI_NODEKIND_COLUMN);
1274 tNode = smiGetNextNode(tNode, SMI_NODEKIND_COLUMN)) {
1275 ppNode = smiGetParentNode(tNode);
1276 ppNode = smiGetParentNode(ppNode);
1278 if (cmpSmiNodes(node->smiNode, ppNode)) {
1282 if ((tNode->status == SMI_STATUS_DEPRECATED
1283 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
1284 || (tNode->status == SMI_STATUS_OBSOLETE
1285 && !SHOW_DEPR_OBSOLETE))
1288 typeName = algGetTypeName(tNode);
1289 len = strlen(tNode->name) + (typeName ? strlen(typeName)+2 : 1);
1290 switch (tNode->status) {
1291 case SMI_STATUS_DEPRECATED:
1292 case SMI_STATUS_OBSOLETE:
1293 len += strlen(getStatusString(tNode->status)) +3;
1294 case SMI_STATUS_MANDATORY:
1295 case SMI_STATUS_OPTIONAL:
1296 case SMI_STATUS_CURRENT:
1297 case SMI_STATUS_UNKNOWN:
1300 node->dia.w = max(node->dia.w, len
1302 + ATTRSPACESIZE + 5);
1303 node->dia.h += TABLEELEMHEIGHT;
1313 * Calculates the size of a group-node for the UML representation.
1315 static GraphNode *calcGroupSize(int group, int *idCount)
1317 GraphNode *calcNode, *node;
1321 for (calcNode = graph->nodes; calcNode; calcNode = calcNode->nextPtr) {
1322 if (calcNode->group == group) break;
1325 if (!calcNode) return NULL;
1328 calcNode->dia.w = strlen(calcNode->smiNode->name) * HEADFONTSIZETABLE
1329 + HEADSPACESIZETABLE;
1330 calcNode->dia.h = TABLEHEIGHT + TABLEBOTTOMHEIGHT;
1332 for (node = graph->nodes; node; node = node->nextPtr) {
1333 if (node->group == group) {
1334 tNode = node->smiNode;
1336 if ((tNode->status == SMI_STATUS_DEPRECATED
1337 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
1338 || (tNode->status == SMI_STATUS_OBSOLETE
1339 && !SHOW_DEPR_OBSOLETE))
1342 stringlen = strlen(tNode->name) + strlen(algGetTypeName(tNode)) +2;
1343 switch (tNode->status) {
1344 case SMI_STATUS_DEPRECATED:
1345 case SMI_STATUS_OBSOLETE:
1346 stringlen += strlen(getStatusString(tNode->status)) +3;
1347 case SMI_STATUS_MANDATORY:
1348 case SMI_STATUS_OPTIONAL:
1349 case SMI_STATUS_CURRENT:
1350 case SMI_STATUS_UNKNOWN:
1353 calcNode->dia.w = max(calcNode->dia.w, stringlen
1355 + ATTRSPACESIZE + 5);
1356 calcNode->dia.h += TABLEELEMHEIGHT;
1365 /* ------------------------------------------------------------------------- */
1369 static int invalidType(SmiBasetype basetype)
1371 return (basetype == SMI_BASETYPE_FLOAT32)
1372 || (basetype == SMI_BASETYPE_FLOAT64)
1373 || (basetype == SMI_BASETYPE_FLOAT128);
1376 static int countTCs(int modc, SmiModule **modv)
1379 int i, invalid, j = 0;
1381 for (i=0; i<modc; i++) {
1382 for(smiType = smiGetFirstType(modv[i]);
1383 smiType; smiType = smiGetNextType(smiType)) {
1384 if (smiType->status != SMI_STATUS_UNKNOWN) {
1385 invalid = invalidType(smiType->basetype);
1397 static void calcModuleIdentityCount(int modc, SmiModule **modv,
1398 int *miCount, int modId[])
1402 SmiRevision *smiRevision;
1404 /* MODULE-IDENTITY */
1406 for (i = 0; i < modc; i++) {
1408 smiNode = smiGetModuleIdentityNode(modv[i]);
1410 /* name of the module */
1413 /* revision history of the module */
1414 smiRevision = smiGetFirstRevision(modv[i]);
1419 smiRevision = smiGetNextRevision(smiRevision)) {
1427 static void calcNotificationTypeCount(int modc, SmiModule **modv,
1428 int *miCount, int nType[])
1433 /* NOTIFICATION-TYPE */
1435 for (i = 0; i < modc; i++) {
1437 smiNode = smiGetModuleIdentityNode(modv[i]);
1439 /* name of the module */
1441 /* name of the notification */
1442 for (smiNode = smiGetFirstNode(modv[i], SMI_NODEKIND_NOTIFICATION);
1444 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NOTIFICATION)) {
1445 if ((smiNode->status == SMI_STATUS_DEPRECATED
1446 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
1447 || (smiNode->status == SMI_STATUS_OBSOLETE
1448 && !SHOW_DEPR_OBSOLETE))
1457 static void calcObjectGroupCount(int modc, SmiModule **modv,
1458 int *miCount, int oGroup[])
1465 for (i = 0; i < modc; i++) {
1467 smiNode = smiGetModuleIdentityNode(modv[i]);
1469 /* name of the module */
1471 /* name of the group */
1472 for (smiNode = smiGetFirstNode(modv[i], SMI_NODEKIND_GROUP);
1474 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_GROUP)) {
1475 if (!isObjectGroup(smiNode))
1477 if ((smiNode->status == SMI_STATUS_DEPRECATED
1478 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
1479 || (smiNode->status == SMI_STATUS_OBSOLETE
1480 && !SHOW_DEPR_OBSOLETE))
1489 static void calcNotificationGroupCount(int modc, SmiModule **modv,
1490 int *miCount, int nGroup[])
1495 /* NOTIFICATION-GROUP */
1497 for (i = 0; i < modc; i++) {
1499 smiNode = smiGetModuleIdentityNode(modv[i]);
1501 /* name of the module */
1503 /* name of the group */
1504 for (smiNode = smiGetFirstNode(modv[i], SMI_NODEKIND_GROUP);
1506 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_GROUP)) {
1507 if (!isNotificationGroup(smiNode))
1509 if ((smiNode->status == SMI_STATUS_DEPRECATED
1510 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
1511 || (smiNode->status == SMI_STATUS_OBSOLETE
1512 && !SHOW_DEPR_OBSOLETE))
1521 static void calcModuleComplianceCount(int modc, SmiModule **modv,
1522 int *miCount, int mCompl[])
1528 SmiNode *smiNode, *smiNode2;
1529 SmiModule *smiModule2;
1530 SmiElement *smiElement;
1531 SmiOption *smiOption;
1532 SmiRefinement *smiRefinement;
1534 /* MODULE-COMPLIANCE */
1536 for (i = 0; i < modc; i++) {
1538 smiNode = smiGetModuleIdentityNode(modv[i]);
1540 /* name of the module */
1542 /* name of the compliance */
1543 for (smiNode = smiGetFirstNode(modv[i], SMI_NODEKIND_COMPLIANCE);
1545 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_COMPLIANCE)) {
1546 if ((smiNode->status == SMI_STATUS_DEPRECATED
1547 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
1548 || (smiNode->status == SMI_STATUS_OBSOLETE
1549 && !SHOW_DEPR_OBSOLETE))
1553 /* modules for the compliance */
1554 done = xstrdup("+");
1555 for (module = modv[i]->name; module; ) {
1556 /* name of the module */
1558 /* mandatory groups */
1561 for (smiOption = smiGetFirstOption(smiNode); smiOption;
1562 smiOption = smiGetNextOption(smiOption)) {
1563 smiNode2 = smiGetOptionNode(smiOption);
1564 smiModule2 = smiGetNodeModule(smiNode2);
1565 if (!strcmp(smiModule2->name, module)) {
1570 for (smiRefinement = smiGetFirstRefinement(smiNode);
1572 smiRefinement = smiGetNextRefinement(smiRefinement)) {
1573 smiNode2 = smiGetRefinementNode(smiRefinement);
1574 smiModule2 = smiGetNodeModule(smiNode2);
1575 if (!strcmp(smiModule2->name, module)) {
1579 /* find next module */
1580 done = xrealloc(done,
1581 strlen(done)+strlen(module)+2*sizeof(char));
1582 strcat(done, module);
1585 for (smiElement = smiGetFirstElement(smiNode);
1587 smiElement = smiGetNextElement(smiElement)) {
1588 sprintf(s, "+%s+", smiGetNodeModule(smiGetElementNode(
1589 smiElement))->name);
1590 if ((!strstr(done, s))) {
1591 module = smiGetNodeModule(smiGetElementNode(
1604 * calculate the number of entries in the module-information-section.
1605 * headings for empty sections are counted here, but they are omitted
1606 * in the svg, so the calculated number is an upper bound. the maximal
1607 * size of this gap is 4*(modc+1). this may be considered as a bug.
1609 static void prepareModInfo(int modc, SmiModule **modv, int *miCount,
1610 int modId[], int nType[], int oGroup[], int nGroup[], int mCompl[])
1612 calcModuleIdentityCount(modc, modv, miCount, modId);
1613 calcNotificationTypeCount(modc, modv, miCount, nType);
1614 calcObjectGroupCount(modc, modv, miCount, oGroup);
1615 calcNotificationGroupCount(modc, modv, miCount, nGroup);
1616 calcModuleComplianceCount(modc, modv, miCount, mCompl);
1620 /* ------------------------------------------------------------------------- */
1622 static void populateMarkupList(SmiNode *smiNode, int *miNr,
1623 StringListElem markupList[], int miCount)
1626 SmiElement *smiElement;
1627 StringListElem *lastElem;
1628 StringListElem *tElem;
1629 StringListElem *newElem;
1630 StringListElem *cloneElem;
1632 markupList[*miNr].miElem = smiNode->name;
1633 markupList[*miNr].status = smiNode->status;
1634 markupList[*miNr].nextPtr = NULL;
1636 for (smiElement = smiGetFirstElement(smiNode); smiElement;
1637 smiElement = smiGetNextElement(smiElement)) {
1639 newElem = xmalloc(sizeof(StringListElem));
1640 memset(newElem, 0, sizeof(StringListElem));
1641 newElem->miElem = smiGetElementNode(smiElement)->name;
1642 newElem->status = smiGetElementNode(smiElement)->status;
1644 if (markupList[*miNr].nextPtr == NULL) {
1645 markupList[*miNr].nextPtr = newElem;
1647 for (tElem = markupList[*miNr].nextPtr;
1648 tElem; tElem = tElem->nextPtr) {
1651 lastElem->nextPtr = newElem;
1653 if (isNotificationGroup(smiNode)) {
1654 for (i=0; i<miCount; i++) {
1655 if (markupList[i].miElem == NULL)
1657 if (markupList[i].miElem != newElem->miElem)
1659 for (tElem = markupList[i].nextPtr;
1660 tElem; tElem = tElem->nextPtr) {
1661 cloneElem = xmalloc(sizeof(StringListElem));
1662 memcpy(cloneElem, tElem, sizeof(StringListElem));
1663 newElem->nextPtr = cloneElem;
1664 newElem = newElem->nextPtr;
1671 static void printInformationNode(SmiNode *smiNode,
1672 float *x, float *y, int *miNr,
1673 StringListElem markupList[], int miCount)
1677 SmiElement *smiElement;
1678 StringListElem *tElem;
1680 printf(" <g id=\"MI%i\" transform=\"translate", *miNr);
1681 printf("(%.2f,%.2f)\">\n", *x, *y);
1682 printf(" <text id=\"%s\"", smiNode->name);
1683 printf(" fill=\"%s\"", printFillColor(smiNode->status));
1685 if (!STATIC_OUTPUT) {
1686 smiElement = smiGetFirstElement(smiNode);
1687 if (smiElement || smiNode->description) {
1688 printf(" onmousemove=\"");
1690 if (smiNode->description) {
1691 tooltip = (char *)xmalloc(2*strlen(smiNode->description));
1692 parseTooltip(smiNode->description, tooltip);
1693 printf("ShowTooltipMZ(evt,'%s')", tooltip);
1696 if (smiElement && smiNode->description) {
1699 for (j = 0; smiElement;
1700 j++, smiElement = smiGetNextElement(smiElement)) {
1704 printf("colorText('%s','red')",
1705 smiGetElementNode(smiElement)->name);
1706 if (isNotificationGroup(smiNode)) {
1707 /* parse markupList */
1708 for (k=0; k<miCount; k++) {
1709 if (markupList[k].miElem == NULL)
1711 if (markupList[k].miElem !=
1712 smiGetElementNode(smiElement)->name)
1714 for (tElem = markupList[k].nextPtr;
1715 tElem; tElem = tElem->nextPtr) {
1716 printf(";colorText('%s','red')", tElem->miElem);
1721 if (j || smiNode->description) {
1725 smiElement = smiGetFirstElement(smiNode);
1727 printf(" onclick=\"setStatus(evt,'red','%s')",
1728 printFillColor(smiNode->status));
1730 for (j = 0; smiElement;
1731 j++, smiElement = smiGetNextElement(smiElement)) {
1732 printf(";changeColor(evt,'%s','red','%s')",
1733 smiGetElementNode(smiElement)->name,
1734 printFillColor(smiGetElementNode(smiElement)->status));
1735 if (isNotificationGroup(smiNode)) {
1736 /* parse markupList */
1737 for (k=0; k<miCount; k++) {
1738 if (markupList[k].miElem == NULL)
1740 if (markupList[k].miElem !=
1741 smiGetElementNode(smiElement)->name)
1743 for (tElem = markupList[k].nextPtr;
1744 tElem; tElem = tElem->nextPtr) {
1745 printf(";changeColor(evt,'%s','red','%s')",
1746 tElem->miElem, printFillColor(tElem->status));
1755 smiElement = smiGetFirstElement(smiNode);
1756 if (smiElement || smiNode->description) {
1757 printf(" onmouseout=\"");
1759 if (smiNode->description) {
1760 printf("HideTooltip(evt)");
1762 if (smiElement && smiNode->description) {
1765 for (j = 0; smiElement;
1766 j++, smiElement = smiGetNextElement(smiElement)) {
1770 printf("colorText('%s',", smiGetElementNode(smiElement)->name);
1772 printFillColor(smiGetElementNode(smiElement)->status));
1773 if (isNotificationGroup(smiNode)) {
1774 /* parse markupList */
1775 for (k=0; k<miCount; k++) {
1776 if (markupList[k].miElem == NULL)
1778 if (markupList[k].miElem !=
1779 smiGetElementNode(smiElement)->name)
1781 for (tElem = markupList[k].nextPtr;
1782 tElem; tElem = tElem->nextPtr) {
1783 printf(";colorText('%s',", tElem->miElem);
1784 printf("'%s')", printFillColor(tElem->status));
1789 if (j || smiNode->description) {
1794 printf(">%s", smiNode->name);
1795 switch (smiNode->status) {
1796 case SMI_STATUS_DEPRECATED:
1797 case SMI_STATUS_OBSOLETE:
1798 printf(" (%s)", getStatusString(smiNode->status));
1799 case SMI_STATUS_MANDATORY:
1800 case SMI_STATUS_OPTIONAL:
1801 case SMI_STATUS_CURRENT:
1802 case SMI_STATUS_UNKNOWN:
1805 printf("</text>\n");
1807 *y += TABLEELEMHEIGHT;
1811 static void printComplianceNode(SmiNode *smiNode, int modc, SmiModule **modv,
1812 float *x, float *y, int *miNr, int i,
1813 StringListElem markupList[], int miCount)
1815 int j, k, foreign_exists, textColor = 0;
1821 SmiModule *smiModule2;
1822 SmiElement *smiElement;
1823 /* SmiRevision *smiRevision; */
1824 SmiOption *smiOption;
1825 SmiRefinement *smiRefinement;
1826 StringListElem *tElem;
1828 printf(" <g id=\"MI%i\" transform=\"translate", *miNr);
1829 printf("(%.2f,%.2f)\">\n", *x, *y);
1831 switch (smiNode->status) {
1832 case SMI_STATUS_DEPRECATED:
1833 printf(" fill=\"rgb(40%%,40%%,40%%)\"");
1836 case SMI_STATUS_OBSOLETE:
1837 printf(" fill=\"rgb(60%%,60%%,60%%)\"");
1840 case SMI_STATUS_CURRENT:
1841 case SMI_STATUS_MANDATORY:
1842 printf(" fill=\"rgb(0%%,0%%,0%%)\"");
1845 case SMI_STATUS_OPTIONAL:
1846 printf(" fill=\"rgb(20%%,20%%,20%%)\"");
1849 case SMI_STATUS_UNKNOWN:
1854 if (!STATIC_OUTPUT) {
1855 printf(" <tspan style=\"text-anchor:middle\"");
1856 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
1858 printf(" <tspan x=\"5\"");
1860 if (!STATIC_OUTPUT && smiNode->description) {
1861 tooltip = (char *)xmalloc(2*strlen(smiNode->description));
1862 parseTooltip(smiNode->description, tooltip);
1863 printf(" onmousemove=\"ShowTooltipMZ(evt,'%s')", tooltip);
1865 printf("\" onmouseout=\"HideTooltip(evt)\"");
1867 printf(">%s", smiNode->name);
1868 switch (smiNode->status) {
1869 case SMI_STATUS_DEPRECATED:
1870 case SMI_STATUS_OBSOLETE:
1871 printf(" (%s)", getStatusString(smiNode->status));
1872 case SMI_STATUS_MANDATORY:
1873 case SMI_STATUS_OPTIONAL:
1874 case SMI_STATUS_CURRENT:
1875 case SMI_STATUS_UNKNOWN:
1878 printf("</tspan>\n");
1879 printf(" </text>\n");
1882 *y += TABLEELEMHEIGHT;
1884 /* modules for the compliance */
1885 *x += TABLEELEMHEIGHT;
1886 done = xstrdup("+");
1887 for (module = modv[i]->name; module; ) {
1889 if (module == modv[i]->name) {
1892 for (j = 0; j < modc; j++) {
1893 if (module == modv[j]->name) {
1899 printf(" <g id=\"MI%i\" transform=\"translate", *miNr);
1900 printf("(%.2f,%.2f)\">\n", *x, *y);
1901 printf(" <text fill=\"rgb(%i%%,%i%%,%i%%)\">\n",
1902 textColor, textColor, textColor);
1903 if (!STATIC_OUTPUT) {
1904 printf(" <tspan style=\"text-anchor:middle\"");
1905 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
1907 if (!foreign_exists && !STATIC_OUTPUT) {
1908 printf(" <tspan fill=\"%s\" x=\"5\">\n", linkcolor);
1909 printf(" <a xlink:href=\"%s", link);
1910 for (k=0; k<modc; k++) {
1911 printf("&mibs=%s", modv[k]->name);
1913 printf("&mibs=%s\">", module);
1914 printf("%s", module);
1916 printf(" </tspan>\n");
1918 printf(" <tspan x=\"5\">%s</tspan>\n", module);
1920 printf(" </text>\n");
1923 *y += TABLEELEMHEIGHT;
1925 /* mandatory groups */
1926 *x += TABLEELEMHEIGHT;
1927 *x += TABLEBOTTOMHEIGHT;
1928 printf(" <g id=\"MI%i\" transform=\"translate", *miNr);
1929 printf("(%.2f,%.2f)\">\n", *x, *y);
1930 printf(" <text id=\"mandatorygroups%s%s\"", smiNode->name, module);
1931 printf(" fill=\"rgb(%i%%,%i%%,%i%%)\"",
1932 textColor, textColor, textColor);
1933 if (!STATIC_OUTPUT && foreign_exists) {
1934 smiElement = smiGetFirstElement(smiNode);
1936 printf(" onmousemove=\"");
1938 for (j = 0; smiElement;
1939 j++, smiElement = smiGetNextElement(smiElement)) {
1940 if (!strcmp(smiGetNodeModule(smiGetElementNode(
1941 smiElement))->name, module)) {
1945 printf("colorText('%s','red')",
1946 smiGetElementNode(smiElement)->name);
1947 /* parse markupList */
1948 for (k=0; k<miCount; k++) {
1949 if (markupList[k].miElem == NULL)
1951 if (markupList[k].miElem !=
1952 smiGetElementNode(smiElement)->name)
1954 for (tElem = markupList[k].nextPtr;
1955 tElem; tElem = tElem->nextPtr) {
1956 printf(";colorText('%s','red')", tElem->miElem);
1965 smiElement = smiGetFirstElement(smiNode);
1967 printf(" onclick=\"setStatus(evt,'red','%s')",
1968 printFillColor(smiNode->status));
1970 for (j = 0; smiElement;
1971 j++, smiElement = smiGetNextElement(smiElement)) {
1972 if (!strcmp(smiGetNodeModule(smiGetElementNode(
1973 smiElement))->name, module)) {
1974 printf(";changeColor(evt,'%s','red','%s')",
1975 smiGetElementNode(smiElement)->name,
1976 printFillColor(smiGetElementNode(smiElement)->status));
1977 /* parse markupList */
1978 for (k=0; k<miCount; k++) {
1979 if (markupList[k].miElem == NULL)
1981 if (markupList[k].miElem !=
1982 smiGetElementNode(smiElement)->name)
1984 for (tElem = markupList[k].nextPtr;
1985 tElem; tElem = tElem->nextPtr) {
1986 printf(";changeColor(evt,'%s','red','%s')",
1987 tElem->miElem, printFillColor(tElem->status));
1996 smiElement = smiGetFirstElement(smiNode);
1998 printf(" onmouseout=\"");
2000 for (j = 0; smiElement;
2001 j++, smiElement = smiGetNextElement(smiElement)) {
2002 if (!strcmp(smiGetNodeModule(smiGetElementNode(
2003 smiElement))->name, module)) {
2007 printf("colorText('%s',",
2008 smiGetElementNode(smiElement)->name);
2010 printFillColor(smiGetElementNode(smiElement)->status));
2011 /* parse markupList */
2012 for (k=0; k<miCount; k++) {
2013 if (markupList[k].miElem == NULL)
2015 if (markupList[k].miElem !=
2016 smiGetElementNode(smiElement)->name)
2018 for (tElem = markupList[k].nextPtr;
2019 tElem; tElem = tElem->nextPtr) {
2020 printf(";colorText('%s',", tElem->miElem);
2021 printf("'%s')", printFillColor(tElem->status));
2030 printf(">Mandatory Groups</text>\n");
2032 *y += TABLEELEMHEIGHT;
2036 for (smiOption = smiGetFirstOption(smiNode); smiOption;
2037 smiOption = smiGetNextOption(smiOption)) {
2038 smiNode2 = smiGetOptionNode(smiOption);
2039 smiModule2 = smiGetNodeModule(smiNode2);
2040 if (!strcmp(smiModule2->name, module)) {
2041 printf(" <g id=\"MI%i\" transform=", *miNr);
2042 printf("\"translate(%.2f,%.2f)\">\n", *x, *y);
2043 printf(" <text id=\"group%s%s%s\"",
2044 smiNode->name, smiNode2->name, module);
2045 printf(" fill=\"rgb(%i%%,%i%%,%i%%)\"",
2046 textColor, textColor, textColor);
2047 if (!STATIC_OUTPUT) {
2048 printf(" onmousemove=\"");
2049 if (smiOption->description) {
2050 tooltip = (char *)xmalloc(2*strlen(
2051 smiOption->description));
2052 parseTooltip(smiOption->description, tooltip);
2053 printf("ShowTooltipMZ(evt,'%s')", tooltip);
2056 if (smiOption->description && foreign_exists)
2058 if (foreign_exists) {
2059 printf("colorText('%s','salmon')", smiNode2->name);
2060 /* parse markupList */
2061 for (j=0; j<miCount; j++) {
2062 if (markupList[j].miElem == NULL)
2064 if (markupList[j].miElem != smiNode2->name)
2066 for (tElem = markupList[j].nextPtr;
2067 tElem; tElem = tElem->nextPtr) {
2068 printf(";colorText('%s','salmon')",
2074 if (foreign_exists) {
2075 printf("\" onclick=\"setStatus(evt,'salmon','%s')",
2076 printFillColor(smiNode2->status));
2077 printf(";changeColor(evt,'%s','salmon','%s')",
2078 smiNode2->name, printFillColor(smiNode2->status));
2079 /* parse markupList */
2080 for (j=0; j<miCount; j++) {
2081 if (markupList[j].miElem == NULL)
2083 if (markupList[j].miElem != smiNode2->name)
2085 for (tElem = markupList[j].nextPtr;
2086 tElem; tElem = tElem->nextPtr) {
2087 printf(";changeColor(evt,'%s','salmon','%s')",
2089 printFillColor(tElem->status));
2094 printf("\" onmouseout=\"");
2095 if (smiOption->description) {
2096 printf("HideTooltip(evt)");
2098 if (smiOption->description && foreign_exists)
2100 if (foreign_exists) {
2101 printf("colorText('%s',", smiNode2->name);
2102 printf("'%s')", printFillColor(smiNode2->status));
2103 /* parse markupList */
2104 for (j=0; j<miCount; j++) {
2105 if (markupList[j].miElem == NULL)
2107 if (markupList[j].miElem != smiNode2->name)
2109 for (tElem = markupList[j].nextPtr;
2110 tElem; tElem = tElem->nextPtr) {
2111 printf(";colorText('%s',", tElem->miElem);
2112 printf("'%s')", printFillColor(tElem->status));
2118 printf(">Group %s</text>\n", smiNode2->name);
2120 *y += TABLEELEMHEIGHT;
2126 for (smiRefinement = smiGetFirstRefinement(smiNode); smiRefinement;
2127 smiRefinement = smiGetNextRefinement(smiRefinement)) {
2128 smiNode2 = smiGetRefinementNode(smiRefinement);
2129 smiModule2 = smiGetNodeModule(smiNode2);
2130 if (!strcmp(smiModule2->name, module)) {
2131 printf(" <g id=\"MI%i\" transform=", *miNr);
2132 printf("\"translate(%.2f,%.2f)\">\n", *x, *y);
2133 printf(" <text id=\"object%s%s%s\"",
2134 smiNode->name, smiNode2->name, module);
2135 printf(" fill=\"rgb(%i%%,%i%%,%i%%)\"",
2136 textColor, textColor, textColor);
2137 if (!STATIC_OUTPUT) {
2138 printf(" onmousemove=\"");
2139 if (smiRefinement->description) {
2140 tooltip = (char *)xmalloc(2*strlen(
2141 smiRefinement->description));
2142 parseTooltip(smiRefinement->description, tooltip);
2143 printf("ShowTooltipMZ(evt,'%s')", tooltip);
2146 if (smiRefinement->description && foreign_exists)
2149 printf("colorText('%s','salmon')", smiNode2->name);
2151 if (foreign_exists) {
2152 printf("\" onclick=\"setStatus(evt,'salmon','%s')",
2153 printFillColor(smiNode2->status));
2154 printf(";changeColor(evt,'%s','salmon','%s')",
2155 smiNode2->name, printFillColor(smiNode2->status));
2158 printf("\" onmouseout=\"");
2159 if (smiRefinement->description) {
2160 printf("HideTooltip(evt)");
2162 if (smiRefinement->description && foreign_exists)
2164 if (foreign_exists) {
2165 printf("colorText('%s',", smiNode2->name);
2166 printf("'%s')", printFillColor(smiNode2->status));
2170 printf(">Object %s</text>\n", smiNode2->name);
2172 *y += TABLEELEMHEIGHT;
2176 *x -= TABLEELEMHEIGHT;
2177 *x -= TABLEBOTTOMHEIGHT;
2179 /* find next module */
2180 done = xrealloc(done, strlen(done)+strlen(module)+2*sizeof(char));
2181 strcat(done, module);
2184 for (smiElement = smiGetFirstElement(smiNode); smiElement;
2185 smiElement = smiGetNextElement(smiElement)) {
2186 sprintf(s, "+%s+", smiGetNodeModule(smiGetElementNode(
2187 smiElement))->name);
2188 if ((!strstr(done, s))) {
2189 module = smiGetNodeModule(smiGetElementNode(smiElement))->name;
2195 *x -= TABLEELEMHEIGHT;
2198 static void printModuleIdentity(int modc, SmiModule **modv,
2199 float *x, float *y, int *miNr)
2204 /* SmiElement *smiElement; */
2205 SmiRevision *smiRevision;
2208 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2210 printf(" <text>\n");
2211 if (!STATIC_OUTPUT) {
2212 printf(" <tspan style=\"text-anchor:middle\"");
2213 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2215 printf(" <tspan x=\"5\">Modules</tspan>\n");
2216 printf(" </text>\n");
2219 *y += TABLEELEMHEIGHT;
2220 for (i = 0; i < modc; i++) {
2221 smiNode = smiGetModuleIdentityNode(modv[i]);
2224 /* name and description of the module. */
2225 *x += TABLEELEMHEIGHT;
2226 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2228 printf(" <text>\n");
2229 if (!STATIC_OUTPUT) {
2230 printf(" <tspan style=\"text-anchor:middle\"");
2231 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2233 printf(" <tspan x=\"5\"");
2234 if (!STATIC_OUTPUT) {
2235 if (modv[i]->description || modc > 1) {
2236 printf(" onmousemove=\"");
2238 if (modv[i]->description) {
2239 tooltip = (char *)xmalloc(2*strlen(modv[i]->description));
2240 parseTooltip(modv[i]->description, tooltip);
2241 printf("ShowTooltipMZ(evt,'%s')", tooltip);
2244 if (modv[i]->description && modc > 1) {
2249 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
2250 if (tNode->smiModule == modv[i] && tNode->use) {
2254 if (tNode->group == 0) {
2255 printf("colorText('%s','blanchedalmond')",
2256 tNode->smiNode->name);
2258 printf("colorText('%s','blanchedalmond')",
2259 smiGetParentNode(tNode->smiNode)->name);
2265 if (modv[i]->description || modc > 1) {
2266 printf("\" onmouseout=\"");
2268 if (modv[i]->description) {
2269 printf("HideTooltip(evt)");
2271 if (modv[i]->description && modc > 1) {
2276 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
2277 if (tNode->smiModule == modv[i] && tNode->use) {
2281 if (tNode->group == 0) {
2282 printf("colorText('%s','white')",
2283 tNode->smiNode->name);
2285 printf("colorText('%s','white')",
2286 smiGetParentNode(tNode->smiNode)->name);
2292 if (modv[i]->description || modc > 1) {
2296 printf(">%s</tspan>\n", modv[i]->name);
2297 printf(" </text>\n");
2300 *y += TABLEELEMHEIGHT;
2301 *x -= TABLEELEMHEIGHT;
2303 /* revision history of the module. */
2304 *x += 2*TABLEELEMHEIGHT;
2305 *x += TABLEBOTTOMHEIGHT;
2306 smiRevision = smiGetFirstRevision(modv[i]);
2308 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2310 printf(" <text>1970-01-01</text>\n");
2313 *y += TABLEELEMHEIGHT;
2316 smiRevision = smiGetNextRevision(smiRevision)) {
2317 printf(" <g id=\"MI%i\" transform=\"translate", *miNr);
2318 printf("(%.2f,%.2f)\">\n", *x, *y);
2320 if (!STATIC_OUTPUT && smiRevision->description && strcmp(
2321 smiRevision->description,
2322 "[Revision added by libsmi due to a LAST-UPDATED clause.]")) {
2323 tooltip = (char *)xmalloc(2*
2324 strlen(smiRevision->description));
2325 parseTooltip(smiRevision->description, tooltip);
2326 printf(" onmousemove=\"ShowTooltipMZ(evt,'%s')\"",
2328 printf(" onmouseout=\"HideTooltip(evt)\"");
2331 printf(">%s</text>\n", getTimeString(smiRevision->date));
2333 *y += TABLEELEMHEIGHT;
2337 *x -= 2*TABLEELEMHEIGHT;
2338 *x -= TABLEBOTTOMHEIGHT;
2341 *y += TABLEELEMHEIGHT;
2344 static void printNotificationType(int modc, SmiModule **modv,
2345 float *x, float *y, int *miNr, int nType[],
2346 StringListElem markupList[], int miCount)
2350 int statusOrder[5] = {
2352 SMI_STATUS_MANDATORY,
2353 SMI_STATUS_OPTIONAL,
2354 SMI_STATUS_DEPRECATED,
2358 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2360 printf(" <text>\n");
2361 if (!STATIC_OUTPUT) {
2362 printf(" <tspan style=\"text-anchor:middle\"");
2363 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2365 printf(" <tspan x=\"5\">Notifications</tspan>\n");
2366 printf(" </text>\n");
2369 *y += TABLEELEMHEIGHT;
2370 for (i = 0; i < modc; i++) {
2373 smiNode = smiGetModuleIdentityNode(modv[i]);
2376 /* name of the module */
2377 *x += TABLEELEMHEIGHT;
2378 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2380 printf(" <text>\n");
2381 if (!STATIC_OUTPUT) {
2382 printf(" <tspan style=\"text-anchor:middle\"");
2383 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2385 printf(" <tspan x=\"5\">%s</tspan>\n", modv[i]->name);
2386 printf(" </text>\n");
2389 *y += TABLEELEMHEIGHT;
2390 *x -= TABLEELEMHEIGHT;
2392 /* name, status and description of the notification */
2393 *x += 2*TABLEELEMHEIGHT;
2394 *x += TABLEBOTTOMHEIGHT;
2395 for (j=0; j<5; j++) {
2396 for (smiNode = smiGetFirstNode(modv[i],
2397 SMI_NODEKIND_NOTIFICATION);
2399 smiNode = smiGetNextNode(smiNode,
2400 SMI_NODEKIND_NOTIFICATION)) {
2401 if (smiNode->status != statusOrder[j])
2403 if ((smiNode->status == SMI_STATUS_DEPRECATED
2404 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
2405 || (smiNode->status == SMI_STATUS_OBSOLETE
2406 && !SHOW_DEPR_OBSOLETE))
2409 populateMarkupList(smiNode, miNr, markupList, miCount);
2410 printInformationNode(smiNode, x, y, miNr,
2411 markupList, miCount);
2414 *x -= 2*TABLEELEMHEIGHT;
2415 *x -= TABLEBOTTOMHEIGHT;
2418 *y += TABLEELEMHEIGHT;
2421 static void printObjectGroup(int modc, SmiModule **modv,
2422 float *x, float *y, int *miNr, int oGroup[],
2423 StringListElem markupList[], int miCount)
2427 int statusOrder[5] = {
2429 SMI_STATUS_MANDATORY,
2430 SMI_STATUS_OPTIONAL,
2431 SMI_STATUS_DEPRECATED,
2435 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2437 printf(" <text>\n");
2438 if (!STATIC_OUTPUT) {
2439 printf(" <tspan style=\"text-anchor:middle\"");
2440 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2442 printf(" <tspan x=\"5\">Object Groups</tspan>\n");
2443 printf(" </text>\n");
2446 *y += TABLEELEMHEIGHT;
2447 for (i = 0; i < modc; i++) {
2450 smiNode = smiGetModuleIdentityNode(modv[i]);
2453 /* name of the module */
2454 *x += TABLEELEMHEIGHT;
2455 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2457 printf(" <text>\n");
2458 if (!STATIC_OUTPUT) {
2459 printf(" <tspan style=\"text-anchor:middle\"");
2460 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2462 printf(" <tspan x=\"5\">%s</tspan>\n", modv[i]->name);
2463 printf(" </text>\n");
2466 *y += TABLEELEMHEIGHT;
2467 *x -= TABLEELEMHEIGHT;
2469 /* name, status and description of the group */
2470 *x += 2*TABLEELEMHEIGHT;
2471 *x += TABLEBOTTOMHEIGHT;
2472 for (j=0; j<5; j++) {
2473 for (smiNode = smiGetFirstNode(modv[i], SMI_NODEKIND_GROUP);
2475 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_GROUP)) {
2476 if (!isObjectGroup(smiNode))
2478 if (smiNode->status != statusOrder[j])
2480 if ((smiNode->status == SMI_STATUS_DEPRECATED
2481 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
2482 || (smiNode->status == SMI_STATUS_OBSOLETE
2483 && !SHOW_DEPR_OBSOLETE))
2486 populateMarkupList(smiNode, miNr, markupList, miCount);
2487 printInformationNode(smiNode, x, y, miNr,
2488 markupList, miCount);
2491 *x -= 2*TABLEELEMHEIGHT;
2492 *x -= TABLEBOTTOMHEIGHT;
2495 *y += TABLEELEMHEIGHT;
2498 static void printNotificationGroup(int modc, SmiModule **modv,
2499 float *x, float *y, int *miNr, int nGroup[],
2500 StringListElem markupList[], int miCount)
2504 int statusOrder[5] = {
2506 SMI_STATUS_MANDATORY,
2507 SMI_STATUS_OPTIONAL,
2508 SMI_STATUS_DEPRECATED,
2512 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2514 printf(" <text>\n");
2515 if (!STATIC_OUTPUT) {
2516 printf(" <tspan style=\"text-anchor:middle\"");
2517 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2519 printf(" <tspan x=\"5\">Notification Groups</tspan>\n");
2520 printf(" </text>\n");
2523 *y += TABLEELEMHEIGHT;
2524 for (i = 0; i < modc; i++) {
2527 smiNode = smiGetModuleIdentityNode(modv[i]);
2530 /* name of the module */
2531 *x += TABLEELEMHEIGHT;
2532 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2534 printf(" <text>\n");
2535 if (!STATIC_OUTPUT) {
2536 printf(" <tspan style=\"text-anchor:middle\"");
2537 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2539 printf(" <tspan x=\"5\">%s</tspan>\n", modv[i]->name);
2540 printf(" </text>\n");
2543 *y += TABLEELEMHEIGHT;
2544 *x -= TABLEELEMHEIGHT;
2546 /* name, status and description of the group */
2547 *x += 2*TABLEELEMHEIGHT;
2548 *x += TABLEBOTTOMHEIGHT;
2549 for (j=0; j<5; j++) {
2550 for (smiNode = smiGetFirstNode(modv[i], SMI_NODEKIND_GROUP);
2552 smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_GROUP)) {
2553 if (!isNotificationGroup(smiNode))
2555 if (smiNode->status != statusOrder[j])
2557 if ((smiNode->status == SMI_STATUS_DEPRECATED
2558 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
2559 || (smiNode->status == SMI_STATUS_OBSOLETE
2560 && !SHOW_DEPR_OBSOLETE))
2563 populateMarkupList(smiNode, miNr, markupList, miCount);
2564 printInformationNode(smiNode, x, y, miNr,
2565 markupList, miCount);
2568 *x -= 2*TABLEELEMHEIGHT;
2569 *x -= TABLEBOTTOMHEIGHT;
2572 *y += TABLEELEMHEIGHT;
2575 static void printModuleCompliance(int modc, SmiModule **modv,
2576 float *x, float *y, int *miNr, int mCompl[],
2577 StringListElem markupList[], int miCount)
2581 int statusOrder[5] = {
2583 SMI_STATUS_MANDATORY,
2584 SMI_STATUS_OPTIONAL,
2585 SMI_STATUS_DEPRECATED,
2589 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2591 printf(" <text>\n");
2592 if (!STATIC_OUTPUT) {
2593 printf(" <tspan style=\"text-anchor:middle\"");
2594 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2596 printf(" <tspan x=\"5\">Compliance Statements</tspan>\n");
2597 printf(" </text>\n");
2600 *y += TABLEELEMHEIGHT;
2601 for (i = 0; i < modc; i++) {
2604 smiNode = smiGetModuleIdentityNode(modv[i]);
2607 /* name of the module */
2608 *x += TABLEELEMHEIGHT;
2609 printf(" <g id=\"MI%i\" transform=\"translate(%.2f,%.2f)\">\n",
2611 printf(" <text>\n");
2612 if (!STATIC_OUTPUT) {
2613 printf(" <tspan style=\"text-anchor:middle\"");
2614 printf(" onclick=\"collapse(evt)\">--</tspan>\n");
2616 printf(" <tspan x=\"5\">%s</tspan>\n", modv[i]->name);
2617 printf(" </text>\n");
2620 *y += TABLEELEMHEIGHT;
2621 *x -= TABLEELEMHEIGHT;
2623 /* name, status and description of the compliance */
2624 *x += 2*TABLEELEMHEIGHT;
2625 for (j=0; j<5; j++) {
2626 for (smiNode = smiGetFirstNode(modv[i],
2627 SMI_NODEKIND_COMPLIANCE);
2629 smiNode = smiGetNextNode(smiNode,
2630 SMI_NODEKIND_COMPLIANCE)) {
2631 if (smiNode->status != statusOrder[j])
2633 if ((smiNode->status == SMI_STATUS_DEPRECATED
2634 && !SHOW_DEPRECATED && !SHOW_DEPR_OBSOLETE)
2635 || (smiNode->status == SMI_STATUS_OBSOLETE
2636 && !SHOW_DEPR_OBSOLETE))
2638 printComplianceNode(smiNode, modc, modv, x, y, miNr, i,
2639 markupList, miCount);
2642 *x -= 2*TABLEELEMHEIGHT;
2645 *y += TABLEELEMHEIGHT;
2648 static void printModuleInformation(int modc, SmiModule **modv,
2649 float x, float y, float maxHeight,
2650 int modId[], int nType[], int oGroup[],
2651 int nGroup[], int mCompl[], int miCount)
2654 float scale = 1, miHeight;
2656 int nTypePrint = 0, oGroupPrint = 0, nGroupPrint = 0, mComplPrint = 0;
2658 StringListElem *markupList = xcalloc(miCount,sizeof(StringListElem));
2660 /* only print sections containig information */
2661 for (i = 0; i < modc; i++) {
2662 modIdPrint |= modId[i];
2663 nTypePrint |= nType[i];
2664 oGroupPrint |= oGroup[i];
2665 nGroupPrint |= nGroup[i];
2666 mComplPrint |= mCompl[i];
2669 /* count blank lines */
2700 /* test if we must shrink moduleInformation to fit it into canvas */
2701 miHeight = ((miCount + i - (2 * j)) * 15 + 10);
2702 if (miHeight > maxHeight)
2703 scale *= maxHeight/miHeight;
2705 printf(" <g transform=\"translate(%.2f,%.2f) scale(%.2f)\">\n",
2708 /* now use x and y as relative coordinates. */
2713 printModuleIdentity(modc, modv, &x, &y, &miNr);
2715 printNotificationType(modc, modv, &x, &y, &miNr, nType, markupList,
2718 printObjectGroup(modc, modv, &x, &y, &miNr, oGroup, markupList,
2721 printNotificationGroup(modc, modv, &x, &y, &miNr, nGroup, markupList,
2724 printModuleCompliance(modc, modv, &x, &y, &miNr, mCompl, markupList,
2729 if (markupList) xfree(markupList);
2733 /* ------------------------------------------------------------------------- */
2736 static float fa(float d, float k)
2738 return (float) (d*d/k);
2741 static float fr(float d, float k)
2743 return (float) (k*k/d);
2746 static int overlap(GraphNode *vNode, GraphNode *uNode)
2748 if (vNode->dia.x+vNode->dia.w/2>=uNode->dia.x-uNode->dia.w/2 &&
2749 vNode->dia.x-vNode->dia.w/2<=uNode->dia.x+uNode->dia.w/2 &&
2750 vNode->dia.y+vNode->dia.h/2>=uNode->dia.y-uNode->dia.h/2 &&
2751 vNode->dia.y-vNode->dia.h/2<=uNode->dia.y+uNode->dia.h/2) {
2759 * test if node and edge intersect
2761 static float intersect(GraphNode *node, GraphEdge *edge)
2763 float a, b, intersect = 0;
2765 /* handle case in which edge is parallel to y-axis */
2766 if (edge->endNode->dia.x == edge->startNode->dia.x) {
2767 if ((node->dia.x-node->dia.w/2 < edge->endNode->dia.x &&
2768 node->dia.x+node->dia.w/2 < edge->endNode->dia.x) ||
2769 (node->dia.x-node->dia.w/2 > edge->endNode->dia.x &&
2770 node->dia.x+node->dia.w/2 > edge->endNode->dia.x))
2772 intersect = node->dia.x - edge->startNode->dia.x;
2774 /* calculate a and b for y=ax+b */
2775 a = (edge->endNode->dia.y - edge->startNode->dia.y) /
2776 (edge->endNode->dia.x - edge->startNode->dia.x);
2777 b = edge->startNode->dia.y - (a * edge->startNode->dia.x);
2778 /* test if entire node is above or under edge */
2779 if ((node->dia.y-node->dia.h/2 - (a * node->dia.x-node->dia.w/2) > b &&
2780 node->dia.y+node->dia.h/2 - (a * node->dia.x-node->dia.w/2) > b &&
2781 node->dia.y-node->dia.h/2 - (a * node->dia.x+node->dia.w/2) > b &&
2782 node->dia.y+node->dia.h/2 - (a * node->dia.x+node->dia.w/2) > b) ||
2783 (node->dia.y-node->dia.h/2 - (a * node->dia.x-node->dia.w/2) < b &&
2784 node->dia.y+node->dia.h/2 - (a * node->dia.x-node->dia.w/2) < b &&
2785 node->dia.y-node->dia.h/2 - (a * node->dia.x+node->dia.w/2) < b &&
2786 node->dia.y+node->dia.h/2 - (a * node->dia.x+node->dia.w/2) < b))
2788 intersect = (a * node->dia.x - node->dia.y + b) /
2789 (float)(sqrt(a*a+1));
2791 /* test if node is over upper end of edge or under lower end of edge */
2792 if (node->dia.y+node->dia.h/2 <
2793 min(edge->startNode->dia.y,edge->endNode->dia.y) ||
2794 node->dia.y-node->dia.h/2 >
2795 max(edge->startNode->dia.y,edge->endNode->dia.y)) {
2799 /* node and edge intersect */
2804 * Implements the springembedder. Look at LNCS 2025, pp. 71-86.
2805 * and: http://citeseer.ist.psu.edu/fruchterman91graph.html
2806 * Input: Graph with known width and height of nodes.
2807 * Output: Coordinates (x,y) for the nodes.
2808 * Only the nodes and edges with use==1 are considered.
2810 static void layoutComponent(GraphComponent *component,
2811 int nodeoverlap, int edgeoverlap)
2814 float k, xDelta, yDelta, absDelta, absDisp, t, dist;
2815 GraphNode *vNode, *uNode;
2821 for (i=0; i<ITERATIONS; i++) {
2822 /* calculate repulsive forces */
2823 for (vNode = component->firstComponentNode; vNode;
2824 vNode = vNode->nextComponentNode) {
2825 vNode->dia.xDisp = 0;
2826 vNode->dia.yDisp = 0;
2827 for (uNode = component->firstComponentNode; uNode;
2828 uNode = uNode->nextComponentNode) {
2831 xDelta = vNode->dia.x - uNode->dia.x;
2832 yDelta = vNode->dia.y - uNode->dia.y;
2833 absDelta = (float) (sqrt(xDelta*xDelta + yDelta*yDelta));
2834 vNode->dia.xDisp += (xDelta/absDelta)*fr(absDelta, k);
2835 vNode->dia.yDisp += (yDelta/absDelta)*fr(absDelta, k);
2836 /* add another repulsive force if the nodes overlap */
2837 if (nodeoverlap && overlap(vNode, uNode)) {
2838 vNode->dia.xDisp += 4*(xDelta/absDelta)*fr(1/absDelta, k);
2839 vNode->dia.yDisp += 4*(yDelta/absDelta)*fr(1/absDelta, k);
2843 for (eEdge = graph->edges; eEdge; eEdge = eEdge->nextPtr) {
2844 if (!eEdge->use || eEdge->startNode->component != component)
2846 /* add another repulsive force if edge and any node overlap */
2848 for (vNode = component->firstComponentNode; vNode;
2849 vNode = vNode->nextComponentNode) {
2850 if (eEdge->startNode == vNode ||
2851 eEdge->endNode == vNode ||
2852 overlap(eEdge->startNode, vNode) ||
2853 overlap(eEdge->endNode, vNode))
2855 if ((dist = intersect(vNode, eEdge))) {
2856 if (eEdge->startNode->dia.x == eEdge->endNode->dia.x) {
2857 eEdge->startNode->dia.xDisp -=
2858 8*(dist/fabsf(dist))*fr(1/dist, k);
2859 eEdge->endNode->dia.xDisp -=
2860 8*(dist/fabsf(dist))*fr(1/dist, k);
2862 8*(dist/fabsf(dist))*fr(1/dist, k);
2864 xDelta = -1*(eEdge->endNode->dia.y
2865 -eEdge->startNode->dia.y)
2866 /(eEdge->endNode->dia.x
2867 -eEdge->startNode->dia.x);
2869 absDelta = (float) (sqrt(xDelta*xDelta
2871 eEdge->startNode->dia.xDisp +=
2872 8*(xDelta/absDelta)*fr(1/dist, k);
2873 eEdge->startNode->dia.yDisp +=
2874 8*(yDelta/absDelta)*fr(1/dist, k);
2875 eEdge->endNode->dia.xDisp +=
2876 8*(xDelta/absDelta)*fr(1/dist, k);
2877 eEdge->endNode->dia.yDisp +=
2878 8*(yDelta/absDelta)*fr(1/dist, k);
2880 8*(xDelta/absDelta)*fr(1/dist, k);
2882 8*(yDelta/absDelta)*fr(1/dist, k);
2887 /* calculate attractive forces */
2888 xDelta = eEdge->startNode->dia.x - eEdge->endNode->dia.x;
2889 yDelta = eEdge->startNode->dia.y - eEdge->endNode->dia.y;
2890 absDelta = (float) (sqrt(xDelta*xDelta + yDelta*yDelta));
2891 eEdge->startNode->dia.xDisp -= (xDelta/absDelta)*fa(absDelta, k);
2892 eEdge->startNode->dia.yDisp -= (yDelta/absDelta)*fa(absDelta, k);
2893 eEdge->endNode->dia.xDisp += (xDelta/absDelta)*fa(absDelta, k);
2894 eEdge->endNode->dia.yDisp += (yDelta/absDelta)*fa(absDelta, k);
2896 /* limit the maximum displacement to the temperature t */
2897 for (vNode = component->firstComponentNode; vNode;
2898 vNode = vNode->nextComponentNode) {
2899 absDisp = (float) (sqrt(vNode->dia.xDisp*vNode->dia.xDisp
2900 + vNode->dia.yDisp*vNode->dia.yDisp));
2901 vNode->dia.x += (vNode->dia.xDisp/absDisp)*min(absDisp, t);
2902 vNode->dia.y += (vNode->dia.yDisp/absDisp)*min(absDisp, t);
2904 /* reduce the temperature as the layout approaches a better configuration */
2910 /* ------------------------------------------------------------------------- */
2913 static void addNodeToComponent(GraphNode *tNode, GraphComponent *tComponent)
2917 tNode->component = tComponent;
2918 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
2921 if (tEdge->startNode == tNode && tEdge->endNode->component == NULL) {
2922 tEdge->endNode->nextComponentNode = tNode->nextComponentNode;
2923 tNode->nextComponentNode = tEdge->endNode;
2924 addNodeToComponent(tEdge->endNode, tComponent);
2926 if (tEdge->endNode == tNode && tEdge->startNode->component == NULL) {
2927 tEdge->startNode->nextComponentNode = tNode->nextComponentNode;
2928 tNode->nextComponentNode = tEdge->startNode;
2929 addNodeToComponent(tEdge->startNode, tComponent);
2935 /* split the graph into components */
2936 static void splitGraphIntoComponents()
2939 GraphComponent *tComponent;
2940 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
2943 if (tNode->component == NULL) {
2944 tComponent = graphInsertComponent(graph);
2945 tComponent->firstComponentNode = tNode;
2946 addNodeToComponent(tNode, tComponent);
2952 /* layout components (except first) and calculate bounding boxes and offsets */
2953 static void layoutComponents(float *yMin, float *yMax, float *x)
2956 GraphComponent *tComponent;
2959 for (tComponent = graph->components->nextPtr; tComponent;
2960 tComponent = tComponent->nextPtr) {
2961 layoutComponent(tComponent, 0, 0);
2962 /* FIXME do we need a stage with nodeoverlap and without edgeoverlap? */
2963 layoutComponent(tComponent, 1, 0);
2964 layoutComponent(tComponent, 1, 1);
2966 for (tNode = tComponent->firstComponentNode; tNode;
2967 tNode = tNode->nextComponentNode) {
2968 if (tNode->dia.x - tNode->dia.w/2 < tComponent->xMin)
2969 tComponent->xMin = tNode->dia.x - tNode->dia.w/2;
2970 if (tNode->dia.x + tNode->dia.w/2 > tComponent->xMax)
2971 tComponent->xMax = tNode->dia.x + tNode->dia.w/2;
2972 if (tNode->dia.y - tNode->dia.h/2 < tComponent->yMin)
2973 tComponent->yMin = tNode->dia.y - tNode->dia.h/2;
2974 if (tNode->dia.y + tNode->dia.h/2 > tComponent->yMax)
2975 tComponent->yMax = tNode->dia.y + tNode->dia.h/2;
2978 tComponent->xOffset = *x - tComponent->xMin;
2979 *x += 10 + tComponent->xMax - tComponent->xMin;
2980 tComponent->yOffset = -0.5*(tComponent->yMin+tComponent->yMax);
2981 if (tComponent->yMin + tComponent->yOffset < *yMin)
2982 *yMin = tComponent->yMin + tComponent->yOffset;
2983 if (tComponent->yMax + tComponent->yOffset > *yMax)
2984 *yMax = tComponent->yMax + tComponent->yOffset;
2989 /* Print SVG to stdout */
2990 static void printSVG(int modc, SmiModule **modv, int miCount, int idCount,
2991 float xMin, float yMin, float xMax, float yMax,
2992 int nodecount, int TCcount,
2993 int modId[], int nType[], int oGroup[],
2994 int nGroup[], int mCompl[])
2996 GraphComponent *tComponent;
3001 /* output of svg to stdout begins here */
3002 printSVGHeaderAndTitle(modc, modv, miCount, idCount,
3003 xMin, yMin, xMax, yMax);
3005 /* module doesn't contain any objects. */
3006 if (nodecount == 0) {
3014 /* loop through components (except first) to print edges and nodes */
3015 for (tComponent = graph->components->nextPtr; tComponent;
3016 tComponent = tComponent->nextPtr) {
3017 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
3018 if (!tEdge->use || tEdge->startNode->component != tComponent)
3020 printSVGConnection(tEdge);
3022 for (tNode = tComponent->firstComponentNode; tNode;
3023 tNode = tNode->nextComponentNode) {
3024 printSVGObject(tNode, &classNr, modc, modv);
3026 /* enclose component in its bounding box */
3028 printf(" <rect x=\"%.2f\" y=\"%.2f\" width=\"%.2f\" height=\"%.2f\"\n",
3029 tComponent->xMin + tComponent->xOffset,
3030 tComponent->yMin + tComponent->yOffset,
3031 tComponent->xMax - tComponent->xMin,
3032 tComponent->yMax - tComponent->yMin);
3033 printf(" fill=\"none\" stroke=\"green\" stroke-width=\"1\"/>\n");
3037 /* print single nodes */
3038 for (tNode = graph->components->firstComponentNode; tNode;
3039 tNode = tNode->nextComponentNode) {
3040 if (tNode->group == 0) {
3041 printSVGObject(tNode, &classNr, modc, modv);
3043 printSVGGroup(tNode->group, &classNr, modc, modv);
3047 /* print Module-Information */
3048 printModuleInformation(modc, modv, xMax-MODULE_INFO_WIDTH, yMin+10,
3050 modId, nType, oGroup, nGroup, mCompl, miCount);
3052 /* output of svg to stdout ends here */
3053 printSVGClose(xMin, yMin, xMax, yMax);
3057 /* prepare nodes and edges for drawing */
3058 static void prepareNodesAndEdges(int *idCount, float *xMax, int *nodecount,
3059 int *singleNodes, float *maxHeight)
3061 GraphNode *tNode, *lastNode = NULL;
3063 GraphComponent *tComponent;
3067 /* find edges which are supposed to be drawn */
3068 for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
3069 if (tEdge->connection != GRAPH_CON_UNKNOWN
3070 && tEdge->startNode->smiNode->nodekind != SMI_NODEKIND_SCALAR
3071 && tEdge->endNode->smiNode->nodekind != SMI_NODEKIND_SCALAR
3072 && tEdge->startNode != tEdge->endNode) {
3074 tEdge->startNode->degree++;
3075 tEdge->endNode->degree++;
3079 tComponent = graphInsertComponent(graph);
3081 /* prepare nodes which are supposed to be drawn */
3082 for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
3083 tNode = calcNodeSize(tNode, idCount);
3084 if (tNode->smiNode->nodekind != SMI_NODEKIND_SCALAR) {
3086 if (tNode->degree == 0) {
3087 /* single nodes are members of the first component. */
3088 if (tComponent->firstComponentNode == NULL) {
3089 tComponent->firstComponentNode = tNode;
3091 lastNode->nextComponentNode = tNode;
3094 tNode->component = tComponent;
3095 tNode->dia.x = x + tNode->dia.w/2;
3096 x += 10 + tNode->dia.w;
3098 if (tNode->dia.h > *maxHeight)
3099 *maxHeight = tNode->dia.h;
3103 for (group = 1; group <= algGetNumberOfGroups(); group++) {
3104 tNode = calcGroupSize(group, idCount);
3106 /* groupnodes are members of the first component. */
3107 if (tComponent->firstComponentNode == NULL) {
3108 tComponent->firstComponentNode = tNode;
3110 lastNode->nextComponentNode = tNode;
3113 tNode->component = tComponent;
3114 tNode->dia.x = x + tNode->dia.w/2;
3115 x += 10 + tNode->dia.w;
3117 if (tNode->dia.h > *maxHeight)
3118 *maxHeight = tNode->dia.h;
3121 if (tComponent->firstComponentNode == NULL)
3128 * generate SVG diagram and print it to stdout:
3129 * - identify and prepare nodes and egdes
3130 * - split graph into its components
3131 * - layout components
3132 * - prepare module information
3134 * - print components
3135 * - print module information
3138 static void generateSVG(int modc, SmiModule **modv)
3140 int nodecount=0, singleNodes=1, miCount=0;
3141 int i, idCount=0, TCcount=0, miPrint=0;
3142 float x=10, xMin=0, yMin=0, xMax=0, yMax=0, maxHeight=0;
3144 int *modId = xcalloc(modc,sizeof(int));
3145 int *nType = xcalloc(modc,sizeof(int));
3146 int *oGroup = xcalloc(modc,sizeof(int));
3147 int *nGroup = xcalloc(modc,sizeof(int));
3148 int *mCompl = xcalloc(modc,sizeof(int));
3150 /* prepare nodes and edges for drawing */
3151 prepareNodesAndEdges(&idCount, &xMax, &nodecount, &singleNodes, &maxHeight);
3153 /* split the graph into components */
3154 splitGraphIntoComponents();
3156 /* layout components (except first) and calculate bounding boxes and offsets */
3157 layoutComponents(&yMin, &yMax, &x);
3159 if (graph->components->nextPtr)
3165 /* adjust values for the first component (component of single nodes) */
3166 graph->components->yOffset = yMax + maxHeight/2;
3168 yMax += maxHeight + 10;
3170 /* module doesn't contain any objects. */
3171 if (nodecount == 0) {
3172 TCcount = countTCs(modc, modv);
3181 /* count entries in the ModuleInformation-Section */
3182 prepareModInfo(modc, modv, &miCount, modId, nType, oGroup, nGroup, mCompl);
3185 /* enlarge canvas for ModuleInformation if it is supposed to be printed */
3186 for (i = 0; i < modc; i++) {
3187 miPrint |= modId[i];
3188 miPrint |= nType[i];
3189 miPrint |= oGroup[i];
3190 miPrint |= nGroup[i];
3191 miPrint |= mCompl[i];
3194 xMax += MODULE_INFO_WIDTH;
3197 printSVG(modc, modv, miCount, idCount, xMin, yMin, xMax, yMax, nodecount,
3198 TCcount, modId, nType, oGroup, nGroup, mCompl);
3209 static void buildLink(int modc, SmiModule **modv)
3212 const char *url = URL;
3213 /* note: first string, so no & required */
3214 const char *widthstr = "width=";
3215 const char *heightstr = "&height=";
3216 const char *deprstr = "&deprobs=deprecated";
3217 const char *deprobsstr = "&deprobs=obsolete";
3221 length = strlen(url);
3222 sprintf(width, "%i", CANVASWIDTH);
3223 sprintf(height, "%i", CANVASHEIGHT);
3224 length += strlen(widthstr) + strlen(width);
3225 length += strlen(heightstr) + strlen(height);
3226 if (SHOW_DEPRECATED) {
3227 length += strlen(deprstr);
3229 if (SHOW_DEPR_OBSOLETE) {
3230 length += strlen(deprobsstr);
3232 link = xmalloc(length + 1);
3234 strcat(link, widthstr);
3235 strcat(link, width);
3236 strcat(link, heightstr);
3237 strcat(link, height);
3238 if (SHOW_DEPRECATED) {
3239 strcat(link, deprstr);
3241 if (SHOW_DEPR_OBSOLETE) {
3242 strcat(link, deprobsstr);
3247 static void calcConceptualModel()
3250 algCheckLinksByName();
3251 algConnectLonelyNodes();
3252 algCheckForDependency();
3253 algCheckForPointerRels();
3257 /* ------------------------------------------------------------------------- */
3261 static void dumpSvg(int modc, SmiModule **modv, int flags, char *output)
3265 buildLink(modc, modv);
3267 if (flags & SMIDUMP_FLAG_UNITE) {
3269 graph = xmalloc(sizeof(Graph));
3270 graph->nodes = NULL;
3271 graph->edges = NULL;
3272 graph->components = NULL;
3275 for (i = 0; i < modc; i++) {
3276 algCreateNodes(modv[i]);
3279 calcConceptualModel();
3281 generateSVG(modc, modv);
3286 for (i = 0; i < modc; i++) {
3288 graph = xmalloc(sizeof(Graph));
3289 graph->nodes = NULL;
3290 graph->edges = NULL;
3291 graph->components = NULL;
3294 algCreateNodes(modv[i]);
3296 calcConceptualModel();
3298 generateSVG(1, &(modv[i]));
3305 if (fflush(stdout) || ferror(stdout)) {
3306 perror("smidump: write error");
3317 static SmidumpDriverOption opt[] = {
3318 { "width", OPT_INT, &CANVASWIDTH, 0,
3319 "width of the svg output (default=1100)"},
3320 { "height", OPT_INT, &CANVASHEIGHT, 0,
3321 "height of the svg output (default=700)"},
3322 { "show-deprecated", OPT_FLAG, &SHOW_DEPRECATED, 0,
3323 "show deprecated items"},
3324 { "show-depr-obsolete", OPT_FLAG, &SHOW_DEPR_OBSOLETE, 0,
3325 "show deprecated and obsolete items"},
3326 { "static-output", OPT_FLAG, &STATIC_OUTPUT, 0,
3327 "disable all interactivity (e.g. for printing)"},
3328 { 0, OPT_END, 0, 0 }
3331 static SmidumpDriver driver = {
3335 SMIDUMP_DRIVER_CANT_OUTPUT,
3341 smidumpRegisterDriver(&driver);