Skip to content

Instantly share code, notes, and snippets.

@lelanthran
Last active December 24, 2020 10:21
Show Gist options
  • Save lelanthran/d74dd064c7b2b68adae0763a93fbbd02 to your computer and use it in GitHub Desktop.
Save lelanthran/d74dd064c7b2b68adae0763a93fbbd02 to your computer and use it in GitHub Desktop.
C function to reformat textual content into paragraphs
/* gcc -ggdb -W -Wall -pedantic -o reformat.elf reformat.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <stdbool.h>
/* ************************************************************************* *
* TODO
* 1. Copy the line
* 2. Add in some options
* 3. Add in "stretching" so that lines are fully justified.
* 4. Allow caller to specify border characters (unicode?)
*/
static void reformat_stretch (char *line, size_t shortfall, size_t line_len)
{
size_t insp = (size_t)-1;
size_t idx = rand () % line_len;
bool dir_forward = rand () % 2 ? false : true;
#define FIND_FORWARD(from,c) do {\
while (!insp && from) {\
if (line[from]==c) {\
insp = &line[from];\
}\
from--;
}\
} while (0)
#define FIND_BACKWARD(from,c) do {\
while (!insp && from<line_len) {\
if (line[from]==c) {\
insp = &line[from];\
}\
from++;
}\
} while (0)
while (shortfall--) {
insp = (size_t)-1;
if (dir_forward) {
FIND_FORWARD (idx, '.');
} else {
FIND_BACKWARD (idx, '.');
}
if (insp==(size_t)-1)
break;
dir_forward = !dir_forward;
}
}
static char *reformat (const char *src, size_t width, uint64_t flags)
{
#define FIND_END_MARGIN(begin,end,margin_width) do {\
begin += margin_width;\
if (begin > end)\
begin = end;\
} while (0)
#define FIND_PRECEDING_SPACE(end,begin,margin_width) do {\
if ((end - begin) > margin_width) {\
while (end > begin && !(isspace (*end))) \
end--;\
}\
} while (0)
#define STRNCPY(dst,src,maxlen) do {\
for (size_t i=0; i<maxlen; i++) {\
if ((strchr ("\n\r\b\a\f\t\v", src[i]))==NULL) {\
dst[i] = src[i];\
} else {\
dst[i] = ' ';\
}\
}\
} while (0)
/* ************************************************* */
if (!src)
return NULL;
// Count the maximum number of linebreaks we will be adding
size_t srclen = strlen (src) + 1;
size_t nbreaks = srclen / width;
// Use the number of linebreaks we will add + 1 + the srclen
// to allocate the return value.
size_t retlen = srclen + 1 + nbreaks;
char *ret = calloc (retlen, 1);
// Allocate a buffer to process a single line at a time
size_t line_len = width + 1;
char *line = calloc (line_len, 1);
width--;
// Copy the src one complete line at a time to the return buffer
const char *start = src;
const char *end = &src[srclen];
while (start < end) {
const char *tmp = start;
FIND_END_MARGIN (tmp, end, width+1);
FIND_PRECEDING_SPACE (tmp, start, width);
memset (line, 0, line_len);
STRNCPY (line, start, tmp - start);
start = tmp + 1;
if (start < end) {
size_t string_len = strlen (line);
size_t shortfall = line_len - string_len;
reformat_stretch (line, shortfall, string_len);
}
printf ("[%s]\n", line);
}
return ret;
}
#define TEST1 \
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "\
"incididunt ut labore et dolore magna aliqua. In hac habitasse platea dictumst "\
"quisque sagittis. Tincidunt eget nullam non nisi. Elementum facilisis leo vel "\
"fringilla est ullamcorper. Tortor posuere ac ut consequat semper. Porta lorem "\
"mollis aliquam ut porttitor leo a diam sollicitudin. Erat imperdiet sed "\
"euismod nisi porta. Adipiscing at in tellus integer feugiat scelerisque. "\
"Leo vel fringilla est ullamcorper eget nulla facilisi etiam. Pharetra et "\
"ultrices neque ornare aenean euismod. Vitae turpis massa sed elementum tempus "\
"egestas sed sed. Aliquet nec ullamcorper sit amet risus. Mi tempus imperdiet "\
"nulla malesuada pellentesque elit."\
#define TEST2 \
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "\
"incididunt ut labore et dolore magna aliqua. In hac habitasse platea dictumst "\
"quisque sagittis. Tincidunt eget nullam non nisi. Elementum facilisis leo vel "\
"fringilla est ullamcorper. Tortor posuere ac ut consequat semper. Porta lorem "\
"mollis aliquam ut porttitor leo a diam sollicitudin. Erat imperdiet sed "\
"euismod nisi porta. Adipiscing at in tellus integer feugiat scelerisque. "\
"Leo vel fringilla est ullamcorper eget nulla facilisi etiam. Pharetra et "\
"ultrices neque ornare aenean euismod. Vitae turpis massa sed elementum tempus "\
"egestas sed sed. Aliquet nec ullamcorper sit amet risus. Mi tempus imperdiet "\
"nulla malesuada pellentesque elit."\
#define TEST3 \
"Lorem ipsum dolor sit amet, consectetur\nadipiscing elit, sed do eiusmod tempor "\
"incididunt ut labore et dolore magna aliqua. In\nhac habitasse platea dictumst "\
"quisque sagittis. Tincidunt eget nullam non nisi. Elementum\nfacilisis leo vel "\
"fringilla est ullamcorper. Tortor posuere ac ut consequat semper.\nPorta lorem "\
"mollis aliquam ut porttitor leo a diam sollicitudin. Erat imperdiet\nsed "\
"euismod\nnisi porta. Adipiscing at in tellus integer feugiat scelerisque. "\
"Leo vel fringilla est ullamcorper eget nulla facilisi etiam. Pharetra et "\
"ultrices neque ornare\naenean euismod. Vitae turpis massa sed elementum tempus "\
"egestas sed sed. Aliquet nec ullamcorper sit\namet risus. Mi tempus imperdiet "\
"nulla malesuada pellentesque elit."\
int main (void)
{
const char *test[] = {
TEST1, TEST2, TEST3,
};
for (size_t i=0; i<sizeof test/sizeof test[0]; i++) {
char *tmp = reformat (test[i], (i+1) * 40, 0);
printf ("%s\n", tmp);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment