diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2004-04-01 23:14:20 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2004-04-01 23:14:20 +0000 |
commit | f43bea8517c4ba4479453545c85327b306e37596 (patch) | |
tree | 8f90c3e8e69924d3dc1023f01f41edee1c3f9746 /usr.bin | |
parent | 3ae31f15c97a86e11066e7195bd3e1d74c12d122 (diff) |
knf and ansi, mostly from joris vink
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/fmt/fmt.c | 787 |
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); +} + |