/* wasp - convert a picture from GIF, IFF, Sun rasterfile, 
 * PPM or SRGR to IFF or SRGR,
 * optionally scaling it and performing various operations on it.
 * copyright Steven Reiz 1990, 1991, 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
 * usage: see the usage routine below
 */

#define MAIN
#include "wasp.h"
#ifndef NOSH
#include "wasp.sh"
#endif

static short zap_option=0;

#ifdef __STDC__
main(int argc, char **argv)
#else
main(argc, argv)
int argc;
char **argv;
#endif
{
#ifdef DEBUG
    resetsecs();
#endif
    initvars();
    do_options(argc, argv);
    if ((infd=open(infilename, O_RDONLY))<0)
	error1(E0_FATAL, E1_IO, E2_OPEN, E3_ERRNO, infilename);
    if (!read_srgr() && !read_iff() && !read_gif() && !read_ras() && !read_ppm()) {
        printe("%s is not in IFF, GIF87a, Sun rasterfile, ppm or SRGR format\n", infilename);
        exit(1);
    }
    close(infd);
    if ((outfd=open(outfilename, O_WRONLY|O_CREAT|O_TRUNC, 0644))<0)
	error1(E0_FATAL, E1_IO, E2_CREAT, E3_ERRNO, 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;
    }
    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     : ilbm output mode, SHAM aka sliced HAM",
	"-dyn        : ilbm output mode, CTBL aka dynamic ham/hires",
	"-lace|nolace: ilbm output interlace, on or off",
	"-hires|lores|ham|ehb: ilbm output mode",
	"operations:",
	"-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       : cut a rectangle out of the picture and drop the rest",
	"-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
};


#ifdef __STDC__
usage(void)
#else
usage()
#endif
{
	char **p;

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


#ifdef __STDC__
initvars(void)
#else
initvars()
#endif
{
	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;
#ifdef AMIGA
	get_scr_size();
#endif
}


#ifdef __STDC__
void *cmalloc(unsigned int n)
#else
void *cmalloc(n)
unsigned int n;
#endif
{
    void *p;

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


#ifdef __STDC__
void *ccalloc(unsigned int n)
#else
void *ccalloc(n)
unsigned int n;
#endif
{
    void *p;

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


#ifdef __STDC__
void *crealloc(void *q, unsigned int n)
#else
void *crealloc(q, n)
void *q;
unsigned int n;
#endif
{
    void *p;

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


#ifdef __STDC__
lowcase(char *s)
#else
lowcase(s)
char *s;
#endif
{
    char c;

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


#ifdef __STDC__
u_long ceillog2(u_long a)
#else
u_long ceillog2(a)
u_long a;
#endif
{
    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);
}


#ifdef DEBUG
#ifndef AMIGA
#ifdef __STDC__
resetsecs(void)
#else
resetsecs()
#endif
{
}


#ifdef __STDC__
long centisecs(void)
#else
long centisecs()
#endif
{
    return 0;
}
#endif
#endif


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_UNKNOWN 31
	NULL
};


#ifdef __STDC__
int stringcode(char *s)
#else
int stringcode(s)
char *s;
#endif
{
    char **p;

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


#ifdef __STDC__
do_options(int argc, char **argv)
#else
do_options(argc, argv)
int argc;
char **argv;
#endif
{
    int i, j;

    if (argc<2)
        usage();
    for (i=1; i<argc && argv[i][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_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_CLIP:       /* these operations are handled below */
        case S_XAVERAGE:
	case S_XMIRROR:
	case S_YMIRROR:
	case S_TRANSPOSE:
        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;
        default:
        	usage();
        break;
        }
    }
    if (argc>i+2)
        usage();
    infilename=argv[i];
    if (argc>i+1)
	outfilename=argv[i+1];
    else
	outfilename=NULL;
}


#ifdef __STDC__
do_operations(int argc, char **argv)
#else
do_operations(argc, argv)
int argc;
char **argv;
#endif
{
    int i;

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