/*

  Splitter 3.02

  This program can split files into several portions with a defined
  size or into a defined number of portions and can join them together
  again. It's main purpose is to write larger files and especially
  archives to disks. It was designed to compile under ANSI C and with
  some small modifications even under K&R C, and thus to run on any
  system which supports these.

  Version 1.0  on 18-October-1993   First reliable version.
  Version 1.1  on 18-October-1993   Replaced fclose()/fopen() by rewind().
  Version 1.2  on 24-November-1993  Works now with MSDOS systems;
				    uses a buffer for join.
  Version 1.21 on 25-November-1993  Removed a small bug in the output.
  Version 2.0  on 22-September-1994 Added default sizes for filesystems.
				    Uses Buffer for read/write. Uses fileheader
				    for recognition and restauration.
  Version 2.1  on 31-March-1995	    Options -r (splitted portion range, only
				    with -p and -s) and -f (force overwrite)
				    added. Bug removed when allocating smaller
				    buffer. Multivolume joining enhanced.
  Version 3.0  on 22-February-1996  Complete rewrite. Enhanced command line
				    parsing. Joining and multivolume via
				    command name.
  Version 3.01 on 27-February-1996  Removed bug in splitpath generation.
  Version 3.02 on 5-March-1996	    Removed another small bug in splitpath
				    generation. Cleaned up usage info.
				    Removed bug with empty files.

  This program was developed on an Amiga 1200 with the SAS/C development system
  and the GNU emacs editor, the UNIX adaptions were written on a Linux PC with
  gcc and emacs.

  Usage:
   Splitter [-n] [-d] [-l] [-m] [-g] [-f] [-q] [-j {<sources>} <destination>]
     [-h] [[-p <n>] [-s <n>[k|m]] [-s <disktype>] [-r <s> [<e>]] <file> <dir>]

   Joiner [-h] [-d] [-n] [-m] [-g] [-f] {<sources>} <destination>

    file	the file to be splitted.
    dir		directory where to put the splitted parts.
    sources	source directories and files.
    destination destination path for joined file.
    -h		show help.
    -n		write/expect no header.
    -d		MSDOS filename option: eight characters without dot.
    -l		long filenames; resets the MSDOS switch.
    -m		multivolume split/join; pause after each file.
    -g		go ahead; resets the multivolume switch.
    -f		overwrite existing files without asking (force).
    -q		ask before overwriting files (query).
    -j		join splitted parts.
    -p		split into <n> portions.
    -s		split into portions of <n> bytes size each.
    -r		extract only portions in the range from s(tart) to e(nd).

  General:
   To get from Splitter, type the option "-h". Without options, Splitter
   will will do the standard action depending on the command name. If the
   command name contains the string "join" or "Join", splitter will react
   as if called with the option "-j". Otherwise it will split <source> to
   portions with the size of the first file system. If the command name
   contains "m" or "M", the multivolume option will be set automatically.
   If Splitter is compiled for a MSDOS platform, the MSDOS option is set.
   If the macro FORCE is defined, files are overwritten by default.
   To compile this program on a UNIX platform, the macro UNIX must be
   defined; for MSDOS computers, the MSDOS macro must be defined; the AMIGA
   macro is normally set by the compiler on the Amiga. The strings in
   the text define section may be changed to another language (or better
   english.. :-). If you do so, please let me have these.

  Splitting:
   There are two different approaches to split a file. The one produces
   the requested number of portion files with the same size each. Use
   "-p <n>" as options for this. The other produces several portions of
   the requested size. The size may be given directly in bytes, kbytes
   or mbytes. Use "-s <n>[k|m]" for this. Or it may be given as the
   destination disk type. Use option "-s <disktype>", where disktype may
   be any one of the filesystem sizes as listed by the option "-h". If
   no option is specified, the file is splitted as though <disktype> had
   beed set to the first in the list. <source> ist the path of the source
   file, <dir> is the path of the (optional) destination directory. The
   option "-d" makes the destination filenames msdos compliant. If "-n"
   is given, no header is written, the portions may be joined then by
   AmigaDOS' Join or unix' cat command. "-r <s> [<e>]" extracts only the
   portion <s> or the prtions <s> to <e>. "-m" lets Splitter pause before
   writing each portion so that a removable medium may be changed. If
   "-f" is specified, Splitter overwrites files without asking.

  Joining:
   Calling Splitter with a name that contains the word 'join' (i.e. via
   softlink) or with the option "-j" will create the original file from
   the portions. If the destination file name is given, only one source
   directory is required. This and any further source directory is scanned
   for the needed portions, and any source file is checked if it is a
   portion. If the destination is a directory at least one source file
   must be given. The destination file name is then derived from the
   header or from this file's name if no header can be found. The option
   "-d" makes Splitter look for source files with msdos compliant filenames.
   "-m" lets Splitter pause before reading the next directory. The option
   "-f" makes Splitter overwrite files without asking. If "-n" is given,
   Splitter does not look for headers.

DISCLAIMER:
  I am in no way responsible for any problems that arise directly or
  indirectly from the use of this program.

Copyright notice:
  This is freeware. You may give this program to anyone you like and
  upload it to any mailbox, bulletin board or software server or include
  it on any public domain distribution on disk or on CD-ROM as long as
  you charge only a small fee for medium and copy and leave this file as
  it is. But you may not use this program for commercial purposes without
  prior written permission from me. You may not distribute changed
  versions of this program.
  If you have any ideas how to improve this program, please mail
  them to me. My mail address is included in the info #define.

The author:
  I'm a student of computer science at the university of Tuebingen,
  Germany. If you like this program, please let me know. This program
  was intentionally made freeware. If you have written some shareware
  program, be so kind to let me have it for free if you use Splitter
  frequently.
  Please feel free to mail me any ideas concerning this program.

My address:
  Martin Schlodder
  Uhlandstr. 18
  D-72336 Balingen

EMAIL:
  schlodder@student.uni-tuebingen.de
*/

/*
  Select the appropriate #define statement or use the define compiler
  option to choose the system on which you want to compile this source.
  These defines are neccessary to select the right path seperators.
  If you know any more file systems, please mail their path rules to
  me and i will include them.
#define AMIGA
#define MSDOS
#define UNIX
*/

/*
  Some more filesystems for the Amiga may be enabled by the following:
#define AMIFS      Amiga file systems
#define AMIDC      AmigaOS 3.0 DirCache file system
#define AMIPFS     PFS file system
#define AMIDS      DiskSpare device
*/

