#include #include #include typedef struct { int width; /* Maximum line length, excluding terminating LF */ int height; /* Line count */ int size; /* File size */ int capacity; /* Buffer size */ char *data; /* File contents */ char *cursor; /* Current read position */ } FileInfo; /* Load file to memory, returns 0 on success */ static int LoadFile(FILE *infile, FileInfo *data) { int read_size; do { data->capacity += 0x10000; if( (data->data = realloc(data->data, data->capacity + 1)) == NULL ) return !puts("Out of memory"); read_size = fread(data->data + data->size, 1, 0x10000, infile); data->size += read_size; } while( read_size == 0x10000 ); /* Always make sure file ends with a LF */ data->data[data->size] = '\n'; data->cursor = data->data; return 0; } /* Get file dimensions */ static void GetFileDimensions(FileInfo *file) { int width; int i, j; for(i = 0; i < file->size; i = j + 1) { for(j = i; j < file->size && file->data[j] != '\n'; j++); width = j - i; if( width > file->width ) file->width = width; file->height++; } } /* Output concatenated files */ static void Concat(int argc, FileInfo *files) { int max_line_count = 0; int i, j, width; for(i = 1; i < argc; i++) { if( files[i].height > max_line_count ) max_line_count = files[i].height; } for(i = 0; i < max_line_count; i++) { for(j = 1; j < argc; j++) { width = 0; if( files[j].cursor - files[j].data < files[j].size ) { while( *(files[j].cursor) != '\n' ) { putchar(*(files[j].cursor)); width++; files[j].cursor++; } files[j].cursor++; } for(; width < files[j].width; width++) putchar(' '); } putchar('\n'); } } int main(int argc, char **argv) { int i, j; FileInfo *files; FILE *infile; /* Load files */ if( (files = (FileInfo*)calloc(sizeof(FileInfo), argc)) == NULL ) return !puts("Out of memory"); for(i = 1; i < argc; i++) { for(j = 1; j < i; j++) { if( strcmp(argv[i], argv[j]) == 0 ) { /* Duplicate file specified on command line, no need to load the same file again. */ memcpy(&files[i], &files[j], sizeof(FileInfo)); break; } } if( j < i ) continue; if( strcmp(argv[i], "-") == 0 ) { /* Load stdin */ if( LoadFile(stdin, &files[i]) != 0 ) return 1; } else { if( (infile = fopen(argv[i], "rb")) == NULL ) return printf("Can not open %s\n", argv[i]); j = LoadFile(infile, &files[i]); fclose(infile); if( j != 0 ) return 1; } GetFileDimensions(&files[i]); } /* Output concatenated files */ Concat(argc, files); /* Don't bother freeing memory */ return 0; }