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