/*
  If FORCE is defined, Splitter does not ask before overwriting files
  by default.
#define FORCE
*/

/*
  If DBUG is defined, each function will print it's arguments.
#define DBUG
*/

/*
  The following #define block contains every text printed by Splitter.
  The messages are collected to make translation easier.
*/
/*
  Info is printed if the -h option is set.
*/
#define info1 "\nSplitter V3.02 on March 5, 1996\n\
(c)1993-1996 by Martin Schlodder\n\n"
#define info1s info1 "\
Usage: %s [-n] [-d] [-l] [-m] [-g] [-f] [-q] [-j {<sources>} <destination>]\n\
  [-h] [[-p <n>] [-s <n>[k|m]] [-s <disktype>] [-r <s> [<e>]] <file> <dir>]\n\
 file\t\tthe file to be splitted.\n\
 dir\t\tdirectory where tp put the splitted parts.\n\
 sources\tsource directories and files.\n\
 destination\tdestination path for joined file.\n\
 -h\t\tshow this help page.\n\
 -n\t\twrite/expect no header.\n\
 -d\t\tMSDOS filename option: eight chars without dot.\n\
 -l\t\tlong filenames; resets the MSDOS switch.\n\
 -m\t\tmultivolume split/join; pause after each file.\n\
 -g\t\tgo ahead; resets the multivolume switch.\n\
 -f\t\toverwrite existing files fithout asking (force).\n\
 -q\t\task before overwriting files (query).\n\
 -j\t\tjoin splitted parts.\n\
 -p\t\tsplit into <n> portions.\n\
 -s\t\tsplit into portions of <n> [k|m]bytes size each.\n\
 -r\t\textract only portions in the range from s(tart) to e(end).\n\
If neither -j nor -p nor -s are set, Splitter will create portions of\n\
the size from the first line of the list below.\n\n\
[Press <Return> to continue]"
#define info1j info1 "\
Usage: %s [-h] [-n] [-d] [-l] [-m] [-g] [-f] [-q] {<sources>} <destination>\n\
 sources\tsource directories and files.\n\
 destination\tdestination path for joined file.\n\
 -h\t\tshow this help page.\n\
 -n\t\twrite/expect no header.\n\
 -d\t\tMSDOS filename option: eight chars without dot.\n\
 -l\t\tlong filenames; resets the MSDOS switch.\n\
 -m\t\tmultivolume split/join; pause after each file.\n\
 -g\t\tgo ahead; resets the multivolume switch.\n\
 -f\t\toverwrite existing files fithout asking (force).\n\
 -q\t\task before overwriting files (query).\n"
#define info2 "\nFile system sizes:  (for <disktype>)"
#define main_fs " %-12s - %7d bytes - %s."
#define main_end "\n\
Address:\n\
 Martin Schlodder\n\
 Uhlandstr. 18\n\
 D-72336 Balingen\n\n\
Internet:\n\
 schlodder@zdv.uni-tuebingen.de\n"

/*
  This text is shown before waiting for a key press when the -w option is set.
*/
#define make_multi_part "Please insert volume and press <Return>"

/*
  This text is shown when a file will be overwritten and the -q option is set.
  The key definition is the positive answer (overwrite).
*/
#define query_overwrite_a "Overwrite file \"%s\"? [y(es)|n(o)|a(ll)] "
#define query_overwrite "Overwrite file \"%s\"? [y(es)|n(o)] "
#define query_yes 'y'
#define query_all 'a'

/*
  These texts are used to print the success message after joining.
*/
#define join_heads "Headers found."
#define join_Joined "Joined \"%s\""
#define join_file ", \"%s\""
#define join_to " to \"%s\"."
#define multi_join "Joined one portion to \"%s\"."
#define multi_join_n "Joined %d portions to \"%s\"."

/*
  These texts are used to print the success message after splitting.
*/
#define split_Splitted "Splitted \"%s\" into "
#define split_portion "one portion of %d bytes."
#define split_portions "%d portions of %d bytes."
#define split_portion_and "one portion of %d bytes and\none portion of %d bytes."
#define split_portions_and "%d portions of %d bytes and\none portion of %d bytes."
#define split_Extract "Extracted portions %d to %d."
#define split_Extract_one "Extracted portion %d."

/*
  These are the error messages.
*/
#define err_bad_dest "Destination must be a directory."
#define err_bad_file "Bad file name definition."
#define err_bad_files "No portions found."
#define err_bad_num "Bad number specification for option '-p'."
#define err_bad_range "Range parameters illegal."
#define err_bad_size "Bad size specification for option '-s'."
#define err_file_empty "Source file is empty."
#define err_no_args "Need a file name to split. Type '%s -h' for help."
#define err_no_file "Need a file name."
#define err_no_files "Destination path or portion paths must contain a filename."
#define err_no_mem "Not enough memory."
#define err_no_name "The source files must have a splitter format name\nif joining portions without header."
#define err_no_portion "Can't find any files to join."
#define err_no_source "Need a source directory or source files to join."
#define err_open_dest "Couldn't open \"%s\" as destination."
#define err_open_dir "Could't read directory \"%s\"."
#define err_open_source "Couldn't open \"%s\" as source."
#define err_portion_missing "Can't find portion %d."
#define err_read "Error while reading."
#define err_read_head "Error while reading header."
#define err_seek "Error while seeking file."
#define err_unknown_option "Unknown option '-%c'."
#define err_write "Error while writing."
#define err_write_abort "File not overwritten. Execution aborted."
#define err_write_head "Error while writing header."
#define err_wrong_portion "Portion number differs from header number."

/*
  These are the warning messages.
*/
#define warn_size "WARNING! Source file size changed."
#define warn_t_size "WARNING! Destination file size changed."
#define warn_files_missing "WARNING! Some portions are missing."
#define warn_n_files_missing "WARNING! %d portions are missing."
#define warn_one_file_missing "WARNING! One portion is missing."
#define warn_wrong_portion "WARNING! Wrong portion in source file list."

