busybox/coreutils/cut.c
Denys Vlasenko 22542eca18 getopt32: remove opt_complementary
function                                             old     new   delta
vgetopt32                                           1318    1392     +74
runsvdir_main                                        703     713     +10
bb_make_directory                                    423     425      +2
collect_cpu                                          546     545      -1
opt_chars                                              3       -      -3
opt_complementary                                      4       -      -4
tftpd_main                                           567     562      -5
ntp_init                                             476     471      -5
zcip_main                                           1266    1256     -10
xxd_main                                             428     418     -10
whois_main                                           140     130     -10
who_main                                             463     453     -10
which_main                                           212     202     -10
wget_main                                           2535    2525     -10
watchdog_main                                        291     281     -10
watch_main                                           222     212     -10
vlock_main                                           399     389     -10
uuencode_main                                        332     322     -10
uudecode_main                                        316     306     -10
unlink_main                                           45      35     -10
udhcpd_main                                         1482    1472     -10
udhcpc_main                                         2762    2752     -10
tune2fs_main                                         290     280     -10
tunctl_main                                          366     356     -10
truncate_main                                        218     208     -10
tr_main                                              518     508     -10
time_main                                           1134    1124     -10
tftp_main                                            286     276     -10
telnetd_main                                        1873    1863     -10
tcpudpsvd_main                                      1785    1775     -10
taskset_main                                         521     511     -10
tar_main                                            1009     999     -10
tail_main                                           1644    1634     -10
syslogd_main                                        1967    1957     -10
switch_root_main                                     368     358     -10
svlogd_main                                         1454    1444     -10
sv                                                  1296    1286     -10
stat_main                                            104      94     -10
start_stop_daemon_main                              1028    1018     -10
split_main                                           542     532     -10
sort_main                                            796     786     -10
slattach_main                                        624     614     -10
shuf_main                                            504     494     -10
setsid_main                                           96      86     -10
setserial_main                                      1132    1122     -10
setfont_main                                         388     378     -10
setconsole_main                                       78      68     -10
sendmail_main                                       1209    1199     -10
sed_main                                             677     667     -10
script_main                                         1077    1067     -10
run_parts_main                                       325     315     -10
rtcwake_main                                         454     444     -10
rm_main                                              175     165     -10
reformime_main                                       119     109     -10
readlink_main                                        123     113     -10
rdate_main                                           246     236     -10
pwdx_main                                            189     179     -10
pstree_main                                          317     307     -10
pscan_main                                           663     653     -10
popmaildir_main                                      818     808     -10
pmap_main                                             80      70     -10
nc_main                                             1042    1032     -10
mv_main                                              558     548     -10
mountpoint_main                                      477     467     -10
mount_main                                          1264    1254     -10
modprobe_main                                        768     758     -10
modinfo_main                                         333     323     -10
mktemp_main                                          200     190     -10
mkswap_main                                          324     314     -10
mkfs_vfat_main                                      1489    1479     -10
microcom_main                                        715     705     -10
md5_sha1_sum_main                                    521     511     -10
man_main                                             867     857     -10
makedevs_main                                       1052    1042     -10
ls_main                                              563     553     -10
losetup_main                                         432     422     -10
loadfont_main                                         89      79     -10
ln_main                                              524     514     -10
link_main                                             75      65     -10
ipcalc_main                                          544     534     -10
iostat_main                                         2397    2387     -10
install_main                                         768     758     -10
id_main                                              480     470     -10
i2cset_main                                         1239    1229     -10
i2cget_main                                          380     370     -10
i2cdump_main                                        1482    1472     -10
i2cdetect_main                                       682     672     -10
hwclock_main                                         406     396     -10
httpd_main                                           741     731     -10
grep_main                                            837     827     -10
getty_main                                          1559    1549     -10
fuser_main                                           297     287     -10
ftpgetput_main                                       345     335     -10
ftpd_main                                           2232    2222     -10
fstrim_main                                          251     241     -10
fsfreeze_main                                         77      67     -10
fsck_minix_main                                     2921    2911     -10
flock_main                                           314     304     -10
flashcp_main                                         740     730     -10
flash_eraseall_main                                  833     823     -10
fdformat_main                                        532     522     -10
expand_main                                          680     670     -10
eject_main                                           335     325     -10
dumpleases_main                                      630     620     -10
du_main                                              314     304     -10
dos2unix_main                                        441     431     -10
diff_main                                           1350    1340     -10
df_main                                             1064    1054     -10
date_main                                           1095    1085     -10
cut_main                                             961     951     -10
cryptpw_main                                         228     218     -10
crontab_main                                         575     565     -10
crond_main                                          1149    1139     -10
cp_main                                              370     360     -10
common_traceroute_main                              3834    3824     -10
common_ping_main                                    1767    1757     -10
comm_main                                            239     229     -10
cmp_main                                             655     645     -10
chrt_main                                            379     369     -10
chpst_main                                           704     694     -10
chpasswd_main                                        308     298     -10
chown_main                                           171     161     -10
chmod_main                                           158     148     -10
cat_main                                             428     418     -10
bzip2_main                                           120     110     -10
blkdiscard_main                                      264     254     -10
base64_main                                          221     211     -10
arping_main                                         1665    1655     -10
ar_main                                              556     546     -10
adjtimex_main                                        406     396     -10
adduser_main                                         882     872     -10
addgroup_main                                        411     401     -10
acpid_main                                          1198    1188     -10
optstring                                             11       -     -11
opt_string                                            18       -     -18
OPT_STR                                               25       -     -25
ubi_tools_main                                      1288    1258     -30
ls_options                                            31       -     -31
------------------------------------------------------------------------------
(add/remove: 0/6 grow/shrink: 3/129 up/down: 86/-1383)      Total: -1297 bytes
   text	   data	    bss	    dec	    hex	filename
 915428	    485	   6876	 922789	  e14a5	busybox_old
 914629	    485	   6872	 921986	  e1182	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2017-08-08 21:55:02 +02:00

