//Find out how far the next line is indented static int NextLineIndent(PCSTR input, int tabWidth) { int indent = 0; PCSTR nextLine1 = strchr(input, '\n'); PCSTR nextLine2 = strchr(input, '\r'); if(nextLine2 != NULL && (nextLine1 == NULL || nextLine2 < nextLine1)) nextLine1 = nextLine2; //This is the last line if(nextLine1 == NULL) return -1; if(*nextLine1 == '\r') nextLine1++; if(*nextLine1 == '\n') nextLine1++; while(*nextLine1 == ' ' || *nextLine1 == '\t') { indent += CharLen(*nextLine1, tabWidth); nextLine1++; } if(*nextLine1 == '\r' || *nextLine1 == '\n' || *nextLine1 == '\0') { //Blank lines don't have indents indent = -1; } return indent; }
Word Word::InnerConstructor(char* const backingArray) { Word word; word._length = CharLen(backingArray); word._backing = backingArray; return word; }
Word operator+(char const* lhs, const Word& rhs) { int lhsLength = CharLen(lhs); // Calculate the total length of the new Word instance. int newTotalLength = lhsLength + rhs.Length(); auto newArray = std::unique_ptr<char[]>(new char[newTotalLength + 1]); if (newTotalLength != 0) { // Copy current word object into array. for (int i = 0; i < lhsLength; ++i) { newArray[i] = lhs[i]; } char const* rhsBacking = rhs.CStr(); // Copy second portion. for (int i = lhsLength, b = 0; i < newTotalLength; ++i, ++b) { newArray[i] = rhsBacking[b]; } newArray[newTotalLength] = '\0'; } Word word(newArray.get()); return word; }
Word Word::operator+(char const* rhs) const { int rhsLength = CharLen(rhs); int addedLength = _length + rhsLength; char* newArray = nullptr; if (addedLength != 0) { newArray = new char[addedLength + 1]; // Copy current word object into array. for (int i = 0; i < _length; ++i) { newArray[i] = _backing[i]; } // Copy second portion. for (int i = _length, b = 0; i < addedLength; ++i, ++b) { newArray[i] = rhs[b]; } newArray[addedLength] = '\0'; } return InnerConstructor(newArray); }
DWORD CTWordWrap(PCSTR input, PSTR *output, int tabWidth, int columns) { DWORD ceError = ERROR_SUCCESS; StringBuffer result; int pos = 0; int start; int column; int i; int previousIndent = -1; int nextIndent; memset(&result, 0, sizeof(result)); while(input[pos] != '\0') { int indentColumns; int lastWhite = 0; start = pos; column = 0; while(input[pos] == ' ' || input[pos] == '\t') { column += CharLen(input[pos], tabWidth); pos++; } indentColumns = column; nextIndent = NextLineIndent(input + pos, tabWidth); if(indentColumns > 0 && (nextIndent == indentColumns || previousIndent == indentColumns)) { //The line following this one is indented the same amount. If this //line wraps, we'll indent it an extra tab to differentiate the //two lines. indentColumns += tabWidth; } if(input[pos] == '\r' && input[pos] == '\n') { //Blank lines don't have indents previousIndent = -1; } else previousIndent = column; for(i = 0; i < column; i++) { ceError = CTStringBufferAppendLength(&result, " ", 1); CLEANUP_ON_DWORD(ceError); } start = pos; while(input[pos] != '\n' && input[pos] != '\r' && input[pos] != '\0') { if(input[pos] == '\f') { //This marks how far to indent the text ceError = CTStringBufferAppendLength(&result, input + start, pos - start); CLEANUP_ON_DWORD(ceError); indentColumns = column; pos++; start = pos; } if(column + CharLen(input[pos], tabWidth) > columns && columns != -1) { //Wrap the line //If there was any white space in this line, break it there, //otherwise break it in the middle of the word if(lastWhite > start) pos = lastWhite; //First the text in this line ceError = CTStringBufferAppendLength(&result, input + start, pos - start); CLEANUP_ON_DWORD(ceError); //Now add the newline ceError = CTStringBufferAppendLength(&result, "\n", 1); CLEANUP_ON_DWORD(ceError); //Finally the indent for the new line for(column = 0; column < indentColumns; column++) { ceError = CTStringBufferAppendLength(&result, " ", 1); CLEANUP_ON_DWORD(ceError); } //Skip any whitespace while(input[pos] == ' ' || input[pos] == '\t') { pos++; } start = pos; continue; } if(isspace((int)input[pos])) lastWhite = pos; if(input[pos] == '\t') { //First add the text before the tab ceError = CTStringBufferAppendLength(&result, input + start, pos - start); CLEANUP_ON_DWORD(ceError); //Now expand the tab into spaces for(i = 0; i < tabWidth; i++) { ceError = CTStringBufferAppendLength(&result, " ", 1); CLEANUP_ON_DWORD(ceError); } start = pos + 1; } column += CharLen(input[pos], tabWidth); pos++; } if(input[pos] == '\n') pos++; if(input[pos] == '\r') pos++; //Copy the line ceError = CTStringBufferAppendLength(&result, input + start, pos - start); CLEANUP_ON_DWORD(ceError); } ceError = CTStringBufferAppendLength(&result, "\0", 1); CLEANUP_ON_DWORD(ceError); *output = result.data; result.data = NULL; cleanup: CTStringBufferDestroy(&result); return ceError; }
Word::Word(char const* const chars) : _length(CharLen(chars)) { InitWord(chars); }