/* File imstar.c
 * June 24, 2016
 * By Jessica Mink, Harvard-Smithsonian Center for Astrophysics
 * Send bug reports to jmink@cfa.harvard.edu

   Copyright (C) 1996-2016
   Smithsonian Astrophysical Observatory, Cambridge, MA USA

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>
#include <math.h>
#include "libwcs/wcs.h"
#include "libwcs/fitsfile.h"
#include "libwcs/wcscat.h"

#define CAT_DEFAULT	0
#define CAT_ASCII	1
#define CAT_STARBASE	2
#define CAT_DAOFIND	3

#define MAXFILES 1000
static int maxnfile = MAXFILES;

static char *RevMsg = "IMSTAR WCSTools 3.9.7, 26 April 2022, Jessica Mink (jmink@cfa.harvard.edu)";

static int verbose = 0;		/* verbose flag */
static int debug = 0;		/* debugging flag */
static int version = 0;		/* If 1, print only program name and version */
static int rot = 0;		/* Angle to rotate image (multiple of 90 deg) */
static int mirror = 0;		/* If 1, flip image right-left before rotating*/
static int printcounts = 0;	/* If 1, print counts instead of magnitudes */

static void PrintUsage();
static void ListStars();
extern char *RotFITS();
extern void setstarsig();
extern void setbmin();
extern void setmaxrad();
extern void setborder();
extern void setimcat();
extern void setparm();
extern void setrot();
extern void setcenter();
extern void setsys();
extern void setsecpix();
extern void setsecpix2();
extern void setrefpix();
extern void setmirror();
extern void setrotate();

extern struct WorldCoor *GetFITSWCS();

static int wfile = 0;		/* True to print output file */
static double magoff = 90.0;
static int rasort = 0;
static int printhead = 0;
static int nstar = 0;
static double eqout = 0.0;
static int sysout = -1;
static int outform = 0;		/* Output catalog format */
static int setuns = 0;		/* Change to unsigned integer flag */
static int imsearch = 1;	/* If 1, search for stars in image */
static int region_char;
static int region_radius;
static int rotatewcs = 1;	/* If 1, rotate FITS WCS keywords in image */

