/* wasp - convert a picture from GIF, IFF, Sun rasterfile, 
 * PPM, Hamlab or SRGR to IFF, SRGR or PPM,
 * optionally scaling it and performing various operations on it.
 * Copyright 1991 by Steven Reiz, see the COPYING file for more info.
 * 1/12/90 - 2/6/91, 23/6/91, 30/6/91, 3/7/91 - 8/7/91,
 * 24/7/91, 22/10/91, 16/11/91, 8/12/91, 27/12/91 - 1/1/92
 * usage: see the usage routine below
 */

static char *sourcefile=__FILE__;

#define MAIN
#include "wasp.h"

static short zap_option=0;
static int testpatx=0, testpaty;

main(int argc, char **argv)
{
    initvars();
    do_options(argc, argv);
    if (testpatx)
	testpat(testpatx, testpaty);
    else {
	copen_in(infilename);
	if (!read_srgr() && !read_iff() && !read_gif() && !read_ras()
	 && !read_ppm() && !read_hl()) {
	    printe("%s is not in IFF, GIF87a, Sun rasterfile, ppm, Hamlab or SRGR format\n", infilename);
	    exit(1);
	}
	if (infd!=0)
	    close(infd);
    }
    assert(rgb);
    copen_out(outfilename);
    if (zap_option)
	unlink(infilename);
    scaley(yc, yd);
    scalex(xa, xb);
    do_operations(argc, argv);
    switch (outputformat) {
    case IFF:
	write_iff();
    break;
    case SRGR:
	write_srgr();
    break;
    case PPM:
	write_ppm();
    break;
    default:
	printe("unknown output format\n");
	exit(1);
    break;
    }
    if (outfd!=1)
	close(outfd);
    exit(0);
}


char *usagestr[]=
{
	"usage: wasp [options] [operations] [parameters] infile|- [outfile|-]",
	"options:",
	"-zap        : delete infile after it has been read",
	"-gifmaptrunc: truncate gif colormap entries to 4 bits i.s.o. rounding them",
	"-iff|srgr|ppm: the output format, IFF ILBM, SRGR or ppm",
	"-rgb n      : ilbm output mode, direct RGB with n bitplanes",
	"-nocompr    : ilbm output will not be compressed",
	"-asc        : autoscale, scales to fit the entire picture on the screen",
	"-nohires    : asc hint, no hires output mode for pictures with more than 16 colors",
	"-nohires!   : asc hint, no hires output mode",
	"-scrw n     : asc hint, screen width in lores pixels",
	"-scrh n     : asc hint, screen height in nolace pixels",
	"-sliced|dyn|mp: multimap ilbm output, sliced=SHAM|dynamic=CTBL|multipalette=PCHG",
	"-lace|nolace: ilbm output interlace, on or off",
	"-hires|lores|ham|ehb: ilbm output mode",
	"operations:",
	"-testpat x y: create a test pattern of x columns and y rows",
	"-x a/b      : scale horizontal, producing a columns out of every b input columns",
	"-y c/d      : scale vertical, producing c rows out of every d input rows",
	"-clip minx maxx miny maxy: cut a rectangle out of the picture and drop the rest",
	"-enlarge x y: enlarge the picture to x columns and y rows",
	"-xaverage   : same as -x 1/2, but averaging the two input columns",
	"-xmirror    : mirror the picture in a vertical mirror",
	"-ymirror    : mirror the picture in a horizontal mirror",
	"-transpose  : mirror the picture diagonally, in mirror y=x",
	"parameters:",
	"-cmeth m    : counting method, all1|alldif|allfdif|j1|j21|jdif|jdifsh|jfdif|jfdifsh|hmgs|hmcubic",
	"-dmeth m    : distribution method, mu|wf|ehb|mue|hs|con",
	"-dmeth2 m   : iterative ham second distribution method",
	"-threshold n: counting threshold",
	NULL
};


void
usage(void)
{
	char **p;

	printe("wasp %s, %s %s, Copyright 1991,1992 by Steven Reiz\n",
	 version+14, __DATE__, __TIME__);
	for (p=usagestr; *p; ++p)
		printe("%s\n", *p);
	exit(1);
}


