1/*++
2/* NAME
3/*	line_wrap 3
4/* SUMMARY
5/*	wrap long lines upon output
6/* SYNOPSIS
7/*	#include <line_wrap.h>
8/*
9/*	void	line_wrap(string, len, indent, output_fn, context)
10/*	const char *buf;
11/*	int	len;
12/*	int	indent;
13/*	void	(*output_fn)(const char *str, int len, int indent, char *context);
14/*	char	*context;
15/* DESCRIPTION
16/*	The \fBline_wrap\fR routine outputs the specified string via
17/*	the specified output function, and attempts to keep output lines
18/*	shorter than the specified length. The routine does not attempt to
19/*	break long words that do not fit on a single line. Upon output,
20/*	trailing whitespace is stripped.
21/*
22/* Arguments
23/* .IP string
24/*	The input, which cannot contain any newline characters.
25/* .IP len
26/*	The desired maximal output line length.
27/* .IP indent
28/*	The desired amount of indentation of the second etc. output lines
29/*	with respect to the first output line. A negative indent causes
30/*	only the first line to be indented; a positive indent causes all
31/*	but the first line to be indented. A zero count causes no indentation.
32/* .IP output_fn
33/*	The output function that is called with as arguments a string
34/*	pointer, a string length, a non-negative indentation count, and
35/*	application context. A typical implementation looks like this:
36/* .sp
37/* .nf
38/* .na
39void print(const char *str, int len, int indent, char *context)
40{
41    VSTREAM *fp = (VSTREAM *) context;
42
43    vstream_fprintf(fp, "%*s%.*s", indent, "", len, str);
44}
45/* .fi
46/* .ad
47/* .IP context
48/*	Application context that is passed on to the output function.
49/*	For example, a VSTREAM pointer, or a structure that contains
50/*	a VSTREAM pointer.
51/* BUGS
52/*	No tab expansion and no backspace processing.
53/* LICENSE
54/* .ad
55/* .fi
56/*	The Secure Mailer license must be distributed with this software.
57/* AUTHOR(S)
58/*	Wietse Venema
59/*	IBM T.J. Watson Research
60/*	P.O. Box 704
61/*	Yorktown Heights, NY 10598, USA
62/*--*/
63
64/* System library. */
65
66#include <sys_defs.h>
67#include <string.h>
68#include <ctype.h>
69
70/* Utility library. */
71
72#include <line_wrap.h>
73
74/* line_wrap - wrap long lines upon output */
75
76void    line_wrap(const char *str, int len, int indent, LINE_WRAP_FN output_fn,
77		          char *context)
78{
79    const char *start_line;
80    const char *word;
81    const char *next_word;
82    const char *next_space;
83    int     line_len;
84    int     curr_len;
85    int     curr_indent;
86
87    if (indent < 0) {
88	curr_indent = -indent;
89	curr_len = len + indent;
90    } else {
91	curr_indent = 0;
92	curr_len = len;
93    }
94
95    /*
96     * At strategic positions, output what we have seen, after stripping off
97     * trailing blanks.
98     */
99    for (start_line = word = str; word != 0; word = next_word) {
100	next_space = word + strcspn(word, " \t");
101	if (word > start_line) {
102	    if (next_space - start_line > curr_len) {
103		line_len = word - start_line;
104		while (line_len > 0 && ISSPACE(start_line[line_len - 1]))
105		    line_len--;
106		output_fn(start_line, line_len, curr_indent, context);
107		while (*word && ISSPACE(*word))
108		    word++;
109		if (start_line == str) {
110		    curr_indent += indent;
111		    curr_len -= indent;
112		}
113		start_line = word;
114	    }
115	}
116	next_word = *next_space ? next_space + 1 : 0;
117    }
118    line_len = strlen(start_line);
119    while (line_len > 0 && ISSPACE(start_line[line_len - 1]))
120	line_len--;
121    output_fn(start_line, line_len, curr_indent, context);
122}
123