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 (3.9 kb)"
  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        getopt32(argv, "^" "123" "\0" "=2");
  66        argv += optind;
  67
  68        for (i = 0; i < 2; ++i) {
  69                stream[i] = xfopen_stdin(argv[i]);
  70        }
  71
  72        order = 0;
  73        thisline[1] = thisline[0] = NULL;
  74        while (1) {
  75                if (order <= 0) {
  76                        free(thisline[0]);
  77                        thisline[0] = xmalloc_fgetline(stream[0]);
  78                }
  79                if (order >= 0) {
  80                        free(thisline[1]);
  81                        thisline[1] = xmalloc_fgetline(stream[1]);
  82                }
  83
  84                i = !thisline[0] + (!thisline[1] << 1);
  85                if (i)
  86                        break;
  87                order = strcmp(thisline[0], thisline[1]);
  88
  89                if (order >= 0)
  90                        writeline(thisline[1], order ? 1 : 2);
  91                else
  92                        writeline(thisline[0], 0);
  93        }
  94
  95        /* EOF at least on one of the streams */
  96        i &= 1;
  97        if (thisline[i]) {
  98                /* stream[i] is not at EOF yet */
  99                /* we did not print thisline[i] yet */
 100                char *p = thisline[i];
 101                writeline(p, i);
 102                while (1) {
 103                        free(p);
 104                        p = xmalloc_fgetline(stream[i]);
 105                        if (!p)
 106                                break;
 107                        writeline(p, i);
 108                }
 109        }
 110
 111        if (ENABLE_FEATURE_CLEAN_UP) {
 112                fclose(stream[0]);
 113                fclose(stream[1]);
 114        }
 115
 116        return EXIT_SUCCESS;
 117}
 118