fmt(1): reformat with indent(1).

Failed attempt to get nearer to style(9) and the format from the
original OpenBSD code. At least it should be readable now.

No functional change.
This commit is contained in:
Pedro F. Giffuni 2016-04-13 01:46:48 +00:00
parent 6dbd80fa74
commit 86aba0f293
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=297901

View File

@ -1,4 +1,4 @@
/* $OpenBSD: fmt.c,v 1.16 2000/06/25 15:35:42 pjanzen Exp $ */
/* $OpenBSD: fmt.c,v 1.21 2004/04/01 23:14:19 tedu Exp $ */
/* Sensible version of fmt
*
@ -171,6 +171,7 @@
#ifndef lint
static const char copyright[] =
"Copyright (c) 1997 Gareth McCaughan. All rights reserved.\n";
#endif /* not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -198,20 +199,38 @@ __FBSDID("$FreeBSD$");
* (returning 0 instead), but we do complain about bad numbers.
*/
static size_t
get_positive(const char *s, const char *err_mess, int fussyP) {
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); }
if (*t) {
if (fussyP)
goto Lose;
else
return 0;
}
if (result <= 0) {
Lose: errx(EX_USAGE, "%s", err_mess);
}
return (size_t)result;
}
static size_t
get_nonnegative(const char *s, const char *err_mess, int fussyP) {
get_nonnegative(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); }
if (*t) {
if (fussyP)
goto Lose;
else
return 0;
}
if (result < 0) {
Lose: errx(EX_USAGE, "%s", err_mess);
}
return (size_t)result;
}
@ -243,8 +262,7 @@ static void process_stream (FILE *, const char *);
static size_t indent_length(const wchar_t *, size_t);
static int might_be_header(const wchar_t *);
static void new_paragraph(size_t, size_t);
static void output_word (size_t, size_t, const wchar_t *, size_t,
size_t);
static void output_word(size_t, size_t, const wchar_t *, size_t, size_t);
static void output_indent(size_t);
static void center_stream(FILE *, const char *);
static wchar_t *get_line(FILE *, size_t *);
@ -256,7 +274,8 @@ static void * xrealloc (void *, size_t);
* all in top-down order. Hence, |main| comes first.
*/
int
main(int argc, char *argv[]) {
main(int argc, char *argv[])
{
int ch; /* used for |getopt| processing */
wchar_t *tmp;
size_t len;
@ -306,9 +325,13 @@ main(int argc, char *argv[]) {
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() */
/*
* 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);
@ -318,7 +341,8 @@ main(int argc, char *argv[]) {
max_length = goal_length;
}
continue;
case 'h': default:
case 'h':
default:
fprintf(stderr,
"usage: fmt [-cmps] [-d chars] [-l num] [-t num]\n"
" [-w width | -width | goal [maximum]] [file ...]\n"
@ -334,34 +358,40 @@ main(int argc, char *argv[]) {
" goal set target width to goal\n");
exit(ch == 'h' ? 0 : EX_USAGE);
}
argc -= optind; argv += optind;
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;
--argc;
++argv;
if (argc > 0
&& (max_length = get_positive(*argv, "max length must be positive", 0))
!= 0) {
--argc; ++argv;
--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;
if (max_length >= SIZE_T_MAX / sizeof (wchar_t)) errx(EX_USAGE, "max length too large");
if (goal_length == 0)
goal_length = 65;
if (max_length == 0)
max_length = goal_length + 10;
if (max_length >= SIZE_T_MAX / sizeof(wchar_t))
errx(EX_USAGE, "max length too large");
/* really needn't be longer */
output_buffer = XMALLOC((max_length + 1) * sizeof(wchar_t));
/* 2. Process files. */
if (argc > 0) {
while (argc-->0) process_named_file(*argv++);
}
else {
while (argc-- > 0)
process_named_file(*argv++);
} else {
process_stream(stdin, "standard input");
}
@ -374,12 +404,19 @@ main(int argc, char *argv[]) {
/* Process a single file, given its name.
*/
static void
process_named_file(const char *name) {
process_named_file(const char *name)
{
FILE *f = fopen(name, "r");
if (!f) { warn("%s", name); ++n_errors; }
else {
if (!f) {
warn("%s", name);
++n_errors;
} else {
process_stream(f, name);
if (ferror(f)) { warn("%s", name); ++n_errors; }
if (ferror(f)) {
warn("%s", name);
++n_errors;
}
fclose(f);
}
}
@ -397,33 +434,41 @@ typedef enum {
* except that centering is handled separately.
*/
static void
process_stream(FILE *stream, const char *name) {
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;
/* ^-- header_type of previous line; -1 at para start */
wchar_t *line;
size_t length;
if (centerP) { center_stream(stream, name); return; }
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;
{
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 (and we don't format troff),
* 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.
/*
* We need a new paragraph if and only if: this line
* is blank, OR it's a troff request (and we don't
* format troff), 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)
@ -436,53 +481,69 @@ process_stream(FILE *stream, const char *name) {
para_line_number = 0;
first_indent = np;
last_indent = np;
if (header_type==hdr_Header) last_indent=2; /* for cont. lines */
if (header_type == hdr_Header)
last_indent = 2; /* for cont. lines */
if (length == 0 || (line[0] == '.' && !format_troff)) {
if (length == 0)
putwchar('\n');
else
wprintf(L"%.*ls\n", (int)length, line);
wprintf(L"%.*ls\n", (int)length,
line);
prev_header_type = hdr_ParagraphStart;
continue;
}
}
else {
/* If this is an indented paragraph other than a mail header
* continuation, set |last_indent|.
} else {
/*
* If this is an indented paragraph other
* than a mail header continuation, set
* |last_indent|.
*/
if (np != last_indent && header_type != hdr_Continuation)
if (np != last_indent &&
header_type != hdr_Continuation)
last_indent = np;
}
prev_header_type = header_type;
}
{ size_t n=np;
{
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] != ' ')
while (n + word_length < length &&
line[n + word_length] != ' ')
++word_length;
space_length = word_length;
while (n+space_length < length && line[n+space_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);
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)) { warn("%s", name); ++n_errors; }
if (ferror(stream)) {
warn("%s", name);
++n_errors;
}
}
/* How long is the indent on this line?
*/
static size_t
indent_length(const wchar_t *line, size_t length) {
indent_length(const wchar_t *line, size_t length)
{
size_t n = 0;
while (n<length && *line++ == ' ') ++n;
while (n < length && *line++ == ' ')
++n;
return n;
}
@ -493,35 +554,45 @@ indent_length(const wchar_t *line, size_t length) {
* conservative to avoid mangling ordinary civilised text.
*/
static int
might_be_header(const wchar_t *line) {
if (!iswupper(*line++)) return 0;
while (*line && (iswalnum(*line) || *line=='-')) ++line;
might_be_header(const wchar_t *line)
{
if (!iswupper(*line++))
return 0;
while (*line && (iswalnum(*line) || *line == '-'))
++line;
return (*line == ':' && iswspace(line[1]));
}
/* Begin a new paragraph with an indent of |indent| spaces.
*/
static void
new_paragraph(size_t old_indent, size_t indent) {
new_paragraph(size_t old_indent, size_t indent)
{
if (output_buffer_length) {
if (old_indent>0) output_indent(old_indent);
if (old_indent > 0)
output_indent(old_indent);
wprintf(L"%.*ls\n", (int)output_buffer_length, output_buffer);
}
x=indent; x0=0; output_buffer_length=0; pending_spaces=0;
x = indent;
x0 = 0;
output_buffer_length = 0;
pending_spaces = 0;
output_in_paragraph = 0;
}
/* Output spaces or tabs for leading indentation.
*/
static void
output_indent(size_t n_spaces) {
output_indent(size_t n_spaces)
{
if (output_tab_width) {
while (n_spaces >= output_tab_width) {
putwchar('\t');
n_spaces -= output_tab_width;
}
}
while (n_spaces-- > 0) putwchar(' ');
while (n_spaces-- > 0)
putwchar(' ');
}
/* Output a single word, or add it to the buffer.
@ -529,7 +600,8 @@ 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 wchar_t *word, size_t length, size_t spaces) {
output_word(size_t indent0, size_t indent1, const wchar_t *word, size_t length, size_t spaces)
{
size_t new_x;
size_t indent = output_in_paragraph ? indent1 : indent0;
size_t width;
@ -541,53 +613,67 @@ output_word(size_t indent0, size_t indent1, const wchar_t *word, size_t length,
new_x = x + pending_spaces + width;
/* 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 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 = wcschr(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.
/*
* After adding the word we still aren't at the goal length,
* so clearly we add it to the buffer rather than outputing
* it.
*/
wmemset(output_buffer+output_buffer_length, L' ', pending_spaces);
x0 += pending_spaces; x += pending_spaces;
wmemset(output_buffer + output_buffer_length, L' ',
pending_spaces);
x0 += pending_spaces;
x += pending_spaces;
output_buffer_length += pending_spaces;
wmemcpy(output_buffer + output_buffer_length, word, length);
x0 += width; x += width; output_buffer_length += length;
x0 += width;
x += width;
output_buffer_length += 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.
} 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);
if (indent > 0)
output_indent(indent);
wprintf(L"%.*ls", (int)output_buffer_length, output_buffer);
if (x0==0 || (new_x <= max_length && new_x-goal_length <= goal_length-x)) {
if (x0 == 0 || (new_x <= max_length &&
new_x - goal_length <= goal_length - x)) {
wprintf(L"%*ls", (int)pending_spaces, L"");
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.
} else {
/*
* If the word takes us over the limit on its own,
* just spit it out and don't bother buffering it.
*/
if (indent + width > max_length) {
putwchar('\n');
if (indent>0) output_indent(indent);
if (indent > 0)
output_indent(indent);
write_out_word:
wprintf(L"%.*ls", (int)length, word);
x0 = 0; x = indent1; pending_spaces = 0;
x0 = 0;
x = indent1;
pending_spaces = 0;
output_buffer_length = 0;
}
else {
} else {
wmemcpy(output_buffer, word, length);
x0 = width; x = width+indent1; pending_spaces = spaces;
x0 = width;
x = width + indent1;
pending_spaces = spaces;
output_buffer_length = length;
}
}
@ -600,22 +686,34 @@ output_word(size_t indent0, size_t indent1, const wchar_t *word, size_t length,
* format them neatly.
*/
static void
center_stream(FILE *stream, const char *name) {
center_stream(FILE *stream, const char *name)
{
wchar_t *line, *p;
size_t length;
size_t width;
int cwidth;
while ((line = get_line(stream, &length)) != 0) {
size_t l = length;
while (l>0 && iswspace(*line)) { ++line; --l; }
while (l > 0 && iswspace(*line)) {
++line;
--l;
}
length = l;
for (p = line, width = 0; p < &line[length]; p++)
width += (cwidth = wcwidth(*p)) > 0 ? cwidth : 1;
l = width;
while (l<goal_length) { putwchar(' '); l+=2; }
while (l < goal_length) {
putwchar(' ');
l += 2;
}
wprintf(L"%.*ls\n", (int)length, line);
}
if (ferror(stream)) { warn("%s", name); ++n_errors; }
if (ferror(stream)) {
warn("%s", name);
++n_errors;
}
}
/* Get a single line from a stream. Expand tabs, strip control
@ -630,7 +728,8 @@ center_stream(FILE *stream, const char *name) {
* |pending_spaces|.
*/
static wchar_t *
get_line(FILE *stream, size_t *lengthp) {
get_line(FILE *stream, size_t *lengthp)
{
static wchar_t *buf = NULL;
static size_t length = 0;
size_t len = 0;
@ -640,21 +739,36 @@ get_line(FILE *stream, size_t *lengthp) {
size_t col = 0;
int cwidth;
if (buf==NULL) { length=100; buf=XMALLOC(length * sizeof(wchar_t)); }
if (buf == NULL) {
length = 100;
buf = XMALLOC(length * sizeof(wchar_t));
}
while ((ch = getwc(stream)) != '\n' && ch != WEOF) {
if (len+spaces_pending==0 && ch=='.' && !format_troff) troff=1;
if (ch==' ') ++spaces_pending;
if (len + spaces_pending == 0 && ch == '.' && !format_troff)
troff = 1;
if (ch == ' ')
++spaces_pending;
else if (troff || iswprint(ch)) {
while (len + spaces_pending >= length) {
length*=2; buf=xrealloc(buf, length * sizeof(wchar_t));
length *= 2;
buf = xrealloc(buf, length * sizeof(wchar_t));
}
while (spaces_pending > 0) {
--spaces_pending;
buf[len++] = ' ';
col++;
}
while (spaces_pending > 0) { --spaces_pending; buf[len++]=' '; col++; }
buf[len++] = ch;
col += (cwidth = wcwidth(ch)) > 0 ? cwidth : 1;
} else if (ch == '\t')
spaces_pending += tab_width -
(col + spaces_pending) % tab_width;
else if (ch == '\b') {
if (len)
--len;
if (col)
--col;
}
else if (ch=='\t')
spaces_pending += tab_width - (col+spaces_pending)%tab_width;
else if (ch=='\b') { if (len) --len; if (col) --col; }
}
*lengthp = len;
return (len > 0 || ch != WEOF) ? buf : 0;
@ -663,8 +777,11 @@ get_line(FILE *stream, size_t *lengthp) {
/* (Re)allocate some memory, exiting with an error if we can't.
*/
static void *
xrealloc(void *ptr, size_t nbytes) {
xrealloc(void *ptr, size_t nbytes)
{
void *p = realloc(ptr, nbytes);
if (p == NULL) errx(EX_OSERR, "out of memory");
if (p == NULL)
errx(EX_OSERR, "out of memory");
return p;
}