#include <stdio.h>
#include <string.h>
#define MIN(a,b) a < b ? a : b
#define MAX_LINE_SIZE 256
char* from;
char* to;
// Get a line up to len from file and save it into word, returning wether
// anything was read
int get_line(FILE* file, char* word, size_t len)
{
int i = 0;
char c;
for (; i < len - 1 && (c = getc(file)) != EOF; i++ )
{
if (c != '\n')
{
// Skip carriage returns
if (c != '\r')
word[i] = c;
else
i -= 1;
}
else
break;
}
word[i] = '\0';
return i;
}
// Move a set number of lines further down the file
void forward(FILE* file, long lines)
{
char temp[MAX_LINE_SIZE];
for (long i = 0; i < lines; i++)
get_line(file, temp, MAX_LINE_SIZE);
}
// Get the line in file, beginning at file_pos and return the new file_pos
void fget_line(FILE* file, long* file_pos, char* word, int bufsize)
{
fseek(file, *file_pos, SEEK_SET);
get_line(file, word, bufsize);
*file_pos = ftell(file);
}
// Count the number of lines in the file corresponding to filename
long count_lines(char* filename)
{
long lines = 0;
char line[MAX_LINE_SIZE];
FILE* file = fopen(filename, "r");
while ((get_line(file, line, MAX_LINE_SIZE)))
lines++;
fclose(file);
return lines;
}
int main(int argc, char** argv)
{
if (argc == 2)
{
// Create the file to use alongside the original one
char swap_name[strlen(argv[1]) + 6];
strcpy(swap_name, argv[1]);
strcat(swap_name, ".swap");
from = argv[1];
to = swap_name;
long total_len = count_lines(from);
for (long sub_len = 1; sub_len < total_len; sub_len *= 2)
{
FILE* from_file_a = fopen(from, "r");
FILE* from_file_b = fopen(from, "r");
forward(from_file_b, sub_len);
FILE* to_file = fopen(to, "w");
for (long remaining_len = total_len; remaining_len > 0; remaining_len -= sub_len * 2)
{
if (remaining_len > sub_len)
{
long a_pos = 0;
long b_pos = 0;
long a_len = sub_len;
long b_len = MIN(sub_len, remaining_len - sub_len);
char a_val[MAX_LINE_SIZE];
char b_val[MAX_LINE_SIZE];
get_line(from_file_a, a_val, MAX_LINE_SIZE);
get_line (from_file_b, b_val, MAX_LINE_SIZE);
for (int cycles = 0; cycles < a_len + b_len; cycles++)
{
if (a_pos == a_len || strcmp(a_val, b_val) > 0)
{
b_pos++;
fprintf(to_file, "%s\n", b_val);
if (b_pos != b_len)
get_line(from_file_b, b_val, MAX_LINE_SIZE);
}
else
{
a_pos++;
fprintf(to_file, "%s\n", a_val);
if (a_pos != a_len)
get_line(from_file_a, a_val, MAX_LINE_SIZE);
}
}
// Advance the positions for the next cycle
forward(from_file_a, a_len);
if (remaining_len > sub_len * 3)
forward (from_file_b, b_len);
}
else
{
char line[MAX_LINE_SIZE];
while ((get_line(from_file_b, line, MAX_LINE_SIZE)))
fprintf(to_file, "%s\n", line);
}
}
fclose(from_file_a);
fclose(from_file_b);
fclose(to_file);
// Swap the two "adresses"
char* temp = to;
to = from;
from = temp;
}
// Make sure the sorted lines are in the original file
if (to == argv [1])
{
FILE* to_file = fopen(argv[1], "w");
FILE* from_file = fopen ( swap_name, "r" );
char line[MAX_LINE_SIZE];
while ((get_line ( from_file, line, MAX_LINE_SIZE)))
fprintf(to_file, "%s\n", line);
}
remove(swap_name);
}
return 0;
}