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