/* fold -- wrap each input line to fit in specified width. This is the fold utility
Copyright (C) 1991-2018 Free Software Foundation, Inc.
This program 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 3 of the License, or
(at your option) any later version.
This program 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, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* Written by David MacKenzie, djm@gnu.ai.mit.edu. */
#include <config.h> Provides system specific information
#include <stdio.h> Provides standard I/O capability
#include <getopt.h> ...!includes auto-comment...
#include <sys/types.h> Provides system data types
#include "system.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "fadvise.h" ...!includes auto-comment...
#include "xdectoint.h" ...!includes auto-comment...
#define TAB_WIDTH 8 Line 31
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "fold" Line 34
#define AUTHORS proper_name ("David MacKenzie") Line 36
/* If nonzero, try to break on whitespace. */
static bool break_spaces; Line 39
/* If nonzero, count bytes, not column positions. */
static bool count_bytes; Line 42
/* If nonzero, at least one of the files we read was standard input. */
static bool have_read_stdin; Line 45
static char const shortopts[] = "bsw:0::1::2::3::4::5::6::7::8::9::"; Line 47
static struct option const longopts[] = Line 49
{
{"bytes", no_argument, NULL, 'b'}, Line 51
{"spaces", no_argument, NULL, 's'}, Line 52
{"width", required_argument, NULL, 'w'}, Line 53
{GETOPT_HELP_OPTION_DECL}, Line 54
{GETOPT_VERSION_OPTION_DECL}, Line 55
{NULL, 0, NULL, 0} Line 56
}; Block 1
void Line 59
usage (int status) Line 60
{
if (status != EXIT_SUCCESS) Line 62
emit_try_help (); ...!common auto-comment...
else Line 64
{
printf (_("\ Line 66
Usage: %s [OPTION]... [FILE]...\n\ Line 67
"), Line 68
program_name); Line 69
fputs (_("\ Line 70
Wrap input lines in each FILE, writing to standard output.\n\ Line 71
"), stdout); Line 72
emit_stdin_note (); ...!common auto-comment...
emit_mandatory_arg_note (); ...!common auto-comment...
fputs (_("\ Line 77
-b, --bytes count bytes rather than columns\n\ Line 78
-s, --spaces break at spaces\n\ Line 79
-w, --width=WIDTH use WIDTH columns instead of 80\n\ Line 80
"), stdout); Line 81
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 82
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 83
emit_ancillary_info (PROGRAM_NAME); Line 84
}
exit (status); Line 86
} Block 2
/* Assuming the current column is COLUMN, return the column that
printing C will move the cursor to.
The first column is 0. */
static size_t Line 93
adjust_column (size_t column, char c) Line 94
{
if (!count_bytes) Line 96
{
if (c == '\b') Line 98
{
if (column > 0) Line 100
column--; Line 101
}
else if (c == '\r') Line 103
column = 0; Line 104
else if (c == '\t') Line 105
column += TAB_WIDTH - column % TAB_WIDTH; Line 106
else /* if (isprint (c)) */ Line 107
column++; Line 108
}
else Line 110
column++; Line 111
return column; Line 112
} Block 3
/* Fold file FILENAME, or standard input if FILENAME is "-",
to stdout, with maximum line length WIDTH.
Return true if successful. */
static bool Line 119
fold_file (char const *filename, size_t width) Line 120
{
FILE *istream; Line 122
int c; Line 123
size_t column = 0; /* Screen column where next char will go. */ Line 124
size_t offset_out = 0; /* Index in 'line_out' for next char. */ Line 125
static char *line_out = NULL; Line 126
static size_t allocated_out = 0; Line 127
int saved_errno; Line 128
if (STREQ (filename, "-")) Line 130
{
istream = stdin; Line 132
have_read_stdin = true; Line 133
}
else Line 135
istream = fopen (filename, "r"); Line 136...!syscalls auto-comment...
if (istream == NULL) Line 138
{
error (0, errno, "%s", quotef (filename)); Line 140
return false; Line 141
}
fadvise (istream, FADVISE_SEQUENTIAL); Line 144...!syscalls auto-comment...
while ((c = getc (istream)) != EOF) Line 146
{
if (offset_out + 1 >= allocated_out) Line 148
line_out = X2REALLOC (line_out, &allocated_out); Line 149
if (c == '\n') Line 151
{
line_out[offset_out++] = c; Line 153
fwrite (line_out, sizeof (char), offset_out, stdout); Line 154...!syscalls auto-comment...
column = offset_out = 0; Line 155
continue; Line 156
}
rescan: Line 159
column = adjust_column (column, c); Line 160
if (column > width) Line 162
{
/* This character would make the line too long.
Print the line plus a newline, and make this character
start the next line. */
if (break_spaces) Line 167
{
bool found_blank = false; Line 169
size_t logical_end = offset_out; Line 170
/* Look for the last blank. */
while (logical_end) Line 173
{
--logical_end; Line 175
if (isblank (to_uchar (line_out[logical_end]))) Line 176
{
found_blank = true; Line 178
break; Line 179
}
}
if (found_blank) Line 183
{
size_t i; Line 185
/* Found a blank. Don't output the part after it. */
logical_end++; Line 188
fwrite (line_out, sizeof (char), (size_t) logical_end, Line 189...!syscalls auto-comment...
stdout); Line 190
putchar ('\n'); Line 191
/* Move the remainder to the beginning of the next line.
The areas being copied here might overlap. */
memmove (line_out, line_out + logical_end, Line 194
offset_out - logical_end); Line 195
offset_out -= logical_end; Line 196
for (column = i = 0; i < offset_out; i++) Line 197
column = adjust_column (column, line_out[i]); Line 198
goto rescan; Line 199
}
}
if (offset_out == 0) Line 203
{
line_out[offset_out++] = c; Line 205
continue; Line 206
}
line_out[offset_out++] = '\n'; Line 209
fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); Line 210...!syscalls auto-comment...
column = offset_out = 0; Line 211
goto rescan; Line 212
}
line_out[offset_out++] = c; Line 215
}
saved_errno = errno; Line 218
if (offset_out) Line 220
fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); Line 221...!syscalls auto-comment...
if (ferror (istream)) Line 223
{
error (0, saved_errno, "%s", quotef (filename)); Line 225
if (!STREQ (filename, "-")) Line 226
fclose (istream); Line 227...!syscalls auto-comment...
return false; Line 228
}
if (!STREQ (filename, "-") && fclose (istream) == EOF) Line 230...!syscalls auto-comment...
{
error (0, errno, "%s", quotef (filename)); Line 232
return false; Line 233
}
return true; Line 236
} Block 4
int
main (int argc, char **argv) Line 240
{
size_t width = 80; Line 242
int i; Line 243
int optc; Line 244
bool ok; Line 245
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
break_spaces = count_bytes = have_read_stdin = false; Line 255
while ((optc = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) Line 257
{
char optargbuf[2]; Line 259
switch (optc) Line 261
{
case 'b': /* Count bytes rather than columns. */ Line 263
count_bytes = true; Line 264
break; Line 265
case 's': /* Break at word boundaries. */ Line 267
break_spaces = true; Line 268
break; Line 269
case '0': case '1': case '2': case '3': case '4': Line 271
case '5': case '6': case '7': case '8': case '9': Line 272
if (optarg) Line 273
optarg--; Line 274
else Line 275
{
optargbuf[0] = optc; Line 277
optargbuf[1] = '\0'; Line 278
optarg = optargbuf; Line 279
}
FALLTHROUGH; Line 281
case 'w': /* Line width. */ Line 282
width = xdectoumax (optarg, 1, SIZE_MAX - TAB_WIDTH - 1, "", Line 283
_("invalid number of columns"), 0); Line 284
break; Line 285
case_GETOPT_HELP_CHAR; Line 287
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 289
default: Line 291
usage (EXIT_FAILURE); Line 292
}
}
if (argc == optind) Line 296
ok = fold_file ("-", width); Line 297
else Line 298
{
ok = true; Line 300
for (i = optind; i < argc; i++) Line 301
ok &= fold_file (argv[i], width); Line 302
}
if (have_read_stdin && fclose (stdin) == EOF) Line 305...!syscalls auto-comment...
die (EXIT_FAILURE, errno, "-"); Line 306
return ok ? EXIT_SUCCESS : EXIT_FAILURE; Line 308
} Block 5