/*
SaM - Split and Merge Files
written by Ralf Einhorn
(einhorn@rvs.uni-hannover.de, einhorn@t-online.de)

based on SaM for DOS
last changes 970320 970410
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int split (char *name, char *base, int sf_size)
/* name=filename, base=basename, sf_size=single filesize in KBytes */
{
  FILE *rdptr;
  FILE *wrtptr;
  int file_size = 0;
  int len_read = 0;
  int len_write = 0;
  int blocks = 0;
  int last_blocks = 0;
  int parts = 0;
  char data[1024];
  char *dstname;
  int ext_pos;
  int x;
  int go_on = 1;
  int testbyte;

  if (!base || !strncmp (base, ".", 1))
    {
      base = (char *) malloc (strlen (name));
      strcpy (base, name);
    }

  if (!sf_size)
    sf_size = 1423;
  printf ("\nsplit '%s' into '%s.xx', %i kbytes blocks\n", name, base, sf_size);
  ext_pos = strlen (base) + 1;
  dstname = (char *) malloc (ext_pos + 5);
  strcpy (dstname, base);
  strcat (dstname, ".AA");

  rdptr = fopen (name, "rb");
  if (rdptr == NULL)
    {
      printf ("read error: cannot open '%s'\n", name);
      return (-1);
    }
  else
    {
      while (go_on)
	{
	  parts++;
	  dstname[ext_pos] = (65 + ((parts - 1) / 26));
	  dstname[ext_pos + 1] = (65 + ((parts - 1) % 26));
	  printf ("writing part %d, '%s'\r", parts, dstname);
	  wrtptr = fopen (dstname, "rb");
	  if (wrtptr != NULL)	/* file already exists! */
	    {
	      printf ("file error: '%s' exists, remove it first\n", dstname);
	      return (-1);
	    }
	  wrtptr = fopen (dstname, "wb");
	  if (wrtptr == NULL)	/* disk error */
	    {
	      printf ("write error, cannot write '%s'\n", dstname);
	      return (-1);
	    }

	  for (x = 0; x < sf_size; x++)
	    {
	      len_read = fread (data, 1, 1024, rdptr);
	      len_write = fwrite (data, 1, len_read, wrtptr);

	      if (len_write < len_read)
		{
		  printf ("write error, (part %d) disk full?\n", parts);
		  return (-1);
		}

	      if (len_read < 1024)
		{
		  last_blocks = x;
		  printf ("\nfinished\n");
		  go_on = 0;
		  break; /* leave loop */
		}
	      else
		blocks++;
	    }

	  /* if we read exactly the whole file we dont need another 0-byte part (very unusual)*/ 
	  testbyte = fgetc(rdptr);
	  if (feof (rdptr))
	    {
	      printf("\nfinished - file complete!\n");
	      go_on = 0;
	    }
	  else
	    ungetc(testbyte, rdptr); 
	  fclose (wrtptr);
	}

      file_size = 1024 * blocks + len_read;
      printf ("filename.....: %s\ntotal size...: %d\nparts........: %d\n", name, file_size, parts);
      fclose (rdptr);
      strcpy (dstname, base);
      strcat (dstname, ".SLF");
      wrtptr = fopen (dstname, "r");
      if (wrtptr != NULL) /* file already exists! (normally, we started merge then ?!) */
	{
	  printf ("overwrite old logfile, ");
	  fclose (wrtptr);
	}
      printf ("writing log-file, '%s'\n", dstname);
      wrtptr = fopen (dstname, "w");	/* overwrite it, anyway */
      if (wrtptr == NULL)
	{
	  printf ("write error, cannot write logfile '%s'\n", dstname);
	  return (-1);
	}
      else
	{
	  fprintf (wrtptr, "%s\n", name);
	  fprintf (wrtptr, "size=%d\n", file_size);
	  fprintf (wrtptr, "parts=%d\n", parts);
	  fprintf (wrtptr, "\nwritten by SaM (UNIX)\n");
	  fclose (wrtptr);
	}
    }
}


