Word Wrapping in C
I recently ran into a situation where I needed to wrap text to a certain number of columns to support the standard 80×24 Linux console without making a complete mess of the screen. Since I found no standard way of doing this, I wrote this little function to handle it for me.
There are no dependencies on any external libraries. Pass in your storage, your string, and the number of columns to wrap to, and this will do the rest.
/*
* This function will wrap large amounts of a text into a manageable and human-readable width
* word by word. Just specify the number of columns you are working with and feed it a string,
* and it will return a new string (including added line breaks) to accommodate the area you
* are working with.
*
* {{{ proto( void ) wrap( char out, char str, int columns )
*/
void wrap( char *out, char *str, int columns )
{
int len, n, w, wordlen=0, linepos=0, outlen=0;
/*
* Find length of string 'str' without using string.h
*/
for( len=0; str[len]; ++len );
/*
* Allocate the full space of 'str' to 'word', so there is no possible way that the string
* could contain a word that does not fit into the 'word' variable.
*/
char word[len];
/*
* Loop through each individual character in the passed array (str) and detect white space
* and word length to determine how to handle line wrapping.
*/
for( n=0; n<=len; n++ )
{
/*
* Detect spaces and newlines. We cannot gurantee that the passed string is null-
* terminated, so we also need to handle cases where we reach the end of the string
* without encountering wite space characters.
*/
if( str[n] == ' ' || str[n] == '\n' || n == len )
{
/*
* If the current word will not fit on the current line, add a newline.
*/
if( linepos > columns )
{
out[outlen++] = '\n';
linepos = wordlen;
}
/*
* Append the found word to the output and reset the word character array in
* preparation for accepting characters for the next word.
*/
for( w=0; w<wordlen; w++ )
{
out[outlen++] = word[w];
word[w] = '\0';
}
/*
* If we reach the end of the string, add the null-terminator character.
*/
if( n == len )
out[outlen] = '\0';
/*
* If we encounter a newline character, append it to the string as usual, but
* set the line position counter back to 0 (new line = start count from 0 again).
*/
else if( str[n] == '\n' )
{
out[outlen] = str[n];
linepos=0;
}
/*
* If the word fits in the current line without trouble, just add the space.
*/
else
{
out[outlen] = ' ';
linepos++;
}
/*
* Increment the final output length for the next loop, and set the word length
* counter back to 0 (newline or space = new word).
*/
outlen++;
wordlen=0;
}
/*
* If the current character is in the middle of a word somewhere, just append it and
* move on, incrementing counters.
*/
else
{
word[wordlen++] = str[n];
linepos++;
}
}
}
/* }}} */
Examples
Wrap at 50 columns:
$ ./a.out Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas pulvinar blandit diam nec mattis. Sed a ipsum nec ante porttitor feugiat. Morbi ipsum lacus, dignissim at bibendum in, consectetur eget ipsum. Donec dolor nibh, scelerisque ac sodales et, posuere ac nulla. Aliquam eget tincidunt ante. Vestibulum justo leo, congue ut luctus ut, venenatis non dui. Cras sapien risus, blandit at semper eu, cursus eu est. In hac habitasse platea dictumst. Fusce libero dolor, commodo nec rhoncus eu, rutrum vel arcu. Vivamus ultrices faucibus tellus ac feugiat. Ut imperdiet metus sed erat feugiat sed porta lorem tristique. Mauris quis erat vel ante cursus pretium. Curabitur arcu erat, consequat ac ornare et, venenatis eu diam. Curabitur posuere dui vitae tortor cursus cursus. Pellentesque adipiscing lobortis sem at varius. Mauris pellentesque sollicitudin ultricies. Maecenas in tellus turpis. Integer convallis mollis elit eu placerat. Nunc volutpat consectetur facilisis. Curabitur eros arcu, dapibus ut convallis non, rhoncus non magna.
Wrap at 20 columns:
$ ./a.out Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas pulvinar blandit diam nec mattis. Sed a ipsum nec ante porttitor feugiat. Morbi ipsum lacus, dignissim at bibendum in, consectetur eget ipsum. Donec dolor nibh, scelerisque ac sodales et, posuere ac nulla. Aliquam eget tincidunt ante. Vestibulum justo leo, congue ut luctus ut, venenatis non dui. Cras sapien risus, blandit at semper eu, cursus eu est. In hac habitasse platea dictumst. Fusce libero dolor, commodo nec rhoncus eu, rutrum vel arcu. Vivamus ultrices faucibus tellus ac feugiat. Ut imperdiet metus sed erat feugiat sed porta lorem tristique. Mauris quis erat vel ante cursus pretium. Curabitur arcu erat, consequat ac ornare et, venenatis eu diam. Curabitur posuere dui vitae tortor cursus cursus. Pellentesque adipiscing lobortis sem at varius. Mauris pellentesque sollicitudin ultricies. Maecenas in tellus turpis. Integer convallis mollis elit eu placerat. Nunc volutpat consectetur facilisis. Curabitur eros arcu, dapibus ut convallis non, rhoncus non magna.
*Update 11/24/2011: This solution is useful if you need to word wrap inside of a C program. If you are shell scripting, you can use the “fold” command, which comes standard with the “coreutils” package in EL-based distributions.
Usage: fold [OPTION]... [FILE]...
Wrap input lines in each FILE (standard input by default), writing to
standard output.
Mandatory arguments to long options are mandatory for short options too.
-b, --bytes count bytes rather than columns
-c, --characters count characters rather than columns
-s, --spaces break at spaces
-w, --width=WIDTH use WIDTH columns instead of 80
--help display this help and exit
--version output version information and exit
Report bugs to <bug-coreutils@gnu.org>.
$ whatis fold
fold (1) – wrap each input line to fit in specified width
fold (1p) – filter for folding lines
$ rpm -qf $(which fold)
coreutils-8.4-9.el6.x86_64
Urk. Didn’t read all the way down. You put it at the end there. Cheers.