busybox/coreutils/comm.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Mini comm implementation for busybox
   4 *
   5 * Copyright (C) 2005 by Robert Sullivan <cogito.ergo.cogito@gmail.com>
   6 *
   7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   8 */
   9//config:config COMM
  10//config:       bool "comm"
  11//config:       default y
  12//config:       help
  13//config:         comm is used to compare two files line by line and return
  14//config:         a three-column output.
  15
  16//applet:IF_COMM(APPLET(comm, BB_DIR_USR_BIN, BB_SUID_DROP))
  17
  18//kbuild:lib-$(CONFIG_COMM) += comm.o
  19
  20//usage:#define comm_trivial_usage
  21//usage:       "[-123] FILE1 FILE2"
  22//usage:#define comm_full_usage "\n\n"
  23//usage:       "Compare FILE1 with FILE2\n"
  24//usage:     "\n        -1      Suppress lines unique to FILE1"
  25//usage:     "\n        -2      Suppress lines unique to FILE2"
  26//usage:     "\n        -3      Suppress lines common to both files"
  27
  28#include "libbb.h"
  29
  30#define COMM_OPT_1 (1 << 0)
  31#define COMM_OPT_2 (1 << 1)
  32#define COMM_OPT_3 (1 << 2)
  33
  34/* writeline outputs the input given, appropriately aligned according to class */
  35static void writeline(char *line, int class)
  36{
  37        int flags = option_mask32;
  38        if (class == 0) {
  39                if (flags & COMM_OPT_1)
  40                        return;
  41        } else if (class == 1) {
  42                if (flags & COMM_OPT_2)
  43                        return;
  44                if (!(flags & COMM_OPT_1))
  45                        putchar('\t');
  46        } else /*if (class == 2)*/ {
  47                if (flags & COMM_OPT_3)
  48                        return;
  49                if (!(flags & COMM_OPT_1))
  50                        putchar('\t');
  51                if (!(flags & COMM_OPT_2))
  52                        putchar('\t');
  53        }
  54        puts(line);
  55}
  56
  57int comm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  58int comm_main(int argc UNUSED_PARAM, char **argv)
  59{
  60        char *thisline[2];
  61        FILE *stream[2];
  62        int i;
  63        int order;
  64
  65        opt_complementary = "=2";
  66        getopt32(argv, "123");
  67        argv += optind;
  68
  69        for (i = 0; i < 2; ++i) {
  70                stream[i] = xfopen_stdin(argv[i]);
  71        }
  72
  73        order = 0;
  74        thisline[1] = thisline[0] = NULL;
  75        while (1) {
  76                if (order <= 0) {
  77                        free(thisline[0]);
  78                        thisline[0] = xmalloc_fgetline(stream[0]);
  79                }
  80                if (order >= 0) {
  81                        free(thisline[1]);
  82                        thisline[1] = xmalloc_fgetline(stream[1]);
  83                }
  84
  85                i = !thisline[0] + (!thisline[1] << 1);
  86                if (i)
  87                        break;
  88                order = strcmp(thisline[0], thisline[1]);
  89
  90                if (order >= 0)
  91                        writeline(thisline[1], order ? 1 : 2);
  92                else
  93                        writeline(thisline[0], 0);
  94        }
  95
  96        /* EOF at least on one of the streams */
  97        i &= 1;
  98        if (thisline[i]) {
  99                /* stream[i] is not at EOF yet */
 100                /* we did not print thisline[i] yet */
 101                char *p = thisline[i];
 102                writeline(p, i);
 103                while (1) {
 104                        free(p);
 105                        p = xmalloc_fgetline(stream[i]);
 106                        if (!p)
 107                                break;
 108                        writeline(p, i);
 109                }
 110        }
 111
 112        if (ENABLE_FEATURE_CLEAN_UP) {
 113                fclose(stream[0]);
 114                fclose(stream[1]);
 115        }
 116
 117        return EXIT_SUCCESS;
 118}
 119