1 /*
2 This file is part of dia2code. It generates code from an UML Dia Diagram.
3 Copyright (C) 2000-2014 Javier O'Hara - 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 /* NB: If you use CORBA stereotypes, you will need the file p_orb.h
21    found in the runtime/cpp directory.  */
22 
23 #include "config.h"
24 
25 #include <iostream>
26 #include <cassert>
27 #include <algorithm>
28 
29 #if defined(_WIN32) || defined(_WIN64)
30 #include <direct.h>
31 #else
32 #include <sys/stat.h>
33 #endif
34 
35 #include "GenerateCode.hpp"
36 #include "scan_tree.hpp"
37 #include "string2.hpp"
38 
39 #define eq  !strcmp
40 
GenerateCode(DiaGram & diagram,const char * ext,uint8_t version_,bool handleIncludePackage_,bool noLoopSupport_)41 GenerateCode::GenerateCode (DiaGram    & diagram,
42                             const char * ext,
43                             uint8_t      version_,
44                             bool         handleIncludePackage_,
45                             bool         noLoopSupport_) :
46     dia (diagram),
47     license (),
48     outdir ("."),
49     file_ext (ext),
50     file (),
51     version (version_),
52     indent (4),
53     indentlevel (0),
54     overwrite (true),
55     buildtree (false),
56     bOpenBraceOnNewline (false),
57     oneClassOneHeader (false),
58     handleIncludePackage (handleIncludePackage_),
59     noLoopSupport (noLoopSupport_)
60 #ifdef ENABLE_CORBA
61     , isCorba (false)
62 #endif
63 {
64 }
65 
66 
67 DiaGram &
getDia()68 GenerateCode::getDia () {
69     return dia;
70 }
71 
72 
73 const std::string &
getLicense() const74 GenerateCode::getLicense () const {
75     return license;
76 }
77 
78 
79 void
setLicense(const char * lic)80 GenerateCode::setLicense (const char * lic) {
81     license.assign (lic);
82 }
83 
84 
85 const char *
getOutdir() const86 GenerateCode::getOutdir () const {
87     return outdir.c_str ();
88 }
89 
90 
91 const std::string *
getOutdirS() const92 GenerateCode::getOutdirS () const {
93     return &outdir;
94 }
95 
96 
97 void
setOutdir(const char * dir)98 GenerateCode::setOutdir (const char * dir) {
99     outdir.assign (dir);
100 }
101 
102 
103 bool
getOverwrite() const104 GenerateCode::getOverwrite () const {
105     return overwrite;
106 }
107 
108 
109 void
setOverwrite(bool over)110 GenerateCode::setOverwrite (bool over) {
111     overwrite = over;
112 }
113 
114 
115 bool
getBuildTree() const116 GenerateCode::getBuildTree () const {
117     return buildtree;
118 }
119 
120 
121 void
setBuildTree(bool build)122 GenerateCode::setBuildTree (bool build) {
123     if (build) {
124         oneClassOneHeader = true;
125     }
126     buildtree = build;
127 
128     return;
129 }
130 
131 
132 bool
getOpenBraceOnNewline() const133 GenerateCode::getOpenBraceOnNewline () const {
134     return bOpenBraceOnNewline;
135 }
136 
137 
138 void
setOpenBraceOnNewline(bool newline)139 GenerateCode::setOpenBraceOnNewline (bool newline) {
140     bOpenBraceOnNewline = newline;
141 }
142 
143 bool
getOneClass() const144 GenerateCode::getOneClass () const {
145     return oneClassOneHeader;
146 }
147 
148 
149 void
setOneClass(bool value)150 GenerateCode::setOneClass (bool value) {
151     oneClassOneHeader = value;
152 }
153 
154 void
setHandleIncludePackage(bool val)155 GenerateCode::setHandleIncludePackage (bool val) {
156     handleIncludePackage = val;
157 }
158 
159 
160 #ifdef ENABLE_CORBA
161 bool
getCorba() const162 GenerateCode::getCorba () const {
163     return isCorba;
164 }
165 #endif
166 
167 void
openOutfile(const std::string & filename,declaration & d)168 GenerateCode::openOutfile (const std::string & filename, declaration & d) {
169     static std::string outfilename;
170     std::string tmpname;
171 
172     outfilename.assign (outdir);
173     outfilename.append (1, SEPARATOR);
174     outfilename.append (filename);
175     outfilename.append (".");
176     outfilename.append (getFileExt ());
177 
178     std::ifstream f (outfilename.c_str ());
179 
180     if ((f.good ()) && (!overwrite)) {
181         f.close();
182         throw std::string ("Overwrite " + outfilename + " is forbidden.\n");
183     }
184     else {
185         f.close();
186     }
187 
188     file.push_back (new std::ofstream ());
189     file.back ()->open (outfilename.c_str ());
190     if (!file.back ()->is_open ()) {
191         file.back ()->close ();
192         throw std::string ("Failed to create " + outfilename + ".\n");
193     }
194 
195     tmpname = strtoupper (filename);
196     assert (indentlevel == 0);
197     writeStartHeader (tmpname);
198 
199     writeLicense ();
200 
201     getDia ().cleanIncludes ();
202     getDia ().determineIncludes (d, !handleIncludePackage, noLoopSupport);
203 #ifdef ENABLE_CORBA
204     if (getDia ().getUseCorba ()) {
205         writeInclude ("p_orb.h");
206         getFile () << "\n";
207     }
208 #endif
209 
210     if (d.decl_kind == dk_class) {
211         writeBeforeInclude (d.u.this_class);
212     }
213     writeInclude (getDia ().getIncludes ());
214     if (d.decl_kind == dk_class) {
215         writeAfterInclude (d.u.this_class);
216     }
217 
218     return;
219 }
220 
221 void
closeOutfile()222 GenerateCode::closeOutfile () {
223     writeEndHeader ();
224     assert (indentlevel == 0);
225     file.back ()->close ();
226     delete file.back ();
227     file.pop_back ();
228 }
229 
230 void
generate_code()231 GenerateCode::generate_code () {
232     std::list <declaration>::iterator it2;
233     std::list <umlClassNode *> tmplist = getDia ().getUml ();
234 
235     for (umlClassNode * it : tmplist) {
236         if (!it->isPushed ()) {
237             getDia ().push (it);
238         }
239     }
240 
241     // Generate a file for each outer declaration.
242     it2 = getDia ().getDeclBegin ();
243     while (it2 != getDia ().getDeclEnd ()) {
244         if (it2->decl_kind == dk_class) {
245             if ((getDia ().getGenClasses ().empty ()) ||
246                 (isPresent (getDia ().getGenClasses (),
247                             it2->u.this_class->getName ().c_str ()) ^
248                                                   getDia ().getInvertSel ())) {
249                 genDecl (*it2, true);
250             }
251         }
252         else {
253             genDecl (*it2, true);
254         }
255 
256         ++it2;
257     }
258 }
259 
260 const char *
getFileExt() const261 GenerateCode::getFileExt () const {
262     return file_ext.c_str ();
263 }
264 
265 
266 void
setFileExt(const char * ext)267 GenerateCode::setFileExt (const char * ext) {
268     file_ext.assign (ext);
269 }
270 
271 
272 const char *
getBodyFileExt() const273 GenerateCode::getBodyFileExt () const {
274     return body_file_ext.c_str ();
275 }
276 
277 
278 void
setBodyFileExt(const char * ext)279 GenerateCode::setBodyFileExt (const char * ext) {
280     body_file_ext.assign (ext);
281 }
282 
283 
284 std::ofstream &
getFile()285 GenerateCode::getFile () {
286     return *file.back ();
287 }
288 
289 char *
subst(char * str,const char search,char replace)290 subst (char *str, const char search, char replace) {
291     char *p;
292     while ((p = strchr (str, search)) != NULL) {
293         *p = replace;
294     }
295     return str;
296 }
297 
298 char *
nospc(char * str)299 nospc (char *str) {
300     return subst (str, ' ', '_');
301 }
302 
303 bool
passByReference(umlClass & cl) const304 GenerateCode::passByReference (umlClass & cl) const {
305     if (cl.isStereotypeTypedef ()) {
306         umlClassNode *ref = findByName (dia.getUml (),
307                                         cl.getName ().c_str ());
308         if (ref == NULL) {
309             return false;
310         }
311         return passByReference (*ref);
312     }
313     return (!cl.isStereotypeConst () &&
314             !cl.isStereotypeEnum ());
315 }
316 
317 #ifdef ENABLE_CORBA
318 static bool
isOoClass(umlClass & cl)319 isOoClass (umlClass &cl) {
320     const char *st;
321     st = cl.getStereotype ().c_str ();
322     if (strlen (st) == 0) {
323         return true;
324     }
325     return (!isConstStereo (st) &&
326             !isTypedefStereo (st) &&
327             !isEnumStereo (st) &&
328             !isStructStereo (st) &&
329             !eq (st, "CORBAUnion") &&
330             !eq (st, "CORBAException"));
331 }
332 #endif
333 
334 const char *
cppName(std::string name)335 GenerateCode::cppName (std::string name) {
336     static std::string buf;
337 #ifdef ENABLE_CORBA
338     if (dia.getUseCorba ()) {
339         if (name.compare ("boolean") == 0 || name.compare ("char") == 0 || name.compare ("octet") == 0 ||
340             name.compare ("short") == 0 ||
341             name.compare ("long") == 0 ||
342             name.compare ("float") == 0 ||
343             name.compare ("double") == 0 ||
344             name.compare ("string") == 0 ||
345             name.compare ("any") == 0) {
346                 buf.assign (strPackage ("CORBA"));
347                 buf.append (nospc (const_cast <char *> (
348                                             strtoupperfirst (name).c_str ())));
349         }
350         else if (name.compare ("long long") == 0) {
351             buf.assign (strPackage ("CORBA"));
352             buf.append ("LongLong");
353         }
354         else if (name.compare ("unsigned short") == 0) {
355             buf.assign (strPackage ("CORBA"));
356             buf.append ("UShort");
357         }
358         else if (name.compare ("unsigned long") == 0) {
359             buf.assign (strPackage ("CORBA"));
360             buf.append ("ULong");
361         }
362         else if (name.compare ("unsigned long long") == 0) {
363             buf.assign (strPackage ("CORBA"));
364             buf.append ("ULongLong");
365         }
366         else {
367             buf.assign (name);
368         }
369     } else
370 #endif
371     {
372         buf.assign (name);
373     }
374     return buf.c_str ();
375 }
376 
377 const char *
fqname(const umlClassNode & node,bool use_ref_type) const378 GenerateCode::fqname (const umlClassNode &node, bool use_ref_type) const {
379     static std::string buf;
380 
381     buf.clear ();
382     if (node.getPackage () != NULL) {
383         std::list <umlPackage *> pkglist;
384 
385         umlPackage::makePackageList (node.getPackage (), pkglist);
386         for (const umlPackage * it : pkglist) {
387             buf.append (strPackage (it->getName ().c_str ()));
388         }
389     }
390     if (use_ref_type) {
391         buf.append (strPointer (node.getName ()));
392     }
393     else {
394         buf.append (node.getName ());
395     }
396     return buf.c_str ();
397 }
398 
399 void
genClass(const umlClassNode & node)400 GenerateCode::genClass (const umlClassNode & node) {
401 #ifdef ENABLE_CORBA
402     const char *name = node.getName ().c_str ();
403 #endif
404     Visibility tmpv = Visibility::IMPLEMENTATION;
405 
406     if (node.getName ().empty ()) {
407         std::cerr << "A class have an empty name.\n";
408     }
409 
410 #ifdef ENABLE_CORBA
411     isCorba = node.isStereotypeCorba ();
412 #endif
413 
414     // Check that if class is abstract, at least one class are abstract.
415     if (node.isAbstract ()) {
416         bool absok = false;
417 
418         for (const umlOperation & umlo : node.getOperations ()) {
419             if (umlo.getInheritance () == Inheritance::ABSTRACT) {
420                 absok = true;
421             }
422         }
423 
424         if ((!absok) && (!node.getOperations ().empty ())) {
425             std::cerr << "Class " << fqname (node, false)
426                       << " is abstract but no operation is defined as abstract.\n";
427         }
428     }
429 
430     writeClassComment (node.getComment ());
431     writeClassStart (node);
432     incIndentLevel ();
433 
434     if (!node.getAssociations ().empty ()) {
435         writeComment ("Associations");
436         for (const umlassoc & assoc : node.getAssociations ()) {
437             writeAssociation (node, assoc, tmpv);
438         }
439     }
440 
441     if (!node.getAttributes ().empty ()) {
442 #ifdef ENABLE_CORBA
443         if (isCorba) {
444             writeComment ("Public state members");
445             getFile () << spc () << "public:\n";
446             incIndentLevel ();
447             for (const umlAttribute & umla : node.getAttributes ()) {
448                 const char *member = umla.getName ().c_str ();
449                 umlClassNode *ref;
450                 if (umla.getVisibility () != '0') {
451                     continue;
452                 }
453                 if (umla.isStatic ()) {
454                     std::cerr << "CORBAValue " << name << "/" << member
455                               << ": static not supported.\n",
456                 }
457                 ref = findByName (dia.getUml (), umla.getType ().c_str ());
458                 if (ref != NULL) {
459                     getFile () << spc () << fqname (*ref, true);
460                 }
461                 else {
462                     getFile () << spc () << cppName (umla.getType ());
463                 }
464                 if (!bOpenBraceOnNewline) {
465                     getFile () << " " << member << " () { return _" << member
466                          << "; }\n";
467                 }
468                 else {
469                     getFile () << " " << member << " ()\n" << spc () << "{\n";
470                     incIndentLevel ();
471                     getFile () << spc () << "return _" << member << ";\n";
472                     decIndentLevel ();
473                     getFile () << spc () << "}\n";
474                 }
475                 getFile () << spc () << "void " << member << " (";
476                 if (ref != NULL) {
477                     int by_ref = passByReference (*ref);
478                     if (by_ref) {
479                         getFile () << "const ";
480                     }
481                     getFile () << fqname (*ref, true);
482                     if (by_ref) {
483                         getFile () << "&";
484                     }
485                 }
486                 else {
487                     getFile () << cppName (umla.getType ());
488                 }
489                 if (!bOpenBraceOnNewline) {
490                     getFile () << " value_) { _" << member << " = value_; }\n";
491                 }
492                 else {
493                     getFile () << " value_)\n" << spc () << "{\n";
494                     incIndentLevel ();
495                     getFile () << spc () << "_" << member << " = value_;";
496                     decIndentLevel ();
497                     getFile () << spc () << "}\n";
498                 }
499             }
500             decIndentLevel ();
501         }
502         else
503 #endif
504         {
505             writeComment ("Attributes");
506             for (const umlAttribute & umla : node.getAttributes ()) {
507                 if (umla.getName ().empty ()) {
508                     std::cerr << "An attribute of the "
509                               << fqname (node, false)
510                               << " class have an empty name.\n";
511                 }
512                 if (umla.getType ().empty ()) {
513                     std::cerr << "An attribute of the " << fqname (node, false)
514                               << " class have an empty type.\n";
515                 }
516                 writeAttribute (node, umla, tmpv);
517             }
518         }
519     }
520 
521     if (!node.getOperations ().empty ()) {
522         writeComment ("Operations");
523 #ifdef ENABLE_CORBA
524         if (isCorba) {
525             getFile () << spc () << "public :\n";
526         }
527 #endif
528         for (const umlOperation & umlo : node.getOperations ()) {
529             if (umlo.isStereotypeGetSet ()) {
530                 writeFunctionGetSet (node, umlo, tmpv);
531             }
532             else {
533                 writeFunction (node, umlo, tmpv);
534             }
535         }
536     }
537 
538 #ifdef ENABLE_CORBA
539     if ((!node.getAttributes ().empty ()) && (isCorba)) {
540         getFile () << "\n";
541         decIndentLevel ();
542         writeComment ("State member implementation");
543         getFile () << spc () << "private :\n";
544         incIndentLevel ();
545         for (const umlAttribute & umla : node.getAttributes ()) {
546             umlClassNode *ref = findByName (dia.getUml (),
547                                             umla.getType ().c_str ());
548             getFile () << spc ();
549             if (ref != NULL) {
550                 getFile () << fqname (*ref, isOoClass (*ref));
551                 /*
552                  * FIXME: Find a better way to decide whether to use
553                  * a pointer.
554                 */
555             }
556             else {
557                 getFile () << cppName (umla.getType ());
558             }
559             getFile () << " _" << umla.getName () << ";\n";
560         }
561     }
562 #endif
563 
564     decIndentLevel ();
565     writeClassEnd ();
566 }
567 
568 const char *
dirName(umlPackage * pkg,char separator)569 dirName (umlPackage * pkg, char separator) {
570     static std::string buf;
571     std::list <umlPackage *>::const_iterator it;
572     std::list <umlPackage *> pkglist;
573 
574     buf.clear ();
575     umlPackage::makePackageList (pkg, pkglist);
576     it = pkglist.begin ();
577     while (it != pkglist.end ()) {
578         buf.append ((*it)->getName ());
579         ++it;
580         if (it != pkglist.end ()) {
581             buf.append (1, separator);
582         }
583     }
584     return buf.c_str ();
585 }
586 
587 void
genDecl(declaration & d,bool forceOpen)588 GenerateCode::genDecl (declaration &d,
589                        bool forceOpen) {
590 #ifdef ENABLE_CORBA
591     const char *name;
592     std::list <umlAttribute>::const_iterator umla;
593 #endif
594     const umlClassNode *node;
595 
596     if ((d.decl_kind == dk_class) && (d.u.this_class->isStereotypeExtern ())) {
597         return;
598     }
599     if ((d.decl_kind == dk_module) &&
600         (d.u.this_module->pkg->isStereotypeExtern ())) {
601         return;
602     }
603 
604     if ((buildtree) && (d.decl_kind == dk_module)) {
605         std::string folder;
606 
607         folder.assign (outdir);
608         folder.append (1, SEPARATOR);
609         folder.append (dirName (d.u.this_module->pkg, SEPARATOR));
610 
611         if (
612 #if defined(_WIN32) || defined(_WIN64)
613         _mkdir (folder.c_str ()) != 0
614 #else
615         mkdir (folder.c_str (), 0777) != 0
616 #endif
617         ) {
618             if (errno != EEXIST) {
619                 throw std::string (std::string ("Fail to create folder ") +
620                                    folder + std::string (".\n"));
621             }
622         }
623     }
624 
625     if (forceOpen && (!oneClassOneHeader || !d.decl_kind == dk_module)) {
626         std::string name_;
627 
628         if (d.decl_kind == dk_module) {
629             if (buildtree) {
630                 name_ = dirName (d.u.this_module->pkg, SEPARATOR);
631             }
632             else {
633                 name_ = dirName (d.u.this_module->pkg, '-');
634             }
635         } else {
636             if (d.u.this_class->getPackage () != NULL) {
637                 if (buildtree) {
638                     name_.assign (dirName (d.u.this_class->getPackage (),
639                                            SEPARATOR));
640                     name_.append (1, SEPARATOR);
641                 }
642                 else {
643                     name_.assign (dirName (d.u.this_class->getPackage (),
644                                            '-'));
645                     name_.append (1, '-');
646                 }
647             }
648             name_.append (d.u.this_class->getName ());
649         }
650 
651         openOutfile (name_, d);
652     }
653 
654     if (d.decl_kind == dk_module) {
655         for (declaration & it : d.u.this_module->contents) {
656             genDecl (it, oneClassOneHeader);
657         }
658         if (forceOpen && !oneClassOneHeader) {
659             closeOutfile ();
660         }
661         return;
662     }
663 
664     node = d.u.this_class;
665 
666     writeNameSpaceStart (node);
667 #ifdef ENABLE_CORBA
668     name = node->getName ().c_str ();
669     umla = node->getAttributes ().begin ();
670 #endif
671 
672 #ifdef ENABLE_CORBA
673     if (eq (stype, "CORBANative")) {
674         writeComment (std::string ("CORBANative: ") +
675                       node->getName () +
676                       std::string ("\n"));
677     }
678     else
679 #endif
680     if (node->isStereotypeEnum ()) {
681         if (!node->getOperations ().empty ()) {
682             std::cerr << "Class \"" << node->getName ()
683                       << "\" is enum. All operations are ignored.\n";
684         }
685         if (!node->getTemplates ().empty ()) {
686             std::cerr << "Class \"" << node->getName ()
687                       << "\" is enum. All templates are ignored.\n";
688         }
689         if (node->isAbstract ()) {
690             std::cerr << "Class \"" << node->getName ()
691                       << "\" is abstact. Ignored.\n";
692         }
693         writeEnum (*node);
694     }
695     else if (node->isStereotypeStruct ()) {
696         writeStruct (*node);
697     }
698 #ifdef ENABLE_CORBA
699     else if (eq (stype, "CORBAException")) {
700         std::cerr << name << ": CORBAException not yet implemented.\n";
701 
702     }
703     else if (eq (stype, "CORBAUnion")) {
704         if (umla == node->getAttributes ().end ()) {
705             throw std::string ("Attributes not set at union " + name + "\n");
706         }
707         std::cerr << name << ": CORBAUnion not yet fully implemented.\n";
708         if (bOpenBraceOnNewline) {
709             writeComment ("CORBAUnion");
710             getFile () << spc () << "class " << name << "\n";
711             getFile () << spc () << "{\n";
712         }
713         else {
714             writeComment ("CORBAUnion");
715             getFile () << spc () << "class " << name << " {\n";
716         }
717         getFile () << spc () << "public :\n";
718         incIndentLevel ();
719         getFile () << spc () << (*umla).getType () << " _d();\n\n";
720         ++umla;
721         while (umla != node->getAttributes ().end ()) {
722             (*umla).check (name);
723             getFile () << spc () << cppName ((*umla).getType ()) << " "
724                  << (*umla).getName () << " ();\n";
725             getFile () << spc () << "void " << (*umla).getName () << " ("
726                  << cppName ((*umla).getType ())
727                  << " _value);\n\n";
728             ++umla;
729         }
730         decIndentLevel ();
731         getFile () << spc () << "};\n\n";
732 
733     }
734 #endif
735     else if (node->isStereotypeTypedef ()) {
736         writeTypedef (*node);
737     }
738     else {
739         genClass (*node);
740     }
741 
742     writeNameSpaceEnd (d.u.this_class);
743 
744     if (forceOpen) {
745         closeOutfile ();
746     }
747 }
748 
749 
750 std::string &
spc() const751 GenerateCode::spc () const {
752     static std::string spcbuf;
753 
754     spcbuf.assign (indent * indentlevel, ' ');
755 
756     return spcbuf;
757 }
758 
759 uint8_t
getVersion() const760 GenerateCode::getVersion () const {
761     return version;
762 }
763 
764 void
setVersion(uint8_t version_)765 GenerateCode::setVersion (uint8_t version_) {
766     version = version_;
767 }
768 
769 uint32_t
getIndent() const770 GenerateCode::getIndent () const {
771     return indent;
772 }
773 
774 
775 void
setIndent(uint8_t spaces)776 GenerateCode::setIndent (uint8_t spaces) {
777     if ((spaces < 1) || (spaces > 8)) {
778         return;
779     }
780 
781     indent = spaces & 15;
782 
783     return;
784 }
785 
786 
787 void
incIndentLevel()788 GenerateCode::incIndentLevel () {
789     indentlevel++;
790 }
791 
792 
793 void
decIndentLevel()794 GenerateCode::decIndentLevel () {
795     assert (indentlevel != 0);
796     indentlevel--;
797 }
798 
799 void
writeFile()800 GenerateCode::writeFile () {
801 #if defined(_WIN32) || defined(_WIN64)
802     FILE * licensefile;
803     if ((fopen_s (&licensefile, license.c_str (), "r") != 0) ||
804         (licensefile == NULL)) {
805         throw std::string ("Can't open the license file " + license + ".\n");
806     }
807 #else
808     FILE * licensefile = fopen (license.c_str (), "r");
809 
810     if (!licensefile) {
811         throw std::string ("Can't open the license file " + license + ".\n");
812     }
813 #endif
814 
815     int lc;
816     rewind (licensefile);
817     while ((lc = fgetc (licensefile)) != EOF) {
818         getFile () << static_cast <char> (lc);
819     }
820 
821     fclose (licensefile);
822 }
823 
824 
825 const char *
comment(const std::string & comment_,const std::string & startFirstLine,const std::string & startOtherLines,const char * endLastLine)826 GenerateCode::comment (const std::string & comment_,
827                        const std::string & startFirstLine,
828                        const std::string & startOtherLines,
829                        const char * endLastLine) {
830     static std::string buf;
831     size_t start = 0;
832     size_t end;
833 
834     buf.clear ();
835 
836     end = comment_.find ("\n", start);
837     while (end != std::string::npos)
838     {
839         if (start == 0) {
840             buf.append (startFirstLine);
841         }
842         else {
843             buf.append (startOtherLines);
844         }
845         buf.append (comment_.substr (start, end-start));
846         buf.append ("\n");
847         start = end + 1;
848         end = comment_.find ("\n", start);
849     }
850 
851     if (start == 0) {
852         buf.append (startFirstLine);
853     }
854     else {
855         buf.append (startOtherLines);
856     }
857     buf.append (comment_.substr (start, end-start));
858     buf.append (endLastLine);
859 
860     return buf.c_str ();
861 }
862 
863 void
writeLicense1(const char * start,const char * end)864 GenerateCode::writeLicense1 (const char * start, const char * end) {
865     if (getLicense ().empty ()) {
866         return;
867     }
868 
869     getFile () << start << "\n";
870     writeFile ();
871     getFile () << end << "\n\n";
872 }
873 
874 const char *
visibility1(std::string desc,const Visibility & vis)875 GenerateCode::visibility1 (std::string desc,
876                            const Visibility & vis) {
877     switch (vis) {
878         case Visibility::PUBLIC :
879             return "public";
880         case Visibility::PRIVATE :
881             return "private";
882         case Visibility::PROTECTED :
883             return "protected";
884         case Visibility::IMPLEMENTATION :
885             std::cerr << desc + ": implementation not applicable. Default: public.\n";
886             return "public";
887         default :
888             throw std::string ("Unknown visibility.\n");
889     }
890 }
891 
892 void
writeFunctionGetSet1(const umlClassNode & node,const umlOperation & ope,Visibility & curr_visibility)893 GenerateCode::writeFunctionGetSet1 (const umlClassNode & node,
894                                     const umlOperation & ope,
895                                     Visibility & curr_visibility) {
896     std::string tmpname;
897 
898     if ((!ope.getType ().compare ("bool")) ||
899         (!ope.getType ().compare ("boolean")) ||
900         (!ope.getType ().compare ("Boolean"))) {
901         tmpname.assign ("is");
902     }
903     else {
904         tmpname.assign ("get");
905     }
906     tmpname.append (strtoupperfirst (ope.getName ()));
907     umlOperation ope2 (tmpname,
908                        ope.getType (),
909                        "",
910                        ope.getVisibility (),
911                        ope.getInheritance (),
912                        ope.isStatic (),
913                        true,
914                        false,
915                        false,
916                        false);
917     writeFunction (node,ope2, curr_visibility);
918 
919     umlAttribute parameter ("value",
920                             "",
921                             ope.getType (),
922                             "",
923                             ope.getVisibility (),
924                             ope.getInheritance (),
925                             ope.isStatic (),
926                             ope.isConstant (),
927                             Kind::IN);
928     tmpname.assign ("set");
929     tmpname.append (strtoupperfirst (ope.getName ()));
930     ope2 = umlOperation (tmpname,
931                          "void",
932                          "",
933                          ope.getVisibility (),
934                          ope.getInheritance (),
935                          ope.isStatic (),
936                          false,
937                          false,
938                          false,
939                          false);
940     ope2.addParameter (parameter);
941     writeFunction (node, ope2, curr_visibility);
942 }
943 
944 bool
writeInclude1(const std::list<std::pair<std::list<umlPackage * >,const umlClassNode * >> & name,const char * startIncludeSystem,const char * endIncludeSystem,const char * startIncludeFile,const char * endIncludeFile,bool forceExtExtern)945 GenerateCode::writeInclude1 (const std::list <std::pair <
946                                                       std::list <umlPackage *>,
947                                                 const umlClassNode *> > & name,
948                              const char * startIncludeSystem,
949                              const char * endIncludeSystem,
950                              const char * startIncludeFile,
951                              const char * endIncludeFile,
952                              bool forceExtExtern) {
953     bool ret = false;
954     // List of include then if (true) the class is system and should not be
955     // generated.
956     std::list <std::pair <std::string, bool> > incs;
957 
958     for (const std::pair <std::list <umlPackage *>,
959                                            const umlClassNode *> & it : name) {
960         std::string include;
961         std::pair <std::string, bool> add;
962 
963         if (it.second == NULL) {
964             continue;
965         }
966 
967         ret = true;
968 
969         if (getBuildTree () || it.second->isStereotypeExtern ()) {
970             if (!it.first.empty ()) {
971                 for (const umlPackage * pack : it.first) {
972                     include.append (pack->getName ());
973                     include.append (1, SEPARATOR);
974                 }
975             }
976             include.append (it.second->getName ());
977         }
978         else if (getOneClass ()) {
979             if (!it.first.empty ()) {
980                 for (const umlPackage * pack : it.first) {
981                     include.append (pack->getName ());
982                     include.append ("-");
983                 }
984             }
985             include.append (it.second->getName ());
986         }
987         else {
988             if (!it.first.empty ()) {
989                 include.append ((*it.first.begin ())->getName ());
990             }
991             else {
992                 include.append (it.second->getName ());
993             }
994         }
995         if ((forceExtExtern) || (!it.second->isStereotypeExtern ())) {
996             include.append (".");
997             include.append (getFileExt ());
998         }
999         add.first = include;
1000         add.second = it.second->isStereotypeExtern ();
1001         if (std::find (incs.begin (),
1002                        incs.end (),
1003                        add) == incs.end ()) {
1004             if (add.second) {
1005                 incs.push_front (add);
1006             }
1007             else {
1008                 incs.push_back (add);
1009             }
1010         }
1011     }
1012 
1013     for (const std::pair <std::string, bool> & add : incs) {
1014         if (add.second) {
1015             getFile () << spc () << startIncludeSystem << add.first
1016                        << endIncludeSystem;
1017         }
1018         else {
1019             getFile () << spc () << startIncludeFile << add.first
1020                        << endIncludeFile;
1021         }
1022     }
1023     if (!incs.empty ()) {
1024         getFile () << "\n";
1025     }
1026 
1027     return ret;
1028 }
1029 
1030 void
writeBeforeInclude(umlClassNode *)1031 GenerateCode::writeBeforeInclude (umlClassNode *) {
1032 }
1033 
1034 void
writeAfterInclude(umlClassNode *)1035 GenerateCode::writeAfterInclude (umlClassNode *) {
1036 }
1037 
~GenerateCode()1038 GenerateCode::~GenerateCode () {
1039 }
1040 
1041 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1042