summaryrefslogtreecommitdiffstats
path: root/src/util/line_wrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/line_wrap.c')
-rw-r--r--src/util/line_wrap.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/src/util/line_wrap.c b/src/util/line_wrap.c
new file mode 100644
index 0000000..0f399e8
--- /dev/null
+++ b/src/util/line_wrap.c
@@ -0,0 +1,122 @@
+/*++
+/* 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);
+}