How to split text into multiple lines

[cross-posted on stack exchange]

I have an OLED display screen (256x64) and I want to split a paragraph of text into multiple lines (i.e. "left aligned") to fit on the OLED.

I will do this from my own function call, and my question here is about how to write this function. There are many ways to skin this cat, but I'm looking for the most sensible and elegant way.

I'm using the u8g graphics library, which has a function that returns the width of a string for a given font. It can also return the height of a font. There's no reason, then, to pass line height into my function, only the starting x and y position, the text, and the x-position at which to wrap the text.

Question 1: is this sensible?

void drawMultiLine (char* text, byte startx, byte starty, byte endx)

I'm not considering pagination or scrolling, so there's no need for an "endy" variable. Nor am I concerned about the case where a word is too long to fit on one line. Ideally it would break the line even if there was no space, but it doesn't matter if it extends beyond the display x coordinate.

Question 2: how would you write this function?

Can you provide a top-level description of the most efficient way to do this?

For example, I have tried this, but gave-up because it seemed too convoluted:

  • loop through each character of the text[] array, and assign each char to the equivalent array index of a buffer buff[]
  • null terminate the buff for each iteration of this loop, in order that we can use u8g.getStrWidthto return the width of the string so far
  • stop looping when u8g.getStrWidth(buff) > endx - startx
  • now the text in char array buff would fit within the width of the display if we printed it, however we want to wrap words, so trace backwards from the end of buff[] array to find the first ASCII space
  • add the null termination character at the array index of this space
  • continue somehow from the first character of the word we stopped at, and loop all the above until we have as many lines as the paragraph of text requires

The above uses three intermediate variables to track indices, three loops, and I think it's generally inelegant.

Normally it is best to operate on data in-place. Don't copy strings. If you can hack the string-width function to take another parameter of string length then you don't need to copy to a separate null terminated string.

Alternatively,scan the string to find spaces. Make a best guess at which space to replace with a null. Then give the width function a pointer to the beginning of that 'line' and let it find the null you placed. If OK then print it, otherwise change that null back to a space and try another.

You also need to consider edge cases like an empty string passed to your function or a single word longer than one line, without spaces.