/*
  These are the known file systems.
*/
struct fs_item
{
  char *name;
  unsigned long size;
  char *desc;
}fs[]={
  {"msd-dd",730112,"MSDOS Double Density Disk"},
  {"msd-hd",1457664,"MSDOS High Density Disk"},
#ifdef AMIFS
  {"amiofs-dd",844240,"Amiga Double Density Disk, OldFileSystem"},
  {"amiofs-hd",1691408,"Amiga High Density Disk, OldFileSystem"},
  {"amiffs-dd",885760,"Amiga Double Density Disk, FastFileSystem"},
  {"amiffs-hd",1774592,"Amiga High Density Disk, FastFileSystem"},
#ifdef AMIDC
  {"amiofsdc-dd",843752,"Amiga Double Density Disk, OldFileSystem, DirCache"},
  {"amiofsdc-hd",1690920,"Amiga High Density Disk, OldFileSystem, DirCache"},
  {"amiffsdc-dd",884736,"Amiga Double Density Disk, FastFileSystem, DirCache"},
  {"amiffsdc-hd",1774080,"Amiga High Density Disk, FastFileSystem, DirCache"},
#endif
#ifdef AMIPFS
  {"amipfs-dd",896512,"Amiga Double Density Disk, ProfFileSystem"},
  {"amipfs-hd",1797632,"Amiga High Density Disk, ProfFileSystem"},
#endif
#ifdef AMIDS
  {"amidsofs-dd",844240,"Amiga Double Density Disk, DiskSpare, OldFileSystem"},
  {"amidsofs-hd",1691408,"Amiga High Density Disk, DiskSpare, OldFileSystem"},
  {"amidsffs-dd",885760,"Amiga Double Density Disk, DiskSpare, FastFileSystem"},
  {"amidsffs-hd",1774592,"Amiga High Density Disk, DiskSpare, FastFileSystem"},
#ifdef AMIDC
  {"amidsofsdc-dd",843752,"Amiga Double Density Disk, DiskSpare, OldFileSystem, DirCache"},
  {"amidsofsdc-hd",1690920,"Amiga High Density Disk, DiskSpare, OldFileSystem, DirCache"},
  {"amidsffsdc-dd",884736,"Amiga Double Density Disk, DiskSpare, FastFileSystem, DirCache"},
  {"amidsffsdc-hd",1774080,"Amiga High Density Disk, DiskSpare, FastFileSystem, DirCache"},
#endif
#ifdef AMIPFS
  {"amidspfs-dd",1003008,"Amiga Double Density Disk, DiskSpare, ProfFileSystem"},
  {"amidspfs-hd",2010624,"Amiga High Density Disk, DiskSpare, ProfFileSystem"},
#endif
#endif
#endif
};

/*
  The maximal length of an input string:
*/
#define STRMAX 256

/*
  Standard includes.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>

/*
  Each file is preceded with a fileheader (if the -n option was not set)
  consisting of the following structure:
*/
#define hd_magic "Splitter"
#define hd_name (8+4+8+4+8+1)
#define hd_namesize 31
struct header{
  short number;
  unsigned long size;
  short tnumber;
  unsigned long tsize;
  char name[hd_namesize];
};
#define hd_size (hd_name+hd_namesize) 

/*
  This is the version information for the Amiga's shell command 'Version'.
*/
#ifdef AMIGA
char *amiga_version="$VER: Splitter 3.02 (5.3.96)   ©1993-1996 by Martin Schlodder";
#endif

/*
  The only global variables are some status flags, the range parameters
  and a string buffer.
*/
int rstart,rend,msdos,head,multi,query;
char buf[STRMAX];

/*
  int WriteHead(FILE *fh,header *hd)
    fh:       File handle.
    hd:       Pointer to header structure.
    returns:  Nonzero if error occurs.
  This function writes the header from the the structure hd into the file fh. 
*/
int WriteHead(FILE *fh,struct header *hd){
  char hdbuf[hd_size];
#ifdef DBUG
  printf("\nWriteHead($%08X,{%d,%lu,%d,%lu,\"%s\"});\n",fh,hd->number,hd->size,hd->tnumber,hd->tsize,hd->name);
#endif
  sprintf(hdbuf,"%s%4X%8X%4X%8X ",hd_magic,hd->number,hd->size,hd->tnumber,hd->tsize);
  memcpy(hdbuf+hd_name,hd->name,hd_namesize);
  if(fwrite(hdbuf,1,hd_size,fh)!=hd_size)
    return(1);
  return(0);
}

/*
  int ReadHead(FILE *fh,header *hd)
    fh:       File handle.
    hd:       Pointer to header structure.
    returns:  Nonzero if error occurs.
  This function reads the header from the file fh into the structure hd.
*/
int ReadHead(FILE *fh,struct header *hd){
  char buf[hd_size];
#ifdef DBUG
  printf("\nReadHead($%x,$%x);\n",fh,hd);
#endif
  if(fread(buf,1,hd_size,fh)!=hd_size){
#ifdef DBUG
    puts("\nReadHead() -> 1");
#endif
    return(1);
  }
  if(4!=sscanf(buf,hd_magic "%4hx%8lx%4hx%8lx ",&hd->number,&hd->size,&hd->tnumber,&hd->tsize)){
#ifdef DBUG
    puts("\nReadHead() -> 1");
#endif
    return(1);
  }
  memcpy(hd->name,buf+hd_name,hd_namesize);
#ifdef DBUG
  printf("\nReadHead() -> 0   hd: {%d,%lu,%d,%lu,\"%s\"}\n",hd->number,hd->size,hd->tnumber,hd->tsize,hd->name);
#endif
  return(0);
}

