/*
 * Merge v1.5 by Fucking Hostile of SIN                                       
 *                                                                         
 * This program is based on ListMerge by The Messiah. I thought that when  
 * he made that it was a pretty good idea cuz a lot of people have asked   
 * about programs to combine word list. Anyways his version is for Windows 
 * so i figured i'd make a spiffy version for Linux users to use. This is 
 * not the final version there are still things I need to do to it. I am 
 * just releasing this is sort of a progress thing. I have some other stuff
 * that I am working on right now also so I am pretty busy. Version 2.0 
 * will be the final version tho. This implements the mergesort algorithm.
 *                                                            
 * Contact at: fh@sinnerz.com 
 * SIN: http://www.sinnerz.com
 * Homepage: http://roo.unixnet.org/~fh
 *                  
 */

 #include <stdio.h>
 #include <string.h>

 #include <stdlib.h>
 #include <malloc.h>     

 /*
 merge 2 files in one
 */

 //#define MAX(a,b) ((a)>(b))?(b):(a)

 int MAX(int a,int b){
      return ((a)>(b))?(a):(b);
 }

 #define MAX_LINES 0x10000
 #define MIN_LENGTH 0x10000

 void mergesort (char* *array, int left, int right);
 void merge (char* *A, int first1, int last1, int first2, int last2);
 void move (char* *list1, int first1, int last1, char* *list2, int first2);

 int MyCompare(char*szOne,char*szTwo){
      return(strcmp(szOne,szTwo));
 }


 void mergesort (char* *array, int left, int right) {
   if (left < right) {
     mergesort (array, left, (left+right)/2);
     mergesort (array, (left+right)/2 + 1, right);
 //    merge (array, left, (left+right)/2, (left+right)/2+1, last);
     merge (array, left, (left+right)/2, (left+right)/2+1, right);
   }
 }


 void merge (char* *A, int first1, int last1, int first2, int last2) {
   char** temp;
   int index, index1, index2;
   int num;

   temp=(char**)malloc(sizeof(char*)*MAX(last1+1,last2+1));

   index = 0;
   index1 = first1;
   index2 = first2;

   num = last1 - first1 + last2 - first2 + 2;

   /*
    *  Merge the two lists back together until one list runs out of
    *  items...
    *
    */

   while ((index1 <= last1) && (index2 <= last2)) {
      if (MyCompare(A[index1],A[index2])<0){
           temp[index++] = A[index1++];
      }
      else{
           temp[index++] = A[index2++];
      }
   }

   /*
    *  At which point fill in the merged list with the "rest" of the
    *  non exhausted list.
    *
    */

   if (index1 > last1)
     move (A, index2, last2, temp, index);
   else
     move (A, index1, last1, temp, index);


   /* finally move our merged array in temp space to the real array */
   move(temp, 0, num-1, A, first1);
   free(temp);
 }


 void move (char* *list1, int first1, int last1, char* *list2, int first2) {
   while (first1 <= last1)
     list2[first2++] = list1[first1++];
 }

 long MyFileLength(FILE*in){
      long lLen,lPos;
      if(in==NULL){
           return(-1);
      }
      lPos=ftell(in);
      fseek(in,0,SEEK_END);  
      lLen=ftell(in);
      fseek(in,lPos,SEEK_SET); 
      return(lLen);
 }


 int main(int argc,char* argv[]){
 
     FILE* in;
      FILE* out;
      int nOfFiles=0;
      long* plFileLength;

      char* sRow;
      char** buffer;
      char** ArrayLine;

      int i,j,k;
      long l, lLenFile;

      /*check args*/
      if (argc<4){
           printf("\n\n Merge v1.5 by Fucking Hostile\n\n");
           printf("Usage: merge FileIn.1 ... FileTxtIn.n
           FileTextOut.3\n");
           return(-1);
      }

      out=fopen(argv[argc-1],"wt");

      if(out==NULL){
           printf("error opening output file '%s'\n",argv[argc-1]);
           fclose(out);
           free(sRow);
           return(-1);
      }
      buffer=(char**)malloc((argc-2)*sizeof(char*));  
      if(buffer==NULL){
           printf("buffer[] memory allocation error\n");
           return(-1);
      }
      ArrayLine=(char**)malloc(MAX_LINES*(sizeof(char*)));  
      if(ArrayLine==NULL){
           printf("ArrayLine memory allocation error\n");
           return(-1);
      }
      plFileLength=(long*)malloc((argc-2)*sizeof(long)); 
      if(plFileLength==NULL){
           printf("plFileLength memory allocation error\n");
           return(-1);
      }


      j=0;  

      for(k=0;k<argc-2;k++){
           in=fopen(argv[k+1],"rt");
           lLenFile=MyFileLength(in);
           if(lLenFile<=0){
                printf("File Length error\n");
                return(-2);
           }
           buffer[k]=(char*)malloc(sizeof(char*)*(lLenFile+1)); 
           if(buffer[k]==NULL){
                printf("buffer[i][]alloc error\n");
                return(-3);
           }

           l=plFileLength[k]=fread( buffer[k], 1, lLenFile, in );
           buffer[k][ l ]='\0';
 //        ArrayLine[j]=&(buffer[k][j]);
           ArrayLine[j]=buffer[k];
           j++;
           for(i=0;i<l;i++){
                if (buffer[k][i]=='\n'){
                     buffer[k][i]='\0';
                     ArrayLine[j]=&buffer[k][i+1];
                     j++;
                }
           }

           fclose(in);
           j--;
      }  /*next input file*/


 /*sort*/
      mergesort (ArrayLine, 0, j);

 /*save data into output file*/
      for(i=0;i<=j;i++){
           lLenFile=fprintf(out ,"%s\n", ArrayLine[i] );
      }
 /*
 a problem free(buffer);  ??
 */
      for(i=0;i<argc-2;i++){
           free(buffer[i]);
      }
      free(ArrayLine);
      free(plFileLength);
      free(buffer);



      fclose(out);
      return(0);
 }