int merge (char *base, char *name, int log_parts, int log_size)
     /* name=filename, base=basename */
{
  FILE *rdptr;
  FILE *wrtptr;
  int len_read = 0;
  int len_write = 0;
  int total_size = 0;
  char data[1024];
  char *srcname;
  char *dummy = (char *) malloc (255);
  int ext_pos;
  int go_on = 1;
  int parts = 1;
  int last_part = 0;

  /* check existance of file "name" (destination) */
   wrtptr = fopen (name, "rb");
  if (wrtptr != NULL) /* file already exists! */
    {
      printf ("\nfile error: '%s' exists, remove it first\n", name);
      fclose (wrtptr);
   }
  else
    {
      printf ("\nmerge '%s.xx' to '%s'\n", base, name);
      ext_pos = strlen (base) + 1;
      srcname = (char *) malloc (ext_pos + 5);
      wrtptr = fopen (name, "wb"); /* reopen for writing */
      
      while (go_on)
	{     
	  strcpy (srcname, base);
	  strcat (srcname, ".--");
	  srcname[ext_pos] = (65 + ((parts - 1) / 26));
	  srcname[ext_pos + 1] = (65 + ((parts - 1) % 26));
	  /* printf("searching for '%s'..", srcname); */
	  rdptr = fopen (srcname, "rb");
	  if (rdptr == NULL)
	    {
	      printf("'%s' not found", srcname);
	      strcat (srcname, "Z");
	      printf(" searching for '%s'..", srcname);
	      rdptr = fopen (srcname, "rb");
	      if (rdptr == NULL)
		{
		  printf ("'%s' not found - exit\n", srcname);
		  parts--;
		  go_on = 0;
		}
	      else
		{
		  printf("found last part.\n");
		  last_part = 1;
		}
	    }
	  else
	    {
	      /* printf("found\n"); */
	    }

	  if (go_on)
	    {
	      printf ("reading part %d: '%s'", parts, srcname);
	      if (log_parts)
		printf (" parts to read: %d", log_parts - parts);
	      if (log_size)
		printf (" bytes to read: %d", log_size - total_size);
	      printf("\r");
	      
	      while (!feof(rdptr))
		{
		  len_read = fread (data, 1, 1024, rdptr);
		  len_write = fwrite (data, 1, len_read, wrtptr);
		  total_size += len_write;
		  
		  if (len_write < len_read)
		    {
		      printf ("\nwrite error, (part %d) disk full?\n", parts);
		      return (-1);
		    }
		}
	      fclose (rdptr);
	      if (parts == log_parts)
		last_part = 1;
	      if (last_part) 
		go_on = 0;
	      else parts++;
	    }
	}
      fclose (wrtptr);
      printf ("\nfinished, total size = %d bytes, %d parts\n", total_size, parts );
      if (log_parts)
	if (log_parts - parts)
	  printf ("WARNING: number of parts differ: log-file: %d, found: %d\n", log_parts, parts);
	/* else 
	  printf ("number of parts (%d) o.k.\n", parts); */
     if (log_size)
       if (log_size - total_size)
	 printf ("WARNING: filesizes differ: log-file: %d, read: %d\n", log_size, total_size);
	/* else 
	  printf ("filesize (%d bytes) o.k.\n", total_size); */
    }
}
      