/*
  Join(char *dest,char *paths[],int num)
    dest:     Destination path or empty string.
    paths:    Array of source paths.
    num:      Number of source paths.
  Global:
    msdos:    -use-  Filenames of portions are supposed to be MSDOS
                     compatible (eight characters, no dots).
    head:     -use-  Try to find header.
    query:    -use-  Ask before overwriting existing files.
    multi:    -use-  Join from multiple volumes using MultiJoin().
  Calls:
    ReadHead: Read header from portion file.
  Join() joins the portions to the original file. Dest is a directory or
  file, paths is NULL if num is 0. Frees 'paths' allocated by main().
*/
void Join(char *dest,char **paths,int num){
  int i,j,k,fnum,dnum,dir,tnum,chunks;
  unsigned long tsize,size,asize,read,written,twritten;
  int *isdir,*findex,*jindex;
  char *sbuf,*tbuf,*dfile,*pos,*name;
  char **sfiles,**files, **dirs;
  FILE *source,*dhand;
  DIR *dfd;
  struct header hd;
#ifdef DBUG
  printf("\nJoin(\"%s\",({",dest);
  for(i=0;i<num-1;i++)
    printf("\"%s\",",paths[i]);
  if(num)
    printf("\"%s\"",paths[i]);
  printf("}),%d);   Uses: multi(%s), head(%s), query(%s), msdos(%s)\n",num,multi?"TRUE":"FALSE",head?"TRUE":"FALSE",query?"TRUE":"FALSE",msdos?"TRUE":"FALSE");
#endif
  dir=0;
  if(!num){
    puts(err_no_source);
    free(paths);
    exit(EXIT_FAILURE);
  }
  if(dfd=opendir(dest)){
    closedir(dfd);
    dir=1;
  }
  if(!(isdir=(int *)malloc(num*sizeof(int)))){
    puts(err_no_mem);
    free(paths);
    exit(EXIT_FAILURE);
  }
  for(i=dnum=0;i<num;i++)
    if(dfd=opendir(paths[i])){
      closedir(dfd);
      isdir[i]=1;
      dnum++;
    }
    else
      isdir[i]=0;
  fnum=num-dnum;
  files=dirs=0;
  if(dnum && !(dirs=(char **)malloc(dnum*sizeof(char *)))){
    puts(err_no_mem);
    free(paths);
    free(isdir);
    exit(EXIT_FAILURE);
  }
  if(fnum && !(files=(char **)malloc(fnum*sizeof(char *)))){
    puts(err_no_mem);
    free(paths);
    free(isdir);
    free(dirs);
    exit(EXIT_FAILURE);
  }
  for(i=dnum=fnum=0;i<num;i++)
    if(isdir[i])
      dirs[dnum++]=paths[i];
    else
      files[fnum++]=paths[i];
  free(paths);
  free(isdir);
  size=0;
  tnum=0;
  if(fnum){
    if(!(findex=(int *)malloc(fnum*sizeof(int)))){
      puts(err_no_mem);
      free(files);
      if(dnum)
	free(dirs);
      exit(EXIT_FAILURE);
    }
    if(!(source=fopen(files[0],"rb"))){
      printf(err_open_source "\n",files[0]);
      free(findex);
      free(files);
      if(dnum)
	free(dirs);
      exit(EXIT_FAILURE);
    }
    if(head && ReadHead(source,&hd))
      head=0;
    if(head){
      size=hd.size>size?hd.size:size;
      findex[0]=hd.number;
    }
    else{
      if(fseek(source,0L,SEEK_END)){
	puts(err_seek);
	fclose(source);
	free(findex);
	free(files);
	if(dnum)
	  free(dirs);
	exit(EXIT_FAILURE);
      }
      size=(asize=ftell(source))>size?asize:size;
    }
    fclose(source);
    for(i=1;i<fnum;i++){
      if(!(source=fopen(files[i],"rb"))){
	printf(err_open_source "\n",files[i]);
	free(findex);
	free(files);
	if(dnum)
	  free(dirs);
	exit(EXIT_FAILURE);
      }
      if(head){
	if(ReadHead(source,&hd)){
	  puts(err_read_head);
	  fclose(source);
	  free(findex);
	  free(files);
	  if(dnum)
	    free(dirs);
	  exit(EXIT_FAILURE);
	}
	size=hd.size>size?hd.size:size;
	findex[i]=hd.number;
      }
      else{
	if(fseek(source,0L,SEEK_END)){
	  puts(err_seek);
	  fclose(source);
	  free(findex);
	  free(files);
	  if(dnum)
	    free(dirs);
	  exit(EXIT_FAILURE);
	}
	size=(asize=ftell(source))>size?asize:size;
      }
      fclose(source);
    }
    if(head){
      tnum=hd.tnumber;
      tsize=hd.tsize;
    }
    else{
      for(i=0;i<fnum;i++)
	tnum=(findex[i]=atoi(files[i]+strlen(files[i])-3))>tnum?findex[i]:tnum;
    }
    if(!(jindex=(int *)calloc(tnum,sizeof(int)))){
      puts(err_no_mem);
      free(findex);
      free(files);
      if(dnum)
	free(dirs);
      exit(EXIT_FAILURE);
    }
    for(i=0;i<tnum;i++)
      for(j=0;j<fnum;j++)
	if(findex[j]==i+1){
	  jindex[i]=j+1;
	  break;
	}
    free(findex);
    if(dir){
#ifndef UNIX
      if(i=strlen(dest)){
#ifdef AMIGA
	if(dest[--i]=='/' || dest[i]==':')
	  j=0;
#else
	if(dest[--i]=='\\' || dest[i]==':')
	  j=0;
#endif
	else
	  j=1;
      }
      else
	j=0;
      if(head){
	if(!(dfile=(char *)malloc(strlen(hd.name)+strlen(dest)+j+1))){
	  puts(err_no_mem);
	  free(jindex);
	  free(files);
	  if(dnum)
	    free(dirs);
	  exit(EXIT_FAILURE);
	}
#ifdef AMIGA
	sprintf(dfile,"%s%s%s",dest,j?"/":"",hd.name);
#else
	sprintf(dfile,"%s%s%s",dest,j?"\\":"",hd.name);
#endif
      }
      else{
#ifdef AMIGA
	if(!(pos=strrchr(files[0],'/')) && !(pos=strrchr(files[0],':')))
	  pos=files[0];
#else
	if(!(pos=strrchr(files[0],'\\')) && !(pos=strrchr(files[0],':')))
	  pos=files[0];
#endif
	if(!(dfile=(char *)malloc(strlen(pos)+strlen(dest)+j-3))){
	  puts(err_no_mem);
	  free(jindex);
	  free(files);
	  if(dnum)
	    free(dirs);
	  exit(EXIT_FAILURE);
	}
#ifdef AMIGA
	sprintf(dfile,"%s%s%.*s",dest,j?"/":"",strlen(pos)-4,pos);
#else
	sprintf(dfile,"%s%s%.*s",dest,j?"\\":"",strlen(pos)-4,pos);
#endif
      }
#else
      if(head){
	if(!(dfile=(char *)malloc(strlen(hd.name)+strlen(dest)+1))){
	  puts(err_no_mem);
	  free(jindex);
	  free(files);
	  if(dnum)
	    free(dirs);
	  exit(EXIT_FAILURE);
	}
	sprintf(dfile,"%s/%s",dest,hd.name);
      }
      else{
	if(!(pos=strrchr(files[0],'/')))
	  pos=files[0];
	if(!(dfile=(char *)malloc(strlen(pos)+strlen(dest)-3))){
	  puts(err_no_mem);
	  free(jindex);
	  free(files);
	  if(dnum)
	    free(dirs);
	  exit(EXIT_FAILURE);
	}
	sprintf(dfile,"%s/%.*s",dest,strlen(pos)-4,pos);
      }
#endif
    }
    else
      dfile=dest;
  }
  else{
    if(dir){
      puts(err_no_files);
      free(dirs);
      exit(EXIT_FAILURE);
    }
    dfile=dest;
  }
  if(query && (dhand=fopen(dfile,"rb"))){
    fclose(dhand);
    printf(query_overwrite,dfile);
    gets(buf);
    if(buf[0]!=query_yes){
      puts(err_write_abort);
      if(fnum){
	free(jindex);
	free(files);
      }
      if(dnum)
	free(dirs);
      exit(EXIT_FAILURE);
    }
  }
  if(fnum && head){
    if(!(name=(char *)malloc(strlen(hd.name)+1))){
      puts(err_no_mem);
      free(jindex);
      free(files);
      if(dnum)
	free(dirs);
      if(dir)
	free(dfile);
      exit(EXIT_FAILURE);
    }
    strcpy(name,hd.name);
  }
  else{
#ifdef AMIGA
    if((pos=strrchr(dfile,'/')) || (pos=strrchr(dfile,':')))
      pos++;
#endif
#ifdef MSDOS
    if((pos=strrchr(dfile,'\\')) || (pos=strrchr(dfile,':')))
      pos++;
#endif
#ifdef UNIX
    if(pos=strrchr(dfile,'/'))
      pos++;
#endif
    else
      pos=dfile;
    if(!(name=(char *)malloc(strlen(pos)+1))){
      puts(err_no_mem);
      if(fnum){
	free(jindex);
	free(files);
      }
      if(dnum)
	free(dirs);
      if(dir)
	free(dfile);
      exit(EXIT_FAILURE);
    }
    strcpy(name,pos);
  }
  if(msdos){
    if(pos=strchr(name,'.'))
      pos[0]='\0';
    if(strlen(name)>8)
      name[8]='\0';
  }
  if(dnum){
    if(!(sfiles=(char **)malloc(dnum*sizeof(char *)))){
      puts(err_no_mem);
      free(name);
      if(fnum){
	free(jindex);
	free(files);
      }
      free(dirs);
      if(dir)
	free(dfile);
      exit(EXIT_FAILURE);
    }
    for(i=0;i<dnum;i++){
#ifndef UNIX
      if(k=strlen(dirs[i])){
#ifdef AMIGA
	if(dirs[i][--k]=='/' || dirs[i][k]==':')
	  j=0;
#else
	if(dirs[i][--k]=='\\' || dirs[i][k]==':')
	  j=0;
#endif
	else
	  j=1;
      }
      else
	j=0;
      if(!(sfiles[i]=(char *)malloc(strlen(dirs[i])+j+strlen(name)+1))){
	puts(err_no_mem);
	free(name);
	for(j=0;j<i;j++)
	  free(sfiles[j]);
	free(sfiles);
	if(fnum){
	  free(jindex);
	  free(files);
	}
	free(dirs);
	if(dir)
	  free(dfile);
	exit(EXIT_FAILURE);
      }
#ifdef AMIGA
      sprintf(sfiles[i],"%s%s%s",dirs[i],j?"/":"",name);
#else
      sprintf(sfiles[i],"%s%s%s",dirs[i],j?"\\":"",name);
#endif
#else
      if(!(sfiles[i]=(char *)malloc(strlen(dirs[i])+strlen(name)+2))){
	puts(err_no_mem);
	free(name);
	for(j=0;j<i;j++)
	  free(sfiles[j]);
	free(sfiles);
	if(fnum){
	  free(jindex);
	  free(files);
	}
	free(dirs);
	if(dir)
	  free(dfile);
	exit(EXIT_FAILURE);
      }
      sprintf(sfiles[i],"%s/%s",dirs[i],name);
#endif
    }
    free(dirs);
  }
  if(!fnum){
    if(multi){
      puts(make_multi_part);
      gets(buf);
    }
    for(i=0;i<dnum;i++){
      if(!(sbuf=malloc(strlen(sfiles[i])+5))){
	puts(err_no_mem);
	free(name);
	for(i=0;i<dnum;i++)
	  free(sfiles[i]);
	free(sfiles);
	exit(EXIT_FAILURE);
      }
      sprintf(sbuf,"%s.001",sfiles[i]);
      if(source=fopen(sbuf,"rb"))
	break;
      free(sbuf);
    }
    free(sbuf);
    if(!source){
      puts(err_no_portion);
      free(name);
      for(i=0;i<dnum;i++)
	free(sfiles[i]);
      free(sfiles);
      exit(EXIT_FAILURE);
    }
    if(head && ReadHead(source,&hd))
      head=0;
    if(head){
      tnum=hd.tnumber;
      tsize=hd.tsize;
      size=hd.size;
    }
    else{
      tnum=1;
      if(fseek(source,0L,SEEK_END)){
	puts(err_seek);
	fclose(source);
	free(name);
	for(i=0;i<dnum;i++)
	  free(sfiles[i]);
	free(sfiles);
	exit(EXIT_FAILURE);
      }
      size=ftell(source);
    }
    fclose(source);
  }
  if(!(dhand=fopen(dfile,"wb"))){
    printf(err_open_dest "\n",dfile);
    free(name);
    if(dnum){
      for(i=0;i<dnum;i++)
	free(sfiles[i]);
      free(sfiles);
    }
    if(fnum){
      free(jindex);
      free(files);
    }
    if(dir)
      free(dfile);
    exit(EXIT_FAILURE);
  }
  if(!size){
    puts(err_file_empty);
    free(name);
    if(dnum){
      for(i=0;i<dnum;i++)
	free(sfiles[i]);
      free(sfiles);
    }
    if(fnum){
      free(jindex);
      free(files);
    }
    if(dir)
      free(dfile);
    exit(EXIT_FAILURE);
  }
  if(!(tbuf=(char *)malloc(asize=size))){
    while(asize>10000 && !tbuf)
      tbuf=(char *)malloc(asize=(asize+1)/2);
    if(!tbuf){
      puts(err_no_mem);
      fclose(dhand);
      free(name);
      if(dnum){
	for(i=0;i<dnum;i++)
	  free(sfiles[i]);
	free(sfiles);
      }
      if(fnum){
	free(jindex);
	free(files);
      }
      if(dir)
	free(dfile);
      exit(EXIT_FAILURE);
    }
  }
  chunks=(size+asize-1)/asize;
  if(!multi && head)
    puts(join_heads);
  for(i=0,twritten=0;!head||i<tnum;i++){
    if(fnum && i<tnum && (j=jindex[i])>0){
      if(!(source=fopen(files[j-1],"rb"))){
	printf(err_open_source "\n",files[j-1]);
	fclose(source);
	fclose(dhand);
	free(tbuf);
	free(name);
	if(dnum){
	  for(i=0;i<dnum;i++)
	    free(sfiles[i]);
	  free(sfiles);
	}
	free(jindex);
	free(files);
	if(dir)
	  free(dfile);
	exit(EXIT_FAILURE);
      }
      if(!multi)
	if(i)
	  printf(join_file,files[j-1]);
	else
	  printf(join_Joined,files[j-1]);
      if(head && ReadHead(source,&hd)){
	puts(err_read_head);
	fclose(source);
	fclose(dhand);
	free(tbuf);
	free(name);
	if(dnum){
	  for(i=0;i<dnum;i++)
	    free(sfiles[i]);
	  free(sfiles);
	}
	free(jindex);
	free(files);
	if(dir)
	  free(dfile);
	exit(EXIT_FAILURE);
      }
    }
    else{
      if(!dnum){
	if(!head && i>=tnum)
	  break;
	printf("\n" err_portion_missing "\n",i+1);
	fclose(dhand);
	free(tbuf);
	free(name);
	free(jindex);
	free(files);
	if(dir)
	  free(dfile);
	exit(EXIT_FAILURE);
      }
      if(multi && (i||fnum)){
	puts(make_multi_part);
	gets(buf);
      }
      for(j=0;j<dnum;j++){
	if(!(sbuf=malloc(strlen(sfiles[j])+5))){
	  puts(err_no_mem);
	  fclose(dhand);
	  free(tbuf);
	  free(name);
	  for(i=0;i<dnum;i++)
	    free(sfiles[i]);
	  free(sfiles);
	  if(fnum){
	    free(jindex);
	    free(files);
	  }
	  if(dir)
	    free(dfile);
	  exit(EXIT_FAILURE);
	}
	sprintf(sbuf,"%s.%03d",sfiles[j],i+1);
	if(source=fopen(sbuf,"rb"))
	  break;
	free(sbuf);
      }
      if(source && !multi)
	if(i)
	  printf(join_file,sbuf);
	else
	  printf(join_Joined,sbuf);
      free(sbuf);
      if(!source){
	if(!head && i>=tnum)
	  break;
	printf("\n" err_portion_missing "\n",i+1);
	fclose(dhand);
	free(tbuf);
	free(name);
	for(i=0;i<dnum;i++)
	  free(sfiles[i]);
	free(sfiles);
	if(fnum){
	  free(jindex);
	  free(files);
	}
	if(dir)
	  free(dfile);
	exit(EXIT_FAILURE);
      }
      if(head && ReadHead(source,&hd)){
	puts(err_read_head);
	fclose(source);
	fclose(dhand);
	free(tbuf);
	free(name);
	for(i=0;i<dnum;i++)
	  free(sfiles[i]);
	free(sfiles);
	if(fnum){
	  free(jindex);
	  free(files);
	}
	if(dir)
	  free(dfile);
	exit(EXIT_FAILURE);
      }
    }
    if(head && hd.number!=i+1){
      puts(err_wrong_portion);
      fclose(source);
      fclose(dhand);
      free(tbuf);
      free(name);
      if(dnum){
	for(i=0;i<dnum;i++)
	  free(sfiles[i]);
	free(sfiles);
      }
      if(fnum){
	free(jindex);
	free(files);
      }
      if(dir)
	free(dfile);
      exit(EXIT_FAILURE);
    }
    for(j=0,written=0;j<chunks;j++){
      if(!(read=fread(tbuf,1,asize,source))){
	puts(err_read);
	fclose(source);
	fclose(dhand);
	free(tbuf);
	free(name);
	if(dnum){
	  for(i=0;i<dnum;i++)
	    free(sfiles[i]);
	  free(sfiles);
	}
	if(fnum){
	  free(jindex);
	  free(files);
	}
	if(dir)
	  free(dfile);
	exit(EXIT_FAILURE);
      }
      if(fwrite(tbuf,1,read,dhand)!=read){
	puts(err_write);
	fclose(source);
	fclose(dhand);
	free(tbuf);
	free(name);
	if(dnum){
	  for(i=0;i<dnum;i++)
	    free(sfiles[i]);
	  free(sfiles);
	}
	if(fnum){
	  free(jindex);
	  free(files);
	}
	if(dir)
	  free(dfile);
	exit(EXIT_FAILURE);
      }
      written+=read;
    }
    twritten+=written;
    fclose(source);
    if(head && hd.size!=written)
      puts(warn_size);
  }
  fclose(dhand);
  free(tbuf);
  free(name);
  if(dnum){
    for(j=0;j<dnum;j++)
      free(sfiles[j]);
    free(sfiles);
  }
  if(fnum){
    free(jindex);
    free(files);
  }
  if(multi){
    if(i-1)
      printf(multi_join_n "\n",i,dfile);
    else
      printf(multi_join "\n",dfile);
  }
  else
    printf(join_to "\n",dfile);
  if(dir)
    free(dfile);
  if(head){
    if(multi)
      puts(join_heads);
    if(twritten!=tsize)
      puts(warn_t_size);
  }
  exit(0);
}

