[mapguide-commits] r10197 - branches/4.0/MgDev/Bindings/src/IMake
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Sun Sep 28 08:44:55 PDT 2025
Author: jng
Date: 2025-09-28 08:44:55 -0700 (Sun, 28 Sep 2025)
New Revision: 10197
Modified:
branches/4.0/MgDev/Bindings/src/IMake/IMake.cpp
Log:
IMake update:
- When linkifying Mg class names, if we're linkifying an exception and it is not MgException, transform to MgException with MgExceptionCodes.the_name_of_specific_exception
- Transplant getter method documentation to any .net properties
- Fix truncated exception descriptions due to not following until end of comments or next directive.
- Insert pragmas to generated .net constants file to suppress certain distracting warnings.
- Fix vector overshoot when trying to process trailing trivia.
- Add stub to make testing/debugging future problems easier.
Modified: branches/4.0/MgDev/Bindings/src/IMake/IMake.cpp
===================================================================
--- branches/4.0/MgDev/Bindings/src/IMake/IMake.cpp 2025-09-28 15:39:32 UTC (rev 10196)
+++ branches/4.0/MgDev/Bindings/src/IMake/IMake.cpp 2025-09-28 15:44:55 UTC (rev 10197)
@@ -14,7 +14,7 @@
java
};
-static char version[] = "1.6.2";
+static char version[] = "1.6.3";
static char EXTERNAL_API_DOCUMENTATION[] = "(NOTE: This API is not officially supported and may be subject to removal in a future release without warning. Use with caution.)";
static string module;
@@ -607,6 +607,29 @@
stringReplace(str, ">", ">");
}
+bool startsWith(const std::string& str, const std::string& prefix)
+{
+ if (prefix.length() > str.length()) {
+ return false;
+ }
+ return str.compare(0, prefix.length(), prefix) == 0;
+}
+
+bool endsWith(const std::string& str, const std::string& suffix)
+{
+ // Handle empty suffix
+ if (suffix.empty()) {
+ return true; // Empty string is a suffix of any string
+ }
+
+ // Handle suffix longer than string
+ if (suffix.length() > str.length()) {
+ return false;
+ }
+
+ return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
+}
+
string linkifyCSharpDocFragment(const string& str)
{
// Explode the fragment into a space delimited list.
@@ -671,11 +694,26 @@
suffix += elems[i][j];
}
output.append(prefix);
- output.append("<see cref=\"");
- output.append(nspace);
- output.append(".");
- output.append(mgClassName);
- output.append("\" />");
+
+ if (startsWith(mgClassName, "Mg") && endsWith(mgClassName, "Exception") && mgClassName != "MgException")
+ {
+ output.append("<see cref=\"");
+ output.append(nspace);
+ output.append(".MgException");
+ output.append("\" /> with code <see cref=\"");
+ output.append(nspace);
+ output.append("MgExceptionCodes.");
+ output.append(mgClassName);
+ output.append("\" />");
+ }
+ else
+ {
+ output.append("<see cref=\"");
+ output.append(nspace);
+ output.append(".");
+ output.append(mgClassName);
+ output.append("\" />");
+ }
output.append(suffix);
} else {
output.append(elems[i]);
@@ -947,7 +985,7 @@
return javaDoc;
}
-string doxygenToCsharpDoc(const string& commentStr, bool isPublished)
+string doxygenToCsharpDoc(const string& commentStr, bool isPublished, bool onlyBrief)
{
//See doxygenToJavaDoc for how we do this sorcery
@@ -995,7 +1033,6 @@
descriptionParts.push_back(token);
i++;
}
-
continue;
}
else if (elems[i].find("\\param") != std::string::npos) {
@@ -1039,8 +1076,22 @@
}
else if (elems[i].find("\\exception") != std::string::npos) {
std::string except = elems[i].substr(elems[i].find("\\exception") + 10);
+ i++;
+ //Keep going until we find the next doxygen directive or end of comments
+ while (i < elems.size() && elems[i].find("\\") == std::string::npos) {
+ if (elems[i].find("<!-- Syntax in .Net, Java, and PHP -->") != std::string::npos ||
+ elems[i].find("<!-- Example (PHP) -->") != std::string::npos ||
+ elems[i].find("<!-- Example (Java) -->") != std::string::npos ||
+ elems[i].find("<!-- Example (C#) -->") != std::string::npos) {
+ i++;
+ continue;
+ }
+ std::string token = elems[i].substr(3);
+ if (!token.empty())
+ except += token;
+ i++;
+ }
exceptionParts.push_back(except);
- i++;
continue;
}
i++;
@@ -1048,8 +1099,8 @@
// ---------------------- csharpDoc START ------------------------ //
std::string csharpDoc = "\n///<summary>\n";
-
- if (descriptionParts.size() > 0) {
+ if (onlyBrief)
+ {
if (!isPublished) {
csharpDoc.append("/// ");
csharpDoc.append(EXTERNAL_API_DOCUMENTATION);
@@ -1057,105 +1108,136 @@
}
for (size_t i = 0; i < descriptionParts.size(); i++) {
csharpDoc.append("///");
- csharpDoc.append(linkifyCSharpDocFragment(descriptionParts[i]));
+ csharpDoc.append(linkifyCSharpDocFragment(descriptionParts[i]));
csharpDoc.append("\n");
}
csharpDoc.append("///</summary>\n");
- } else {
- if (!isPublished) {
- csharpDoc.append("/// ");
- csharpDoc.append(EXTERNAL_API_DOCUMENTATION);
- csharpDoc.append("\n");
- } else {
- csharpDoc.append("///TODO: API Documentation is missing or failed to translate doxygen brief directive (message inserted by IMake.exe)\n");
+ }
+ else
+ {
+ if (descriptionParts.size() > 0) {
+ if (!isPublished) {
+ csharpDoc.append("/// ");
+ csharpDoc.append(EXTERNAL_API_DOCUMENTATION);
+ csharpDoc.append("\n");
+ }
+ for (size_t i = 0; i < descriptionParts.size(); i++) {
+ csharpDoc.append("///");
+ csharpDoc.append(linkifyCSharpDocFragment(descriptionParts[i]));
+ csharpDoc.append("\n");
+ }
+ csharpDoc.append("///</summary>\n");
}
- csharpDoc.append("///</summary>\n");
- }
+ else {
+ if (!isPublished) {
+ csharpDoc.append("/// ");
+ csharpDoc.append(EXTERNAL_API_DOCUMENTATION);
+ csharpDoc.append("\n");
+ }
+ else {
+ csharpDoc.append("///TODO: API Documentation is missing or failed to translate doxygen brief directive (message inserted by IMake.exe)\n");
+ }
+ csharpDoc.append("///</summary>\n");
+ }
- if (paramParts.size() > 0) {
- for (size_t i = 0; i < paramParts.size(); i++) {
- std::string paramPart = paramParts[i];
- stripHtml(paramPart);
- xmlEscapeString(paramPart);
+ if (paramParts.size() > 0) {
+ for (size_t i = 0; i < paramParts.size(); i++) {
+ std::string paramPart = paramParts[i];
+ stripHtml(paramPart);
+ xmlEscapeString(paramPart);
- std::vector<std::string> pelems;
- std::stringstream pss(linkifyCSharpDocFragment(paramPart));
- std::string pitem;
- while(std::getline(pss, pitem, ' ')) {
- if (!pitem.empty())
- pelems.push_back(pitem);
- }
-
- if (pelems.size() > 1) { //Should be
- csharpDoc.append("///<param name=\"");
- csharpDoc.append(pelems[0]);
- csharpDoc.append("\">");
- csharpDoc.append("\n///");
- for (size_t i = 1; i < pelems.size(); i++) {
- csharpDoc.append(" ");
- csharpDoc.append(pelems[i]);
+ std::vector<std::string> pelems;
+ std::stringstream pss(linkifyCSharpDocFragment(paramPart));
+ std::string pitem;
+ while (std::getline(pss, pitem, ' ')) {
+ if (!pitem.empty())
+ pelems.push_back(pitem);
}
- csharpDoc.append("\n///</param>\n");
+
+ if (pelems.size() > 1) { //Should be
+ csharpDoc.append("///<param name=\"");
+ csharpDoc.append(pelems[0]);
+ csharpDoc.append("\">");
+ csharpDoc.append("\n///");
+ for (size_t i = 1; i < pelems.size(); i++) {
+ csharpDoc.append(" ");
+ csharpDoc.append(pelems[i]);
+ }
+ csharpDoc.append("\n///</param>\n");
+ }
}
}
- }
- if (returnParts.size() > 0) {
- csharpDoc.append("///<returns>");
- for (size_t i = 0; i < returnParts.size(); i++) {
- string retPart = returnParts[i];
- stripHtml(retPart);
- csharpDoc.append(linkifyCSharpDocFragment(retPart));
- if (i < returnParts.size() - 1)
- csharpDoc.append("\n/// ");
+ if (returnParts.size() > 0) {
+ csharpDoc.append("///<returns>");
+ for (size_t i = 0; i < returnParts.size(); i++) {
+ string retPart = returnParts[i];
+ stripHtml(retPart);
+ csharpDoc.append(linkifyCSharpDocFragment(retPart));
+ if (i < returnParts.size() - 1)
+ csharpDoc.append("\n/// ");
+ }
+ csharpDoc.append("\n///</returns>\n");
}
- csharpDoc.append("\n///</returns>\n");
- }
- if (exceptionParts.size() > 0) {
- for (size_t i = 0; i < exceptionParts.size(); i++) {
+ if (exceptionParts.size() > 0) {
+ for (size_t i = 0; i < exceptionParts.size(); i++) {
- std::vector<std::string> eelems;
- std::stringstream ess(exceptionParts[i]);
- std::string eitem;
- while(std::getline(ess, eitem, ' ')) {
- if (!eitem.empty())
- eelems.push_back(eitem);
- }
+ std::vector<std::string> eelems;
+ std::stringstream ess(exceptionParts[i]);
+ std::string eitem;
+ while (std::getline(ess, eitem, ' ')) {
+ if (!eitem.empty())
+ eelems.push_back(eitem);
+ }
- if (eelems.size() > 0)
- {
- //Skip anything that is not of the form:
- //\exception MgExceptionType Description of cases when the exception is thrown
- //
- //So the first token must start with "Mg"
- std::string t("Mg");
- if (eelems[0].compare(0, t.length(), t) == 0)
+ if (eelems.size() > 0)
{
- csharpDoc.append("///<exception cref=\"");
- csharpDoc.append(nspace);
- csharpDoc.append(".MgException\">");
- if (eelems.size() > 1) {
- csharpDoc.append("with code (<see cref=\"");
- csharpDoc.append(nspace);
- csharpDoc.append(".MgExceptionCodes.");
- csharpDoc.append(eelems[0]);
- csharpDoc.append("\" />) ");
- for (size_t j = 1; j < eelems.size(); j++) {
- csharpDoc.append(" ");
- csharpDoc.append(eelems[j]);
+ //Skip anything that is not of the form:
+ //\exception MgExceptionType Description of cases when the exception is thrown
+ //
+ //So the first token must start with "Mg"
+ std::string t("Mg");
+ if (eelems[0].compare(0, t.length(), t) == 0)
+ {
+ if (eelems[0] == "MgException")
+ {
+ csharpDoc.append("///<exception cref=\"");
+ csharpDoc.append(nspace);
+ csharpDoc.append(".MgException\">");
+ for (size_t j = 1; j < eelems.size(); j++) {
+ csharpDoc.append(" ");
+ csharpDoc.append(eelems[j]);
+ }
+ csharpDoc.append("</exception>\n");
}
- csharpDoc.append("</exception>\n");
+ else
+ {
+ csharpDoc.append("///<exception cref=\"");
+ csharpDoc.append(nspace);
+ csharpDoc.append(".MgException\">");
+ if (eelems.size() > 1) {
+ csharpDoc.append("with code (<see cref=\"");
+ csharpDoc.append(nspace);
+ csharpDoc.append(".MgExceptionCodes.");
+ csharpDoc.append(eelems[0]);
+ csharpDoc.append("\" />) ");
+ for (size_t j = 1; j < eelems.size(); j++) {
+ csharpDoc.append(" ");
+ csharpDoc.append(eelems[j]);
+ }
+ csharpDoc.append("</exception>\n");
+ }
+ else {
+ csharpDoc.append(eelems[0]);
+ csharpDoc.append("\"></exception>\n");
+ }
+ }
}
- else {
- csharpDoc.append(eelems[0]);
- csharpDoc.append("\"></exception>\n");
- }
}
}
}
}
-
// ---------------------- csharpDoc END ------------------------ //
//csharpDoc.append("///\n");
if (isDeprecated)
@@ -1177,7 +1259,7 @@
convertedDoc = doxygenToJavaDoc(commentStr, true); //EXTERNAL_API only applies to class members, so treat this fragment as PUBLISHED_API
fprintf(docOutFile, "\n%%typemap(javaclassmodifiers) %s %%{%s public %s%%}\n", className.c_str(), convertedDoc.c_str(), classKeyword.c_str());
} else if(language == csharp) {
- convertedDoc = doxygenToCsharpDoc(commentStr, true); //EXTERNAL_API only applies to class members, so treat this fragment as PUBLISHED_API
+ convertedDoc = doxygenToCsharpDoc(commentStr, true, false); //EXTERNAL_API only applies to class members, so treat this fragment as PUBLISHED_API
fprintf(docOutFile, "\n%%typemap(csclassmodifiers) %s %%{%s public partial %s%%}\n", className.c_str(), convertedDoc.c_str(), classKeyword.c_str());
}
}
@@ -1221,6 +1303,9 @@
bool bPastLastParen = false;
while(j < elems.size()) {
j++;
+ if (j >= elems.size())
+ break;
+
if (bPastLastParen)
{
// We're not appending to methodName at this point. We are only
@@ -1265,7 +1350,7 @@
convertedDoc = doxygenToJavaDoc(commentStr, isPublished);
fprintf(docOutFile, "\n%%javamethodmodifiers %s %%{%s public%%}\n", swigMethodDecl.c_str(), convertedDoc.c_str());
} else if(language == csharp) {
- convertedDoc = doxygenToCsharpDoc(commentStr, isPublished);
+ convertedDoc = doxygenToCsharpDoc(commentStr, isPublished, false);
fprintf(docOutFile, "\n%%csmethodmodifiers %s %%{%s public%%}\n", swigMethodDecl.c_str(), convertedDoc.c_str());
}
}
@@ -1384,7 +1469,7 @@
convertedDoc = doxygenToJavaDoc(commentStr, isPublished);
fprintf(outfile, "%s\n ", convertedDoc.c_str());
} else if (language == csharp) {
- convertedDoc = doxygenToCsharpDoc(commentStr, isPublished);
+ convertedDoc = doxygenToCsharpDoc(commentStr, isPublished, false);
fprintf(outfile, "%s\n ", convertedDoc.c_str());
}
commentStr.clear();
@@ -1559,6 +1644,16 @@
if (bLegacyDotNetPropGeneration)
{
+ // NOTE: __set if specified is generally specified alongside the __get which
+ // is normally applied on the *getter* method. What this means is that the property
+ // doc (which may be both get/set) will assume the commentary of the getter, which
+ // is undesirable, but is still a net positive over zero commentary!
+ if (!commentStr.empty())
+ {
+ auto csDoc = doxygenToCsharpDoc(commentStr, true, true);
+ fprintf(propertyFile, "%s\n", csDoc.c_str());
+ }
+
fprintf(propertyFile, "public %s%s %s\n{\n",
inherited ? "new " : "",
propType.c_str(), propName.c_str());
@@ -1755,7 +1850,7 @@
convertedDoc = doxygenToJavaDoc(commentStr, true);
fprintf(outfile, "%s", convertedDoc.c_str());
} else if (language == csharp) {
- convertedDoc = doxygenToCsharpDoc(commentStr, true);
+ convertedDoc = doxygenToCsharpDoc(commentStr, true, false);
fprintf(outfile, "%s", convertedDoc.c_str());
}
}
@@ -1958,8 +2053,15 @@
{
if(nameSpace != "")
{
- if(language == csharp)
+ if (language == csharp)
+ {
+ fprintf(outfile, "// Generated by IMake. DO NOT MODIFY\n");
+ // There will be /// fragments emitted in places not in expected comment sections
+ fprintf(outfile, "#pragma warning disable CS1587\n");
+ // We may link to classes that exist in a monolithic context, but not in a split context
+ fprintf(outfile, "#pragma warning disable CS1574\n");
fprintf(outfile, "namespace %s {\n\n", nameSpace.c_str());
+ }
}
}
@@ -2021,8 +2123,26 @@
exit(1);
}
+void testFragmentConversion();
+
int main(int argc, char** argv)
{
+ // Uncomment to test/debug specific headers/files
+ /*
+ translateMode = false; // true for constants, false for everything else
+ absPaths = true;
+ language = csharp;
+ typeReplacements["STRING"] = "string";
+ classes["MgResourcePermission"] = true;
+ outfile = fopen("C:\\Workspace\\mg-4.0\\Constants.cs", "w");
+ docOutFile = fopen("C:\\Workspace\\mg-4.0\\doc.i", "w");
+ processHeaderFile("C:\\Workspace\\mg-4.0\\MgDev\\Common\\Geometry\\Coordinate.h", ".");
+ fclose(outfile);
+ fclose(docOutFile);
+ //testFragmentConversion();
+ return 0;
+ */
+
printf("\nIMake - SWIG Interface generator");
printf("\nVersion %s\n\n", version);
@@ -2182,3 +2302,28 @@
}
return 0;
}
+
+void testFragmentConversion()
+{
+ std::string commentStr = R"(///////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Gets the grid scale of the coordinate system at the specified
+/// longitude/latitude point.
+/// Throws an exception MgCoordinateSystemNotReadyException if the
+/// coordinate system has not been successfully initialized;
+/// InvalidArgument of the specified coordinate is not
+/// mathematically valid.
+///
+/// \param dLongitude (double)
+/// The longitude coordinate
+/// \param dLatitude (double)
+/// The latitude coordinate
+///
+/// \return
+/// The grid scale
+///)";
+ auto csharpXml = doxygenToCsharpDoc(commentStr, true, false);
+ auto csharpXml2 = doxygenToCsharpDoc(commentStr, true, true);
+
+ auto javaDoc = doxygenToJavaDoc(commentStr, true);
+}
\ No newline at end of file
More information about the mapguide-commits
mailing list