summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2013-12-10 14:12:48 +0800
committerJeremy Kerr <jk@ozlabs.org>2014-01-31 08:46:34 +0800
commit485680a5bfeb952fd652a59efcce35636d6aec00 (patch)
tree8f3f09ede88b8e60eb5a19a5a29de4e83451934e
parent5a271400e9b5396cb90258b7582fe7ac6bcc2230 (diff)
downloadpetitboot-485680a5bfeb952fd652a59efcce35636d6aec00.zip
petitboot-485680a5bfeb952fd652a59efcce35636d6aec00.tar.gz
lib/fold: Add text fold utility
We want to fold help text into the ncurses UI, so add a little module to split text into lines. Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/fold/fold.c44
-rw-r--r--lib/fold/fold.h27
-rw-r--r--test/lib/Makefile.am3
-rw-r--r--test/lib/test-fold.c157
5 files changed, 232 insertions, 1 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 1c19e11..f6009cf 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -20,6 +20,8 @@ AM_CFLAGS = $(DEFAULT_CFLAGS)
noinst_LTLIBRARIES = libpbcore.la
libpbcore_la_SOURCES = \
+ fold/fold.h \
+ fold/fold.c \
log/log.h \
log/log.c \
list/list.c \
diff --git a/lib/fold/fold.c b/lib/fold/fold.c
new file mode 100644
index 0000000..ec10c8c
--- /dev/null
+++ b/lib/fold/fold.c
@@ -0,0 +1,44 @@
+
+#include "fold/fold.h"
+
+void fold_text(const char *text,
+ int linelen,
+ int line_cb(void *arg, const char *start, int len),
+ void *arg)
+{
+ const char *start, *end, *sep;
+ int rc = 0;
+
+ start = end = sep = text;
+
+ while (!rc) {
+
+ if (*end == '\n') {
+ rc = line_cb(arg, start, end - start);
+ start = sep = ++end;
+
+ } else if (*end == '\0') {
+ line_cb(arg, start, end - start);
+ rc = 1;
+
+ } else if (end - start >= linelen - 1) {
+ if (sep != start) {
+ /* split on a previous word boundary, if
+ * possible */
+ rc = line_cb(arg, start, sep - start);
+ start = end = ++sep;
+ } else {
+ /* otherwise, break the word */
+ end++;
+ rc = line_cb(arg, start, end - start);
+ start = sep = end;
+ }
+
+ } else {
+ end++;
+ /* record our last separator */
+ if (*end == ' ')
+ sep = end;
+ }
+ }
+}
diff --git a/lib/fold/fold.h b/lib/fold/fold.h
new file mode 100644
index 0000000..834fcf2
--- /dev/null
+++ b/lib/fold/fold.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef FOLD_H
+#define FOLD_H
+
+void fold_text(const char *text,
+ int linelen,
+ int line_cb(void *arg, const char *start, int len),
+ void *arg);
+
+#endif /* FOLD_H */
+
diff --git a/test/lib/Makefile.am b/test/lib/Makefile.am
index ae6027f..ed570af 100644
--- a/test/lib/Makefile.am
+++ b/test/lib/Makefile.am
@@ -31,7 +31,8 @@ check_PROGRAMS = list-test \
test-process-async \
test-process-async-stdout \
test-process-parent-stdout \
- test-process-both
+ test-process-both \
+ test-fold
TESTS = $(check_PROGRAMS)
diff --git a/test/lib/test-fold.c b/test/lib/test-fold.c
new file mode 100644
index 0000000..1f58fdf
--- /dev/null
+++ b/test/lib/test-fold.c
@@ -0,0 +1,157 @@
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <fold/fold.h>
+#include <list/list.h>
+#include <talloc/talloc.h>
+
+struct line {
+ const char *buf;
+ unsigned int len;
+ struct list_item list;
+};
+
+struct ctx {
+ struct list lines;
+};
+
+struct test {
+ const char *in;
+ unsigned int linelen;
+ const char *out[];
+};
+
+/* split on newline boundaries, no actual folding */
+struct test test_split = {
+ .in = "Lorem ipsum dolor\nsit amet,\nconsectetuer\n",
+ .linelen = 20,
+ .out = {
+ "Lorem ipsum dolor",
+ "sit amet,",
+ "consectetuer",
+ "",
+ NULL,
+ },
+};
+
+/* fold a long line */
+struct test test_fold_line = {
+ .in = "Lorem ipsum dolor sit amet, consectetuer adipiscing "
+ "elit, sed diam nonummy nibh euismod tincidunt ut "
+ "laoreet dolore magna aliquam erat volutpat.",
+ .linelen = 20,
+ .out = {
+ "Lorem ipsum dolor",
+ "sit amet,",
+ "consectetuer",
+ "adipiscing elit,",
+ "sed diam nonummy",
+ "nibh euismod",
+ "tincidunt ut",
+ "laoreet dolore",
+ "magna aliquam erat",
+ "volutpat.",
+ NULL
+ },
+};
+
+/* break a word */
+struct test test_break = {
+ .in = "Lorem ipsum dolor sit amet, consectetuer",
+ .linelen = 10,
+ .out = {
+ "Lorem",
+ "ipsum",
+ "dolor sit",
+ "amet,",
+ "consectetu",
+ "er",
+ NULL
+ },
+};
+
+static struct test *tests[] = {
+ &test_split, &test_fold_line, &test_break,
+};
+
+static void __attribute__((noreturn)) fail(struct ctx *ctx,
+ struct test *test, const char *msg)
+{
+ struct line *line;
+ int i;
+
+ fprintf(stderr, "%s\n", msg);
+ fprintf(stderr, "input:\n%s\n", test->in);
+
+ fprintf(stderr, "expected:\n");
+ for (i = 0; test->out[i]; i++)
+ fprintf(stderr, " '%s'\n", test->out[i]);
+
+ fprintf(stderr, "actual:\n");
+ list_for_each_entry(&ctx->lines, line, list) {
+ char *buf = talloc_strndup(ctx, line->buf, line->len);
+ fprintf(stderr, " '%s'\n", buf);
+ talloc_free(buf);
+ }
+
+ exit(EXIT_FAILURE);
+}
+
+static int fold_line_cb(void *arg, const char *start, int len)
+{
+ struct ctx *ctx = arg;
+ struct line *line;
+
+ line = talloc(ctx, struct line);
+ line->buf = start;
+ line->len = len;
+ list_add_tail(&ctx->lines, &line->list);
+
+ return 0;
+}
+
+static void run_test(struct test *test)
+{
+ struct line *line;
+ struct ctx *ctx;
+ int i;
+
+ ctx = talloc(NULL, struct ctx);
+ list_init(&ctx->lines);
+ fold_text(test->in, test->linelen, fold_line_cb, ctx);
+
+ i = 0;
+ list_for_each_entry(&ctx->lines, line, list) {
+ if (!test->out[i])
+ fail(ctx, test,
+ "fold_text returned more lines than expected");
+
+ if (line->len > test->linelen)
+ fail(ctx, test, "line too long");
+
+ if (line->len != strlen(test->out[i]))
+ fail(ctx, test, "line lengths differ");
+
+ if (strncmp(line->buf, test->out[i], line->len))
+ fail(ctx, test, "line data differs");
+
+ i++;
+ }
+
+ if (test->out[i])
+ fail(ctx, test, "fold_text returned fewer lines than expected");
+
+ talloc_free(ctx);
+}
+
+int main(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++)
+ run_test(tests[i]);
+
+ return EXIT_SUCCESS;
+}
OpenPOWER on IntegriCloud