/*
  Split(char *file,char *path,int num,unsigned long size)
    file:     Source file.
    path:     Destination path.
    num:      Number of portions. Mutually exclusive with size.
    size:     Size of the portions. Mutually exclusive with num.
  Global:
    rstart:   -use-  First protion to extract.
    rend:     -use-  Last Portion to extract.
    msdos:    -use-  Filenames of portions are made MSDOS compatible (eight
                     characters, no dots).
    head:     -use-  Write header.
    multi:    -use-  Split to multiple volumes, waiting after each portion.
    query:    -use-  Ask before overwriting existing files.
  Calls:
    WriteHead:  Write header to portion file.
  This function does the splitting. If Splitter was called with the -p
  command set, num is provided. If the -s command or no command was set
  (default size), size will be valid. file is always valid, path may be
  NULL.
*/
void Split(char *file,char *path,int num,unsigned long size){
  int i,j,cnum;
  unsigned long tsize,csize,asize,rsize,rcsize,acsize;
  char *dfile,*dpath,*dbuf,*tbuf,*pos,*name;
  struct header hd;
  FILE *source,*dest;
  DIR *dfd;
#ifdef DBUG
  printf("\nSplit(\"%s\",",file);
  if(path)
    printf("\"%s\",",path);
  else
    printf("0,");
  printf("%d,%lu);   Uses: rstart(%d), rend(%d), msdos(%s), head(%s), multi(%s), query(%s)\n",num,size,rstart,rend,msdos?"TRUE":"FALSE",head?"TRUE":"FALSE",multi?"TRUE":"FALSE",query?"TRUE":"FALSE");
#endif
  if(head){
    if(size)
      size=size-hd_size;
    for(i=0;i<hd_namesize;i++)
      hd.name[i]='\0';
  }
  if(dfd=opendir(file)){
    closedir(dfd);
    printf(err_open_source "\n",file);
    exit(EXIT_FAILURE);
  }
  if(!(source=fopen(file,"rb"))){
    printf(err_open_source "\n",file);
    exit(EXIT_FAILURE);
  }
  pos=0;
#ifdef AMIGA
  if((name=strrchr(file,'/')) || (pos=strrchr(file,':')))
    if(pos)
      name=pos+1;
    else
      name++;
#endif
#ifdef MSDOS
  if((name=strrchr(file,'\\')) || (pos=strrchr(file,':')))
    if(pos)
      name=pos+1;
    else
      name++;
#endif
#ifdef UNIX
  if(name=strrchr(file,'/'))
    name++;
#endif
  else
    name=file;
  if(!(dfile=malloc(strlen(name)+1))){
    puts(err_no_mem);
    fclose(source);
    exit(EXIT_FAILURE);
  }
  strcpy(dfile,name);
  if(path){
    if(!(dfd=opendir(path))){
      puts(err_bad_dest);
      fclose(source);
      free(dfile);
      exit(EXIT_FAILURE);
    }
    closedir(dfd);
#ifndef UNIX
    if(i=strlen(path)){
#ifdef AMIGA
      if(path[--i]=='/' || path[i]==':')
	j=0;
#else
      if(path[--i]=='\\' || path[i]==':')
	j=0;
#endif
      else
	j=1;
    }
    else
      j=0;
    if(!(dpath=(char *)malloc(strlen(path)+j+1))){
      puts(err_no_mem);
      fclose(source);
      free(dfile);
      exit(EXIT_FAILURE);
    }
#ifdef AMIGA
    sprintf(dpath,"%s%s",path,j?"/":"");
#else
    sprintf(dpath,"%s%s",path,j?"\\":"");
#endif
#else
    if(!(dpath=(char *)malloc(strlen(path)+2))){
      puts(err_no_mem);
      fclose(source);
      free(dfile);
      exit(EXIT_FAILURE);
    }
    sprintf(dpath,"%s/",path);
#endif
  }
  else{
    if(!(dpath=malloc(name-file+1))){
      puts(err_no_mem);
      fclose(source);
      free(dfile);
      exit(EXIT_FAILURE);
    }
    sprintf(dpath,"%.*s",name-file,file);
  }
  if(msdos){
    if(pos=strchr(dfile,'.'))
      pos[0]='\0';
    if(strlen(dfile)>8)
      dfile[8]='\0';
  }
  if(head)
    sprintf(hd.name,"%.*s",hd_namesize-1,name);
  if(!(dbuf=(char *)malloc(strlen(dpath)+strlen(dfile)+5))){
    puts(err_no_mem);
    fclose(source);
    free(dfile);
    free(dpath);
    exit(EXIT_FAILURE);
  }
  if(fseek(source,0L,SEEK_END)){
    puts(err_seek);
    fclose(source);
    free(dfile);
    free(dpath);
    free(dbuf);
    exit(EXIT_FAILURE);
  }
  if(!(tsize=ftell(source))){
    puts(err_file_empty);
    fclose(source);
    free(dfile);
    free(dpath);
    free(dbuf);
    exit(EXIT_FAILURE);
  }
  if(size){
    num=(tsize+size-1)/size;
    size=size<tsize?size:tsize;
  }
  else
    size=(tsize+num-1)/num;
  if(head){
    hd.tsize=tsize;
    hd.tnumber=num;
  }
  if(!(tbuf=(char *)malloc(csize=size))){
    while(csize>10000 && !tbuf)
      tbuf=(char *)malloc(csize=(csize+1)/2);
    if(!tbuf){
      puts(err_no_mem);
      fclose(source);
      free(dfile);
      free(dpath);
      free(dbuf);
      exit(EXIT_FAILURE);
    }
  }
  cnum=(size+csize-1)/csize;
  if(rstart){
    i=rstart;
    if(!rend)
      rend=rstart;
    if(rend>num || rstart>rend){
      puts(err_bad_range);
      fclose(source);
      free(dfile);
      free(dpath);
      free(dbuf);
      free(tbuf);
      exit(EXIT_FAILURE);
    }
  }
  else{
    i=1;
    rend=num;
  }
  if(fseek(source,(i-1)*size,SEEK_SET)){
    puts(err_seek);
    fclose(source);
    free(dfile);
    free(dpath);
    free(dbuf);
    free(tbuf);
    exit(EXIT_FAILURE);
  }
  for(rsize=tsize+(2-i)*size;i<=rend;i++){
    rsize-=size;
    asize=(rsize<size?rsize:size);
    if(head){
      hd.number=i;
      hd.size=asize;
    }
    sprintf(dbuf,"%s%s.%03d",dpath,dfile,i);
    if(query && (dest=fopen(dbuf,"rb"))){
      fclose(dest);
      printf(query_overwrite_a,dbuf);
      gets(buf);
      if(buf[0]==query_all)
	query=0;
      else if(buf[0]!=query_yes){
	puts(err_write_abort);
	fclose(source);
	free(dfile);
	free(dpath);
	free(dbuf);
	free(tbuf);
	exit(EXIT_FAILURE);
      }
    }
    if(multi){
      puts(make_multi_part);
      gets(buf);
    }
    if(!(dest=fopen(dbuf,"wb"))){
      printf(err_open_dest "\n",dbuf);
      fclose(source);
      free(dfile);
      free(dpath);
      free(dbuf);
      free(tbuf);
      exit(EXIT_FAILURE);
    }
    if(head && WriteHead(dest,&hd)){
      puts(err_write_head);
      fclose(dest);
      fclose(source);
      free(dfile);
      free(dpath);
      free(dbuf);
      free(tbuf);
      exit(EXIT_FAILURE);
    }
    for(rcsize=asize+csize,j=0;j<cnum;j++){
      rcsize-=csize;
      acsize=(rcsize<csize?rcsize:csize);
      if(fread(tbuf,1,acsize,source)!=acsize){
	puts(err_read);
	fclose(dest);
	fclose(source);
	free(dfile);
	free(dpath);
	free(dbuf);
	free(tbuf);
	exit(EXIT_FAILURE);
      }
      if(fwrite(tbuf,1,acsize,dest)!=acsize){
	puts(err_write);
	fclose(dest);
	fclose(source);
	free(dfile);
	free(dpath);
	free(dbuf);
	free(tbuf);
	exit(EXIT_FAILURE);
      }
    }
    fclose(dest);
  }
  fclose(source);
  free(tbuf);
  free(dbuf);
  free(dpath);
  free(dfile);
  i=head?hd_size:0;
  printf(split_Splitted,file);
  if(num-1)
    if(num*size==tsize)
      printf(split_portions "\n",num,size+i);
    else
      if(num-2)
	printf(split_portions_and "\n",num-1,size+i,rsize+i);
      else
	printf(split_portion_and "\n",size+i,rsize+i);
  else
    printf(split_portion "\n",rsize+i);
  if(rstart)
    if(rstart!=rend)
      printf(split_Extract "\n",rstart,rend);
    else
      printf(split_Extract_one "\n",rstart);
  exit(0);
}

