glue.c (2865B)
1 #if WIN32 2 #include <io.h> /* for setmode() */ 3 #endif 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <stdlib.h> 8 9 #define PUTCHAR putchar 10 #define FPUTS fputs 11 12 #define FieldLast 8 13 14 struct string { 15 char *data; 16 size_t len; 17 size_t cap; 18 }; 19 20 static struct string mergedfields[FieldLast]; 21 static char *fields[FieldLast]; 22 23 /* Splits fields in the line buffer by replacing TAB separators with NUL ('\0') 24 * terminators and assign these fields as pointers. If there are less fields 25 * than expected then the field is an empty string constant. */ 26 void 27 parseline(char *line, char *fields[FieldLast]) 28 { 29 char *prev, *s; 30 size_t i; 31 32 for (prev = line, i = 0; 33 (s = strchr(prev, '\t')) && i < FieldLast - 1; 34 ++i) { 35 *s = '\0'; 36 fields[i] = prev; 37 prev = s + 1; 38 } 39 fields[i++] = prev; 40 /* make non-parsed fields empty. */ 41 for (; i < FieldLast; i++) 42 fields[i] = ""; 43 } 44 45 void 46 printfields(void) 47 { 48 if (!mergedfields[0].len) 49 return; 50 51 fputs(mergedfields[0].data, stdout); 52 fputs("\t", stdout); 53 fputs(mergedfields[1].data, stdout); 54 fputs("\t", stdout); 55 fputs(mergedfields[2].data, stdout); 56 fputs("\t", stdout); 57 fputs(mergedfields[3].data, stdout); 58 fputs("\t", stdout); 59 fputs(mergedfields[4].data, stdout); 60 fputs("\t", stdout); 61 fputs(mergedfields[5].data, stdout); 62 fputs("\t", stdout); 63 fputs(mergedfields[6].data, stdout); 64 fputs("\t", stdout); 65 fputs(mergedfields[7].data, stdout); 66 fputs("\n", stdout); 67 } 68 69 void 70 string_reset(struct string *d) 71 { 72 d->data[0] = '\0'; 73 d->len = 0; 74 } 75 76 void 77 string_set(struct string *d, const char *data) 78 { 79 size_t len; 80 81 len = strlen(data); 82 if (len + 1 >= d->cap) { 83 d->cap = d->cap + len + 1; 84 if (!(d->data = realloc(d->data, d->cap))) { 85 perror(NULL); 86 exit(1); 87 } 88 } 89 memcpy(d->data, data, len + 1); /* copy including NUL byte */ 90 d->len = len; 91 } 92 93 int 94 main(void) 95 { 96 char line[4096], *p; 97 size_t i; 98 99 /* required for Windows binary mode aka more retarded bullshit. */ 100 #if WIN32 101 /* binary mode for stdin, stdout and stderr */ 102 _setmode(0, 0x8000); /* 0x8000 is O_BINARY */ 103 _setmode(1, 0x8000); 104 _setmode(2, 0x8000); 105 #endif 106 107 for (i = 0; i < FieldLast; ++i) { 108 mergedfields[i].cap = 4096; 109 if (!(mergedfields[i].data = calloc(1, 4096))) { 110 perror(NULL); 111 exit(1); 112 } 113 mergedfields[i].len = 0; 114 } 115 116 while (fgets(line, sizeof(line), stdin)) { 117 if ((p = strchr(line, '\n'))) 118 *p = '\0'; 119 120 parseline(line, fields); 121 122 /* primary key */ 123 if (strcmp(fields[0], mergedfields[0].data)) { 124 printfields(); 125 for (i = 0; i < FieldLast; ++i) 126 string_reset(&mergedfields[i]); 127 string_set(&mergedfields[0], fields[0]); 128 } 129 130 for (i = 1; i < FieldLast; ++i) { 131 /* field is set: override with next */ 132 if (!fields[i][0]) 133 continue; 134 string_set(&mergedfields[i], fields[i]); 135 } 136 } 137 printfields(); 138 139 if (ferror(stdin) || (fflush(stdout) && ferror(stdout))) { 140 perror(NULL); 141 exit(1); 142 } 143 144 return 0; 145 }