void
initvars(void)
{
	rgb=NULL;
	outputformat=IFF;
	directrgb= -1;
	compression=COMPR_RLE;
	asc=0;
	hires=HIRES_OK;
	sliced=SLICED_NOT;
	scrw=DEF_SCRW;
	scrh=DEF_SCRH;
	ymode=UNSET;
	xmode=UNSET;
	xa=1; xb=1; yc=1; yd=1;
	countmeth=COUNTMETH_UNSET;
	distrmeth=DISTRMETH_UNSET;
	distrmeth2=DISTRMETH_UNSET;
	curdistrmeth=DISTRMETH_UNSET;
	threshold=1;
	inoperation=0;
	gifmaptrunc=0;
	cread_type=CREAD_STRICT;
#ifdef AMIGA
	get_scr_size();
#endif
}


void *
cmalloc(unsigned int n)
{
    void *p;

    if (!(p=malloc(n)))
	error1(E0_FATAL, E1_NOMEM, E2_UNSPEC, E3_NOMEM, n);
    return p;
}


void *
ccalloc(unsigned int n)
{
    void *p;

    if (!(p=calloc(n, 1)))
	error1(E0_FATAL, E1_NOMEM, E2_UNSPEC, E3_NOMEM, n);
    return p;
}


void *
crealloc(void *q, unsigned int n)
{
    void *p;

    if (!(p=realloc(q, n)))
	error1(E0_FATAL, E1_NOMEM, E2_UNSPEC, E3_NOMEM, n);
    return p;
}


void
lowcase(char *s)
{
    char c;

    while (c= *s) {
        if (c>='A' && c<='Z')
            *s=c-'A'+'a';
        ++s;
    }
}


unsigned long
ceillog2(unsigned long a)
{
    u_long b;
    short i;

    assert(a);
    b=a;
    for (i= -1; b; ++i)
        b>>=1;
    b=1L<<i;
    return (u_long)(a>b ? i+1 : i);
}


static char *sc[]={
#define S_IFF 0
	"iff",
#define S_SRGR 1
	"srgr",
#define S_RGB 2
	"rgb",
#define S_NOCOMPR 3
	"nocompr",
#define S_ASC 4
	"asc",
#define S_NOHIRES 5
	"nohires",
#define S_NOHIRES2 6
	"nohires!",
#define S_SCRW 7
	"scrw",
#define S_SCRH 8
	"scrh",
#define S_SLICED 9
	"sliced",
#define S_DYN 10
	"dyn",
#define S_LACE 11
	"lace",
#define S_NOLACE 12
	"nolace",
#define S_HIRES 13
	"hires",
#define S_LORES 14
	"lores",
#define S_HAM 15
	"ham",
#define S_EHB 16
	"ehb",
#define S_X 17
	"x",
#define S_Y 18
	"y",
#define S_CLIP 19
	"clip",
#define S_XAVERAGE 20
	"xaverage",
#define S_XMIRROR 21
	"xmirror",
#define S_YMIRROR 22
	"ymirror",
#define S_TRANSPOSE 23
	"transpose",
#define S_COUNTMETH 24
	"cmeth",
#define S_DISTRMETH 25
	"dmeth",
#define S_DISTRMETH2 26
	"dmeth2",
#define S_THRESHOLD 27
	"threshold",
#define S_ZAP 28
	"zap",
#define S_GIFMAPTRUNC 29
	"gifmaptrunc",
#define S_PPM 30
	"ppm",
#define S_ENLARGE 31
	"enlarge",
#define S_TESTPAT 32
	"testpat",
#define S_MP 33
	"mp",
#define S_UNKNOWN 34
	NULL
};


stringcode(char *s)
{
    char **p;

    if (!s || *s!='-' || s[1]=='\0')
        return S_UNKNOWN;
    ++s;
    for (p=sc; *p; ++p)
        if (!strcmp(s, *p))
            break;
    return p-sc;
}