320 lines
8.7 KiB
C

/* vi: set sw=4 ts=4: */
/*
* cut.c - minimalist version of cut
*
* Copyright (C) 1999,2000,2001 by Lineo, inc.
* Written by Mark Whitley <markw@codepoet.org>
* debloated by Bernhard Reutner-Fischer
*
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
//config:config CUT
//config: bool "cut (5.3 kb)"
//config: default y
//config: help
//config: cut is used to print selected parts of lines from
//config: each file to stdout.
//applet:IF_CUT(APPLET_NOEXEC(cut, cut, BB_DIR_USR_BIN, BB_SUID_DROP, cut))
//kbuild:lib-$(CONFIG_CUT) += cut.o
//usage:#define cut_trivial_usage
//usage: "[OPTIONS] [FILE]..."
//usage:#define cut_full_usage "\n\n"
//usage: "Print selected fields from each input FILE to stdout\n"
//usage: "\n -b LIST Output only bytes from LIST"
//usage: "\n -c LIST Output only characters from LIST"
//usage: "\n -d CHAR Use CHAR instead of tab as the field delimiter"
//usage: "\n -s Output only the lines containing delimiter"
//usage: "\n -f N Print only these fields"
//usage: "\n -n Ignored"
//usage:
//usage:#define cut_example_usage
//usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n"
//usage: "Hello\n"
//usage: "$ echo \"Hello world\" | cut -f 2 -d ' '\n"
//usage: "world\n"
#include "libbb.h"
/* This is a NOEXEC applet. Be very careful! */
/* option vars */
#define OPT_STR "b:c:f:d:sn"
#define CUT_OPT_BYTE_FLGS (1 << 0)
#define CUT_OPT_CHAR_FLGS (1 << 1)
#define CUT_OPT_FIELDS_FLGS (1 << 2)
#define CUT_OPT_DELIM_FLGS (1 << 3)
#define CUT_OPT_SUPPRESS_FLGS (1 << 4)
struct cut_list {
int startpos;
int endpos;
};
enum {
BOL = 0,
EOL = INT_MAX,
NON_RANGE = -1
};
static int cmpfunc(const void *a, const void *b)
{
return (((struct cut_list *) a)->startpos -
((struct cut_list *) b)->startpos);
}
static void cut_file(FILE *file, char delim, const struct cut_list *cut_lists, unsigned nlists)
{
char *line;
unsigned linenum = 0; /* keep these zero-based to be consistent */
/* go through every line in the file */
while ((line = xmalloc_fgetline(file)) != NULL) {
/* set up a list so we can keep track of what's been printed */
int linelen = strlen(line);
char *printed = xzalloc(linelen + 1);
char *orig_line = line;
unsigned cl_pos = 0;
int spos;
/* cut based on chars/bytes XXX: only works when sizeof(char) == byte */
if (option_mask32 & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS)) {
/* print the chars specified in each cut list */
for (; cl_pos < nlists; cl_pos++) {
spos = cut_lists[cl_pos].startpos;
while (spos < linelen) {
if (!printed[spos]) {
printed[spos] = 'X';
putchar(line[spos]);
}
spos++;
if (spos > cut_lists[cl_pos].endpos
/* NON_RANGE is -1, so if below is true,
* the above was true too (spos is >= 0) */
/* || cut_lists[cl_pos].endpos == NON_RANGE */
) {
break;
}
}
}
} else if (delim == '\n') { /* cut by lines */
spos = cut_lists[cl_pos].startpos;
/* get out if we have no more lists to process or if the lines
* are lower than what we're interested in */
if (((int)linenum < spos) || (cl_pos >= nlists))
goto next_line;
/* if the line we're looking for is lower than the one we were
* passed, it means we displayed it already, so move on */
while (spos < (int)linenum) {
spos++;
/* go to the next list if we're at the end of this one */
if (spos > cut_lists[cl_pos].endpos
|| cut_lists[cl_pos].endpos == NON_RANGE
) {
cl_pos++;
/* get out if there's no more lists to process */
if (cl_pos >= nlists)
goto next_line;
spos = cut_lists[cl_pos].startpos;
/* get out if the current line is lower than the one
* we just became interested in */
if ((int)linenum < spos)
goto next_line;
}
}
/* If we made it here, it means we've found the line we're
* looking for, so print it */
puts(line);
goto next_line;
} else { /* cut by fields */
int ndelim = -1; /* zero-based / one-based problem */
int nfields_printed = 0;
char *field = NULL;
char delimiter[2];
delimiter[0] = delim;
delimiter[1] = 0;
/* does this line contain any delimiters? */
if (strchr(line, delim) == NULL) {
if (!(option_mask32 & CUT_OPT_SUPPRESS_FLGS))
puts(line);
goto next_line;
}
/* process each list on this line, for as long as we've got
* a line to process */
for (; cl_pos < nlists && line; cl_pos++) {
spos = cut_lists[cl_pos].startpos;
do {
/* find the field we're looking for */
while (line && ndelim < spos) {
field = strsep(&line, delimiter);
ndelim++;
}
/* we found it, and it hasn't been printed yet */
if (field && ndelim == spos && !printed[ndelim]) {
/* if this isn't our first time through, we need to
* print the delimiter after the last field that was
* printed */
if (nfields_printed > 0)
putchar(delim);
fputs(field, stdout);
printed[ndelim] = 'X';
nfields_printed++; /* shouldn't overflow.. */
}
spos++;
/* keep going as long as we have a line to work with,
* this is a list, and we're not at the end of that
* list */
} while (spos <= cut_lists[cl_pos].endpos && line
&& cut_lists[cl_pos].endpos != NON_RANGE);
}
}
/* if we printed anything at all, we need to finish it with a
* newline cuz we were handed a chomped line */
putchar('\n');
next_line:
linenum++;
free(printed);
free(orig_line);
}
}
int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int cut_main(int argc UNUSED_PARAM, char **argv)
{
/* growable array holding a series of lists */
struct cut_list *cut_lists = NULL;
unsigned nlists = 0; /* number of elements in above list */
char delim = '\t'; /* delimiter, default is tab */
char *sopt, *ltok;
unsigned opt;
opt = getopt32(argv, "^"
OPT_STR
"\0" "b--bcf:c--bcf:f--bcf",
&sopt, &sopt, &sopt, &ltok
);
// argc -= optind;
argv += optind;
if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS)))
bb_error_msg_and_die("expected a list of bytes, characters, or fields");
if (opt & CUT_OPT_DELIM_FLGS) {
if (ltok[0] && ltok[1]) { /* more than 1 char? */
bb_error_msg_and_die("the delimiter must be a single character");
}
delim = ltok[0];
}
/* non-field (char or byte) cutting has some special handling */
if (!(opt & CUT_OPT_FIELDS_FLGS)) {
static const char _op_on_field[] ALIGN1 = " only when operating on fields";
if (opt & CUT_OPT_SUPPRESS_FLGS) {
bb_error_msg_and_die
("suppressing non-delimited lines makes sense%s",
_op_on_field);
}
if (delim != '\t') {
bb_error_msg_and_die
("a delimiter may be specified%s", _op_on_field);
}
}
/*
* parse list and put values into startpos and endpos.
* valid list formats: N, N-, N-M, -M
* more than one list can be separated by commas
*/
{
char *ntok;
int s = 0, e = 0;
/* take apart the lists, one by one (they are separated with commas) */
while ((ltok = strsep(&sopt, ",")) != NULL) {
/* it's actually legal to pass an empty list */
if (!ltok[0])
continue;
/* get the start pos */
ntok = strsep(&ltok, "-");
if (!ntok[0]) {
s = BOL;
} else {
s = xatoi_positive(ntok);
/* account for the fact that arrays are zero based, while
* the user expects the first char on the line to be char #1 */
if (s != 0)
s--;
}
/* get the end pos */
if (ltok == NULL) {
e = NON_RANGE;
} else if (!ltok[0]) {
e = EOL;
} else {
e = xatoi_positive(ltok);
/* if the user specified and end position of 0,
* that means "til the end of the line" */
if (e == 0)
e = EOL;
e--; /* again, arrays are zero based, lines are 1 based */
if (e == s)
e = NON_RANGE;
}
/* add the new list */
cut_lists = xrealloc_vector(cut_lists, 4, nlists);
/* NB: startpos is always >= 0,
* while endpos may be = NON_RANGE (-1) */
cut_lists[nlists].startpos = s;
cut_lists[nlists].endpos = e;
nlists++;
}
/* make sure we got some cut positions out of all that */
if (nlists == 0)
bb_error_msg_and_die("missing list of positions");
/* now that the lists are parsed, we need to sort them to make life
* easier on us when it comes time to print the chars / fields / lines
*/
qsort(cut_lists, nlists, sizeof(cut_lists[0]), cmpfunc);
}
{
int retval = EXIT_SUCCESS;
if (!*argv)
*--argv = (char *)"-";
do {
FILE *file = fopen_or_warn_stdin(*argv);
if (!file) {
retval = EXIT_FAILURE;
continue;
}
cut_file(file, delim, cut_lists, nlists);
fclose_if_not_stdin(file);
} while (*++argv);
if (ENABLE_FEATURE_CLEAN_UP)
free(cut_lists);
fflush_stdout_and_exit(retval);
}
}