/* 
 * multidsk.c : extracts and adds diskimages from multidsk images
 * 
 * mulitdsk images are simply a collection of double sided (2DD/720kB)
 * disk images concatenated together. Using this util you can add and
 * extract images from a multidsk image (which can be done with dd
 * in Unix BTW).
 *
 * By Sean Young 1998
 */

#include <stdio.h>
#include <errno.h>

int image_copy (FILE*, char*, FILE*, char*);

char	buffer[0x4000]; /* 16kB buffer for copying */

void usage (void)
{
    fprintf (stderr, "Usage: \n"
        "multidsk <multidsk> -e[n] out.dsk...\n"
        "multidsk <multidsk> -a[n] in.dsk...\n");
}

int main(int argc, char *argv[])
{
    char	h;
    int		i,add,n,img;
    long	l;
    FILE	*fmulti, *fdsk;

    if (argc < 4 || argv[2][0] != '-') {
	usage ();
	return (2);
    }

    if (argv[2][1] == 'a')
	add = 1;
    else if (argv[2][1] == 'e')
	add = 0 ;
    else {
	usage ();
	return (2);
    }

    if (!argv[2][2]) n=-1 ;
    else {
	n=0;i=2;
	while (1) {
	    h = argv[2][i++];
	    if (!h) break;
	    if ( (h < '0') || (h > '9') ) {
		usage ();
		return (2);
	    }
	    n=n*10+(int)(h-'0');
	}
	if (!n--) {
	    usage ();
	    return (2);
	}
    }	

    /* if !add, we're extracting images */
    if (!add) {
	fmulti = fopen (argv[1],"rb");
	if (fmulti == NULL) {
	    perror (argv[1]);
	    return (1);
	}

	if (n == -1) n=0; 
	fseek (fmulti, 0L, SEEK_END);
	l = ftell (fmulti);

        if (l % 737280L) {
            printf ("%s: Not multidsk image\n", argv[1]);
            fclose (fmulti);
	    return (1);
        }

	i = l / 737280L;
	if (n >= i) {
	    printf ("%s: Image %d does not exist\n", argv[1], n);
	    fclose (fmulti);
	    return (1);
	}
	fseek (fmulti, (long)n * 737280L, SEEK_SET);

	img = 3;
	while (img < argc) {
	    fdsk = fopen (argv[img], "wb");
	    if (fdsk == NULL) {
		perror (argv[img]);
		fclose (fmulti);
		return (1);
	    }

	    if (image_copy (fmulti,argv[2],fdsk,argv[img]) ) {
		fclose (fmulti);
		fclose (fdsk);
		return (1);
	    }

            fclose (fdsk);
	    img++;
	}
	fclose (fmulti);

	return (0);
    } else {
	/* we're adding/overwriting files */
        fmulti = fopen (argv[1], "wb");
        if (fmulti == NULL) {
	    perror (argv[1]);
	    return (1);
	}

	fseek (fmulti, 0L, SEEK_END);
	l = ftell (fmulti);
	if (l % 737280L) {
	    printf ("%s: Not multidsk image\n", argv[1]);
	    fclose (fmulti);
	}

	/* the stream is at the end of the file, so nothing to do for
	   n == -1 (append at the end) */
	if (n != -1) {
	    if ( ((long)n * 737280L) > l) {
		printf ("%s: Image %d does not exist\n", argv[1], n);
		fclose (fmulti);
	    }
	    fseek (fmulti, (long)n * 737280L, SEEK_SET);
	}

	img = 3;
	while (img < argc) {
	    fdsk = fopen (argv[img], "rb");
	    if (fdsk == NULL) {
	        perror (argv[img]);
		fclose (fmulti);

		return (1);
	    }

	    /* check source disk image */
	    fseek (fdsk, 0L, SEEK_END);
	    l = ftell (fdsk);
	    fseek (fdsk, 0L, SEEK_SET);
	    if (l != 737280L) {
		printf ("%s: Not disk image\n", argv[img]);
		fclose (fdsk); fclose (fmulti) ;
		return (1);
	    }

            if (image_copy (fdsk, argv[img], fmulti, argv[1]) ) {
                fclose (fmulti);
                fclose (fdsk);
                return (1);
            }

            fclose (fdsk);
            img++;
        }
        fclose (fmulti);

        return (0);
    }
}

int image_copy (FILE *fin, char *sin, FILE *fout, char *sout)
{
    int i;

    i = (int)(737280L/(long) sizeof (buffer));
    while (i--) {
	if (sizeof (buffer) != fread (buffer, 1, sizeof (buffer), fin) ) {
	    if (errno) perror (sin) ;
	    else printf ("%s: Not large enough\n", sin);
	    return (1);
	}

        if (sizeof (buffer) != fwrite (buffer, 1, sizeof (buffer), fout) ) {
	    perror (sout);
	    return (1);
        }
    }
    return (0);
}