int
main (ac, av)
int ac;
char **av;
{
    char *str;
    double bmin, arot, drot, xr, yr;
    char rastr[32], decstr[32];
    int readlist = 0;
    char *lastchar;
    char *cstr;
    char filename[128];
    char errmsg[256];
    FILE *flist;
    char *listfile = NULL;
    int maxrad;
    char **fn;
    int ifile, nfile;
    char c;

    nfile = 0;
    fn = (char **)calloc (maxnfile, sizeof(char *));

    /* crack arguments */
    for (av++; --ac > 0; av++) {
   	str = *av; 

	/* Check for help command first */
	if (!str || !strcmp (str, "help") || !strcmp (str, "-help"))
	    PrintUsage (NULL);

	/* Check for version command */
	if (!strcmp (str, "version") || !strcmp (str, "-version")) {
	    version = 1;
	    PrintUsage (NULL);
	    }

	else if (*str == '@') {
	    readlist++;
	    listfile = ++str;
	    str = str + strlen (str) - 1;
	    av++;
	    ac--;
	    }

	else if (strchr (str, '='))
	    setparm (str);

        /* Set RA, Dec, and equinox if WCS-generated argument */
	else if (strsrch (str,":") != NULL) {
	    if (ac < 3)
		PrintUsage (str);
	    else {
		strcpy (rastr, *av);
		ac--;
		strcpy (decstr, *++av);
		ac--;
		setcenter (rastr, decstr);
		setsys (*++av);
		if (sysout < 0) {
		    sysout = wcscsys (*av);
		    eqout = wcsceq (*av);
		    }
		}
	    }

	else if (*str == '-') {
	    while ((c = *++str)) {
		switch (c) {
		case 'v':	/* more verbosity */
		    verbose++;
		    break;
	
		case 'a':       /* Initial rotation angle in degrees */
		    if (ac < 2)
			PrintUsage (str);
		    drot = atof (*++av);
		    arot = fabs (drot);
		    if (arot != 90.0 && arot != 180.0 && arot != 270.0) {
			setrot (drot);
			setrotate (rot);
			rot = 0;
			}
		    else
			rot = atoi (*av);
		    ac--;
		    break;
	
		case 'b':	/* Output FK4 (B1950) coordinates */
		    eqout = 1950.0;
		    sysout = WCS_B1950;
		    break;
	
		case 'c':	/* Output coounts instead of magnitudes */
		    printcounts++;;
		    break;
	
		case 'd':	/* Read image star positions from DAOFIND file */
		    if (ac < 2)
			PrintUsage (str);
		    setimcat (*++av);
		    imsearch = 0;
		    ac--;
		    break;
	
		case 'e':	/* Number of pixels to ignore around image edge */
		    if (ac < 2)
			PrintUsage (str);
		    setborder (atoi (*++av));
		    ac--;
		    break;
	
		case 'f':	/* Write ASCII catalog format for SKYMAP */
		    outform = CAT_ASCII;
		    break;
	
		case 'g':	/* Do not rotate image WCS with image */
		    rotatewcs = 0;
		    break;
	
		case 'h':	/* Output descriptive header */
		    printhead++;
		    break;
	
		case 'i':	/* Image star minimum peak value (or minimum sigma */
		    if (ac < 2)
			PrintUsage (str);
		    bmin = atof (*++av);
		    if (bmin < 0)
			setstarsig (-bmin);
		    else
			setbmin (bmin);
		    ac--;
		    break;
	
		case 'j':	/* Output FK5 (J2000) coordinates */
		    eqout = 2000.0;
		    sysout = WCS_J2000;
		    break;
	
		case 'k':	/* Print each star as it is found */
		    debug++;
		    break;
	
    		case 'l':	/* Left-right reflection before rotating */
		    mirror = 1;
		    setmirror (mirror);
    		    break;
	
		case 'm':	/* Magnitude offset */
		    if (ac < 2)
			PrintUsage (str);
		    magoff = atof (*++av);
		    ac--;
		    break;
	
		case 'n':	/* Number of brightest stars to read */
		    if (ac < 2)
			PrintUsage (str);
		    nstar = atoi (*++av);
		    ac--;
		    break;

		case 'o':	/* Output DAOFIND format */
		    outform = CAT_DAOFIND;
		    break;
	
    		case 'p':	/* Plate scale in arcseconds per pixel */
    		    if (ac < 2)
			PrintUsage (str);
    		    setsecpix (atof (*++av));
    		    ac--;
		    if (ac > 1 && isnum (*(av+1))) {
			setsecpix2 (atof (*++av));
			ac--;
			}
    		    break;
	
		case 'q':	/* Output region file shape for SAOimage */
    		    if (ac < 2)
			PrintUsage (str);
		    cstr = *++av;
		    switch (cstr[0]){
			case 'c':
			    if (cstr[1] == 'i')
				region_char = WCS_CIRCLE;
			    else
				region_char = WCS_CROSS;
			    break;
			case 'd':
			    region_char = WCS_DIAMOND;
			    break;
			case 's':
			    region_char = WCS_SQUARE;
			    break;
			case 'x':
			    region_char = WCS_EX;
			    break;
			case 'v':
			    region_char = WCS_VAR;
			    break;
			case '+':
			    region_char = WCS_CROSS;
			    break;
			case 'o':
			default:
			    region_char = WCS_CIRCLE;
			}
		    if (region_radius == 0)
			region_radius = 10;
    		    ac--;
		    wfile = 1;
		    break;
	
		case 'r':	/* Maximum acceptable radius for a star */
		    if (ac < 2)
			PrintUsage (str);
		    maxrad = (int) atof (*++av);
		    region_radius = maxrad;
		    setmaxrad (maxrad);
		    ac--;
		    break;
	
		case 's':	/* sort by RA */
		    rasort = 1;
		    break;
	
		case 't':	/* Output Starbase tab table */
		    outform = CAT_STARBASE;
		    break;
	
		case 'u':	/* Set 16-bit int image file to unsigned */
		    setuns = 1;
		    break;
	
		case 'w':	/* Write output to file */
		    wfile = 1;
		    break;

		case 'x':	/* X and Y coordinates of reference pixel */
		    if (ac < 3)
			PrintUsage (str);
    		    xr = atof (*++av);
		    ac--;
    		    yr = atof (*++av);
		    ac--;
    		    setrefpix (xr, yr);
    		    break;

		case 'z':       /* Use AIPS classic WCS */
		    setdefwcs (1);
		    break;

		default:
		    sprintf (errmsg, "* Illegal command -%s-", str);
		    PrintUsage (str);
		}
		}
	    }

	/* Save a FITS or IRAF file */
        else if (isfits (str) || isiraf (str)) {
            if (nfile >= maxnfile) {
                maxnfile = maxnfile * 2;
                fn = (char **) realloc ((void *)fn, maxnfile);
                }
            fn[nfile] = str;
            nfile++;
            }

        else {
            sprintf (errmsg, "* %s is not a FITS or IRAF file.", str);
            PrintUsage (errmsg);
            }
	}

    /* Find number of images to search and leave listfile open for reading */
    if (readlist) {
	if ((flist = fopen (listfile, "r")) == NULL) {
	    sprintf (errmsg,"IMSTAR: List file %s cannot be read\n",
		     listfile);
	    PrintUsage (errmsg);
	    }
	while (fgets (filename, 128, flist) != NULL) {
	    lastchar = filename + strlen (filename) - 1;
	    if (*lastchar < 32) *lastchar = 0;
	    ListStars (filename);
	    }
	fclose (flist);
	}

    /* Process image files */
    else if (nfile > 0) {
        for (ifile = 0; ifile < nfile; ifile++) {
            if (verbose)
                printf ("%s:\n", fn[ifile]);
            ListStars (fn[ifile]);
            if (verbose)
                printf ("\n");
            }
        }

    /* Print error message if no image files to process */
    else
        PrintUsage ("* No files to process.");

    return (0);
}