/*
  main(int argc,char *argv[])
    argc:     Number of arguments.
    argv:     Array of arguments.
  Global:
    msdos:    -set-  Filenames use msdos compatible format.
    head:     -set-  Use headers.
    multi:    -set-  Use multiple volumes.
    query:    -set-  Ask before overwriting existing file.
    rstart:   -set-  First protion to extract.   
    rend:     -set-  Last Portion to extract.
  Calls:
    Split:    Split a file.
    Join:     Join splitted parts.
  In main() the arguments are parsed and the appropriate functions
  are called. When calling Join(), 'paths' is not freed.
*/
void main(int argc,char **argv)
{
  int i,j,action,pathnum,portnum,defj;
  unsigned long portsize;
  char *arg,*path,*file,**paths;
#ifdef DBUG
  printf("\nmain(%d,({",argc);
  for(i=0;i<argc-1;i++)
    printf("\"%s\",",argv[i]);
  printf("\"%s\"",argv[i]);
  puts("}));");
#endif
  if(argc==1){
    printf(err_no_args "\n",argv[0]);
    exit(EXIT_FAILURE);
  }
  if(!(paths=(char **)malloc((argc-1)*sizeof(char *)))){
    puts(err_no_mem);
    exit(EXIT_FAILURE);
  }
#ifdef MSDOS
  msdos=1;
#else
  msdos=0;
#endif
  pathnum=rstart=rend=portnum=0;
  portsize=0;
  head=1;
#if FORCE
  query=0;
#else
  query=1;
#endif
  if(strstr(argv[0],"Join") || strstr(argv[0],"join"))
    action=defj=1;
  else
    action=defj=0;
  if(strchr(argv[0],'M') || strchr(argv[0],'m'))
    multi=1;
  else
    multi=0;
  for(i=1;i<argc;i++){
    arg=argv[i];
    if('-'==*arg)
      while(*++arg)
	switch(*arg){
	case 'h':
	  if(defj)
	    printf(info1j,argv[0]);
	  else{
	    printf(info1s,argv[0]);
	    getchar();
	    puts(info2);
	    for(j=0;j<sizeof(fs)/sizeof(struct fs_item);j++)
	      printf(main_fs "\n",fs[j].name,fs[j].size,fs[j].desc);
	  }
	  puts(main_end);
	  free(paths);
	  exit(0);
	case 'j':
	  action=1;
	  break;
	case 's':
	  action=2;
	  if(!*++arg){
	    if(i==argc-1){
	      puts(err_bad_size);
	      free(paths);
	      exit(EXIT_FAILURE);
	    }
	    arg=argv[++i];
	  }
	  for(j=0;j<sizeof(fs)/sizeof(struct fs_item);j++)
	    if(!strcmp(arg,fs[j].name))
	      portsize=fs[j].size;
	  if(!portsize){
	    if(!(portsize=atol(arg))){
	      puts(err_bad_size);
	      free(paths);
	      exit(EXIT_FAILURE);
	    }
	    if(strchr(arg,'k'))
	      portsize*=1024;
	    if(strchr(arg,'m'))
	      portsize*=1024*1024;
	  }
	  *arg--=0;
	  break;
	case 'p':
	  action=3;
	  if(!*++arg){
	    if(i==argc-1){
	      puts(err_bad_num);
	      free(paths);
	      exit(EXIT_FAILURE);
	    }
	    arg=argv[++i];
	  }
	  if(!(portnum=atoi(arg))){
	    puts(err_bad_num);
	    free(paths);
	    exit(EXIT_FAILURE);
	  }
	  *arg--=0;
	  break;
	case 'r':
	  if(!*++arg){
	    if(i==argc-1){
	      puts(err_bad_range);
	      free(paths);
	      exit(EXIT_FAILURE);
	    }
	    arg=argv[++i];
	  }
	  if(!(rstart=atoi(arg))){
	    puts(err_bad_range);
	    free(paths);
	    exit(EXIT_FAILURE);
	  }
	  if(i<argc-1 && !(rend=atoi(argv[++i])))
	    --i;
	  *arg--=0;
	  break;
	case 'd':
	  msdos=1;
	  break;
	case 'l':
	  msdos=0;
	  break;
	case 'n':
	  head=0;
	  break;
	case 'm':
	  multi=1;
	  break;
	case 'g':
	  multi=0;
	  break;
	case 'f':
	  query=0;
	  break;
	case 'q':
	  query=1;
	  break;
	default:
	  printf(err_unknown_option "\n",*arg);
	  free(paths);
	  exit(EXIT_FAILURE);
	}
    else
      paths[pathnum++]=arg;
  }
  if(!pathnum--){
    puts(err_no_file);
    free(paths);
    exit(EXIT_FAILURE);
  }
  if(action!=1){
    file=paths[0];
    if(pathnum)
      path=paths[1];
    else
      path=0;
    free(paths);
  }
  switch(action){
  case 1:
    Join(paths[pathnum],paths,pathnum);
  case 2:
    Split(file,path,0,portsize);
  case 3:
    Split(file,path,portnum,0);
  default:
    Split(file,path,0,fs[0].size);
  }
}
