summaryrefslogtreecommitdiff
path: root/usr.bin/fmt
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2004-04-01 23:14:20 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2004-04-01 23:14:20 +0000
commitf43bea8517c4ba4479453545c85327b306e37596 (patch)
tree8f90c3e8e69924d3dc1023f01f41edee1c3f9746 /usr.bin/fmt
parent3ae31f15c97a86e11066e7195bd3e1d74c12d122 (diff)
knf and ansi, mostly from joris vink
Diffstat (limited to 'usr.bin/fmt')
-rw-r--r--usr.bin/fmt/fmt.c787
1 files changed, 442 insertions, 345 deletions
diff --git a/usr.bin/fmt/fmt.c b/usr.bin/fmt/fmt.c
index f6c0156fdfa..65a1b1ee416 100644
--- a/usr.bin/fmt/fmt.c
+++ b/usr.bin/fmt/fmt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fmt.c,v 1.20 2003/12/01 15:34:26 grange Exp $ */
+/* $OpenBSD: fmt.c,v 1.21 2004/04/01 23:14:19 tedu Exp $ */
/* Sensible version of fmt
*
@@ -170,7 +170,7 @@
#ifndef lint
static const char rcsid[] =
- "$OpenBSD: fmt.c,v 1.20 2003/12/01 15:34:26 grange Exp $";
+ "$OpenBSD: fmt.c,v 1.21 2004/04/01 23:14:19 tedu Exp $";
static const char copyright[] =
"Copyright (c) 1997 Gareth McCaughan. All rights reserved.\n";
#endif /* not lint */
@@ -196,271 +196,293 @@ static const char copyright[] =
* (returning 0 instead), but we do complain about bad numbers.
*/
static size_t
-get_positive(const char *s, const char *err_mess, int fussyP) {
- char *t;
- long result = strtol(s,&t,0);
- if (*t) { if (fussyP) goto Lose; else return 0; }
- if (result<=0) { Lose: errx(EX_USAGE, "%s", err_mess); }
- return (size_t) result;
+get_positive(const char *s, const char *err_mess, int fussyP)
+{
+ char *t;
+ long result = strtol(s, &t, 0);
+
+ if (*t) {
+ if (fussyP)
+ goto Lose;
+ else
+ return 0;
+ }
+ if (result <= 0) {
+Lose:
+ errx(EX_USAGE, "%s", err_mess);
+ }
+
+ return (size_t) result;
}
/* Global variables */
-static int centerP=0; /* Try to center lines? */
-static size_t goal_length=0; /* Target length for output lines */
-static size_t max_length=0; /* Maximum length for output lines */
-static int coalesce_spaces_P=0; /* Coalesce multiple whitespace -> ' ' ? */
-static int allow_indented_paragraphs=0; /* Can first line have diff. ind.? */
-static int tab_width=8; /* Number of spaces per tab stop */
-static size_t output_tab_width=0; /* Ditto, when squashing leading spaces */
-static const char *sentence_enders=".?!"; /* Double-space after these */
-static int grok_mail_headers=0; /* treat embedded mail headers magically? */
-static int format_troff=0; /* Format troff? */
-
-static int n_errors=0; /* Number of failed files. Return on exit. */
-static char *output_buffer=0; /* Output line will be built here */
-static size_t x; /* Horizontal position in output line */
-static size_t x0; /* Ditto, ignoring leading whitespace */
-static size_t pending_spaces; /* Spaces to add before next word */
-static int output_in_paragraph=0; /* Any of current para written out yet? */
+static int centerP = 0; /* Try to center lines? */
+static size_t goal_length = 0; /* Target length for output lines */
+static size_t max_length = 0; /* Maximum length for output lines */
+static int coalesce_spaces_P = 0; /* Coalesce multiple whitespace -> ' ' ? */
+static int allow_indented_paragraphs = 0; /* Can first line have diff. ind.? */
+static int tab_width = 8; /* Number of spaces per tab stop */
+static size_t output_tab_width = 0; /* Ditto, when squashing leading spaces */
+static const char *sentence_enders = ".?!"; /* Double-space after these */
+static int grok_mail_headers = 0; /* treat embedded mail headers magically? */
+static int format_troff = 0; /* Format troff? */
+
+static int n_errors = 0; /* Number of failed files. Return on exit. */
+static char *output_buffer = NULL; /* Output line will be built here */
+static size_t x; /* Horizontal position in output line */
+static size_t x0; /* Ditto, ignoring leading whitespace */
+static size_t pending_spaces; /* Spaces to add before next word */
+static int output_in_paragraph = 0; /* Any of current para written out yet? */
/* Prototypes */
-static void process_named_file(const char *);
-static void process_stream(FILE *, const char *);
-static size_t indent_length(const char *, size_t);
-static int might_be_header(const unsigned char *);
-static void new_paragraph(size_t, size_t);
-static void output_word(size_t, size_t, const char *, size_t, size_t);
-static void output_indent(size_t);
-static void center_stream(FILE *, const char *);
-static char * get_line(FILE *, size_t *);
-static void * xrealloc(void *, size_t);
+static void process_named_file(const char *);
+static void process_stream(FILE *, const char *);
+static size_t indent_length(const char *, size_t);
+static int might_be_header(const unsigned char *);
+static void new_paragraph(size_t, size_t);
+static void output_word(size_t, size_t, const char *, size_t, size_t);
+static void output_indent(size_t);
+static void center_stream(FILE *, const char *);
+static char *get_line(FILE *, size_t *);
+static void *xrealloc(void *, size_t);
+void usage(void);
-#define XMALLOC(x) xrealloc(0,x)
+#define XMALLOC(x) xrealloc(0, x)
/* Here is perhaps the right place to mention that this code is
* all in top-down order. Hence, |main| comes first.
*/
int
-main(int argc, char *argv[]) {
- int ch; /* used for |getopt| processing */
-
-
- (void)setlocale(LC_CTYPE, "");
-
- /* 1. Grok parameters. */
-
- while ((ch = getopt(argc, argv, "0123456789cd:hl:mnpst:w:")) != -1)
- switch(ch) {
- case 'c':
- centerP = 1;
- continue;
- case 'd':
- sentence_enders = optarg;
- continue;
- case 'l':
- output_tab_width
- = get_positive(optarg, "output tab width must be positive", 1);
- continue;
- case 'm':
- grok_mail_headers = 1;
- continue;
- case 'n':
- format_troff = 1;
- continue;
- case 'p':
- allow_indented_paragraphs = 1;
- continue;
- case 's':
- coalesce_spaces_P = 1;
- continue;
- case 't':
- tab_width = get_positive(optarg, "tab width must be positive", 1);
- continue;
- case 'w':
- goal_length = get_positive(optarg, "width must be positive", 1);
- max_length = goal_length;
- continue;
- case '0': case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- /* XXX this is not a stylistically approved use of getopt() */
- if (goal_length==0) {
- char *p;
- p = argv[optind - 1];
- if (p[0] == '-' && p[1] == ch && !p[2])
- goal_length = get_positive(++p, "width must be nonzero", 1);
- else
- goal_length = get_positive(argv[optind]+1,
- "width must be nonzero", 1);
- max_length = goal_length;
- }
- continue;
- case 'h': default:
- fprintf(stderr,
-"Usage: fmt [-cmps] [-d chars] [-l num] [-t num]\n"
-" [-w width | -width | goal [maximum]] [file ...]\n"
-"Options: -c center each line instead of formatting\n"
-" -d <chars> double-space after <chars> at line end\n"
-" -l <n> turn each <n> spaces at start of line into a tab\n"
-" -m try to make sure mail header lines stay separate\n"
-" -n format lines beginning with a dot\n"
-" -p allow indented paragraphs\n"
-" -s coalesce whitespace inside lines\n"
-" -t <n> have tabs every <n> columns\n"
-" -w <n> set maximum width to <n>\n"
-" goal set target width to goal\n");
- exit(ch=='h' ? 0 : EX_USAGE);
- }
- argc -= optind; argv += optind;
-
- /* [ goal [ maximum ] ] */
-
- if (argc>0 && goal_length==0
- && (goal_length=get_positive(*argv,"goal length must be positive", 0))
- != 0) {
- --argc; ++argv;
- if (argc>0
- && (max_length=get_positive(*argv,"max length must be positive", 0))
- != 0) {
- --argc; ++argv;
- if (max_length<goal_length)
- errx(EX_USAGE, "max length must be >= goal length");
- }
- }
- if (goal_length==0) goal_length = 65;
- if (max_length==0) max_length = goal_length+10;
- output_buffer = XMALLOC(max_length+1); /* really needn't be longer */
-
- /* 2. Process files. */
-
- if (argc>0) {
- while (argc-->0) process_named_file(*argv++);
- }
- else {
- process_stream(stdin, "standard input");
- }
-
- /* We're done. */
-
- return n_errors ? EX_NOINPUT : 0;
+main(int argc, char *argv[])
+{
+ int ch; /* used for |getopt| processing */
+
+ (void)setlocale(LC_CTYPE, "");
+
+ /* 1. Grok parameters. */
+ while ((ch = getopt(argc, argv, "0123456789cd:hl:mnpst:w:")) != -1) {
+ switch (ch) {
+ case 'c':
+ centerP = 1;
+ break;
+ case 'd':
+ sentence_enders = optarg;
+ break;
+ case 'l':
+ output_tab_width
+ = get_positive(optarg, "output tab width must be positive", 1);
+ break;
+ case 'm':
+ grok_mail_headers = 1;
+ break;
+ case 'n':
+ format_troff = 1;
+ break;
+ case 'p':
+ allow_indented_paragraphs = 1;
+ break;
+ case 's':
+ coalesce_spaces_P = 1;
+ break;
+ case 't':
+ tab_width = get_positive(optarg, "tab width must be positive", 1);
+ break;
+ case 'w':
+ goal_length = get_positive(optarg, "width must be positive", 1);
+ max_length = goal_length;
+ break;
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ /* XXX this is not a stylistically approved use of getopt() */
+ if (goal_length == 0) {
+ char *p;
+
+ p = argv[optind - 1];
+ if (p[0] == '-' && p[1] == ch && !p[2])
+ goal_length = get_positive(++p, "width must be nonzero", 1);
+ else
+ goal_length = get_positive(argv[optind]+1,
+ "width must be nonzero", 1);
+ max_length = goal_length;
+ }
+ break;
+ case 'h':
+ default:
+ usage();
+ /* NOT REACHED */
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* [ goal [ maximum ] ] */
+ if (argc > 0 && goal_length == 0 &&
+ (goal_length = get_positive(*argv,"goal length must be positive", 0)) != 0) {
+ --argc;
+ ++argv;
+ if (argc > 0 && (max_length = get_positive(*argv,"max length must be positive", 0)) != 0) {
+ --argc;
+ ++argv;
+ if (max_length < goal_length)
+ errx(EX_USAGE, "max length must be >= goal length");
+ }
+ }
+
+ if (goal_length == 0)
+ goal_length = 65;
+ if (max_length == 0)
+ max_length = goal_length+10;
+ output_buffer = XMALLOC(max_length+1); /* really needn't be longer */
+
+ /* 2. Process files. */
+
+ if (argc > 0) {
+ while (argc-- > 0)
+ process_named_file(*argv++);
+ } else {
+ process_stream(stdin, "standard input");
+ }
+
+ /* We're done. */
+ return n_errors ? EX_NOINPUT : 0;
}
/* Process a single file, given its name.
*/
static void
-process_named_file(const char *name) {
- FILE *f=fopen(name, "r");
- if (!f) { perror(name); ++n_errors; }
- else {
- process_stream(f, name);
- fclose(f);
- }
+process_named_file(const char *name)
+{
+ FILE *f;
+
+ if ((f = fopen(name, "r")) == NULL) {
+ perror(name);
+ ++n_errors;
+ } else {
+ process_stream(f, name);
+ fclose(f);
+ }
}
/* Types of mail header continuation lines:
*/
typedef enum {
- hdr_ParagraphStart = -1,
- hdr_NonHeader = 0,
- hdr_Header = 1,
- hdr_Continuation = 2
+ hdr_ParagraphStart = -1,
+ hdr_NonHeader = 0,
+ hdr_Header = 1,
+ hdr_Continuation = 2
} HdrType;
/* Process a stream. This is where the real work happens,
* except that centering is handled separately.
*/
static void
-process_stream(FILE *stream, const char *name) {
- size_t last_indent=SILLY; /* how many spaces in last indent? */
- size_t para_line_number=0; /* how many lines already read in this para? */
- size_t first_indent=SILLY; /* indentation of line 0 of paragraph */
- HdrType prev_header_type=hdr_ParagraphStart;
+process_stream(FILE *stream, const char *name)
+{
+ size_t n;
+ size_t np;
+ size_t last_indent = SILLY; /* how many spaces in last indent? */
+ size_t para_line_number = 0; /* how many lines already read in this para? */
+ size_t first_indent = SILLY; /* indentation of line 0 of paragraph */
+ HdrType prev_header_type = hdr_ParagraphStart;
+ HdrType header_type;
+
/* ^-- header_type of previous line; -1 at para start */
- char *line;
- size_t length;
-
- if (centerP) { center_stream(stream, name); return; }
- while ((line=get_line(stream,&length)) != NULL) {
- size_t np=indent_length(line, length);
- { HdrType header_type=hdr_NonHeader;
- if (grok_mail_headers && prev_header_type!=hdr_NonHeader) {
- if (np==0 && might_be_header(line))
- header_type = hdr_Header;
- else if (np>0 && prev_header_type>hdr_NonHeader)
- header_type = hdr_Continuation;
- }
- /* We need a new paragraph if and only if:
- * this line is blank,
- * OR it's a troff request,
- * OR it's a mail header,
- * OR it's not a mail header AND the last line was one,
- * OR the indentation has changed
- * AND the line isn't a mail header continuation line
- * AND this isn't the second line of an indented paragraph.
- */
- if ( length==0
- || (line[0]=='.' && !format_troff)
- || header_type==hdr_Header
- || (header_type==hdr_NonHeader && prev_header_type>hdr_NonHeader)
- || (np!=last_indent
- && header_type != hdr_Continuation
- && (!allow_indented_paragraphs || para_line_number != 1)) ) {
- new_paragraph(output_in_paragraph ? last_indent : first_indent, np);
- para_line_number = 0;
- first_indent = np;
- last_indent = np;
- /* nroff compatibility */
- if (length>0 && line[0]=='.' && !format_troff) {
- printf("%.*s\n", (int)length, line);
- continue;
- }
- if (header_type==hdr_Header) last_indent=2; /* for cont. lines */
- if (length==0) {
- putchar('\n');
- prev_header_type=hdr_ParagraphStart;
- continue;
- }
- }
- else {
- /* If this is an indented paragraph other than a mail header
- * continuation, set |last_indent|.
- */
- if (np != last_indent && header_type != hdr_Continuation)
- last_indent=np;
- }
- prev_header_type = header_type;
- }
-
- { size_t n=np;
- while (n<length) {
- /* Find word end and count spaces after it */
- size_t word_length=0, space_length=0;
- while (n+word_length < length && line[n+word_length] != ' ')
- ++word_length;
- space_length = word_length;
- while (n+space_length < length && line[n+space_length] == ' ')
- ++space_length;
- /* Send the word to the output machinery. */
- output_word(first_indent, last_indent,
- line+n, word_length, space_length-word_length);
- n += space_length;
- }
- }
- ++para_line_number;
- }
- new_paragraph(output_in_paragraph ? last_indent : first_indent, 0);
- if (ferror(stream)) { perror(name); ++n_errors; }
+ char *line;
+ size_t length;
+
+ if (centerP) {
+ center_stream(stream, name);
+ return;
+ }
+
+ while ((line = get_line(stream, &length)) != NULL) {
+ np = indent_length(line, length);
+ header_type = hdr_NonHeader;
+ if (grok_mail_headers && prev_header_type != hdr_NonHeader) {
+ if (np == 0 && might_be_header(line))
+ header_type = hdr_Header;
+ else if (np > 0 && prev_header_type>hdr_NonHeader)
+ header_type = hdr_Continuation;
+ }
+
+ /* We need a new paragraph if and only if:
+ * this line is blank,
+ * OR it's a troff request,
+ * OR it's a mail header,
+ * OR it's not a mail header AND the last line was one,
+ * OR the indentation has changed
+ * AND the line isn't a mail header continuation line
+ * AND this isn't the second line of an indented paragraph.
+ */
+ if (length == 0 || (line[0] == '.' && !format_troff) ||
+ header_type == hdr_Header ||
+ (header_type == hdr_NonHeader && prev_header_type > hdr_NonHeader) ||
+ (np != last_indent && header_type != hdr_Continuation &&
+ (!allow_indented_paragraphs || para_line_number != 1)) ) {
+ new_paragraph(output_in_paragraph ? last_indent : first_indent, np);
+ para_line_number = 0;
+ first_indent = np;
+ last_indent = np;
+
+ /* nroff compatibility */
+ if (length > 0 && line[0] == '.' && !format_troff) {
+ printf("%.*s\n", (int)length, line);
+ continue;
+ }
+ if (header_type == hdr_Header)
+ last_indent = 2; /* for cont. lines */
+ if (length == 0) {
+ putchar('\n');
+ prev_header_type = hdr_ParagraphStart;
+ continue;
+ } else {
+ /* If this is an indented paragraph other than a mail header
+ * continuation, set |last_indent|.
+ */
+ if (np != last_indent && header_type != hdr_Continuation)
+ last_indent = np;
+ }
+ prev_header_type = header_type;
+ }
+
+ n = np;
+ while (n < length) {
+ /* Find word end and count spaces after it */
+ size_t word_length = 0, space_length = 0;
+ while (n+word_length < length && line[n+word_length] != ' ')
+ ++word_length;
+ space_length = word_length;
+ while (n+space_length < length && line[n+space_length] == ' ')
+ ++space_length;
+ /* Send the word to the output machinery. */
+ output_word(first_indent, last_indent,
+ line+n, word_length, space_length-word_length);
+ n += space_length;
+ }
+ ++para_line_number;
+ }
+
+ new_paragraph(output_in_paragraph ? last_indent : first_indent, 0);
+ if (ferror(stream)) {
+ perror(name);
+ ++n_errors;
+ }
}
/* How long is the indent on this line?
*/
static size_t
-indent_length(const char *line, size_t length) {
- size_t n=0;
- while (n<length && *line++ == ' ') ++n;
- return n;
+indent_length(const char *line, size_t length)
+{
+ size_t n = 0;
+
+ while (n < length && *line++ == ' ')
+ ++n;
+ return n;
}
/* Might this line be a mail header?
@@ -470,36 +492,48 @@ indent_length(const char *line, size_t length) {
* conservative to avoid mangling ordinary civilised text.
*/
static int
-might_be_header(const unsigned char *line) {
- if (!isupper(*line++)) return 0;
- while (*line && (isalnum(*line) || *line=='-')) ++line;
- return (*line==':' && isspace(line[1]));
+might_be_header(const unsigned char *line)
+{
+
+ if (!isupper(*line++))
+ return 0;
+ while (*line && (isalnum(*line) || *line == '-'))
+ ++line;
+ return (*line == ':' && isspace(line[1]));
}
/* Begin a new paragraph with an indent of |indent| spaces.
*/
static void
-new_paragraph(size_t old_indent, size_t indent) {
- if (x0) {
- if (old_indent>0) output_indent(old_indent);
- fwrite(output_buffer, 1, x0, stdout);
- putchar('\n');
- }
- x=indent; x0=0; pending_spaces=0;
- output_in_paragraph = 0;
+new_paragraph(size_t old_indent, size_t indent)
+{
+
+ if (x0) {
+ if (old_indent > 0)
+ output_indent(old_indent);
+ fwrite(output_buffer, 1, x0, stdout);
+ putchar('\n');
+ }
+ x = indent;
+ x0 = 0;
+ pending_spaces = 0;
+ output_in_paragraph = 0;
}
/* Output spaces or tabs for leading indentation.
*/
static void
-output_indent(size_t n_spaces) {
- if (output_tab_width) {
- while (n_spaces >= output_tab_width) {
- putchar('\t');
- n_spaces -= output_tab_width;
- }
- }
- while (n_spaces-- > 0) putchar(' ');
+output_indent(size_t n_spaces)
+{
+
+ if (output_tab_width) {
+ while (n_spaces >= output_tab_width) {
+ putchar('\t');
+ n_spaces -= output_tab_width;
+ }
+ }
+ while (n_spaces-- > 0)
+ putchar(' ');
}
/* Output a single word, or add it to the buffer.
@@ -507,78 +541,101 @@ output_indent(size_t n_spaces) {
* lines of a paragraph. They'll often be the same, of course.
*/
static void
-output_word(size_t indent0, size_t indent1, const char *word, size_t length, size_t spaces) {
- size_t new_x = x+pending_spaces+length;
- size_t indent = output_in_paragraph ? indent1 : indent0;
-
- /* If either |spaces==0| (at end of line) or |coalesce_spaces_P|
- * (squashing internal whitespace), then add just one space;
- * except that if the last character was a sentence-ender we
- * actually add two spaces.
- */
- if (coalesce_spaces_P || spaces==0)
- spaces = strchr(sentence_enders, word[length-1]) ? 2 : 1;
-
- if (new_x<=goal_length) {
- /* After adding the word we still aren't at the goal length,
- * so clearly we add it to the buffer rather than outputing it.
- */
- memset(output_buffer+x0, ' ', pending_spaces);
- x0 += pending_spaces; x += pending_spaces;
- memcpy(output_buffer+x0, word, length);
- x0 += length; x += length;
- pending_spaces = spaces;
- }
- else {
- /* Adding the word takes us past the goal. Print the line-so-far,
- * and the word too iff either (1) the lsf is empty or (2) that
- * makes us nearer the goal but doesn't take us over the limit,
- * or (3) the word on its own takes us over the limit.
- * In case (3) we put a newline in between.
- */
- if (indent>0) output_indent(indent);
- fwrite(output_buffer, 1, x0, stdout);
- if (x0==0 || (new_x <= max_length && new_x-goal_length <= goal_length-x)) {
- printf("%*s", (int)pending_spaces, "");
- goto write_out_word;
- }
- else {
- /* If the word takes us over the limit on its own, just
- * spit it out and don't bother buffering it.
- */
- if (indent+length > max_length) {
- putchar('\n');
- if (indent>0) output_indent(indent);
+output_word(size_t indent0, size_t indent1, const char *word, size_t length, size_t spaces)
+{
+ size_t new_x = x + pending_spaces + length;
+ size_t indent = output_in_paragraph ? indent1 : indent0;
+
+ /* If either |spaces==0| (at end of line) or |coalesce_spaces_P|
+ * (squashing internal whitespace), then add just one space;
+ * except that if the last character was a sentence-ender we
+ * actually add two spaces.
+ */
+ if (coalesce_spaces_P || spaces == 0)
+ spaces = strchr(sentence_enders, word[length-1]) ? 2 : 1;
+
+ if (new_x <= goal_length) {
+ /* After adding the word we still aren't at the goal length,
+ * so clearly we add it to the buffer rather than outputing it.
+ */
+ memset(output_buffer+x0, ' ', pending_spaces);
+ x0 += pending_spaces;
+ x += pending_spaces;
+ memcpy(output_buffer+x0, word, length);
+ x0 += length;
+ x += length;
+ pending_spaces = spaces;
+ } else {
+ /* Adding the word takes us past the goal. Print the line-so-far,
+ * and the word too iff either (1) the lsf is empty or (2) that
+ * makes us nearer the goal but doesn't take us over the limit,
+ * or (3) the word on its own takes us over the limit.
+ * In case (3) we put a newline in between.
+ */
+ if (indent > 0)
+ output_indent(indent);
+ fwrite(output_buffer, 1, x0, stdout);
+ if (x0 == 0 || (new_x <= max_length && new_x-goal_length <= goal_length-x)) {
+ printf("%*s", (int)pending_spaces, "");
+ goto write_out_word;
+ } else {
+ /* If the word takes us over the limit on its own, just
+ * spit it out and don't bother buffering it.
+ */
+ if (indent+length > max_length) {
+ putchar('\n');
+ if (indent > 0)
+ output_indent(indent);
write_out_word:
- fwrite(word, 1, length, stdout);
- x0 = 0; x = indent1; pending_spaces = 0;
- }
- else {
- memcpy(output_buffer, word, length);
- x0 = length; x = length+indent1; pending_spaces = spaces;
- }
- }
- putchar('\n');
- output_in_paragraph = 1;
- }
+ fwrite(word, 1, length, stdout);
+ x0 = 0;
+ x = indent1;
+ pending_spaces = 0;
+ } else {
+ memcpy(output_buffer, word, length);
+ x0 = length;
+ x = length+indent1;
+ pending_spaces = spaces;
+ }
+ }
+
+ putchar('\n');
+ output_in_paragraph = 1;
+ }
}
/* Process a stream, but just center its lines rather than trying to
* format them neatly.
*/
static void
-center_stream(FILE *stream, const char *name) {
- char *line;
- size_t length;
- while ((line=get_line(stream, &length)) != 0) {
- size_t l=length;
- while (l>0 && isspace(*line)) { ++line; --l; }
- length=l;
- while (l<goal_length) { putchar(' '); l+=2; }
- fwrite(line, 1, length, stdout);
- putchar('\n');
- }
- if (ferror(stream)) { perror(name); ++n_errors; }
+center_stream(FILE *stream, const char *name)
+{
+ char *line;
+ size_t length;
+ size_t l;
+
+ while ((line = get_line(stream, &length)) != 0) {
+ l = length;
+ while (l > 0 && isspace(*line)) {
+ ++line;
+ --l;
+ }
+
+ length = l;
+
+ while (l < goal_length) {
+ putchar(' ');
+ l += 2;
+ }
+
+ fwrite(line, 1, length, stdout);
+ putchar('\n');
+ }
+
+ if (ferror(stream)) {
+ perror(name);
+ ++n_errors;
+ }
}
/* Get a single line from a stream. Expand tabs, strip control
@@ -593,38 +650,78 @@ center_stream(FILE *stream, const char *name) {
* |pending_spaces|.
*/
static char *
-get_line(FILE *stream, size_t *lengthp) {
- static char *buf=NULL;
- static size_t length=0;
- size_t len=0;
- int ch;
- size_t spaces_pending=0;
- int troff=0;
-
- if (buf==NULL) { length=100; buf=XMALLOC(length); }
- while ((ch=getc(stream)) != '\n' && ch != EOF) {
- if (len+spaces_pending==0 && ch=='.' && !format_troff) troff=1;
- if (ch==' ') ++spaces_pending;
- else if (troff || !iscntrl(ch)) {
- while (len+spaces_pending >= length) {
- length*=2; buf=xrealloc(buf, length);
- }
- while (spaces_pending > 0) { --spaces_pending; buf[len++]=' '; }
- buf[len++] = ch;
- }
- else if (ch=='\t')
- spaces_pending += tab_width - (len+spaces_pending)%tab_width;
- else if (ch=='\b') { if (len) --len; }
- }
- *lengthp=len;
- return (len>0 || ch!=EOF) ? buf : 0;
+get_line(FILE *stream, size_t *lengthp)
+{
+ int ch;
+ int troff = 0;
+ static char *buf = NULL;
+ static size_t length = 0;
+ size_t len = 0;
+ size_t spaces_pending = 0;
+
+ if (buf == NULL) {
+ length = 100;
+ buf = XMALLOC(length);
+ }
+
+ while ((ch = getc(stream)) != '\n' && ch != EOF) {
+ if ((len + spaces_pending == 0) && (ch == '.' && !format_troff))
+ troff = 1;
+ if (ch == ' ') {
+ ++spaces_pending;
+ } else if (troff || !iscntrl(ch)) {
+ while (len + spaces_pending >= length) {
+ length *= 2;
+ buf = xrealloc(buf, length);
+ }
+
+ while (spaces_pending > 0) {
+ --spaces_pending;
+ buf[len++] = ' ';
+ }
+ buf[len++] = ch;
+ } else if (ch == '\t') {
+ spaces_pending += tab_width - (len+spaces_pending)%tab_width;
+ } else if (ch == '\b') {
+ if (len)
+ --len;
+ }
+ }
+
+ *lengthp = len;
+ return (len > 0 || ch != EOF) ? buf : 0;
}
/* (Re)allocate some memory, exiting with an error if we can't.
*/
static void *
-xrealloc(void *ptr, size_t nbytes) {
- void *p = realloc(ptr, nbytes);
- if (p == NULL) errx(EX_OSERR, "out of memory");
- return p;
+xrealloc(void *ptr, size_t nbytes)
+{
+ void *p;
+
+ p = realloc(ptr, nbytes);
+ if (p == NULL)
+ errx(EX_OSERR, "out of memory");
+ return p;
}
+
+void
+usage(void)
+{
+
+ fprintf(stderr,
+ "Usage: fmt [-cmps] [-d chars] [-l num] [-t num]\n"
+ " [-w width | -width | goal [maximum]] [file ...]\n"
+ "Options: -c center each line instead of formatting\n"
+ " -d <chars> double-space after <chars> at line end\n"
+ " -l <n> turn each <n> spaces at start of line into a tab\n"
+ " -m try to make sure mail header lines stay separate\n"
+ " -n format lines beginning with a dot\n"
+ " -p allow indented paragraphs\n"
+ " -s coalesce whitespace inside lines\n"
+ " -t <n> have tabs every <n> columns\n"
+ " -w <n> set maximum width to <n>\n"
+ " goal set target width to goal\n");
+ exit (0);
+}
+