Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / dump-cm.c
1 /*
2  * dump-cm.c --
3  *
4  *      Operations to dump conceptual models for MIB modules.
5  *
6  * Copyright (c) 2000 A. Mueller, Technical University of Braunschweig.
7  *
8  * See the file "COPYING" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * @(#) $Id: dump-cm.c 2718 2005-08-24 06:59:15Z sperner $
12  */
13
14
15 /* 
16  * -- TO DO --
17  *
18  * Berechnungen der UML Diagramme debuggen
19  *
20  */
21
22
23
24
25
26 #include <config.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #ifdef HAVE_WIN_H
33 #include "win.h"
34 #endif
35
36 #include "smi.h"
37 #include "smidump.h"
38 #include "rea.h"
39
40
41
42 /*
43  * Definitions used by the dia output driver (node layout).
44  */
45
46 static const float HEADFONTSIZETABLE   = (float)0.51;
47 static const float HEADSPACESIZETABLE  = (float)0.6;
48 static const float ATTRFONTSIZE        = (float)0.48;
49 static const float ATTRSPACESIZE       = (float)2.4;
50 static const float RECTCORRECTION      = (float)0.85;
51 static const float EDGEYSPACING        = (float)2.0;
52 static const float TABLEHEIGHT         = (float)2.6;   /* headline of the table */
53 static const float TABLEELEMHEIGHT     = (float)0.675; /* height of one attribute */
54
55 /*
56  * global dia graph layout
57  */
58 static const float YSPACING            = (float)3.0;  /* y space between nodes */
59 static const float XSPACING            = (float)4.0;  /* x space between nodes */ 
60 static const float NEWLINEDISTANCE     = (float)40.0; /* length of one line */
61 static const float XOFFSET             = (float)2.0;  /* left upper start of graph */
62 static const float YOFFSET             = (float)5.0;  /* left upper start of graph */
63
64 /*
65  * position of the dia info note 
66  */
67 static const float XNOTE               = (float)1.0;  /* left upper corner of note */
68 static const float YNOTE               = (float)1.0;  /* left upper corner of note */
69
70 /*
71  * Stereotype Name
72  */
73 static const char* STEREOTYPE          = "smi mib class";
74
75 /*
76  * Property String for index objects
77  */
78 static const char* INDEXPROPERTY       = " {index}";
79
80
81 /* -------------- main functions ------------------------------------------- */
82
83
84 /*
85  * Creates the graph nodes of the given module
86  */
87 static void algCreateNodes(SmiModule *module)
88 {
89     SmiNode *node;
90     
91     /* get tables and scalars from the MIB module */
92     for (node = smiGetFirstNode(module, SMI_NODEKIND_TABLE);
93          node;
94          node = smiGetNextNode(node, SMI_NODEKIND_TABLE)) {
95         if (node->status != SMI_STATUS_OBSOLETE) {
96             if (!SUPPRESS_DEPRECATED || node->status != SMI_STATUS_DEPRECATED)
97                 graphInsertNode(graph, node);
98         }
99     }
100     for (node = smiGetFirstNode(module, SMI_NODEKIND_SCALAR);
101          node;
102          node = smiGetNextNode(node, SMI_NODEKIND_SCALAR)) {
103         if (node->status != SMI_STATUS_OBSOLETE) {
104             if (!SUPPRESS_DEPRECATED || node->status != SMI_STATUS_DEPRECATED)
105                 graphInsertNode(graph, node);
106         }
107     }
108 }
109
110
111
112 /* ------ XML primitives ------                                              */
113
114
115
116
117 static void diaPrintXMLHeader()
118 {
119     printf("<?xml version=\"1.0\"?>\n");
120     printf("<diagram xmlns:dia=\"http://www.lysator.liu.se/~alla/dia/\">\n");
121     printf("  <diagramdata>\n");
122     printf("    <attribute name=\"background\">\n");
123     printf("      <color val=\"#ffffff\"/>\n");
124     printf("    </attribute>\n");
125     printf("    <attribute name=\"paper\">\n");
126     printf("      <composite type=\"paper\">\n");
127     printf("        <attribute name=\"name\">\n");
128     printf("          <string>#A4#</string>\n");
129     printf("        </attribute>\n");
130     printf("        <attribute name=\"tmargin\">\n");
131     printf("         <real val=\"2.82\"/>\n");
132     printf("       </attribute>\n");
133     printf("       <attribute name=\"bmargin\">\n");
134     printf("         <real val=\"2.82\"/>\n");
135     printf("        </attribute>\n");
136     printf("       <attribute name=\"lmargin\">\n");
137     printf("         <real val=\"2.82\"/>\n");
138     printf("       </attribute>\n");
139     printf("       <attribute name=\"rmargin\">\n");
140     printf("         <real val=\"2.82\"/>\n");
141     printf("       </attribute>\n");
142     printf("       <attribute name=\"is_portrait\">\n");
143     printf("         <boolean val=\"true\"/>\n");
144     printf("       </attribute>\n");
145     printf("      <attribute name=\"scaling\">\n");
146     printf("         <real val=\"1\"/>\n");
147     printf("      </attribute>\n");
148     printf("      <attribute name=\"fitto\">\n");
149     printf("        <boolean val=\"false\"/>\n");
150     printf("      </attribute>\n");
151     printf("    </composite>\n");
152     printf("   </attribute>\n");
153     printf("  </diagramdata>\n");
154     printf("  <layer name=\"Background\" visible=\"true\">\n");   
155 }
156
157 static void diaPrintXMLClose()
158 {
159     printf("  </layer>\n");
160     printf("</diagram>\n");
161 }
162
163 /*
164  * prints the type of a given node
165  */  
166 static void diaPrintXMLType(SmiNode *smiNode, int index)
167 {
168     printf("          <attribute name=\"type\">\n");
169     if (index) {
170         printf("            <string>#%s%s#</string>\n",
171                algGetTypeName(smiNode), INDEXPROPERTY);
172     } else {
173         printf("            <string>#%s#</string>\n", algGetTypeName(smiNode));
174     }
175     printf("          </attribute>\n");    
176 }
177
178 /*
179  * index = 0 -> no index element
180  * index = 1 -> index element -> printed with "+"
181  */
182 static void diaPrintXMLAttribute(SmiNode *node, int index)
183 {
184     printf("        <composite type=\"umlattribute\">\n");
185     printf("          <attribute name=\"name\">\n");
186     printf("            <string>#%s#</string>\n", node->name);
187     printf("          </attribute>\n");
188     
189     diaPrintXMLType(node,index);
190     
191     printf("          <attribute name=\"value\">\n");
192     printf("            <string/>\n");
193     printf("          </attribute>\n");
194     printf("          <attribute name=\"visibility\">\n");
195
196     if (node->access == SMI_ACCESS_NOT_ACCESSIBLE) {
197         printf("            <enum val=\"1\"/>\n");
198     } else {
199         printf("            <enum val=\"0\"/>\n");
200     }
201     
202     printf("          </attribute>\n");
203     printf("          <attribute name=\"abstract\">\n");
204     printf("            <boolean val=\"false\"/>\n");
205     printf("          </attribute>\n");
206     printf("          <attribute name=\"class_scope\">\n");
207     
208     if (node->nodekind == SMI_NODEKIND_SCALAR) {
209         printf("            <boolean val=\"true\"/>\n");
210     } else {
211         printf("            <boolean val=\"false\"/>\n");       
212     }
213
214     printf("          </attribute>\n");
215     printf("        </composite>\n");      
216 }
217
218 /*
219  * prints the related scalars for a given table
220  */
221 static void diaPrintXMLRelatedScalars(GraphNode *node)
222 {
223     GraphEdge *tEdge;
224     
225     for (tEdge = graphGetFirstEdgeByNode(graph, node);
226          tEdge;
227          tEdge = graphGetNextEdgeByNode(graph, tEdge, node)) {
228         if (tEdge->startNode == node  &&
229             tEdge->endNode->smiNode->nodekind == SMI_NODEKIND_SCALAR) {
230             tEdge->dia.flags |= DIA_PRINT_FLAG;
231             tEdge->endNode->dia.flags |= DIA_PRINT_FLAG;
232
233             diaPrintXMLAttribute(tEdge->endNode->smiNode,0);
234         }
235     }
236 }
237
238 /*
239  * prints all columns objects of the given node
240  */
241 static void diaPrintXMLAllColumns(GraphNode *node)
242 {
243     SmiModule *module  = NULL;
244     SmiNode   *smiNode = NULL;
245     SmiNode   *ppNode;
246
247     module  = smiGetNodeModule(node->smiNode);
248
249     for (smiNode = smiGetFirstNode(module, SMI_NODEKIND_COLUMN);
250          smiNode;
251          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_COLUMN)) {
252         ppNode = smiGetParentNode(smiNode);
253         ppNode = smiGetParentNode(ppNode);
254         
255         if (!algIsIndexElement(node->smiNode, smiNode) &&
256             cmpSmiNodes(node->smiNode, ppNode))
257             diaPrintXMLAttribute(smiNode, 0);
258     }
259 }
260
261 /*
262  * adds the index to an augmenting table (row-element)
263  */
264 static void diaPrintAugmentIndex(GraphNode *tNode)
265 {
266     GraphEdge  *tEdge;
267     SmiElement *smiElement;
268
269     for (tEdge = graphGetFirstEdgeByNode(graph, tNode);
270          tEdge;
271          tEdge = graphGetNextEdgeByNode(graph, tEdge, tNode)) {
272         if (tEdge->indexkind == SMI_INDEX_AUGMENT) {
273             for (smiElement = smiGetFirstElement(
274                 smiGetFirstChildNode(tEdge->startNode->smiNode));
275                  smiElement;
276                  smiElement = smiGetNextElement(smiElement)) {
277                 if (!cmpSmiNodes(tNode->smiNode, tEdge->startNode->smiNode)) {
278                     diaPrintXMLAttribute(smiGetElementNode(smiElement),1);
279                 }
280             }
281         }
282     }
283 }
284
285 static void diaPrintXMLObject(GraphNode *node, float x, float y)
286 {
287     SmiElement *smiElement;
288     
289     if (!node) return;
290     if (node->dia.flags & DIA_PRINT_FLAG) return;
291
292     node->dia.x = x;
293     node->dia.y = y;
294     node->dia.flags |= DIA_PRINT_FLAG; /* object is now printed */
295     
296     printf("    <object type=\"UML - Class\" version=\"0\" id=\"%s\">\n",
297            node->smiNode->name);
298     printf("      <attribute name=\"obj_pos\">\n");
299     printf("       <point val=\"%.2f,%.2f\"/>\n",x,y);
300     printf("      </attribute>\n");
301     printf("     <attribute name=\"obj_bb\">\n");
302     printf("       <rectangle val=\"0.0,0.0;0.0,0.0\"/>\n");
303     printf("     </attribute>\n");
304     printf("     <attribute name=\"elem_corner\">\n");
305     printf("       <point val=\"%.2f,%.2f\"/>\n",x,y);
306     printf("     </attribute>\n");
307     printf("     <attribute name=\"elem_width\">\n");
308     printf("       <real val=\"%.2f\"/>\n",node->dia.w);
309     printf("     </attribute>\n");
310     printf("     <attribute name=\"elem_height\">\n");
311     printf("       <real val=\"%.2f\"/>\n",node->dia.h);
312     printf("     </attribute>\n");
313     printf("     <attribute name=\"name\">\n");
314     printf("       <string>#%s#</string>\n",
315            smiGetFirstChildNode(node->smiNode)->name);
316     printf("     </attribute>\n");
317     printf("     <attribute name=\"stereotype\">\n");
318     printf("        <string>#%s#</string>\n", STEREOTYPE);
319     printf("     </attribute>\n");
320     printf("     <attribute name=\"abstract\">\n");
321     printf("       <boolean val=\"false\"/>\n");
322     printf("     </attribute>\n");
323     printf("     <attribute name=\"suppress_attributes\">\n");
324     printf("        <boolean val=\"false\"/>\n");    
325     printf("      </attribute>\n");   
326     printf("      <attribute name=\"suppress_operations\">\n");
327     printf("        <boolean val=\"true\"/>\n");
328     printf("      </attribute>\n");
329     printf("     <attribute name=\"visible_attributes\">\n");
330     printf("       <boolean val=\"true\"/>\n");
331     printf("     </attribute>\n");
332     printf("     <attribute name=\"visible_operations\">\n");
333     printf("        <boolean val=\"false\"/>\n");
334     printf("      </attribute>\n");
335
336     printf("     <attribute name=\"attributes\">\n");
337
338     if (node->smiNode->nodekind == SMI_NODEKIND_TABLE) {
339
340         diaPrintXMLRelatedScalars(node);
341
342         diaPrintAugmentIndex(node);
343         
344         for (smiElement = smiGetFirstElement(
345             smiGetFirstChildNode(node->smiNode));
346              smiElement;
347              smiElement = smiGetNextElement(smiElement)) {
348             diaPrintXMLAttribute(smiGetElementNode(smiElement),1);
349         }
350
351         if (PRINT_DETAILED_ATTR) {
352             diaPrintXMLAllColumns(node);
353         }
354     }
355     
356     printf("      </attribute>\n");
357     
358     printf("     <attribute name=\"operations\"/>\n");
359     printf("    <attribute name=\"template\">\n");
360     printf("      <boolean val=\"false\"/>\n");
361     printf("    </attribute>\n");
362     printf("     <attribute name=\"templates\"/>\n");
363     printf("   </object>\n");
364 }
365
366 /*
367  * prints a group of scalars denoted by group
368  */
369 static void diaPrintXMLGroup(int group, float x, float y)
370 {
371     GraphNode *tNode;
372
373     for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
374         if (tNode->group == group) break;
375     }
376
377     if (!tNode) return;
378     
379     printf("    <object type=\"UML - Class\" version=\"0\" id=\"%s\">\n",
380            smiGetParentNode(tNode->smiNode)->name);
381     printf("      <attribute name=\"obj_pos\">\n");
382     printf("       <point val=\"%.2f,%.2f\"/>\n",x,y);
383     printf("      </attribute>\n");
384     printf("     <attribute name=\"obj_bb\">\n");
385     printf("       <rectangle val=\"0.0,0.0;0.0,0.0\"/>\n");
386     printf("     </attribute>\n");
387     printf("     <attribute name=\"elem_corner\">\n");
388     printf("       <point val=\"%.2f,%.2f\"/>\n",x,y);
389     printf("     </attribute>\n");
390     printf("     <attribute name=\"elem_width\">\n");
391     printf("       <real val=\"%.2f\"/>\n",0.0);
392     printf("     </attribute>\n");
393     printf("     <attribute name=\"elem_height\">\n");
394     printf("       <real val=\"%.2f\"/>\n",0.0);
395     printf("     </attribute>\n");
396     printf("     <attribute name=\"name\">\n");
397     printf("       <string>#%s#</string>\n",
398            smiGetParentNode(tNode->smiNode)->name);
399     printf("     </attribute>\n");
400     printf("     <attribute name=\"stereotype\">\n");
401     printf("         <string>#%s#</string>\n", STEREOTYPE);
402     printf("     </attribute>\n");
403     printf("     <attribute name=\"abstract\">\n");
404     printf("       <boolean val=\"false\"/>\n");
405     printf("     </attribute>\n");
406     printf("     <attribute name=\"suppress_attributes\">\n");
407     printf("        <boolean val=\"false\"/>\n");    
408     printf("      </attribute>\n");   
409     printf("      <attribute name=\"suppress_operations\">\n");
410     printf("        <boolean val=\"true\"/>\n");
411     printf("      </attribute>\n");
412     printf("     <attribute name=\"visible_attributes\">\n");
413     printf("       <boolean val=\"true\"/>\n");
414     printf("     </attribute>\n");
415     printf("     <attribute name=\"visible_operations\">\n");
416     printf("        <boolean val=\"false\"/>\n");
417     printf("      </attribute>\n");
418
419     printf("     <attribute name=\"attributes\">\n");
420
421     for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
422         if (tNode->group == group) {
423             diaPrintXMLAttribute(tNode->smiNode,0);
424         }
425     }
426     
427     printf("      </attribute>\n");
428     
429     printf("     <attribute name=\"operations\"/>\n");
430     printf("    <attribute name=\"template\">\n");
431     printf("      <boolean val=\"false\"/>\n");
432     printf("    </attribute>\n");
433     printf("     <attribute name=\"templates\"/>\n");
434     printf("   </object>\n");
435 }
436
437 static float getRectSX(GraphNode *tNode)
438 {
439     return (float) (tNode->dia.w / 2.0 + tNode->dia.x - RECTCORRECTION);
440 }
441
442 static float getRectEX(GraphNode *tNode)
443 {
444     return (float) (tNode->dia.w / 2.0 + tNode->dia.x + RECTCORRECTION);
445 }
446
447 static float getRectSY(GraphNode *tNode)
448 {
449     return (float) (tNode->dia.y - 2.0 - RECTCORRECTION);
450 }
451
452 static float getRectEY(GraphNode *tNode)
453 {
454     return (float) (tNode->dia.y - 2.0 + RECTCORRECTION);
455 }
456
457
458 static int getConPoint(GraphNode *snode, GraphNode *enode)
459 {
460     float x1,y1,x2,y2;
461     int   con = 1;
462     
463     x1 = snode->dia.x;
464     y1 = snode->dia.y;
465     x2 = enode->dia.x;
466     y2 = enode->dia.y;    
467
468     if (x1 == x2 && y1 < y2) con = 6;
469     if (x1 == x2 && y1 > y1) con = 1;
470     if (x1 > x2 && y1 == y2) con = 3;
471     if (x1 < x2 && y1 == y2) con = 4;
472     if (x1 > x2 && y1 > y2)  con = 0;
473     if (x1 > x2 && y1 < y2)  con = 5;
474     if (x1 < x2 && y1 > y2)  con = 2;
475     if (x1 < x2 && y1 < y2)  con = 7;
476
477     return con;
478 }
479
480 static float getObjX(GraphNode *node, int con)
481 {
482     switch (con) {
483     case 0 :
484         return node->dia.x;
485         break;
486     case 1 :
487         return (float) (node->dia.w / 2.0 + node->dia.x);
488         break;
489     case 2 :
490         return node->dia.x + node->dia.w;
491         break;
492     case 3 :
493         return node->dia.x;
494         break;  
495     case 4 :
496         return node->dia.x + node->dia.w;
497         break;
498     case 5 :
499         return node->dia.x;
500         break;  
501     case 6 :
502         return (float) (node->dia.w / 2.0 + node->dia.x);
503         break;
504     case 7 :
505         return node->dia.x + node->dia.w;
506         break;
507     }
508     return 0.0;
509 }
510
511 static float getObjY(GraphNode *node, int con)
512 {
513     switch (con) {
514     case 0 :
515         return node->dia.y;
516         break;
517     case 1 :
518         return node->dia.y;
519         break;
520     case 2 :
521         return node->dia.y;
522         break;
523     case 3 :
524         return (float) (node->dia.y + TABLEHEIGHT / 2.0);
525         break;  
526     case 4 :
527         return (float) (node->dia.y + TABLEHEIGHT / 2.0);
528         break;
529     case 5 :
530         return node->dia.y + node->dia.h;
531         break;  
532     case 6 :
533         return node->dia.y + node->dia.h;
534         break;
535     case 7 :
536         return node->dia.y + node->dia.h;
537         break;
538     }
539     return 0.0;
540 }
541
542 static float getObjYRel(GraphEdge *edge, int con)
543 {
544     GraphNode *node, *node2;
545     float     dist;
546     
547     node = edge->startNode;
548     node2 = edge->endNode;
549     if (node->dia.y < node2->dia.y) {
550         dist = ABS(((node->dia.y + node->dia.h) - node2->dia.y ) / 2.0);
551     } else {
552         dist = ABS((node->dia.y - (node2->dia.y + node2->dia.h)) / 2.0);
553     }
554     
555     switch (con) {
556     case 0 :
557         return node->dia.y - dist;
558         break;
559     case 1 :
560         return node->dia.y - dist;
561         break;
562     case 2 :
563         return node->dia.y - dist;
564         break;
565     case 3 :
566         return (float) (node->dia.y + TABLEHEIGHT / 2.0);
567         break;  
568     case 4 :
569         return (float) (node->dia.y + TABLEHEIGHT / 2.0);
570         break;
571     case 5 :
572         return node->dia.y + node->dia.h + dist;
573         break;  
574     case 6 :
575         return node->dia.y + node->dia.h + dist;
576         break;
577     case 7 :
578         return node->dia.y + node->dia.h + dist;
579         break;
580     }
581     return 0.0;
582 }
583
584 /*
585  * diaPrintXMLCoordinates
586  *
587  * prints and calculates the coordinates of a given edge
588  */
589 static void diaPrintXMLCoordinates(GraphEdge *tEdge)
590 {
591     int scon, econ;
592
593     scon = getConPoint(tEdge->startNode, tEdge->endNode);
594     econ = getConPoint(tEdge->endNode, tEdge->startNode);
595     
596     printf("      <attribute name=\"obj_pos\">\n");
597     printf("        <point val=\"%.2f,%.2f\"/>\n"
598            ,getObjX(tEdge->startNode,scon)
599            ,getObjY(tEdge->startNode,scon));       
600     printf("     </attribute>\n");
601     printf("      <attribute name=\"obj_bb\">\n");
602     printf("       <rectangle val=\"%.2f,%.2f;%.2f,%.2f\"/>\n"
603            ,getRectSX(tEdge->startNode)
604            ,getRectSY(tEdge->startNode)
605            ,getRectEX(tEdge->startNode)
606            ,getRectEY(tEdge->startNode));
607     printf("     </attribute>\n");
608     printf("     <attribute name=\"orth_points\">\n");
609     printf("       <point val=\"%.2f,%.2f\"/>\n"
610            ,getObjX(tEdge->startNode,scon)
611            ,getObjY(tEdge->startNode,scon));    
612     printf("       <point val=\"%.2f,%.2f\"/>\n"
613            ,getObjX(tEdge->startNode,scon)
614            ,getObjYRel(tEdge,scon));
615     printf("       <point val=\"%.2f,%.2f\"/>\n"
616            ,getObjX(tEdge->endNode,econ)
617            ,getObjYRel(tEdge,scon));
618     printf("       <point val=\"%.2f,%.2f\"/>\n"
619            ,getObjX(tEdge->endNode,econ)
620            ,getObjY(tEdge->endNode,econ));      
621     printf("     </attribute>\n");
622 }
623
624 /*
625  * diaPrintXMLConPoints
626  *
627  * prints the connection points of an edge
628  */
629 static void diaPrintXMLConPoints(GraphEdge *tEdge)
630 {
631     int scon, econ;
632
633     scon = getConPoint(tEdge->startNode, tEdge->endNode);
634     econ = getConPoint(tEdge->endNode, tEdge->startNode);
635     
636     printf("    <connections>\n");
637     printf("      <connection handle=\"0\" to=\"%s\" connection=\"%d\"/>\n",
638            tEdge->startNode->smiNode->name,scon);
639     printf("      <connection handle=\"1\" to=\"%s\" connection=\"%d\"/>\n",
640            tEdge->endNode->smiNode->name, econ);
641     printf("    </connections>\n");    
642 }
643
644 static void diaPrintXMLDependency(GraphEdge *tEdge)
645 {
646     if (tEdge->dia.flags & DIA_PRINT_FLAG) return;
647     tEdge->dia.flags |= DIA_PRINT_FLAG;
648
649     printf("    <object type=\"UML - Dependency\" "
650            "version=\"0\" id=\"Depend:%s:%s\">\n",
651            tEdge->startNode->smiNode->name,
652            tEdge->endNode->smiNode->name);    
653
654     diaPrintXMLCoordinates(tEdge);
655     
656     printf("     <attribute name=\"orth_orient\">\n");
657     printf("       <enum val=\"1\"/>\n");
658     printf("       <enum val=\"0\"/>\n");
659     printf("       <enum val=\"1\"/>\n");
660     printf("     </attribute>\n");
661     printf("    <attribute name=\"draw_arrow\">\n");
662     printf("       <boolean val=\"true\"/>\n");
663     printf("      </attribute>\n");
664     printf("     <attribute name=\"name\">\n");
665     printf("        <string/>\n");
666     printf("   </attribute>\n");
667     printf("     <attribute name=\"stereotype\">\n");
668     printf("      <string/>\n");
669     printf("    </attribute>\n");
670
671     diaPrintXMLConPoints(tEdge);
672     
673     printf("    </object>\n");
674 }
675
676 /*
677  * Aggregation is a special case of the association.
678  * If aggregate = 1 it is an aggregation if 0 it is an association.
679  */
680 static void diaPrintXMLAssociation(GraphEdge *tEdge, int aggregate)
681 {
682     if (tEdge->dia.flags & DIA_PRINT_FLAG) return;
683     tEdge->dia.flags |= DIA_PRINT_FLAG;
684     if (aggregate > 1) aggregate = 1;
685     if (aggregate < 0) aggregate = 0;
686     
687     printf("    <object type=\"UML - Association\" "
688            "version=\"0\" id=\"Assoc:%s:%s\">\n",
689            tEdge->startNode->smiNode->name,
690            tEdge->endNode->smiNode->name);
691     
692     diaPrintXMLCoordinates(tEdge);
693     
694     printf("      <attribute name=\"orth_orient\">\n");
695     printf("        <enum val=\"1\"/>\n");
696     printf("        <enum val=\"0\"/>\n");
697     printf("        <enum val=\"1\"/>\n");   
698     printf("      </attribute>\n");
699     printf("      <attribute name=\"name\">\n");
700
701     switch(tEdge->indexkind) {
702     case SMI_INDEX_UNKNOWN :
703         switch (tEdge->enhancedindex) {
704         case GRAPH_ENHINDEX_UNKNOWN :
705             break;
706         case GRAPH_ENHINDEX_TYPES :
707             printf("       <string>#%s#</string>\n","");
708             break;
709         case GRAPH_ENHINDEX_NAMES :
710             printf("       <string>#%s#</string>\n","");
711             break;
712         case GRAPH_ENHINDEX_NOTIFICATION :
713             printf("       <string>#%s#</string>\n","");
714             break;
715         case GRAPH_ENHINDEX_INDEX :
716             /* should not occur - is handled below */
717             printf("       <string>#%s#</string>\n","");
718             break;
719         case GRAPH_ENHINDEX_REROUTE :
720             printf("       <string>#%s#</string>\n","");
721             break;
722         case GRAPH_ENHINDEX_POINTER :
723             printf("       <string>#%s#</string>\n","");
724             break;          
725         }
726         break;
727     case SMI_INDEX_INDEX :
728         printf("       <string>#%s#</string>\n","");
729         break;
730     case SMI_INDEX_AUGMENT :
731         printf("       <string>#%s#</string>\n","augments");
732         break;
733     case SMI_INDEX_SPARSE :
734         printf("       <string>#%s#</string>\n","sparses");
735         break;
736     case SMI_INDEX_REORDER :
737         printf("       <string>#%s#</string>\n","reorders");
738         break;
739     case SMI_INDEX_EXPAND :
740         printf("       <string>#%s#</string>\n","expands");
741         break;
742     }
743     
744     printf("      </attribute>\n");
745     printf("      <attribute name=\"direction\">\n");
746     printf("        <enum val=\"0\"/>\n");
747     printf("      </attribute>\n");
748     printf("      <attribute name=\"ends\">\n");
749     printf("        <composite>\n");
750     printf("          <attribute name=\"role\">\n");
751     printf("            <string/>\n");
752     printf("          </attribute>\n");
753     printf("          <attribute name=\"multiplicity\">\n");
754     
755     switch (tEdge->cardinality) {
756     case GRAPH_CARD_UNKNOWN :
757         printf("       <string># #</string>\n");
758         break;
759     case GRAPH_CARD_ONE_TO_ONE :
760         printf("       <string>#1#</string>\n");
761         break;
762     case GRAPH_CARD_ONE_TO_MANY :
763         printf("       <string>#1#</string>\n");
764         break;
765     case GRAPH_CARD_ZERO_TO_ONE :
766         printf("       <string>#0#</string>\n");
767         break;
768     case GRAPH_CARD_ZERO_TO_MANY :
769         printf("       <string>#0#</string>\n");
770         break;
771     case GRAPH_CARD_ONE_TO_ZERO_OR_ONE :
772         printf("       <string>#1#</string>\n");
773         break;          
774     }
775    
776     printf("          </attribute>\n");
777     printf("          <attribute name=\"arrow\">\n");
778     printf("            <boolean val=\"false\"/>\n");
779     printf("          </attribute>\n");
780     printf("          <attribute name=\"aggregate\">\n");
781     printf("            <enum val=\"0\"/>\n");
782     printf("          </attribute>\n");
783     printf("        </composite>\n");
784     printf("        <composite>\n");
785     printf("          <attribute name=\"role\">\n");
786     printf("            <string/>\n");
787     printf("          </attribute>\n");
788
789     printf("          <attribute name=\"multiplicity\">\n");
790
791     switch (tEdge->cardinality) {
792     case GRAPH_CARD_UNKNOWN :
793         printf("       <string># #</string>\n");
794         break;
795     case GRAPH_CARD_ONE_TO_ONE :
796         printf("       <string>#1#</string>\n");
797         break;
798     case GRAPH_CARD_ONE_TO_MANY :
799         printf("       <string>#*#</string>\n");
800         break;
801     case GRAPH_CARD_ZERO_TO_ONE :
802         printf("       <string>#1#</string>\n");
803         break;
804     case GRAPH_CARD_ZERO_TO_MANY :
805         printf("       <string>#*#</string>\n");
806         break;
807     case GRAPH_CARD_ONE_TO_ZERO_OR_ONE :
808         printf("       <string>#0..1#</string>\n");
809         break;  
810     }
811     
812     printf("          </attribute>\n");
813     printf("          <attribute name=\"arrow\">\n");
814     printf("            <boolean val=\"false\"/>\n");
815     printf("          </attribute>\n");
816     printf("          <attribute name=\"aggregate\">\n");
817     printf("            <enum val=\"%d\"/>\n",aggregate);
818     printf("          </attribute>\n");
819     printf("        </composite>\n");
820     printf("      </attribute>\n");
821
822     diaPrintXMLConPoints(tEdge);
823     
824     printf("    </object>\n");
825 }
826
827 static void diaPrintXMLConnection(GraphEdge *tEdge)
828 {
829     switch (tEdge->connection) {
830     case GRAPH_CON_UNKNOWN:
831         break;
832     case GRAPH_CON_AGGREGATION :
833         diaPrintXMLAssociation(tEdge,1);
834         break;
835     case GRAPH_CON_DEPENDENCY :
836         diaPrintXMLDependency(tEdge);
837         break;
838     case GRAPH_CON_ASSOCIATION :
839         diaPrintXMLAssociation(tEdge,0);
840         break;      
841     }
842 }
843
844 /*
845  * diaPrintXMLInfoNote
846  *
847  * Prints an UML note with a short information on it (Modulename and
848  * smidump version).
849  */
850 static void diaPrintXMLInfoNote(int modc, SmiModule **modv)
851 {
852     size_t  length;
853     float   width;
854     char   *note;
855     int     i;
856
857     const char *s1 = "Conceptual model of ";
858     const char *s2 = "- generated by smidump " SMI_VERSION_STRING;
859
860     /*
861      * Calculate the length of the string...
862      */
863     
864     length = strlen(s1) + strlen(s2) + 1;
865
866     for (i = 0; i < modc; i++) {
867         length += strlen(modv[i]->name) + 1;
868     }
869
870     /*
871      * ... before allocating a buffer and putting the string together.
872      */
873
874     note = xmalloc(length);
875     strcpy(note, s1);
876     for (i = 0; i < modc; i++) {
877         strcat(note, modv[i]->name);
878         strcat(note, " ");
879     }
880     strcat(note, s2);
881
882     width = (float)strlen(note) * (float)0.76;  /* don't ask */
883
884     printf("<object type=\"UML - Note\" version=\"0\" id=\"O0\">\n");
885     printf("  <attribute name=\"obj_pos\">\n");
886     printf("    <point val=\"%.2f,%.2f\"/>\n",XNOTE, YNOTE);
887     printf("  </attribute>\n");
888     printf("  <attribute name=\"obj_bb\">\n");
889     printf("    <rectangle val=\"%.2f,%.2f;%.2f,%.2f\"/>\n",
890            XNOTE-0.5, YNOTE-0.5, XNOTE-0.5 + width, YNOTE - 0.5 + 1.7);
891     printf("  </attribute>\n");
892     printf("  <attribute name=\"elem_corner\">\n");
893     printf("    <point val=\"%.2f,%.2f\"/>\n",XNOTE, YNOTE);
894     printf("  </attribute>\n");
895     printf("  <attribute name=\"elem_width\">\n");
896     printf("    <real val=\"%.2f\"/>\n", width);
897     printf("  </attribute>\n");
898     printf("  <attribute name=\"elem_height\">\n");
899     printf("    <real val=\"1.7\"/>\n");
900     printf("  </attribute>\n");
901     printf("  <attribute name=\"text\">\n");
902     printf("    <composite type=\"text\">\n");
903     printf("      <attribute name=\"string\">\n");
904     printf("        <string>#%s#</string>\n", note);
905     printf("      </attribute>\n");
906     printf("      <attribute name=\"font\">\n");
907     printf("        <font name=\"Courier\"/>\n");
908     printf("      </attribute>\n");
909     printf("      <attribute name=\"height\">\n");
910     printf("        <real val=\"0.8\"/>\n");
911     printf("      </attribute>\n");
912     printf("      <attribute name=\"pos\">\n");
913     printf("        <point val=\"%.2f,%.2f\"/>\n", XNOTE + 0.35, YNOTE + 1.28);
914     printf("      </attribute>\n");
915     printf("      <attribute name=\"color\">\n");
916     printf("        <color val=\"#000000\"/>\n");
917     printf("      </attribute>\n");
918     printf("      <attribute name=\"alignment\">\n");
919     printf("        <enum val=\"0\"/>\n");
920     printf("      </attribute>\n");
921     printf("    </composite>\n");
922     printf("  </attribute>\n");
923     printf("</object>\n");
924
925     xfree(note);
926 }
927
928 /*
929  * diaCalcSize
930  *
931  * Calculates the size of a given node for the UML representation.
932  */
933 static GraphNode *diaCalcSize(GraphNode *node)
934 {
935     GraphEdge  *tEdge;
936     SmiNode    *tNode,*ppNode;
937     SmiElement *smiElement;
938     SmiModule  *module;
939
940     if (node->smiNode->nodekind == SMI_NODEKIND_SCALAR) return node;
941     
942     node->dia.w = (strlen(node->smiNode->name)+4) * HEADFONTSIZETABLE
943         + HEADSPACESIZETABLE;
944     
945     node->dia.h = TABLEHEIGHT;
946     for (smiElement = smiGetFirstElement(
947         smiGetFirstChildNode(node->smiNode));
948          smiElement;
949          smiElement = smiGetNextElement(smiElement)) {
950         
951         tNode = smiGetElementNode(smiElement);
952         
953         node->dia.w = max(node->dia.w, (strlen(tNode->name) +
954                                         strlen(algGetTypeName(tNode)) +
955                                         strlen(INDEXPROPERTY))
956                       * ATTRFONTSIZE
957                       + ATTRSPACESIZE);
958         node->dia.h += TABLEELEMHEIGHT;
959     }
960     
961     for (tEdge = graphGetFirstEdgeByNode(graph,node);
962          tEdge;
963          tEdge = graphGetNextEdgeByNode(graph, tEdge, node)) {
964         if (tEdge->startNode == node &&
965             tEdge->endNode->smiNode->nodekind == SMI_NODEKIND_SCALAR) {
966             node->dia.h += TABLEELEMHEIGHT;
967             tNode = tEdge->endNode->smiNode;
968             
969             node->dia.w = max(node->dia.w, (strlen(tNode->name) +
970                                     strlen(algGetTypeName(tNode)))
971                           * ATTRFONTSIZE
972                           + ATTRSPACESIZE);             
973         }
974     }
975
976     if (PRINT_DETAILED_ATTR && node->smiNode->nodekind == SMI_NODEKIND_TABLE) {
977         module  = smiGetNodeModule(node->smiNode);
978
979         for (tNode = smiGetFirstNode(module, SMI_NODEKIND_COLUMN);
980              tNode;
981              tNode = smiGetNextNode(tNode, SMI_NODEKIND_COLUMN)) {
982             ppNode = smiGetParentNode(tNode);
983             ppNode = smiGetParentNode(ppNode);
984
985             if (cmpSmiNodes(node->smiNode, ppNode)) {
986                 int len;
987                 char *typeName;
988
989                 typeName = algGetTypeName(tNode);
990                 len = strlen(tNode->name) + (typeName ? strlen(typeName) : 0);
991                 node->dia.h += TABLEELEMHEIGHT;
992                 node->dia.w = max(node->dia.w, len)
993                     * ATTRFONTSIZE
994                     + ATTRSPACESIZE;
995             }
996         }
997     }
998     
999     return node;
1000 }
1001
1002 static float diaPrintNode(GraphNode *node, float x, float y)
1003 {
1004     GraphEdge *tEdge;
1005
1006     for (tEdge = graphGetFirstEdgeByNode(graph, node);
1007          tEdge;
1008          tEdge = graphGetNextEdgeByNode(graph, tEdge, node)) {
1009         if (! (tEdge->dia.flags & DIA_PRINT_FLAG)) {
1010             if (node == tEdge->startNode) {
1011                 y += tEdge->endNode->dia.h + YSPACING;    
1012                 diaPrintXMLObject(tEdge->endNode, x, y);
1013                 diaPrintXMLConnection(tEdge);
1014                 y = diaPrintNode(tEdge->startNode, x, y);
1015                               /* (x+tEdge->startNode->dia.w+XSPACING),y); */
1016                 
1017                 y = diaPrintNode(tEdge->endNode,
1018                   (x+tEdge->startNode->dia.w+XSPACING), y);
1019             }
1020         }
1021     }
1022
1023     return y;
1024 }
1025
1026 static void diaPrintXML(int modc, SmiModule **modv)
1027 {
1028     GraphNode *tNode;
1029     GraphEdge *tEdge;
1030     float     x,y,ydiff;
1031     int       group;
1032     
1033     diaPrintXMLHeader();
1034
1035     for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) { 
1036         tNode = diaCalcSize(tNode);
1037     }
1038
1039     diaPrintXMLInfoNote(modc, modv);
1040     
1041     x = XOFFSET;
1042     y = YOFFSET;
1043     ydiff = 0;
1044
1045     for (tEdge = graph->edges; tEdge; tEdge = tEdge->nextPtr) {
1046         if (! (tEdge->dia.flags & DIA_PRINT_FLAG)) {
1047             diaPrintXMLObject(tEdge->startNode, x, y);
1048             x = x + tEdge->startNode->dia.w + XSPACING;
1049
1050             diaPrintXMLObject(tEdge->endNode, x, y);
1051             diaPrintXMLConnection(tEdge);
1052             
1053             ydiff = tEdge->startNode->dia.h;
1054
1055             y = diaPrintNode(tEdge->startNode,x,y);
1056             y = diaPrintNode(tEdge->endNode,x,y);    
1057
1058             y = y + ydiff + YSPACING;
1059             x = XOFFSET;
1060         }
1061     }
1062     
1063     x = XOFFSET;
1064     y += ydiff;
1065     ydiff = 0;
1066     
1067     /* printing singular tables */
1068     for (tNode = graph->nodes; tNode; tNode = tNode->nextPtr) {
1069         if (!graphGetFirstEdgeByNode(graph,tNode) &&
1070             tNode->smiNode->nodekind != SMI_NODEKIND_SCALAR) {
1071             diaPrintXMLObject(tNode,x,y);
1072             
1073             x += tNode->dia.w + XSPACING;
1074             ydiff = max(ydiff, tNode->dia.h);
1075             if (x >= NEWLINEDISTANCE) {
1076                 x = XOFFSET;
1077                 y += ydiff + YSPACING;
1078             }
1079         }
1080     }
1081
1082     /* printing scalar groups */
1083     x = XOFFSET;
1084     y += ydiff + YSPACING;
1085     for (group = 1;
1086          group <= algGetNumberOfGroups();
1087          group++) {
1088         diaPrintXMLGroup(group,x,y);
1089         x += 2.0;
1090         y += 2.0;
1091     }
1092     
1093     diaPrintXMLClose();
1094 }
1095
1096
1097
1098 /* ------------------------------------------------------------------------- */
1099
1100 static void printModuleNames(int modc, SmiModule **modv)
1101 {
1102     int i;
1103     
1104     printf("Conceptual model of: ");
1105
1106     for (i = 0; i < modc; i++) {
1107         printf("%s ", modv[i]->name);
1108     }
1109
1110     printf("(generated by smidump " SMI_VERSION_STRING ")\n\n");
1111 }
1112
1113
1114
1115 static void dumpCm(int modc, SmiModule **modv, int flags, char *output)
1116 {
1117     int       i;
1118
1119     if (flags & SMIDUMP_FLAG_UNITE) {
1120         if (! graph) {
1121             graph = xmalloc(sizeof(Graph));
1122             graph->nodes = NULL;
1123             graph->edges = NULL;
1124             graph->components = NULL;
1125         }
1126         
1127         for (i = 0; i < modc; i++) {
1128             algCreateNodes(modv[i]);
1129         }
1130         
1131         if (XPLAIN) {
1132             printModuleNames(modc, modv);
1133             printf("\n--- First Phase - loading tables and scalars\n\n");
1134             graphShowNodes(graph);
1135             printf("\n");
1136         }
1137         
1138         algLinkTables();
1139         algCheckLinksByName();
1140         algConnectLonelyNodes();
1141         algCheckForDependency();
1142         algCheckForPointerRels();
1143         
1144         if (!XPLAIN) {
1145             diaPrintXML(modc, modv);
1146         }
1147         graphExit(graph);
1148         graph = NULL;
1149     } else {
1150         for (i = 0; i < modc; i++) {
1151             if (! graph) {
1152                 graph = xmalloc(sizeof(Graph));
1153                 graph->nodes = NULL;
1154                 graph->edges = NULL;
1155                 graph->components = NULL;
1156             }
1157             
1158             algCreateNodes(modv[i]);
1159             
1160             if (XPLAIN) {
1161                 printModuleNames(1, &(modv[i]));
1162                 printf("\n--- First Phase - loading tables and scalars\n\n");
1163                 graphShowNodes(graph);
1164                 printf("\n");
1165             }
1166         
1167             algLinkTables();
1168             algCheckLinksByName();
1169             algConnectLonelyNodes();
1170             algCheckForDependency();
1171             algCheckForPointerRels();
1172             
1173             if (!XPLAIN) {
1174                 diaPrintXML(1, &(modv[i]));
1175             }
1176         
1177             graphExit(graph);
1178             graph = NULL;
1179         }
1180     }
1181
1182     if (fflush(stdout) || ferror(stdout)) {
1183         perror("smidump: write error");
1184         exit(1);
1185     }
1186 }
1187
1188
1189
1190 void initCm()
1191 {
1192     static SmidumpDriverOption opt[] = {
1193         { "explain", OPT_FLAG, &XPLAIN, 0,
1194           "explain what the algorithm does"},
1195         { 0, OPT_END, 0, 0 }
1196     };
1197
1198     static SmidumpDriver driver = {
1199         "cm",
1200         dumpCm,
1201         SMI_FLAG_NODESCR,
1202         SMIDUMP_DRIVER_CANT_OUTPUT,
1203         "reverse engineered conceptual model",
1204         opt,
1205         NULL
1206     };
1207
1208     smidumpRegisterDriver(&driver);
1209 }