static void
PrintUsage (command)

char	*command;	/* Name of program being executed */

{
    fprintf (stderr,"%s\n",RevMsg);
    if (version)
	exit (-1);

    if (command != NULL) {
	if (command[0] == '*')
	    fprintf (stderr, "%s\n", command);
	else
	    fprintf (stderr, "* Missing argument for command: %c\n", command[0]);
	exit (1);
	}

    fprintf (stderr,"Find stars in FITS and IRAF image files\n");
    fprintf(stderr,"usage: imstar [-vbsjt] [-m mag_off] [-n num] [-d file][ra dec sys] file.fits ...\n");
    fprintf(stderr,"  -a: Rotation angle in degrees (default 0)\n");
    fprintf(stderr,"  -b: Output B1950 (FK4) coordinates \n");
    fprintf(stderr,"  -c: Output total flux in counts instead of magnitudes\n");
    fprintf(stderr,"  -d: Read following DAOFIND output catalog instead of search \n");
    fprintf(stderr,"  -e: Number of pixels to ignore around image edge \n");
    fprintf(stderr,"  -f: Output simple ASCII catalog format\n");
    fprintf(stderr,"  -g: Do not rotate image WCS with image\n");
    fprintf(stderr,"  -h: Print heading, else do not \n");
    fprintf(stderr,"  -i: Minimum peak value for star in image (<0=-sigma)\n");
    fprintf(stderr,"  -j: Output J2000 (FK5) coordinates \n");
    fprintf(stderr,"  -k: Print each star as it is found for debugging \n");
    fprintf(stderr,"  -l: reflect left<->right before rotating and searching\n");
    fprintf(stderr,"  -m: Magnitude offset (set brightest to abs(offset) if < 0)\n");
    fprintf(stderr,"  -n: Number of brightest stars to print \n");
    fprintf(stderr,"  -o: Output DAOFIND format star list\n");
    fprintf(stderr,"  -p: Plate scale in arcsec per pixel (default 0)\n");
    fprintf(stderr,"  -q: Output region file shape for SAOimage (default o)\n");
    fprintf(stderr,"  -r: Maximum radius for star in pixels \n");
    fprintf(stderr,"  -s: Sort by RA instead of flux \n");
    fprintf(stderr,"  -t: Output Starbase tab table format star list\n");
    fprintf(stderr,"  -u: Set BITPIX to -16 for unsigned integer\n");
    fprintf(stderr,"  -v: Verbose; print star list to stdout\n");
    fprintf(stderr,"  -w: write star list to output file\n");
    fprintf(stderr,"  -x: X and Y coordinates of reference pixel (if not in header or center)\n");
    fprintf (stderr,"  -z: use AIPS classic projections instead of WCSLIB\n");
    fprintf(stderr,"  @listfile: file containing a list of filenames to search\n");
    exit (1);
}