void
do_options(int argc, char **argv)
{
    int i, j;

    if (argc<2)
        usage();
    for (i=1; i<argc && argv[i][0]=='-' && argv[i][1]!='\0'; ++i) {
        lowcase(argv[i]);
        switch (stringcode(argv[i])) {
        case S_IFF:      outputformat=IFF;     break;
        case S_SRGR:     outputformat=SRGR;    break;
	case S_RGB:	 directrgb=atol(argv[++i]); break;
	case S_NOCOMPR:  compression=COMPR_NONE; break;
        case S_ASC:      asc=1;                break;
        case S_NOHIRES:  hires=HIRES_MAYBE;    break;
        case S_NOHIRES2: hires=HIRES_NOT;      break;
        case S_SCRW:     scrw=atol(argv[++i]); break;
        case S_SCRH:     scrh=atol(argv[++i]); break;
        case S_SLICED:   sliced=SLICED_SHAM;   break;
        case S_DYN:	 sliced=SLICED_DYN;    break;
	case S_MP:	 sliced=SLICED_PCHG;   break;
        case S_LACE:     ymode=LACE;           break;
        case S_NOLACE:   ymode=NOLACE;         break;
        case S_HIRES:    xmode=HIRES;          break;
        case S_LORES:    xmode=LORES;          break;
        case S_HAM:      xmode=HAM;            break;
        case S_EHB:      xmode=EHB;            break;
        case S_X: 
            xa=atol(argv[++i]);
            xb=atol(strchr(argv[i], '/')+1);
        break;
        case S_Y:
            yc=atol(argv[++i]);
            yd=atol(strchr(argv[i], '/')+1);
        break;
	case S_TESTPAT:
	    testpatx=atoi(argv[++i]);
	    testpaty=atoi(argv[++i]);
	break;
	/* the operations are handled below, in do_operations */
        case S_XAVERAGE:
	case S_XMIRROR:
	case S_YMIRROR:
	case S_TRANSPOSE:
        break;
        case S_CLIP:
		for (j=0; j<4; ++j) {
			++i;
			if (i>=argc || *argv[i]<'0' || *argv[i]>'9')
				usage();
		}
	break;
	case S_ENLARGE:
		for (j=0; j<2; ++j) {
			++i;
			if (i>=argc || *argv[i]<'0' || *argv[i]>'9')
				usage();
		}
	break;
        case S_COUNTMETH:
		if ((j=cmethnum(argv[++i]))== -1)
			usage();
		countmeth=j;
	break;
        case S_DISTRMETH:
		if ((j=dmethnum(argv[++i]))== -1)
			usage();
		distrmeth=j;
	break;
        case S_THRESHOLD: threshold=atol(argv[++i]); break;
        case S_DISTRMETH2: 
        	xmode=HAM;
		if ((j=dmethnum(argv[++i]))== -1)
			usage();
		distrmeth2=j;
        break;
	case S_ZAP: zap_option=1; break;
	case S_GIFMAPTRUNC: gifmaptrunc=1; break;
	case S_PPM: outputformat=PPM; break;
	case S_UNKNOWN:
		usage();
	break;
        default:
        	assert(0);
        break;
        }
    }
    if (argc<=i || argc>i+2)
        usage();
    infilename=argv[i];
    if (argc>i+1)
	outfilename=argv[i+1];
    else
	outfilename=NULL;
    if (outfilename==NULL && testpatx) {
	outfilename=infilename;
	infilename=NULL;
    }
}


void
do_operations(int argc, char **argv)
{
    int i;

    inoperation=1;
    for (i=1; i<argc; ++i) {
        switch (stringcode(argv[i])) {
        case S_CLIP:
		do_clipping(atoi(argv[i+1]), atoi(argv[i+2]), atoi(argv[i+3]),
		 atoi(argv[i+4]));
	break;
	case S_ENLARGE:
		do_enlarge(atoi(argv[i+1]), atoi(argv[i+2]));
	break;
        case S_XAVERAGE:  xaverage();    break;
	case S_XMIRROR:	  xmirror();	 break;
	case S_YMIRROR:	  ymirror();	 break;
	case S_TRANSPOSE: transpose();	 break;
        }
    }
    inoperation=0;
}
