~mmach/netext73/busybox

« back to all changes in this revision

Viewing changes to editors/cmp.c

  • Committer: mmach
  • Date: 2021-04-14 13:54:24 UTC
  • Revision ID: netbit73@gmail.com-20210414135424-8x3fxf716zs4wflb
1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vi: set sw=4 ts=4: */
 
2
/*
 
3
 * Mini cmp implementation for busybox
 
4
 *
 
5
 * Copyright (C) 2000,2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
 
6
 *
 
7
 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
 
8
 */
 
9
//config:config CMP
 
10
//config:       bool "cmp (4.9 kb)"
 
11
//config:       default y
 
12
//config:       help
 
13
//config:       cmp is used to compare two files and returns the result
 
14
//config:       to standard output.
 
15
 
 
16
//applet:IF_CMP(APPLET(cmp, BB_DIR_USR_BIN, BB_SUID_DROP))
 
17
 
 
18
//kbuild:lib-$(CONFIG_CMP) += cmp.o
 
19
 
 
20
//usage:#define cmp_trivial_usage
 
21
//usage:       "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]"
 
22
//usage:#define cmp_full_usage "\n\n"
 
23
//usage:       "Compare FILE1 with FILE2 (or stdin)\n"
 
24
//usage:     "\n        -l      Write the byte numbers (decimal) and values (octal)"
 
25
//usage:     "\n                for all differing bytes"
 
26
//usage:     "\n        -s      Quiet"
 
27
 
 
28
/* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */
 
29
/* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */
 
30
 
 
31
#include "libbb.h"
 
32
 
 
33
static const char fmt_eof[] ALIGN1 = "cmp: EOF on %s\n";
 
34
static const char fmt_differ[] ALIGN1 = "%s %s differ: char %"OFF_FMT"u, line %u\n";
 
35
// This fmt_l_opt uses gnu-isms.  SUSv3 would be "%.0s%.0s%"OFF_FMT"u %o %o\n"
 
36
static const char fmt_l_opt[] ALIGN1 = "%.0s%.0s%"OFF_FMT"u %3o %3o\n";
 
37
 
 
38
#define OPT_STR "sl"
 
39
#define CMP_OPT_s (1<<0)
 
40
#define CMP_OPT_l (1<<1)
 
41
 
 
42
int cmp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 
43
int cmp_main(int argc UNUSED_PARAM, char **argv)
 
44
{
 
45
        FILE *fp1, *fp2, *outfile = stdout;
 
46
        const char *filename1, *filename2 = "-";
 
47
        off_t skip1 = 0, skip2 = 0, char_pos = 0;
 
48
        int line_pos = 1; /* Hopefully won't overflow... */
 
49
        const char *fmt;
 
50
        int c1, c2;
 
51
        unsigned opt;
 
52
        int retval = 0;
 
53
 
 
54
        opt = getopt32(argv, "^"
 
55
                        OPT_STR
 
56
                        "\0" "-1"
 
57
                        IF_DESKTOP(":?4")
 
58
                        IF_NOT_DESKTOP(":?2")
 
59
                        ":l--s:s--l"
 
60
        );
 
61
        argv += optind;
 
62
 
 
63
        filename1 = *argv;
 
64
        if (*++argv) {
 
65
                filename2 = *argv;
 
66
                if (ENABLE_DESKTOP && *++argv) {
 
67
                        skip1 = XATOOFF(*argv);
 
68
                        if (*++argv) {
 
69
                                skip2 = XATOOFF(*argv);
 
70
                        }
 
71
                }
 
72
        }
 
73
 
 
74
        xfunc_error_retval = 2;  /* missing file results in exitcode 2 */
 
75
        if (opt & CMP_OPT_s)
 
76
                logmode = 0;  /* -s suppresses open error messages */
 
77
        fp1 = xfopen_stdin(filename1);
 
78
        fp2 = xfopen_stdin(filename2);
 
79
        if (fp1 == fp2) {               /* Paranoia check... stdin == stdin? */
 
80
                /* Note that we don't bother reading stdin.  Neither does gnu wc.
 
81
                 * But perhaps we should, so that other apps down the chain don't
 
82
                 * get the input.  Consider 'echo hello | (cmp - - && cat -)'.
 
83
                 */
 
84
                return 0;
 
85
        }
 
86
        logmode = LOGMODE_STDIO;
 
87
 
 
88
        if (opt & CMP_OPT_l)
 
89
                fmt = fmt_l_opt;
 
90
        else
 
91
                fmt = fmt_differ;
 
92
 
 
93
        if (ENABLE_DESKTOP) {
 
94
                while (skip1) { getc(fp1); skip1--; }
 
95
                while (skip2) { getc(fp2); skip2--; }
 
96
        }
 
97
        do {
 
98
                c1 = getc(fp1);
 
99
                c2 = getc(fp2);
 
100
                ++char_pos;
 
101
                if (c1 != c2) {                 /* Remember: a read error may have occurred. */
 
102
                        retval = 1;             /* But assume the files are different for now. */
 
103
                        if (c2 == EOF) {
 
104
                                /* We know that fp1 isn't at EOF or in an error state.  But to
 
105
                                 * save space below, things are setup to expect an EOF in fp1
 
106
                                 * if an EOF occurred.  So, swap things around.
 
107
                                 */
 
108
                                fp1 = fp2;
 
109
                                filename1 = filename2;
 
110
                                c1 = c2;
 
111
                        }
 
112
                        if (c1 == EOF) {
 
113
                                die_if_ferror(fp1, filename1);
 
114
                                fmt = fmt_eof;  /* Well, no error, so it must really be EOF. */
 
115
                                outfile = stderr;
 
116
                                /* There may have been output to stdout (option -l), so
 
117
                                 * make sure we fflush before writing to stderr. */
 
118
                                fflush_all();
 
119
                        }
 
120
                        if (!(opt & CMP_OPT_s)) {
 
121
                                if (opt & CMP_OPT_l) {
 
122
                                        line_pos = c1;  /* line_pos is unused in the -l case. */
 
123
                                }
 
124
                                fprintf(outfile, fmt, filename1, filename2, char_pos, line_pos, c2);
 
125
                                if (opt) {      /* This must be -l since not -s. */
 
126
                                        /* If we encountered an EOF,
 
127
                                         * the while check will catch it. */
 
128
                                        continue;
 
129
                                }
 
130
                        }
 
131
                        break;
 
132
                }
 
133
                if (c1 == '\n') {
 
134
                        ++line_pos;
 
135
                }
 
136
        } while (c1 != EOF);
 
137
 
 
138
        die_if_ferror(fp1, filename1);
 
139
        die_if_ferror(fp2, filename2);
 
140
 
 
141
        fflush_stdout_and_exit(retval);
 
142
}