extern int FindStars ();
extern int pix2wcst();

static void
ListStars (filename)

char	*filename;	/* FITS or IRAF file filename */

{
    char *image = NULL;		/* FITS image */
    char *newimage;		/* Rotated FITS image */
    char *header;		/* FITS header */
    int lhead;			/* Maximum number of bytes in FITS header */
    int nbhead;			/* Actual number of bytes in FITS header */
    char *irafheader = NULL;	/* IRAF image header */
    double *sx=0, *sy=0;	/* image stars, pixels */
    double *sra=0, *sdec=0;	/* image star RA and Dec */
    int ns;			/* n image stars */
    double *smag;		/* image star magnitudes */
    int *sp;			/* peak flux in counts */
    double cra,cdec,dra,ddec,secpix;
    int wp, hp;
    char rastr[32], decstr[32];
    int i, bitpix;
    char headline[160];
    char pixname[256];
    char outfile[256];
    char *ext;
    char temp[32];
    FILE *fd;
    struct WorldCoor *wcs;	/* World coordinate system structure */
    int iraffile = 0;

    /* Open IRAF header */
    if (isiraf (filename)) {
	if ((irafheader = irafrhead (filename, &lhead)) != NULL) {
	    if ((header = iraf2fits (filename,irafheader,lhead,&nbhead)) == NULL) {
		fprintf (stderr, "Cannot translate IRAF header %s/n",filename);
		free (irafheader);
		return;
		}
	    if (imsearch) {
		if ((image = irafrimage (header)) == NULL) {
		    hgetm (header,"PIXFIL", 255, pixname);
		    fprintf (stderr, "Cannot read IRAF pixel file %s\n", pixname);
		    free (irafheader);
		    free (header);
		    return;
		    }
		}
	    iraffile = 1;
	    }
	else {
	    fprintf (stderr, "Cannot read IRAF header file %s\n", filename);
	    return;
	    }
	}

    /* Read FITS image header */
    else {
	if ((header = fitsrhead (filename, &lhead, &nbhead)) != NULL) {
	    if (imsearch) {
		if ((image = fitsrimage (filename, nbhead, header)) == NULL) {
		    fprintf (stderr, "Cannot read FITS image %s\n", filename);
		    free (header);
		    return;
		    }
		}
	    }
	else {
	    fprintf (stderr, "Cannot read FITS file %s\n", filename);
	    return;
	    }
	}
    if (verbose && printhead)
	fprintf (stderr,"%s\n",RevMsg);

    /* Set image to unsigned integer if 16-bit and flag set */
    if (setuns) {
	hgeti4 (header, "BITPIX", &bitpix);
	if (bitpix == 16)
	    hputi4 (header, "BITPIX", -16);
	}

    /* Rotate and/or reflect image */
    if (imsearch && (rot != 0 || mirror)) {
	if ((newimage = RotFITS (filename,header,image,0,0,rot,mirror,bitpix,
				 rotatewcs,verbose)) == NULL) {
	    fprintf (stderr,"Image %s could not be rotated\n", filename);
	    if (iraffile)
		free (irafheader);
	    if (image != NULL)
		free (image);
	    free (header);
	    return;
	    }
	else {
	    if (image != NULL)
		free (image);
	    image = newimage;
	    }
	}

/* Find the stars in an image and use the world coordinate system
 * information in the header to produce a plate catalog with right
 * ascension, declination, and a plate magnitude
 */

    wcs = GetFITSWCS (filename, header,verbose, &cra, &cdec, &dra, &ddec,
		      &secpix, &wp, &hp, &sysout, &eqout);
    if (wcs == NULL)
	outform = CAT_DAOFIND;

    /* Discover star-like things in the image, in pixels */
    ns = FindStars (header, image, &sx, &sy, &smag, &sp, debug, 1);
    if (ns < 1) {
	fprintf (stderr,"ListStars: no stars found in image %s\n", filename);
	wcsfree (wcs);
	free (header);
	if (imsearch)
	    free (image);
	return;
	}

    if (debug) printf ("\n");

    /* Save star positions */
    if (nstar > 0 && ns > nstar)
	ns = nstar;

    /* Sort stars */
    MagSortStars (NULL,NULL,NULL,NULL,NULL,sx, sy, &smag, sp, NULL, ns, 1, 1);

    /* Reset magnitude offset, if negative, so it is value for brightest star */
    /* Default is instrument magnitude */
    if (magoff <= 0.0)
	magoff = -magoff - smag[0];
    else if (magoff > 89.0)
	magoff = 0.0;

    /* Compute right ascension and declination for all stars to be listed */
    sra = (double *) malloc (ns * sizeof (double));
    sdec = (double *) malloc (ns * sizeof (double));
    for (i = 0; i < ns; i++) {
	if (iswcs (wcs))
	    pix2wcs (wcs, sx[i], sy[i], &sra[i], &sdec[i]);
	else {
	    sra[i] = 0.0;
	    sdec[i] = 0.0;
	    }
	smag[i] = smag[i] + magoff;
	}

    /* Sort star-like objects in image by right ascension */
    if (rasort && iswcs (wcs))
	RASortStars (0, sra, sdec, NULL, NULL, sx, sy, &smag, sp, NULL, ns, 1);
    sprintf (headline, "IMAGE	%s", filename);

    /* Open plate catalog file */
    if (strcmp (filename,"stdin")) {
	if (strrchr (filename, '/'))
	    strcpy (outfile, strrchr (filename, '/')+1);
	else
	    strcpy (outfile,filename);
	if ((ext = strsrch (outfile, ".fit")) != NULL ||
	    (ext = strsrch (outfile, ".imh")) != NULL)
	    *ext = (char) 0;
	}
    else {
	strcpy (outfile,filename);
	(void) hgets (header,"OBJECT",64,outfile);
	}

    /* Add rotation and reflection to output file name */
    if (mirror)
	strcat (outfile, "m");
    else if (rot != 0)
	strcat (outfile, "r");
    if (rot != 0) {
	if (rot < 10 && rot > -1) {
	    sprintf (temp,"%1d",rot);
	    strcat (outfile, temp);
	    }
	else if (rot < 100 && rot > -10) {
	    sprintf (temp,"%2d",rot);
	    strcat (outfile, temp);
	    }
	else if (rot < 1000 && rot > -100) {
	    sprintf (temp,"%3d",rot);
	    strcat (outfile, temp);
	    }
	else {
	    sprintf (temp,"%4d",rot);
	    strcat (outfile, temp);
	    }
	}

    if (wfile) {
	if (region_char)
	    strcat (outfile, ".reg");
	else if (outform == CAT_STARBASE)
	    strcat (outfile,".tab");
	else if (outform == CAT_DAOFIND)
	    strcat (outfile,".dao");
	else
	    strcat (outfile,".imstar");
	if (verbose)
	    printf ("%s\n", outfile);
		
	fd = fopen (outfile, "w");
	if (fd == NULL) {
	    fprintf (stderr, "IMSTAR:  cannot write file %s\n", outfile);
            wfile = 0;
            }
	}
    else
	fd = NULL;

    /* Write file of positions for SAOimage regions */
    if (wfile && region_char) {
	int radius, ix, iy;
	char rstr[16];
	fprintf (fd, "# %d stars in %s\n", ns, filename);
	if (verbose)
	    printf ("# %d stars in %s\n", ns, filename);
	switch (region_char) {
	    case WCS_SQUARE:
		strcpy (rstr, "SQUARE");
		break;
	    case WCS_DIAMOND:
		strcpy (rstr, "DIAMOND");
		break;
	    case WCS_CROSS:
		strcpy (rstr, "CROSS");
		break;
	    case WCS_EX:
		strcpy (rstr, "EX");
		break;
	    case WCS_CIRCLE:
	    default:
		strcpy (rstr, "CIRCLE");
	    }
	radius = region_radius;
	for (i = 0; i < ns; i++) {
	    fprintf (fd, "%s(%.2f,%.2f,%d) # %s %d\n",
		     rstr, sx[i], sy[i], radius, filename, i);
	    if (verbose)
		printf ("%s(%.2f,%.2f,%d) # %s %d\n",
			rstr, sx[i], sy[i], radius, filename, i);
	    /* ix = (int)(sx[i] + 0.5);
	    iy = (int)(sy[i] + 0.5);
	    fprintf (fd, "%s(%d,%d,%d) # %s %d\n",
		     rstr, ix, iy, radius, filename, i);
	    if (verbose)
		printf ("%s(%d,%d,%d) # %s %d\n",
			rstr, ix, iy, radius, filename, i); */
	    }
	printf ("%s\n", outfile);
	}
    else {

    /* Write header */
    if (outform == CAT_STARBASE) {
	if (wfile)
	    fprintf (fd,"%s\n", headline);
	else
	    printf ("%s\n", headline);
	}
    else if (outform == CAT_DAOFIND) {
	if (wfile)
	    fprintf (fd,"#%s\n", headline);
	else
	    printf ("#%s\n", headline);
	}

    if (iswcs (wcs)) {
	if (rasort && outform == CAT_STARBASE) {
	    if (wfile)
		fprintf (fd, "rasort	T\n");
	    else
		printf ("rasort	T\n");
	    }

	if (outform == CAT_STARBASE) {
	    if (wcs->sysout == WCS_B1950)
		sprintf (headline, "equinox	1950.0");
	    else
		sprintf (headline, "equinox	2000.0");
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    }
	else if (outform == CAT_ASCII) {
	    if (wcs->sysout == WCS_B1950)
		sprintf (headline, "%s.cat\n", filename);
	    else
		sprintf (headline, "%s.cat/j\n", filename);
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    }
	else if (outform == CAT_DAOFIND) {
	    if (wcs->sysout == WCS_B1950)
		sprintf (headline, "#equinox 1950.0");
	    else
		sprintf (headline, "#equinox 2000.0");
	    if (printcounts)
		strcat (headline, "(counts)");
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    }

	if (outform == CAT_STARBASE) {
	    sprintf (headline, "epoch	%9.4f", wcs->epoch);
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    sprintf (headline, "program	%s", RevMsg);
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    if (printcounts)
		sprintf (headline,"id 	ra      	dec     	counts	x    	y    	peak");
	    else
		sprintf (headline,"id 	ra      	dec     	mag   	x    	y    	peak");
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    sprintf (headline,"---	------------	------------	------	-----	-----	------");
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    }
	else if (outform == CAT_ASCII) {
	    sprintf (headline, "Stars extracted by %s", RevMsg);
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    }
	else if (outform == CAT_DAOFIND) {
	    sprintf (headline, "#Stars extracted by %s", RevMsg);
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    }
	}


    for (i = 0; i < ns; i++) {
	ra2str (rastr, 32, sra[i], 3);
	dec2str (decstr, 32, sdec[i], 2);
	if (printcounts)
	    smag[i] = pow (10.0, smag[i] / -2.5);
	if (outform == CAT_STARBASE) {
	    sprintf (headline, "%d	%s	%s	%.2f	%.2f	%.2f	%d",
		     i+1, rastr,decstr, smag[i], sx[i], sy[i], sp[i]);
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    }
	else if (outform == CAT_DAOFIND) {
	    sprintf (headline, "%7.2f %7.2f %6.2f  %d",
		    sx[i],sy[i],smag[i],sp[i]);
	    if (iswcs (wcs))
		sprintf (headline+strlen(headline), " %s %s", rastr, decstr);
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    }
	else {
	    sprintf (headline, "%3d %s %s %6.2f", i+1,rastr,decstr,smag[i]);
	    if (wcs->nxpix < 100.0 && wcs->nypix > 100.0)
		sprintf (headline+strlen(headline), " %5.2f %5.2f %d", sx[i],sy[i], sp[i]);
	    else if (wcs->nxpix < 1000.0 && wcs->nypix < 1000.0)
		sprintf (headline+strlen(headline), " %6.2f %6.2f %d", sx[i],sy[i], sp[i]);
	    else
		sprintf (headline+strlen(headline), " %7.2f %7.2f %d", sx[i],sy[i], sp[i]);
	    if (wfile)
		fprintf (fd, "%s\n", headline);
	    else
		printf ("%s\n", headline);
	    }
	}
	}

    if (fd) fclose (fd);
    if (sx) free ((char *)sx);
    if (sy) free ((char *)sy);
    if (sp) free ((char *)sp);
    if (sra) free ((char *)sra);
    if (sdec) free ((char *)sdec);
    if (smag) free ((char *)smag);
    wcsfree (wcs);
    free (header);
    if (imsearch)
	free (image);
    return;
}

