summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libshouldbeinlibc/=line.c147
-rw-r--r--libshouldbeinlibc/=line.h128
2 files changed, 275 insertions, 0 deletions
diff --git a/libshouldbeinlibc/=line.c b/libshouldbeinlibc/=line.c
new file mode 100644
index 00000000..30fefcb5
--- /dev/null
+++ b/libshouldbeinlibc/=line.c
@@ -0,0 +1,147 @@
+/* Simple output formatting functions
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <malloc.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <line.h>
+
+/* Return a new line structure, which will output to STREAM. WIDTH is the
+ maximum number of characters per line. If enough memory can't be
+ allocated, 0 is returned. */
+struct line *
+make_line (FILE *stream, unsigned width)
+{
+ struct line *line = malloc (sizeof (struct line));
+ if (line)
+ {
+ line->buf = malloc (width + 2);
+ if (line->buf)
+ {
+ line->max = line->buf + width;
+ line->point = line->buf;
+ line->stream = stream;
+ }
+ else
+ {
+ free (line);
+ line = 0;
+ }
+ }
+ return line;
+}
+
+/* Free LINE and any resources it uses. */
+void
+line_free (struct line *line)
+{
+ if (line->point > line->buf)
+ line_newline (line, 0);
+ free (line->buf);
+ free (line);
+}
+
+/* Adds the text in STR to LINE, wrapping words as necessary to fit.
+ LMARGIN is the left margin used when wrapping; whitespace is deleted at
+ wrap-points. Newlines in STR are honoured by adding a newline and
+ indenting to LMARGIN; any following whitespace is kept. */
+void
+line_fill (struct line *line, char *str, unsigned lmargin)
+{
+ while (*str)
+ {
+ char *word_end = str;
+
+ while (*word_end == ' ')
+ word_end++;
+
+ if (*word_end == '\n')
+ {
+ if (line_column (line) > lmargin)
+ line_newline (line, lmargin);
+ str = word_end + 1;
+ }
+ else if (*word_end)
+ {
+ char *word_start = word_end;
+ while (*word_end && !isspace (*word_end))
+ word_end++;
+ if (line_left (line, word_end - str) >= 0)
+ {
+ line_write (line, str, word_end - str);
+ str = word_end;
+ }
+ else
+ /* Word won't fit on the current line, move to the next one. */
+ {
+ line_newline (line, lmargin);
+ str = word_start; /* Omit spaces when wrapping. */
+ }
+ }
+ }
+}
+
+/* Clean up after a printf to LINE, to take care of any newlines that might
+ have been added. ADDED is the amount the printf has added to the line.
+ We take care of updating LINE's point. */
+void
+_line_cleanup_printf (struct line *line, unsigned added)
+{
+ char *point = line->point, *new_point = point + added, *last_nl = new_point;
+
+ while (last_nl > point)
+ if (*--last_nl == '\n')
+ /* There's a newline; deal. */
+ {
+ last_nl++;
+ fwrite (line->buf, 1, last_nl - line->buf, line->stream);
+ if (last_nl < new_point)
+ bcopy (last_nl, line->buf, new_point - last_nl);
+ new_point -= (last_nl - line->buf);
+ break;
+ }
+
+ line->point = new_point;
+}
+
+/* Add STR, of length LEN, to LINE. */
+void
+line_write (struct line *line, char *str, unsigned len)
+{
+ char *end = memchr (str, '\n', len) ?: str + len;
+ unsigned line_len = end - str;
+ char *p = line->point, *max = line->max;
+ if (line_len > max - p)
+ line_len = max - p;
+ bcopy (str, p, line_len);
+ p += line_len;
+ if (line_len == len)
+ line->point = p;
+ else
+ {
+ char *buf = line->buf;
+ fwrite (buf, 1, p - buf, line->stream);
+ line->point = buf;
+ line_write (line, end + 1, len - line_len - 1);
+ }
+}
diff --git a/libshouldbeinlibc/=line.h b/libshouldbeinlibc/=line.h
new file mode 100644
index 00000000..3305cd3b
--- /dev/null
+++ b/libshouldbeinlibc/=line.h
@@ -0,0 +1,128 @@
+/* Simple output formatting functions
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __LINE_H__
+#define __LINE_H__
+
+#include <stdio.h>
+
+struct line
+{
+ char *buf;
+ char *point, *max;
+ FILE *stream;
+};
+
+extern void
+_line_cleanup_printf (struct line *line, unsigned added);
+
+/* Printf FMT & ARGS to LINE. */
+/* XXX This implementation is kind of bogus because it pretends to deal with
+ newlines in the output, but it just uses LINE's buffer for the output and
+ anything past the end of the buffer will get chopped. A terminating
+ newline will work ok though. */
+#define line_printf(line, fmt, args...) \
+ ({ struct line *_line = (line); \
+ _line_cleanup_printf (_line, \
+ snprintf (_line->point, _line->max - _line->point, (fmt) , ##args)); \
+ })
+
+/* Returns the amount of free space in line after adding AMOUNT characters to
+ it (which will be negative if this would overflow). */
+extern inline int
+line_left (struct line *line, unsigned amount)
+{
+ return line->max - line->point - amount;
+}
+
+/* Return the column position of LINE's output point, which starts at 0. */
+extern inline unsigned
+line_column (struct line *line)
+{
+ return line->point - line->buf;
+}
+
+/* Add enough spaces to LINE to move the point to column TARGET. */
+
+
+extern inline void
+line_indent_to (struct line *line, int target)
+{
+ while (line->point < line->buf + target && line->point < line->max)
+ *line->point++ = ' ';
+}
+
+/* Emit the current contents of LINE and a newline to its stream, and fill
+ LINE with LMARGIN spaces. */
+extern inline void
+line_newline (struct line *line, int lmargin)
+{
+ *line->point++ = '\n';
+ *line->point = '\0';
+ fputs (line->buf, line->stream);
+ line->point = line->buf;
+ if (lmargin)
+ line_indent_to (line, lmargin);
+}
+
+/* If LINE isn't before or at column position LMARGIN, then add a newline
+ and indent to that position. */
+extern inline void
+line_freshline (struct line *line, int lmargin)
+{
+ if (line_column (line) > lmargin)
+ line_newline (line, lmargin);
+}
+
+/* Add a character to LINE, unless it's full. */
+extern inline int
+line_putc (struct line *line, int ch)
+{
+ if (ch == '\n')
+ line_newline (line, 0);
+ else if (line->point < line->max)
+ *line->point++ = ch;
+ return ch;
+}
+
+/* Adds the text in STR to LINE, wrapping words as necessary to fit. LMARGIN
+ is the left margin used when wrapping. */
+void line_fill (struct line *line, char *str, unsigned lmargin);
+
+/* Add STR, of length LEN, to LINE. */
+void line_write (struct line *line, char *str, unsigned len);
+
+/* Add STR to LINE. */
+extern inline void line_puts (struct line *line, char *str)
+{
+ line_write (line, str, strlen (str));
+}
+
+/* Return a new line structure, which will output to STREAM. WIDTH is the
+ maximum number of characters per line. If enough memory can't be
+ allocated, 0 is returned. */
+struct line *make_line (FILE *stream, unsigned width);
+
+/* Free LINE and any resources it uses. */
+void line_free (struct line *line);
+
+#endif /* __LINE_H__ */