Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | /* vi: set sw=4 ts=4: */
/* fold -- wrap each input line to fit in specified width.
Written by David MacKenzie, djm@gnu.ai.mit.edu.
Copyright (C) 91, 1995-2002 Free Software Foundation, Inc.
Modified for busybox based on coreutils v 5.0
Copyright (C) 2003 Glenn McGrath
Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
//config:config FOLD
//config: bool "fold"
//config: default y
//config: help
//config: Wrap text to fit a specific width.
//applet:IF_FOLD(APPLET_NOEXEC(fold, fold, BB_DIR_USR_BIN, BB_SUID_DROP, fold))
//kbuild:lib-$(CONFIG_FOLD) += fold.o
//usage:#define fold_trivial_usage
//usage: "[-bs] [-w WIDTH] [FILE]..."
//usage:#define fold_full_usage "\n\n"
//usage: "Wrap input lines in each FILE (or stdin), writing to stdout\n"
//usage: "\n -b Count bytes rather than columns"
//usage: "\n -s Break at spaces"
//usage: "\n -w Use WIDTH columns instead of 80"
#include "libbb.h"
#include "unicode.h"
/* This is a NOEXEC applet. Be very careful! */
/* Must match getopt32 call */
#define FLAG_COUNT_BYTES 1
#define FLAG_BREAK_SPACES 2
#define FLAG_WIDTH 4
/* Assuming the current column is COLUMN, return the column that
printing C will move the cursor to.
The first column is 0. */
static int adjust_column(unsigned column, char c)
{
if (option_mask32 & FLAG_COUNT_BYTES)
return ++column;
if (c == '\t')
return column + 8 - column % 8;
if (c == '\b') {
if ((int)--column < 0)
column = 0;
}
else if (c == '\r')
column = 0;
else { /* just a printable char */
if (unicode_status != UNICODE_ON /* every byte is a new char */
|| (c & 0xc0) != 0x80 /* it isn't a 2nd+ byte of a Unicode char */
) {
column++;
}
}
return column;
}
/* Note that this function can write NULs, unlike fputs etc. */
static void write2stdout(const void *buf, unsigned size)
{
fwrite(buf, 1, size, stdout);
}
int fold_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int fold_main(int argc UNUSED_PARAM, char **argv)
{
char *line_out = NULL;
const char *w_opt = "80";
unsigned width;
smallint exitcode = EXIT_SUCCESS;
init_unicode();
if (ENABLE_INCLUDE_SUSv2) {
/* Turn any numeric options into -w options. */
int i;
for (i = 1; argv[i]; i++) {
const char *a = argv[i];
if (*a == '-') {
a++;
if (*a == '-' && !a[1]) /* "--" */
break;
if (isdigit(*a))
argv[i] = xasprintf("-w%s", a);
}
}
}
getopt32(argv, "bsw:", &w_opt);
width = xatou_range(w_opt, 1, 10000);
argv += optind;
if (!*argv)
*--argv = (char*)"-";
do {
FILE *istream = fopen_or_warn_stdin(*argv);
int c;
unsigned column = 0; /* Screen column where next char will go */
unsigned offset_out = 0; /* Index in 'line_out' for next char */
if (istream == NULL) {
exitcode = EXIT_FAILURE;
continue;
}
while ((c = getc(istream)) != EOF) {
/* We grow line_out in chunks of 0x1000 bytes */
if ((offset_out & 0xfff) == 0) {
line_out = xrealloc(line_out, offset_out + 0x1000);
}
rescan:
line_out[offset_out] = c;
if (c == '\n') {
write2stdout(line_out, offset_out + 1);
column = offset_out = 0;
continue;
}
column = adjust_column(column, c);
if (column <= width || offset_out == 0) {
/* offset_out == 0 case happens
* with small width (say, 1) and tabs.
* The very first tab already goes to column 8,
* but we must not wrap it */
offset_out++;
continue;
}
/* This character would make the line too long.
* Print the line plus a newline, and make this character
* start the next line */
if (option_mask32 & FLAG_BREAK_SPACES) {
unsigned i;
unsigned logical_end;
/* Look for the last blank. */
for (logical_end = offset_out - 1; (int)logical_end >= 0; logical_end--) {
if (!isblank(line_out[logical_end]))
continue;
/* Found a space or tab.
* Output up to and including it, and start a new line */
logical_end++;
/*line_out[logical_end] = '\n'; - NO! this nukes one buffered character */
write2stdout(line_out, logical_end);
putchar('\n');
/* Move the remainder to the beginning of the next line.
* The areas being copied here might overlap. */
memmove(line_out, line_out + logical_end, offset_out - logical_end);
offset_out -= logical_end;
for (column = i = 0; i < offset_out; i++) {
column = adjust_column(column, line_out[i]);
}
goto rescan;
}
/* No blank found, wrap will split the overlong word */
}
/* Output what we accumulated up to now, and start a new line */
line_out[offset_out] = '\n';
write2stdout(line_out, offset_out + 1);
column = offset_out = 0;
goto rescan;
} /* while (not EOF) */
if (offset_out) {
write2stdout(line_out, offset_out);
}
if (fclose_if_not_stdin(istream)) {
bb_simple_perror_msg(*argv);
exitcode = EXIT_FAILURE;
}
} while (*++argv);
fflush_stdout_and_exit(exitcode);
}
|