/* Feb 29 1996	New program
 * Apr 30 1996	Add FOCAS-style catalog matching
 * May  1 1996	Add initial image center from command line
 * May  2 1996	Set up four star matching modes
 * May 14 1996	Pass verbose flag; allow other reference catalogs
 * May 21 1996	Sort by right ascension; allow output in FK4 or FK5
 * May 29 1996	Add optional new image center coordinates
 * Jun 10 1996	Drop 3 arguments flux sorting subroutine
 * Jul 16 1996	Update input code
 * Aug 26 1996	Change HGETC call to HGETS
 * Aug 27 1996	Remove unused variables after lint
 * Aug 30 1996	Allow border to be set
 * Sep  1 1996	Move parameter defaults to lwcs.h
 * Oct 17 1996	Drop unused variables
 * Dec 10 1996	Improve hot pixel rejection
 * Dec 11 1996	Allow reading from DAOFIND file instead of searching image
 * Dec 11 1996	Add WCS default rotation and use getfitswcs
 *
 * Feb 21 1997  Check pointers against NULL explicitly for Linux
 * Mar 18 1997	Skip WCS calls if no WCS
 * May 28 1997	Add option to read a list of filenames from a file
 * Jul 12 1997  Add option to center reference pixel coords on the command line
 * Nov  7 1997	Print file in tab, DAO, or ASCII format, just like STDOUT
 * Dec 16 1997	Support IRAF 2.11 image headers
 * Dec 16 1997	Fix spacing in non-tab-table output
 *
 * Jan 27 1998  Implement Mark Calabretta's WCSLIB
 * Jan 29 1998  Add -z for AIPS classic WCS projections
 * Feb 18 1998	Version 2.0: Full Calabretta WCS
 * Mar  2 1998	Fix RA sorting bug
 * Mar 27 1998	Version 2.1: Add IRAF TNX projection
 * Mar 27 1998	Version 2.2: Add polynomial plate fit
 * Apr 27 1998	Drop directory from output file name
 * Apr 28 1998	Change coordinate system flags to WCS_*
 * May 28 1998	Include fitsio.h instead of fitshead.h
 * Jun  2 1998  Fix bug in hput()
 * Jun 15 1998	Default to tab table file; ASCII table verbosee
 * Jun 15 1998	Write DAO-format file if -w flag set; ASCII table verbose
 * Jun 17 1998	Add option to set 16-bit files to unsigned int BITPIX=-16
 * Jul 24 1998	Make irafheader char instead of int
 * Jul 27 1998	Fix bug in ra2str() and dec2str() arguments
 * Aug  6 1998	Change fitsio.h to fitsfile.h
 * Sep 17 1998	Add coordinate system to GetFITSWCS() argument list
 * Sep 29 1998	Changesystem and equinox arguments to GetFITSWCS()
 * Oct 14 1998	Use isiraf() to determine file type
 * Oct 27 1998	Add option to write region file to plot results over image
 * Nov 30 1998	Add version and help commands for consistency
 *
 * Apr  7 1999	Add filename argument to GetFITSWCS
 * May 25 1999	Add epoch to output tab table header
 * Jun  9 1999	Set brightest magnitude for any magnitude offset (J-B Marquette)
 * Jun 10 1999	Add option to rotation and reflect image before searching
 * Jun 10 1999	Drop .fits or .imh file extension from output file name
 * Jun 11 1999	Add parameter setting on command line
 * Jul  1 1999	Only free image if it was allocated
 * Jul  7 1999	Fix bug setting rotation
 * Jul  7 1999	Do not add 0 to file name if no rotation
 * Jul  7 1999	If -n argument more than found stars, list only number found
 * Sep 20 1999	Drop second call to pix2wcs
 * Oct 15 1999	Free wcs using wcsfree(); free sp
 * Oct 22 1999	Drop unused variables after lint
 * Oct 22 1999	Add optional second plate scale arg
 * Oct 26 1999	Read reference pixel coordinate from command line without -c
 * Nov 19 1999	Make display and file output formats identical
 *
 * Jan 28 2000	Call setdefwcs() with WCS_ALT instead of 1
 * Mar 15 2000	Add NULL proper motion arguments to RASortStars()
 * Mar 23 2000	Use hgetm() to get the IRAF pixel file name, not hgets()
 *
 * Jan 22 2001	Drop declaration of wcsinit()
 * Jul 25 2001	FindStar() now returns magnitude instead of flux
 * Jul 25 2001	Print to stdout unless writing to a file
 * Oct 25 2001	Allow arbitrary argument order on command line
 * Dec 17 2001	Set mirror and rotation in FindStars()
 *
 * Jan 22 2002	Set edge pixels as integer, not float
 * Jan 23 2002	Add zap=1 to FindStars() call
 *
 * Sep 15 2004	Add missing 0 shift arguments to RotFITS() call (Rob Creager)
 *
 * Jun 21 2006	Clean up code
 *
 * Jan 10 2007	Fix arguments to MagSortStars() and RASortStars()
 * Jan 10 2007	Declare RevMsg static, not const
 * Apr  6 2007	Add -g command to not rotate image WCS with image
 * Apr 27 2007	Set magoff to zero only if greater than 89, not 20
 * Oct 15 2007	Add -c option to print total flux in counts
 *
 * May 13 2015	Print two decimal place, not integer, pixel coordinates
 *
 * Jun 24 2016	Fix sprintf of headline after Ole Streicher
 */
