1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #ifndef RY_PD_CPP_OUTPUT_H
18 #define RY_PD_CPP_OUTPUT_H
20 #include <nel/misc/types_nl.h>
21 #include <nel/misc/debug.h>
22 #include <nel/misc/file.h>
23 #include <nel/misc/path.h>
24 #include <nel/misc/algo.h>
28 inline std::string
lcFirst(std::string str
)
30 if (!str
.empty() && str
[0]>='A' && str
[0]<='Z')
35 inline std::string
padTab(std::string str
, uint sz
)
40 for (i
=0; i
<str
.size(); ++i
)
43 csize
= (csize
+4)&0xfffc;
57 inline std::string
removeDefaultArgs(const std::string
& s
)
62 bool foundEqual
= false;
63 for (i
=0; i
<s
.size(); ++i
)
67 if (foundEqual
&& s
[i
] == ',')
91 SMethod() : IsConst(false), IsInline(false), IsStatic(false), IsVirtual(false), IsAttribute(false), IsSeparator(false) {}
96 std::string ConstructorInit
;
97 std::string Description
;
110 std::vector
<SMethod
> Methods
;
111 std::string DisplayName
;
112 std::string Description
;
119 SMethodId(sint section
=-1, sint method
=-1, CClassGenerator
*generator
=NULL
) : Section(section
), Method(method
), Generator(generator
) {}
123 CClassGenerator
*Generator
;
125 void add(const std::string
&instruction
);
126 void setDescription(const std::string
&description
);
137 std::vector
<SSection
> Sections
;
146 SMethodId CurrentMethod
;
151 void init(const std::string
&name
)
167 void setSection(const std::string
&name
)
170 for (i
=0; i
<Sections
.size(); ++i
)
172 if (Sections
[i
].Name
== name
)
180 void createSection(TSection type
, const std::string
&name
, const std::string
&displayname
=std::string(""), const std::string
&description
=std::string(""))
183 newSection
.Type
= type
;
184 newSection
.Name
= name
;
185 newSection
.DisplayName
= displayname
;
186 newSection
.Description
= description
;
187 CurrentSection
= (sint
)Sections
.size();
188 Sections
.push_back(newSection
);
191 void createPublic(const std::string
&name
, const std::string
&displayname
=std::string(""), const std::string
&description
=std::string(""))
193 createSection(Public
, name
, displayname
, description
);
196 void createProtected(const std::string
&name
, const std::string
&displayname
=std::string(""), const std::string
&description
=std::string(""))
198 createSection(Protected
, name
, displayname
, description
);
201 void createPrivate(const std::string
&name
, const std::string
&displayname
=std::string(""), const std::string
&description
=std::string(""))
203 createSection(Private
, name
, displayname
, description
);
208 SMethodId
startMethod(const std::string
&type
,
209 const std::string
&name
,
210 const std::string
&proto
,
211 const std::string
§ion
=std::string(""),
215 bool isAttribute
= false,
216 const std::string
&init
=std::string(""),
217 bool isVirtual
= false,
220 if (!section
.empty())
223 SSection
&_section
= Sections
[CurrentSection
];
227 newMethod
.Name
= name
;
228 newMethod
.Type
= type
;
229 newMethod
.Proto
= proto
;
230 newMethod
.IsConst
= isConst
;
231 newMethod
.IsInline
= isInline
;
232 newMethod
.IsStatic
= isStatic
;
233 newMethod
.IsVirtual
= isVirtual
;
234 newMethod
.IsAttribute
= isAttribute
;
235 newMethod
.ConstructorInit
= init
;
236 newMethod
.IsSeparator
= isSep
;
238 _section
.Methods
.push_back(newMethod
);
240 CurrentMethod
= SMethodId(CurrentSection
, (sint
)_section
.Methods
.size()-1, this);
242 return CurrentMethod
;
245 SMethod
&get(SMethodId id
)
247 return Sections
[id
.Section
].Methods
[id
.Method
];
250 SMethodId
startConstructor(const std::string
&proto
, const std::string
§ion
=std::string(""), bool isInline
=true, const std::string
&init
=std::string(""))
252 return startMethod("", "", proto
, section
, false, isInline
, false, false, init
);
255 SMethodId
startDestructor(const std::string
§ion
=std::string(""), bool isInline
=true, bool isVirtual
=false)
257 return startMethod("", "~", "", section
, false, isInline
, false, false, "", isVirtual
);
260 SMethodId
startRaw(const std::string
§ion
=std::string(""), bool isInline
=true)
262 return startMethod("", "", "", section
, false, isInline
, false, true, "", false, true);
265 void separator(const std::string
§ion
=std::string(""))
267 startMethod("", "", "", section
, false, false, false, false, "", false, true);
270 void add(const std::string
&instruction
, SMethodId methodId
= SMethodId())
272 if (methodId
.Method
== -1)
273 methodId
= CurrentMethod
;
275 if (instruction
.empty())
278 Sections
[methodId
.Section
].Methods
[methodId
.Method
].Body
+= instruction
+"\n";
281 void setDescription(const std::string
&description
, SMethodId methodId
= SMethodId())
283 if (methodId
.Method
== -1)
284 methodId
= CurrentMethod
;
286 Sections
[methodId
.Section
].Methods
[methodId
.Method
].Description
+= description
;
289 void addOther(const std::string
&other
, const std::string
§ion
=std::string(""))
291 if (!section
.empty())
294 SSection
&_section
= Sections
[CurrentSection
];
296 _section
.Other
+= other
;
299 void addAttribute(const std::string
&type
, const std::string
&name
, const std::string
§ion
=std::string(""), bool isStatic
=false, const std::string
& value
="", bool isFuncPtr
=false, const std::string funcPtrProto
="")
301 startMethod(type
, name
, funcPtrProto
, section
, false, false, isStatic
, true, value
, isFuncPtr
);
305 void flush(CCppOutput
&hFile
, CCppOutput
&cppFile
, CCppOutput
&hInlineFile
);
316 class CFunctionGenerator
320 CFunctionGenerator() : IsInline(false) {}
328 /// function prototype
334 /// is an inlined function
337 /// function description
338 std::string Description
;
340 void init(const std::string
&name
)
346 void setType(const std::string
&type
)
351 void setProto(const std::string
&proto
)
365 void add(const std::string
&instruction
)
367 if (!instruction
.empty())
368 Body
+= instruction
+"\n";
372 void flush(CCppOutput
&hFile
, CCppOutput
&cppFile
, CCppOutput
&hInlineFile
);
389 CCppOutput(bool cppmode
= true) : _CppMode(cppmode
),
390 _XmlMode(false), _NewLine(true), _Indent(0), _DescriptionMode(false), _Clean(true),
391 _XmlInNode(false), _XmlLastSlash(false), _XmlGetNodeName(false), _XmlCloseNode(false), _XmlRootNode(false) {}
397 void setXmlMode() { _XmlMode
= true; _NewLine
= false; }
400 void flush(const std::string
&fileName
);
410 CCppOutput
& operator << (const T
& t
)
412 addToStream(NLMISC::toString(t
).c_str());
417 void setFileHeader(const std::string
& filename
, const std::string
& description
)
421 *this << "/** \\file " << filename
<< "\n";
422 if (!description
.empty())
423 *this << description
<< "\n";
425 *this << "$Id: cpp_output.h,v 1.15 2004/12/13 17:19:01 legros Exp $\n";
439 bool _DescriptionMode
;
442 std::vector
<std::string
> _XmlNodes
;
445 bool _XmlGetNodeName
;
448 std::string _XmlNodeName
;
451 CCppOutput
addToStream (const char* str
)
458 if (!_DescriptionMode
&& *str
== '}')
461 bool triggerDescriptionStart
= false;
462 bool triggerDescriptionEnd
= false;
464 if (!strncmp(str
, "/**", 3))
467 triggerDescriptionStart
= true;
470 if (_DescriptionMode
&& !strncmp(str
, "*/", 2))
473 triggerDescriptionEnd
= true;
476 bool skipChar
= false;
481 if ((*str
== ' ' || *str
== '\t') && !_DescriptionMode
)
488 for (i
=0; i
<_Indent
; ++i
)
492 if (_DescriptionMode
)
495 if (!triggerDescriptionEnd
)
498 if (!triggerDescriptionEnd
&& *str
== '*')
507 if (!_DescriptionMode
&& *str
== '{')
519 if (triggerDescriptionStart
)
520 _DescriptionMode
= true;
521 if (triggerDescriptionEnd
)
522 _DescriptionMode
= false;
531 bool skipChar
= false;
532 bool requireIndent
= false;
537 _XmlCloseNode
= (str
[1] == '/');
538 _XmlRootNode
= (str
[1] == '?');
540 _XmlGetNodeName
= true;
541 _XmlNodeName
.clear();
543 requireIndent
= (!_XmlCloseNode
&& !_XmlRootNode
);
547 else if (*str
== '>')
551 if (!_XmlCloseNode
&& !_XmlRootNode
)
553 _XmlNodes
.push_back(_XmlNodeName
);
556 if (_XmlCloseNode
|| _XmlLastSlash
)
561 nlassert(!_XmlNodes
.empty() && _XmlNodes
.back() == _XmlNodeName
);
562 _XmlNodes
.pop_back();
565 else if (*str
== '\n')
572 if (*str
== ' ' || *str
== '\t')
576 else if (*str
!= '\n' && *str
!= '\r')
579 for (i
=0; i
<_Indent
; ++i
)
585 _XmlLastSlash
= (*str
== '/');
587 if (_XmlInNode
&& _XmlGetNodeName
&& *str
!= '/' && *str
!= '<')
590 _XmlGetNodeName
= false;
593 _XmlNodeName
+= *str
;
616 // Inline implementation
619 inline void CCppOutput::clear()
624 inline bool searchForId(char* buffer
, char** start
, char** end
)
626 const char* id
= "$Id:";
627 uint len
= (uint
)strlen(id
);
628 for (; *buffer
!= '\0'; ++buffer
)
630 if (strncmp(buffer
, id
, len
) == 0)
634 while (**end
!= '\0' && **end
!= '$')
636 if (**end
!= (char)'$')
647 inline void CCppOutput::flush(const std::string
&fileName
)
651 bool overwrite
= true;
653 if (NLMISC::CFile::fileExists(fileName
))
656 if (fi
.open(fileName
))
659 buffer
.resize(fi
.getFileSize(), '*');
660 fi
.serialBuffer((uint8
*)(&(buffer
[0])), fi
.getFileSize());
662 // search for $Id: cpp_output.h,v 1.15 2004/12/13 17:19:01 legros Exp $ string in file...
663 char *searchidstart
, *searchidend
;
664 char *replaceidstart
, *replaceidend
;
666 if (searchForId(&(buffer
[0]), &replaceidstart
, &replaceidend
) &&
667 searchForId(&(_Buffer
[0]), &searchidstart
, &searchidend
))
669 std::string replace
= std::string(replaceidstart
, replaceidend
-replaceidstart
);
670 std::string search
= std::string(searchidstart
, searchidend
-searchidstart
);
671 NLMISC::strFindReplace(_Buffer
, search
, replace
);
674 overwrite
= (buffer
!= _Buffer
);
680 if (f
.open(fileName
))
682 f
.serialBuffer((uint8
*)(_Buffer
.c_str()), (uint
)_Buffer
.size());
687 nlwarning("Unable to open file '%s' for output", fileName
.c_str());
692 nldebug("File '%s' did not changed, skipped", fileName
.c_str());
698 inline void CCppOutput::indent()
704 inline void CCppOutput::unindent()
716 inline void CClassGenerator::flush(CCppOutput
&hFile
, CCppOutput
&cppFile
, CCppOutput
&hInlineFile
)
718 hFile
<< "class " << Name
;
719 if (!Inherit
.empty())
720 hFile
<< " : " << Inherit
;
723 hInlineFile
<< "/* -----------------------------------------\n";
724 hInlineFile
<< " * Inline implementation of " << Name
<< "\n";
725 hInlineFile
<< " * ----------------------------------------- */\n";
727 cppFile
<< "/* -----------------------------------------\n";
728 cppFile
<< " * Static Implementation of " << Name
<< "\n";
729 cppFile
<< " * ----------------------------------------- */\n";
732 for (i
=0; i
<Sections
.size(); ++i
)
734 static const char* stypes
[] = { "public", "protected", "private" };
736 SSection
§ion
= Sections
[i
];
738 if (section
.Methods
.empty() && section
.Other
.empty())
742 for (j
=0; j
<section
.Methods
.size(); ++j
)
743 if (!section
.Methods
[j
].IsSeparator
)
746 if (j
== section
.Methods
.size() && section
.Other
.empty())
750 hFile
<< "\n" << stypes
[section
.Type
] << ":\n\n";
753 if (!section
.DisplayName
.empty())
755 hFile
<< "/// \\name " << section
.DisplayName
<< "\n// @{\n\n";
759 if (!section
.Description
.empty())
761 hFile
<< "/**\n" << section
.Description
<< "\n*/\n\n";
764 while (!section
.Methods
.empty() && section
.Methods
.front().IsSeparator
&& !section
.Methods
.front().IsAttribute
)
765 section
.Methods
.erase(section
.Methods
.begin());
767 while (!section
.Methods
.empty() && section
.Methods
.back().IsSeparator
&& !section
.Methods
.back().IsAttribute
)
768 section
.Methods
.pop_back();
770 for (j
=0; j
<section
.Methods
.size(); ++j
)
772 SMethod
&method
= section
.Methods
[j
];
774 std::string inlinekw
= (method
.IsInline
? std::string("inline ") : std::string(""));
775 std::string statickw
= (method
.IsStatic
? std::string("static ") : std::string(""));
776 std::string virtualkw
= (method
.IsVirtual
? std::string("virtual ") : std::string(""));
777 std::string constkw
= (method
.IsConst
? std::string(" const") : std::string(""));
779 if (!method
.Description
.empty())
781 hFile
<< "\n/**\n" << method
.Description
<< "\n*/\n";
785 if (method
.IsAttribute
&& method
.IsSeparator
)
789 hInlineFile
<< method
.Body
;
793 cppFile
<< method
.Body
;
797 else if (method
.IsSeparator
)
802 else if (method
.IsAttribute
)
804 // pointer to function
805 if (method
.IsVirtual
)
807 hFile
<< padTab(statickw
+method
.Type
, 32) << "(*" <<method
.Name
<< ")(" << method
.Proto
<< ");\n";
810 cppFile
<< padTab(method
.Type
, 32) << "(*" << Name
<< "::" << method
.Name
<< ")(" << method
.Proto
<< ")";
811 if (!method
.ConstructorInit
.empty())
812 cppFile
<< " = " << method
.ConstructorInit
;
818 hFile
<< padTab(statickw
+method
.Type
, 32) << method
.Name
<< ";\n";
821 if (!method
.Proto
.empty())
822 cppFile
<< padTab(method
.Proto
, 32) << Name
<< "::" << method
.Name
;
824 cppFile
<< padTab(method
.Type
, 32) << Name
<< "::" << method
.Name
;
825 if (!method
.ConstructorInit
.empty())
826 cppFile
<< " = " << method
.ConstructorInit
;
832 else if (method
.Type
.empty())
834 hFile
<< virtualkw
<< method
.Name
<< Name
<< "(" << method
.Proto
<< ");\n";
837 hInlineFile
<< inlinekw
<< Name
<< "::" << method
.Name
<< Name
<< "(" << removeDefaultArgs(method
.Proto
) << ")";
838 if (!method
.ConstructorInit
.empty())
839 hInlineFile
<< " : " << method
.ConstructorInit
;
841 hInlineFile
<< "{\n";
842 hInlineFile
<< method
.Body
;
843 hInlineFile
<< "}\n";
847 cppFile
<< Name
<< "::" << method
.Name
<< Name
<< "(" << removeDefaultArgs(method
.Proto
) << ")\n";
849 cppFile
<< method
.Body
;
856 hFile
<< padTab(statickw
+virtualkw
+method
.Type
, 32) << lcFirst(method
.Name
) << "(" << method
.Proto
<< ")" << constkw
<< ";\n";
859 hInlineFile
<< padTab(inlinekw
+method
.Type
, 32) << Name
<< "::" << lcFirst(method
.Name
) << "(" + removeDefaultArgs(method
.Proto
) << ")" << constkw
<< "\n";
860 hInlineFile
<< "{\n";
861 hInlineFile
<< method
.Body
;
862 hInlineFile
<< "}\n";
866 cppFile
<< padTab(method
.Type
, 32) << Name
<< "::" << lcFirst(method
.Name
) << "(" << removeDefaultArgs(method
.Proto
) << ")" << constkw
<< "\n";
868 cppFile
<< method
.Body
;
874 hFile
<< section
.Other
;
876 if (!section
.DisplayName
.empty())
878 hFile
<< "\n// @}\n\n";
884 hInlineFile
<< "// End of inline implementation of " << Name
<< "\n\n";
887 cppFile
<< "// End of static implementation of " << Name
<< "\n\n";
890 inline void CClassGenerator::SMethodId::add(const std::string
&instruction
)
892 nlassert(Generator
!= NULL
);
893 Generator
->add(instruction
, *this);
896 inline void CClassGenerator::SMethodId::setDescription(const std::string
&description
)
898 nlassert(Generator
!= NULL
);
899 Generator
->add(description
, *this);
902 inline void CFunctionGenerator::flush(CCppOutput
&hFile
, CCppOutput
&cppFile
, CCppOutput
&hInlineFile
)
904 std::string inlinekw
= (IsInline
? std::string("inline ") : std::string(""));
906 if (!Description
.empty())
908 hFile
<< "\n/**\n" << Description
<< "\n*/\n";
911 hFile
<< padTab(Type
, 32) << lcFirst(Name
) << "(" << Proto
<< ");\n";
915 hInlineFile
<< padTab(inlinekw
+Type
, 32) << lcFirst(Name
) << "(" << removeDefaultArgs(Proto
) << ")\n";
916 hInlineFile
<< "{\n";
918 hInlineFile
<< "}\n\n";
922 cppFile
<< padTab(Type
, 32) << lcFirst(Name
) << "(" << removeDefaultArgs(Proto
) << ")\n";