1 /*
2 This file is part of dia2code. It generates code from an UML Dia Diagram.
3 Copyright (C) 2001-2014 Chris McGee - Oliver Kellogg
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 
20 #include <stdarg.h>
21 
22 #include "dia2code.hpp"
23 #include "decls.hpp"
24 #include "includes.hpp"
25 
26 static void
check_umlattr(umlattribute * u,char * typename_)27 check_umlattr (umlattribute *u, char *typename_)
28 {
29     /* Check settings that don't make sense for IDL generation.  */
30     if (u->visibility == '1')
31         fprintf (stderr, "%s/%s: ignoring non-visibility\n", typename_, u->name);
32     if (u->isstatic)
33         fprintf (stderr, "%s/%s: ignoring staticness\n", typename_, u->name);
34 }
35 
36 
37 static void
do_operations(char * typename_,umloplist umlo)38 do_operations (char *typename_, umloplist umlo)
39 {
40     if (umlo == NULL)
41         return;
42 
43     print ("// Operations\n");
44 
45     while (umlo != NULL) {
46         umlattrlist tmpa = umlo->key.parameters;
47 
48         print ("");
49 
50         if (umlo->key.attr.isabstract) {
51             fprintf (stderr, "ignoring abstractness\n");
52             /* umlo->key.attr.value[0] = '0'; */
53         }
54         check_umlattr (&umlo->key.attr, typename_);
55 
56         if (strlen (umlo->key.attr.type) > 0)
57             emit ("%s ", umlo->key.attr.type);
58         else
59             emit ("void ");
60         emit ("%s (", umlo->key.attr.name);
61 
62         while (tmpa != NULL) {
63             emit ("in %s %s", tmpa->key.type, tmpa->key.name);
64             if (tmpa->key.value[0] != 0)
65                 fprintf (stderr, "ignoring default value %s\n", tmpa->key.value);
66             tmpa = tmpa->next;
67             if (tmpa != NULL) {
68                 emit (", ");
69             }
70         }
71 
72         emit (")");
73 
74         if (umlo->key.attr.value[0] != 0)
75             fprintf (stderr, "ignoring default value %s", umlo->key.attr.value);
76         emit (";\n");
77         umlo = umlo->next;
78     }
79 }
80 
81 
82 static void
close_scope()83 close_scope ()
84 {
85     indentlevel--;
86     print ("};\n\n");
87 }
88 
89 static void
gen_interface(umlclassnode * node)90 gen_interface (umlclassnode *node)
91 {
92     char *typename_ = node->key->name;
93 
94     print ("interface %s", typename_);
95 
96     if (node->parents != NULL) {
97         umlclasslist parents = node->parents;
98         emit (":");
99         while (parents != NULL) {
100             emit (" %s", parents->key->name);
101             parents = parents->next;
102             if (parents != NULL) {
103                 emit (", ");
104             }
105         }
106     }
107     emit (" {\n");
108     indentlevel++;
109 
110     if (node->associations) {
111         umlassoclist associations = node->associations;
112         print ("// Associations\n");
113         while (associations != NULL) {
114             /* Explicit usage of associations->composite is not
115                supported by IDL. Perhaps we could give some
116                intelligent warning here.  */
117             print ("readonly attribute%s %s;\n",
118                     associations->key->name, associations->name);
119             associations = associations->next;
120         }
121     }
122 
123     if (node->key->attributes != NULL) {
124         umlattrlist umla = node->key->attributes;
125         print ("// Attributes\n");
126         while (umla != NULL) {
127             check_umlattr (&umla->key, typename_);
128             print ("attribute %s %s;\n", umla->key.type, umla->key.name);
129             umla = umla->next;
130         }
131     }
132 
133     do_operations (typename_, node->key->operations);
134     close_scope ();
135 }
136 
137 
138 static void
genDecl(declaration * d)139 genDecl (declaration *d)
140 {
141     char *name;
142     char *stype;
143     umlclassnode *node;
144     umlattrlist umla;
145 
146     if (d == NULL)
147         return;
148 
149     if (d->decl_kind == dk_module) {
150         name = d->u.this_module->pkg->name;
151         print ("module %s {\n", name);
152         indentlevel++;
153         d = d->u.this_module->contents;
154         while (d != NULL) {
155             genDecl (d);
156             d = d->next;
157         }
158         close_scope ();
159         return;
160     }
161 
162     node = d->u.this_class;
163     stype = node->key->stereotype;
164     name = node->key->name;
165     umla = node->key->attributes;
166 
167     if (strlen (stype) == 0) {
168         gen_interface (node);
169         return;
170     }
171 
172     if (eq (stype, "CORBANative")) {
173         print ("native %s;\n\n", name);
174 
175     } else if (isConstStereo (stype)) {
176         if (umla == NULL) {
177             fprintf (stderr, "Error: first attribute not set at const %s\n", name);
178             exit (1);
179         }
180         if (strlen (umla->key.name) > 0)
181             fprintf (stderr, "Warning: ignoring attribute name at const %s\n", name);
182 
183         print ("const %s %s = %s;\n\n", umla->key.type, name, umla->key.value);
184 
185     } else if (isEnumStereo (stype)) {
186         print ("enum %s {\n", name);
187         indentlevel++;
188         while (umla != NULL) {
189             char *literal = umla->key.name;
190             check_umlattr (&umla->key, name);
191             if (strlen (umla->key.type) > 0)
192                 fprintf (stderr, "%s/%s: ignoring type\n", name, literal);
193             print ("%s", literal);
194             if (umla->next)
195                 emit (",");
196             emit ("\n");
197             umla = umla->next;
198         }
199         close_scope ();
200 
201     } else if (isStructStereo (stype) ||
202                eq (stype, "CORBAException")) {
203         int corba_ofst = strncmp (stype, "CORBA", 5) == 0 ? 5 : 0;
204         char *keyword = strtolower (stype + corba_ofst);
205         print ("%s %s {\n", keyword, name);
206         indentlevel++;
207         while (umla != NULL) {
208             char *member = umla->key.name;
209             check_umlattr (&umla->key, name);
210             print ("%s %s;\n", umla->key.type, member);
211             umla = umla->next;
212         }
213         close_scope ();
214 
215     } else if (eq (stype, "CORBAUnion")) {
216         umlattrnode *sw = umla;
217         if (sw == NULL) {
218             fprintf (stderr, "Error: attributes not set at union %s\n", name);
219             exit (1);
220         }
221         if (strlen (sw->key.name) > 0 && !eq (sw->key.name, "switch")) {
222             emit ("%s// #switchname %s %s\n\n", name, sw->key.name);
223         }
224         print ("union %s switch (%s) {\n", name, sw->key.type);
225         indentlevel++;
226         umla = umla->next;
227         while (umla != NULL) {
228             char *member = umla->key.name;
229             check_umlattr (&umla->key, name);
230             print ("case %s:\n", umla->key.value);
231             print ("  %s %s;\n", umla->key.type, member);
232             umla = umla->next;
233         }
234         close_scope ();
235 
236     } else if (isTypedefStereo (stype)) {
237         /* Conventions for CORBATypedef:
238            The first (and only) attribute contains the following:
239            Name:   Empty - the name is taken from the class.
240            Type:   Name of the original type which is typedefed.
241            Value:  Optionally contains array dimension(s) of the typedef.
242                    These dimensions are given in square brackets, e.g.
243                    [3][10]
244          */
245         if (umla == NULL) {
246             fprintf (stderr, "Error: first attribute (impl type) not set "
247                              "at typedef %s\n", name);
248             exit (1);
249         }
250         if (umla->key.name != NULL && strlen (umla->key.name) > 0)  {
251             fprintf (stderr, "Warning: typedef %s: ignoring name field "
252                              "in implementation type attribute\n", name);
253         }
254         print ("typedef %s %s%s;\n\n", umla->key.type, name, umla->key.value);
255 
256     } else if (eq (stype, "CORBAValue")) {
257         print ("");
258         if (node->key->isabstract) {
259             emit ("abstract ");
260         }
261         emit ("valuetype %s", name);
262         if (node->parents != NULL) {
263             umlclasslist parents = node->parents;
264             emit (" :");
265             while (parents != NULL) {
266                 emit (" %s", parents->key->name);
267                 parents = parents->next;
268                 if (parents != NULL) {
269                     emit (", ");
270                 }
271             }
272         }
273         emit (" {\n");
274         indentlevel++;
275         if (node->associations) {
276             umlassoclist associations = node->associations;
277             print ("// Associations\n");
278             while (associations != NULL) {
279                 /* Explicit usage of associations->composite is not
280                    supported by IDL. Perhaps we could give some
281                    intelligent warning here.  */
282                 /* How to map valuetype associations is still an issue of
283                    discussion.  For now, we follow the generate_code_java
284                    style and map them to private members.
285                    FIXME: The user currently has no control over the order
286                    in which the members are generated.  */
287                 print ("private %s %s;\n",
288                         associations->key->name, associations->name);
289                 associations = associations->next;
290             }
291         }
292         if (umla) {
293             print ("// State members\n");
294             while (umla != NULL) {
295                 char *member = umla->key.name;
296                 if (umla->key.isstatic)
297                     fprintf (stderr, "%s/%s: ignoring staticness\n", name, member);
298                 print ("");
299                 if (umla->key.visibility == '1')
300                     emit ("private");
301                 else
302                     emit ("public");
303                 emit (" %s %s;\n", umla->key.type, member);
304                 umla = umla->next;
305             }
306         }
307         do_operations (name, node->key->operations);
308         close_scope ();
309     } else {
310         print ("// %s\n", stype);
311         gen_interface (node);
312     }
313 }
314 
315 
316 static void
put_hfence(char * name)317 put_hfence (char *name)
318 {
319     char *tmpname = strtoupper (name);
320     emit ("#ifndef %s_IDL\n", tmpname);
321     emit ("#define %s_IDL\n\n", tmpname);
322     free (tmpname);
323 }
324 
325 void
generate_code_idl(batch * b)326 generate_code_idl (batch *b)
327 {
328     declaration *d;
329     umlclasslist tmplist = b->classlist;
330 
331     FILE *licensefile = NULL;
332 
333     if (file_ext == NULL)
334         file_ext = "idl";
335 
336     /* open license file */
337     if ( b->license != NULL ) {
338         licensefile = fopen(b->license, "r");
339         if(!licensefile) {
340             fprintf (stderr, "Can't open the license file.\n");
341             exit(2);
342         }
343     }
344 
345     while (tmplist != NULL) {
346         char *name = tmplist->key->name;
347         if (! (is_present (b->classes, name) ^ b->mask)) {
348             push (tmplist, b);
349         }
350         tmplist = tmplist->next;
351     }
352 
353     /* Generate a file for each outer declaration.
354        Rose does it more elegantly. They use components for the files,
355        and realizations for deciding which decl goes into which file.  */
356     d = decls;
357     while (d != NULL) {
358         char *name;
359         char filename[BIG_BUFFER];
360 
361         if (d->decl_kind == dk_module) {
362             name = d->u.this_module->pkg->name;
363         } else {         /* dk_class */
364             name = d->u.this_class->key->name;
365         }
366 
367         sprintf (filename, "%s.%s", name, file_ext);
368         /**
369          * The filename is no longer lowercased.
370          *  Selectively do this as soon as we have a
371          *  command line option for it.
372         */
373 
374         spec = openOutfile (filename, b);
375         if (spec == NULL) {
376             d = d->next;
377             continue;
378         }
379 
380         /* add license to the header */
381         if (b->license != NULL) {
382             int lc;
383             rewind (licensefile);
384             while ((lc = fgetc (licensefile)) != EOF)
385                 emit ("%c", (char) lc);
386         }
387 
388         put_hfence (name);
389 
390         includes = NULL;
391         determineIncludes (d, b);
392         if (includes) {
393             namelist incfile = includes;
394             while (incfile != NULL) {
395                 if (!eq (incfile->name, name)) {
396                     emit ("#include \"%s.%s\"\n", incfile->name, file_ext);
397                 }
398                 incfile = incfile->next;
399             }
400             emit ("\n");
401         }
402 
403         genDecl (d);
404 
405         emit ("#endif\n");   /* from hfence */
406         fclose (spec);
407 
408         d = d->next;
409     }
410 }
411 
412 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
413