diff options
-rw-r--r-- | libshouldbeinlibc/=line.c | 147 | ||||
-rw-r--r-- | libshouldbeinlibc/=line.h | 128 |
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__ */ |