24 : iBufSize(
iSize), iFirstLinePos(0), iAfterLastLinePos(0), iLineDataPos(0),
25 iNextLineDataPos(0), iMaxLineCount(iMaxLines), iLineCount(0), iLineBreakWidth(iLBWidth), fDynamicGrow(fDynamicGrow), fMarkup(fMarkup)
28 if (szIndentChars && *szIndentChars)
30 szIndent =
new char[strlen(szIndentChars)+1];
31 strcpy(szIndent, szIndentChars);
33 else szIndent =
nullptr;
35 if (iBufSize) szBuf =
new char[iBufSize];
else szBuf=
nullptr;
36 if (iMaxLineCount) pLineDataBuf =
new LineData[iMaxLineCount];
else pLineDataBuf=
nullptr;
37 assert(fDynamicGrow || (iBufSize && iMaxLineCount));
43 delete [] pLineDataBuf;
46 if (szIndent)
delete [] szIndent;
49 void C4LogBuffer::GrowLineCountBuffer(
size_t iGrowBy)
53 LineData *pNewBuf =
new LineData[iMaxLineCount += iGrowBy];
54 if (iLineCount) memcpy(pNewBuf, pLineDataBuf,
sizeof(LineData) * iLineCount);
55 delete [] pLineDataBuf;
56 pLineDataBuf = pNewBuf;
59 void C4LogBuffer::GrowTextBuffer(
size_t iGrowBy)
63 char *pNewBuf =
new char[iBufSize += iGrowBy];
64 if (iAfterLastLinePos) memcpy(pNewBuf, szBuf,
sizeof(
char) * iAfterLastLinePos);
69 void C4LogBuffer::DiscardFirstLine()
72 assert(iLineCount && szBuf && !fDynamicGrow);
76 while (szBuf[iFirstLinePos]) ++iFirstLinePos;
80 if (iFirstLinePos == iBufSize || !szBuf[iFirstLinePos] || !iLineCount)
87 if (!iLineCount) iLineDataPos = iNextLineDataPos = 0;
90 void C4LogBuffer::AppendSingleLine(
const char *szLine,
int iLineLength,
const char *szIndent,
CStdFont *pFont,
DWORD dwClr,
bool fNewPar)
93 if (!szLine || !iLineLength || !*szLine)
return;
95 if (iLineCount == iMaxLineCount)
98 GrowLineCountBuffer(4 + iMaxLineCount/2);
105 if (szIndent) iLineLength += strlen(szIndent);
107 if (iLineLength > iBufSize && !fDynamicGrow)
110 szLine += iLineLength - iBufSize;
111 iLineLength = iBufSize;
114 if (iAfterLastLinePos + iLineLength > iBufSize)
119 GrowTextBuffer(std::max(iLineLength, iBufSize/2));
127 while (iFirstLinePos >= iAfterLastLinePos) DiscardFirstLine();
130 if (iAfterLastLinePos < iBufSize) szBuf[iAfterLastLinePos] = 0;
132 iAfterLastLinePos = 0;
137 while (iLineCount &&
Inside(iFirstLinePos, iAfterLastLinePos, iAfterLastLinePos+iLineLength-1))
143 iIndentLen = strlen(szIndent);
144 memcpy(szBuf + iAfterLastLinePos, szIndent, iIndentLen);
147 if (iLineLength - iIndentLen > 1)
148 memcpy(szBuf + iAfterLastLinePos + iIndentLen, szLine, iLineLength-iIndentLen-1);
150 iAfterLastLinePos += iLineLength;
151 szBuf[iAfterLastLinePos - 1] = 0;
155 LineData &rData = pLineDataBuf[iNextLineDataPos];
158 rData.fNewParagraph = fNewPar;
161 if (++iNextLineDataPos == iMaxLineCount)
164 GrowLineCountBuffer(4 + iMaxLineCount/2);
166 iNextLineDataPos = 0;
172 char LineBreakChars [] = { 0x0D, 0x0A,
'|' };
173 int32_t iLineBreakCharCount = 2 + fMarkup;
177 bool fAnyLineBreakChar =
false;
178 for (
int i = 0; i < iLineBreakCharCount; ++i)
179 if (strchr(szLine, LineBreakChars[i]))
181 fAnyLineBreakChar =
true;
184 if (fAnyLineBreakChar)
186 char *szBuf =
new char[strlen(szLine)+1];
187 char *szBufPos, *szPos2 = szBuf, *szBufFind;
188 strcpy(szBuf, szLine);
189 while ((szBufPos = szPos2))
193 for (
int i = 0; i < iLineBreakCharCount; ++i)
194 if ((szBufFind = strchr(szBufPos, LineBreakChars[i])))
195 if (!szPos2 || szBufFind < szPos2)
198 if (szPos2) *szPos2++ =
'\0';
200 if (!*szBufPos)
continue;
205 pFirstLineFont =
nullptr;
214 if (!iLineBreakWidth || !pFont)
216 AppendSingleLine(szLine, strlen(szLine),
nullptr, pFont, dwClr,
true);
221 const char *markupPos = szLine;
228 int iBreakWdt = iLineBreakWidth;
229 if (iLineIndex && szIndent)
231 int32_t iIndentWdt, Q;
233 iBreakWdt -= iIndentWdt;
236 const char *szNextLine;
237 int iNumChars = pFont->
GetMessageBreak(szLine, &szNextLine, iBreakWdt);
242 while (markupPos < szNextLine)
244 if (*markupPos ==
'<')
246 if (markup.
Read(&markupPos))
248 if (markupPos > szNextLine)
251 iNumChars += markupPos - szNextLine + 1;
252 szNextLine = markupPos;
261 if (!opening.empty() || !closing.empty())
263 rline = std::move(opening);
264 rline.append(szLine, iNumChars);
265 rline.append(closing);
266 szLine = rline.c_str();
267 iNumChars = rline.size();
271 AppendSingleLine(szLine, iNumChars, iLineIndex ? szIndent :
nullptr, pFont, dwClr, !iLineIndex);
285 iLineIndex += iLineCount;
286 if (iLineIndex < 0)
return nullptr;
289 if (iLineIndex >= iLineCount)
return nullptr;
291 LineData &rData = pLineDataBuf[(iLineDataPos + iLineIndex) % iMaxLineCount];
292 if (ppFont) *ppFont = rData.pFont;
293 if (pdwClr) *pdwClr = rData.dwClr;
294 if (pfNewPar) *pfNewPar = rData.fNewParagraph;
296 char *szResult = szBuf + iFirstLinePos;
300 while (*szResult++) ;
302 if (szResult == (szBuf+iBufSize) || !*szResult) szResult = szBuf;
311 iFirstLinePos = iAfterLastLinePos = iLineCount = iNextLineDataPos = iLineDataPos = 0;
316 iLineBreakWidth = iToWidth;
bool Inside(T ival, U lbound, V rbound)
C4LogBuffer(int iSize, int iMaxLines, int iLBWidth, const char *szIndentChars=" ", bool fDynamicGrow=false, bool fMarkup=true)
const char * GetLine(int iLineIndex, CStdFont **ppFont, DWORD *pdwClr, bool *pNewParagraph) const
void SetLBWidth(int iToWidth)
void AppendLines(const char *szLine, CStdFont *pFont, DWORD dwClr, CStdFont *pFirstLineFont=nullptr)
std::string OpeningTags() const
std::string ClosingTags() const
bool Read(const char **ppText, bool fSkip=false)
bool GetTextExtent(const char *szText, int32_t &rsx, int32_t &rsy, bool fCheckMarkup=true)
int GetMessageBreak(const char *szMsg, const char **ppNewPos, int iBreakWidth, float fZoom=1.0f)