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 (4.2 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