📄 cut.c
字号:
break;
}
else if (wc == L'\n')
{
putchar ('\n');
idx = 0;
}
else
{
idx += (operating_mode == byte_mode) ? mblength : 1;
if (print_kth (idx))
fwrite (bufpos, mblength, sizeof(char), stdout);
}
buflen -= mblength;
bufpos += mblength;
}
}
#endif
/* Read from stream STREAM, printing to standard output any selected fields. */
static void
cut_fields (FILE *stream)
{
int c;
unsigned int field_idx;
int found_any_selected_field;
int buffer_first_field;
int empty_input;
found_any_selected_field = 0;
field_idx = 1;
c = getc (stream);
empty_input = (c == EOF);
if (c != EOF)
ungetc (c, stream);
/* To support the semantics of the -s flag, we may have to buffer
all of the first field to determine whether it is `delimited.'
But that is unnecessary if all non-delimited lines must be printed
and the first field has been selected, or if non-delimited lines
must be suppressed and the first field has *not* been selected.
That is because a non-delimited line has exactly one field. */
buffer_first_field = (suppress_non_delimited ^ !print_kth (1));
while (1)
{
if (field_idx == 1 && buffer_first_field)
{
int len;
size_t n_bytes;
len = getstr (&field_1_buffer, &field_1_bufsize, stream,
delim, '\n', 0);
if (len < 0)
{
if (ferror (stream) || feof (stream))
break;
xalloc_die ();
}
n_bytes = len;
assert (n_bytes != 0);
/* If the first field extends to the end of line (it is not
delimited) and we are printing all non-delimited lines,
print this one. */
if ((unsigned char) field_1_buffer[n_bytes - 1] != delim)
{
if (suppress_non_delimited)
{
/* Empty. */
}
else
{
fwrite (field_1_buffer, sizeof (char), n_bytes, stdout);
/* Make sure the output line is newline terminated. */
if (field_1_buffer[n_bytes - 1] != '\n')
putchar ('\n');
}
continue;
}
if (print_kth (1))
{
/* Print the field, but not the trailing delimiter. */
fwrite (field_1_buffer, sizeof (char), n_bytes - 1, stdout);
found_any_selected_field = 1;
}
++field_idx;
}
if (c != EOF)
{
if (print_kth (field_idx))
{
if (found_any_selected_field)
{
fwrite (output_delimiter_string, sizeof (char),
output_delimiter_length, stdout);
}
found_any_selected_field = 1;
while ((c = getc (stream)) != delim && c != '\n' && c != EOF)
{
putchar (c);
}
}
else
{
while ((c = getc (stream)) != delim && c != '\n' && c != EOF)
{
/* Empty. */
}
}
}
if (c == '\n')
{
c = getc (stream);
if (c != EOF)
{
ungetc (c, stream);
c = '\n';
}
}
if (c == delim)
++field_idx;
else if (c == '\n' || c == EOF)
{
if (found_any_selected_field
|| (!empty_input && !(suppress_non_delimited && field_idx == 1)))
putchar ('\n');
if (c == EOF)
break;
field_idx = 1;
found_any_selected_field = 0;
}
}
}
#if HAVE_MBRTOWC
static void
cut_fields_mb (FILE *stream)
{
int c;
unsigned int field_idx;
int found_any_selected_field;
int buffer_first_field;
int empty_input;
char buf[MB_LEN_MAX + BUFSIZ]; /* For spooling a read byte sequence. */
char *bufpos; /* Next read position of BUF. */
size_t buflen; /* The length of the byte sequence in buf. */
wint_t wc; /* A gotten wide character. */
size_t mblength; /* The byte size of a multibyte character which shows
as same character as WC. */
mbstate_t state; /* State of the stream. */
int convfail; /* 1, when conversion is failed. Otherwise 0. */
found_any_selected_field = 0;
field_idx = 1;
bufpos = buf;
buflen = 0;
memset (&state, '\0', sizeof(mbstate_t));
c = getc (stream);
empty_input = (c == EOF);
if (c != EOF)
ungetc (c, stream);
else
wc = WEOF;
/* To support the semantics of the -s flag, we may have to buffer
all of the first field to determine whether it is `delimited.'
But that is unnecessary if all non-delimited lines must be printed
and the first field has been selected, or if non-delimited lines
must be suppressed and the first field has *not* been selected.
That is because a non-delimited line has exactly one field. */
buffer_first_field = (suppress_non_delimited ^ !print_kth (1));
while (1)
{
if (field_idx == 1 && buffer_first_field)
{
int len = 0;
while (1)
{
REFILL_BUFFER (buf, bufpos, buflen, stream);
GET_NEXT_WC_FROM_BUFFER
(wc, bufpos, buflen, mblength, state, convfail);
if (wc == WEOF)
break;
field_1_buffer = xrealloc (field_1_buffer, len + mblength);
memcpy (field_1_buffer + len, bufpos, mblength);
len += mblength;
buflen -= mblength;
bufpos += mblength;
if (!convfail && (wc == L'\n' || wc == wcdelim))
break;
}
if (wc == WEOF)
break;
/* If the first field extends to the end of line (it is not
delimited) and we are printing all non-delimited lines,
print this one. */
if (convfail || (!convfail && wc != wcdelim))
{
if (suppress_non_delimited)
{
/* Empty. */
}
else
{
fwrite (field_1_buffer, sizeof (char), len, stdout);
/* Make sure the output line is newline terminated. */
if (convfail || (!convfail && wc != L'\n'))
putchar ('\n');
}
continue;
}
if (print_kth (1))
{
/* Print the field, but not the trailing delimiter. */
fwrite (field_1_buffer, sizeof (char), len - 1, stdout);
found_any_selected_field = 1;
}
++field_idx;
}
if (wc != WEOF)
{
if (print_kth (field_idx))
{
if (found_any_selected_field)
{
fwrite (output_delimiter_string, sizeof (char),
output_delimiter_length, stdout);
}
found_any_selected_field = 1;
}
while (1)
{
REFILL_BUFFER (buf, bufpos, buflen, stream);
GET_NEXT_WC_FROM_BUFFER
(wc, bufpos, buflen, mblength, state, convfail);
if (wc == WEOF)
break;
else if (!convfail && (wc == wcdelim || wc == L'\n'))
{
buflen -= mblength;
bufpos += mblength;
break;
}
if (print_kth (field_idx))
fwrite (bufpos, mblength, sizeof(char), stdout);
buflen -= mblength;
bufpos += mblength;
}
}
if ((!convfail || wc == L'\n') && buflen < 1)
wc = WEOF;
if (!convfail && wc == wcdelim)
++field_idx;
else if (wc == WEOF || (!convfail && wc == L'\n'))
{
if (found_any_selected_field
|| (!empty_input && !(suppress_non_delimited && field_idx == 1)))
putchar ('\n');
if (wc == WEOF)
break;
field_idx = 1;
found_any_selected_field = 0;
}
}
}
#endif
static void
cut_stream (FILE *stream)
{
#if HAVE_MBRTOWC
if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
{
switch (operating_mode)
{
case byte_mode:
if (byte_mode_character_aware)
cut_characters_or_cut_bytes_no_split (stream);
else
cut_bytes (stream);
break;
case character_mode:
cut_characters_or_cut_bytes_no_split (stream);
break;
case field_mode:
cut_fields_mb (stream);
break;
default:
abort ();
}
}
else
#endif
{
if (operating_mode == field_mode)
cut_fields (stream);
else
cut_bytes (stream);
}
}
/* Process file FILE to standard output.
Return 0 if successful, 1 if not. */
static int
cut_file (char *file)
{
FILE *stream;
if (STREQ (file, "-"))
{
have_read_stdin = 1;
stream = stdin;
}
else
{
stream = fopen (file, "r");
if (stream == NULL)
{
error (0, errno, "%s", file);
return 1;
}
}
cut_stream (stream);
if (ferror (stream))
{
error (0, errno, "%s", file);
return 1;
}
if (STREQ (file, "-"))
clearerr (stream); /* Also clear EOF. */
else if (fclose (stream) == EOF)
{
error (0, errno, "%s", file);
return 1;
}
return 0;
}
int
main (int argc, char **argv)
{
int optc, exit_status = 0;
int delim_specified = 0;
char mbdelim[MB_LEN_MAX + 1];
size_t delimlen = 0;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
operating_mode = undefined_mode;
/* By default, all non-delimited lines are printed. */
suppress_non_delimited = 0;
delim = '\0';
have_read_stdin = 0;
while ((optc = getopt_long (argc, argv, "b:c:d:f:ns", longopts, NULL)) != -1)
{
switch (optc)
{
case 0:
break;
case 'b':
/* Build the byte list. */
if (operating_mode != undefined_mode)
FATAL_ERROR (_("only one type of list may be specified"));
operating_mode = byte_mode;
if (set_fields (optarg) == 0)
FATAL_ERROR (_("missing list of positions"));
break;
case 'c':
/* Build the character list. */
if (operating_mode != undefined_mode)
FATAL_ERROR (_("only one type of list may be specified"));
operating_mode = character_mode;
if (set_fields (optarg) == 0)
FATAL_ERROR (_("missing list of positions"));
break;
case 'f':
/* Build the field list. */
if (operating_mode != undefined_mode)
FATAL_ERROR (_("only one type of list may be specified"));
operating_mode = field_mode;
if (set_fields (optarg) == 0)
FATAL_ERROR (_("missing list of fields"));
break;
case 'd':
/* New delimiter. */
/* Interpret -d '' to mean `use the NUL byte as the delimiter.' */
#if HAVE_MBRTOWC
{
if(MB_CUR_MAX > 1)
{
mbstate_t state;
memset (&state, '\0', sizeof(mbstate_t));
delimlen = mbrtowc (&wcdelim, optarg, strnlen(optarg, MB_LEN_MAX), &state);
if (delimlen == (size_t)-1 || delimlen == (size_t)-2)
++force_singlebyte_mode;
else
{
delimlen = (delimlen < 1) ? 1 : delimlen;
if (wcdelim != L'\0' && *(optarg + delimlen) != '\0')
FATAL_ERROR (_("the delimiter must be a single character"));
memcpy (mbdelim, optarg, delimlen);
}
}
if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
#endif
{
if (optarg[0] != '\0' && optarg[1] != '\0')
FATAL_ERROR (_("the delimiter must be a single character"));
delim = (unsigned char) optarg[0];
}
delim_specified = 1;
}
break;
case OUTPUT_DELIMITER_OPTION:
/* Interpret --output-delimiter='' to mean
`use the NUL byte as the delimiter.' */
output_delimiter_length = (optarg[0] == '\0'
? 1 : strlen (optarg));
output_delimiter_string = xstrdup (optarg);
break;
case 'n':
byte_mode_character_aware = 1;
break;
case 's':
suppress_non_delimited = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (2);
}
}
if (operating_mode == undefined_mode)
FATAL_ERROR (_("you must specify a list of bytes, characters, or fields"));
if (delim_specified && operating_mode != field_mode)
FATAL_ERROR (_("a delimiter may be specified only when operating on fields"));
if (suppress_non_delimited && operating_mode != field_mode)
FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\
\tonly when operating on fields"));
if (!delim_specified)
{
delim = '\t';
#ifdef HAVE_MBRTOWC
wcdelim = L'\t';
mbdelim[0] = '\t';
mbdelim[1] = '\0';
delimlen = 1;
#endif
}
if (output_delimiter_string == NULL)
{
#ifdef HAVE_MBRTOWC
if (MB_CUR_MAX > 1 && !force_singlebyte_mode)
{
output_delimiter_string = xstrdup(mbdelim);
output_delimiter_length = delimlen;
}
if (MB_CUR_MAX <= 1 || force_singlebyte_mode)
#endif
{
static char dummy[2];
dummy[0] = delim;
dummy[1] = '\0';
output_delimiter_string = dummy;
output_delimiter_length = 1;
}
}
if (optind == argc)
exit_status |= cut_file ("-");
else
for (; optind < argc; optind++)
exit_status |= cut_file (argv[optind]);
if (have_read_stdin && fclose (stdin) == EOF)
{
error (0, errno, "-");
exit_status = 1;
}
exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -