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 (¨o->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 (¨a->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 (¨a->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 (¨a->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 (¨a->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