resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmDocumentationFormatter.cxx
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing for details.  */
3 #include "cmDocumentationFormatter.h"
4
5 #include <cstring>
6 #include <iomanip>
7 #include <ostream>
8 #include <string>
9 #include <vector>
10
11 #include "cmDocumentationEntry.h"
12 #include "cmDocumentationSection.h"
13
14 cmDocumentationFormatter::cmDocumentationFormatter() = default;
15
16 cmDocumentationFormatter::~cmDocumentationFormatter() = default;
17
18 void cmDocumentationFormatter::PrintFormatted(std::ostream& os,
19                                               const char* text)
20 {
21   if (!text) {
22     return;
23   }
24   const char* ptr = text;
25   while (*ptr) {
26     // Any ptrs starting in a space are treated as preformatted text.
27     std::string preformatted;
28     while (*ptr == ' ') {
29       for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
30         preformatted.append(1, ch);
31       }
32       if (*ptr) {
33         ++ptr;
34         preformatted.append(1, '\n');
35       }
36     }
37     if (!preformatted.empty()) {
38       this->PrintPreformatted(os, preformatted.c_str());
39     }
40
41     // Other ptrs are treated as paragraphs.
42     std::string paragraph;
43     for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
44       paragraph.append(1, ch);
45     }
46     if (*ptr) {
47       ++ptr;
48       paragraph.append(1, '\n');
49     }
50     if (!paragraph.empty()) {
51       this->PrintParagraph(os, paragraph.c_str());
52     }
53   }
54 }
55
56 void cmDocumentationFormatter::PrintPreformatted(std::ostream& os,
57                                                  const char* text)
58 {
59   bool newline = true;
60   for (const char* ptr = text; *ptr; ++ptr) {
61     if (newline && *ptr != '\n') {
62       os << this->TextIndent;
63       newline = false;
64     }
65     os << *ptr;
66     if (*ptr == '\n') {
67       newline = true;
68     }
69   }
70   os << "\n";
71 }
72
73 void cmDocumentationFormatter::PrintParagraph(std::ostream& os,
74                                               const char* text)
75 {
76   os << this->TextIndent;
77   this->PrintColumn(os, text);
78   os << "\n";
79 }
80
81 void cmDocumentationFormatter::SetIndent(const char* indent)
82 {
83   this->TextIndent = indent;
84 }
85
86 void cmDocumentationFormatter::PrintColumn(std::ostream& os, const char* text)
87 {
88   // Print text arranged in an indented column of fixed width.
89   const char* l = text;
90   long column = 0;
91   bool newSentence = false;
92   bool firstLine = true;
93   int width = this->TextWidth - static_cast<int>(strlen(this->TextIndent));
94
95   // Loop until the end of the text.
96   while (*l) {
97     // Parse the next word.
98     const char* r = l;
99     while (*r && (*r != '\n') && (*r != ' ')) {
100       ++r;
101     }
102
103     // Does it fit on this line?
104     if (r - l < (width - column - (newSentence ? 1 : 0))) {
105       // Word fits on this line.
106       if (r > l) {
107         if (column) {
108           // Not first word on line.  Separate from the previous word
109           // by a space, or two if this is a new sentence.
110           if (newSentence) {
111             os << "  ";
112             column += 2;
113           } else {
114             os << " ";
115             column += 1;
116           }
117         } else {
118           // First word on line.  Print indentation unless this is the
119           // first line.
120           os << (firstLine ? "" : this->TextIndent);
121         }
122
123         // Print the word.
124         os.write(l, static_cast<long>(r - l));
125         newSentence = (*(r - 1) == '.');
126       }
127
128       if (*r == '\n') {
129         // Text provided a newline.  Start a new line.
130         os << "\n";
131         ++r;
132         column = 0;
133         firstLine = false;
134       } else {
135         // No provided newline.  Continue this line.
136         column += static_cast<long>(r - l);
137       }
138     } else {
139       // Word does not fit on this line.  Start a new line.
140       os << "\n";
141       firstLine = false;
142       if (r > l) {
143         os << this->TextIndent;
144         os.write(l, static_cast<long>(r - l));
145         column = static_cast<long>(r - l);
146         newSentence = (*(r - 1) == '.');
147       } else {
148         column = 0;
149       }
150     }
151
152     // Move to beginning of next word.  Skip over whitespace.
153     l = r;
154     while (*l == ' ') {
155       ++l;
156     }
157   }
158 }
159
160 void cmDocumentationFormatter::PrintSection(
161   std::ostream& os, cmDocumentationSection const& section)
162 {
163   os << section.GetName() << "\n";
164
165   const std::vector<cmDocumentationEntry>& entries = section.GetEntries();
166   for (cmDocumentationEntry const& entry : entries) {
167     if (!entry.Name.empty()) {
168       os << std::setw(2) << std::left << entry.CustomNamePrefix << entry.Name;
169       this->TextIndent = "                                 ";
170       int align = static_cast<int>(strlen(this->TextIndent)) - 4;
171       for (int i = static_cast<int>(entry.Name.size()); i < align; ++i) {
172         os << " ";
173       }
174       if (entry.Name.size() > strlen(this->TextIndent) - 4) {
175         os << "\n";
176         os.write(this->TextIndent, strlen(this->TextIndent) - 2);
177       }
178       os << "= ";
179       this->PrintColumn(os, entry.Brief.c_str());
180       os << "\n";
181     } else {
182       os << "\n";
183       this->TextIndent = "";
184       this->PrintFormatted(os, entry.Brief.c_str());
185     }
186   }
187   os << "\n";
188 }