/* $NetBSD: line_wrap.c,v 1.2 2017/02/14 01:16:49 christos Exp $ */
/*++
/* NAME
/* line_wrap 3
/* SUMMARY
/* wrap long lines upon output
/* SYNOPSIS
/* #include <line_wrap.h>
/*
/* void line_wrap(string, len, indent, output_fn, context)
/* const char *buf;
/* int len;
/* int indent;
/* void (*output_fn)(const char *str, int len, int indent, void *context);
/* void *context;
/* DESCRIPTION
/* The \fBline_wrap\fR routine outputs the specified string via
/* the specified output function, and attempts to keep output lines
/* shorter than the specified length. The routine does not attempt to
/* break long words that do not fit on a single line. Upon output,
/* trailing whitespace is stripped.
/*
/* Arguments
/* .IP string
/* The input, which cannot contain any newline characters.
/* .IP len
/* The desired maximal output line length.
/* .IP indent
/* The desired amount of indentation of the second etc. output lines
/* with respect to the first output line. A negative indent causes
/* only the first line to be indented; a positive indent causes all
/* but the first line to be indented. A zero count causes no indentation.
/* .IP output_fn
/* The output function that is called with as arguments a string
/* pointer, a string length, a non-negative indentation count, and
/* application context. A typical implementation looks like this:
/* .sp
/* .nf
/* .na
void print(const char *str, int len, int indent, void *context)
{
VSTREAM *fp = (VSTREAM *) context;
vstream_fprintf(fp, "%*s%.*s", indent, "", len, str);
}
/* .fi
/* .ad
/* .IP context
/* Application context that is passed on to the output function.
/* For example, a VSTREAM pointer, or a structure that contains
/* a VSTREAM pointer.
/* BUGS
/* No tab expansion and no backspace processing.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <string.h>
#include <ctype.h>
/* Utility library. */
#include <line_wrap.h>
/* line_wrap - wrap long lines upon output */
void line_wrap(const char *str, int len, int indent, LINE_WRAP_FN output_fn,
void *context)
{
const char *start_line;
const char *word;
const char *next_word;
const char *next_space;
int line_len;
int curr_len;
int curr_indent;
if (indent < 0) {
curr_indent = -indent;
curr_len = len + indent;
} else {
curr_indent = 0;
curr_len = len;
}
/*
* At strategic positions, output what we have seen, after stripping off
* trailing blanks.
*/
for (start_line = word = str; word != 0; word = next_word) {
next_space = word + strcspn(word, " \t");
if (word > start_line) {
if (next_space - start_line > curr_len) {
line_len = word - start_line;
while (line_len > 0 && ISSPACE(start_line[line_len - 1]))
line_len--;
output_fn(start_line, line_len, curr_indent, context);
while (*word && ISSPACE(*word))
word++;
if (start_line == str) {
curr_indent += indent;
curr_len -= indent;
}
start_line = word;
}
}
next_word = *next_space ? next_space + 1 : 0;
}
line_len = strlen(start_line);
while (line_len > 0 && ISSPACE(start_line[line_len - 1]))
line_len--;
output_fn(start_line, line_len, curr_indent, context);
}