void check (char *cl_src, char *cl_dst, char *cl_opt) 
{
  int sam_mode = 0;
  char *src_name;
  char *dst_name = (char *) malloc (255);

  char dummy [128];
  char *log_dst_name = (char*) malloc (255);
  int log_file_size;
  int log_parts;

  int opt_value = 0;
  int ext_pos; 
  FILE *rdptr;

  ext_pos = strlen (cl_src) + 1;
  src_name = (char *) malloc (ext_pos + 5);

  /* try to read logfile */
  strcpy (src_name, cl_src);
  strcat (src_name, ".SLF");
  rdptr = fopen (src_name, "r");
  if (rdptr == NULL)
	{
	  strcpy (src_name, cl_src);
	  strcat (src_name, ".LOG");
	  rdptr = fopen (src_name, "r");
	}
  if (rdptr != NULL)
    {
      printf ("\nreading log-file, '%s'\n", src_name);
      fscanf (rdptr, "%s\n", log_dst_name);
      fscanf (rdptr, "size=%s\n", dummy);
      log_file_size = atoi (dummy);
      fscanf (rdptr, "parts=%s\n", dummy);
      log_parts = atoi (dummy);
      printf ("filename.....: %s\ntotal size...: %d\nparts........: %d\n", log_dst_name, log_file_size, log_parts);
      fclose (rdptr);
      if (!log_parts || !log_file_size)
	{
	  printf ("invalid logfile\n");
	}
      else 
	{
	  if (!cl_dst) 
	    dst_name = log_dst_name;
	  else
	    if (!strncmp (cl_dst, ".", 1))
	      {
		dst_name = cl_src;
		printf ("using '%s' instead of '%s'\n", dst_name, log_dst_name);
	      }
	    else
	      dst_name = cl_dst;
	  merge (cl_src, dst_name, log_parts, log_file_size);
	}
    }
  else
    {
      printf ("no logfile '%s'\n", src_name);
      /* try to find .AA-file */
    
      strcpy (src_name, cl_src);
      strcat (src_name, ".AA");
      rdptr = fopen (src_name, "r");
      if (rdptr != NULL)
	{
	  printf("found file '%s', trying to merge it\n", src_name );
	  if (!cl_dst || !strncmp (cl_dst, ".", 1))
	    dst_name = cl_src;
	  else
	    dst_name = cl_dst;
	  printf ("destination-file: '%s'\n", dst_name);
	  if (cl_opt)
	    {
	      opt_value = atoi(cl_opt);
	      if (opt_value) 
		printf("expecting to find %d parts\n", opt_value);
	    }
	  merge (cl_src, dst_name, opt_value, 0);
	}
      else
	{
	  printf ("no splitted file '%s'\n", src_name);
	  /* try to split a file */
	  
	  rdptr = fopen (cl_src, "rb");
	  if (rdptr != NULL)
	    {
	      printf("found file '%s', going to split it\n", cl_src);
	      if (!cl_dst || !strncmp (cl_dst, ".", 1))
		dst_name = cl_src;
	      else
		dst_name = cl_dst;
	      printf ("destination-file(s): '%s'.xx\n", dst_name);
	      if (cl_opt)
		{
		  opt_value = atoi(cl_opt);
		  if (opt_value) 
		    printf("splitting file into %d kbytes parts\n", opt_value);
		}
	      split (cl_src, dst_name, opt_value);
	    }
	  else
	    {
	      printf("no file '%s'\nseems there is nothing to do for me...\n", cl_src);
	    }
	}
    }
}


int main (int argc, char *argv[])
{
  char *sourcename = NULL;
  char *destname = NULL;
  char *extra_opt = NULL;
  
  if ((argc < 2) || (!strncmp (argv[1], "-h", 2)) || (!strncmp (argv[1], "?", 1)))
    {
      printf ("\nSaM - Split and Merge files   (einhorn@rvs.uni-hannover.de)   V.970410\n");
      printf ("\nusage: %s <input-file> [<output-file>] [<value>]\n", argv[0]);
      printf ("\nsplit: <input-file> is splitted to <output-file>.XX in <value>(KBytes) blocks");
      printf ("\n       if <output-file> is omitted or begins with \".\" <input-file> is taken");
      printf ("\n       if <value> is omitted, 1423 KBytes are used (for 1.44 MB disks)\n");
      printf ("\nmerge: <input-name> is basename for .SLF/.LOG or .XX-files");
      printf ("\n       <output-file> overwrites destination name in logfile ");
      printf ("\n       <value> is optional for the number of parts (no logfile)\n");
      printf ("\nfiles will not be overwritten, please remove them first.");
      printf ("\na file named \"<base>.SLF\", \"<base>.LOG\" or \"<base>.AA\" cannot be splitted.\n");

      return (200);
    }
  else
    {
      if (argc > 1)
	sourcename = argv[1];
      if (argc > 2)
	destname = argv[2];
      if (argc > 3)
	extra_opt = argv[3];
      check (sourcename, destname, extra_opt);
    }
  
}







