/*----------------------------------------------------------------------------*/ /** @file fitsort.c @author Nicolas Devillard @date May 1st, 1996 @version $Revision: 1.4 $ @brief Sorts out FITS keywords The input is a succession of FITS headers delivered through stdin by 'dfits'. On the command line, specify which keywords you wish to display, the output contains for each file, the file name and the keyword values in column format. Example: dfits *.fits | fitsort BITPIX NAXIS NAXIS1 NAXIS2 NAXIS3 The output would be like: File BITPIX NAXIS NAXIS1 NAXIS2 NAXIS3 image1.fits 32 2 256 256 image2.fits -32 3 128 128 40 Using 'fitsort -d ...' would prevent printing the first line (filename and keyword names). The output format is simple: values are separated by tabs, records by linefeeds. When no value is present (no keyword in this header), only a tab is printed out. Example: file1.fits contains NAXIS1=100 NAXIS2=200 file2.fits contains NAXIS1=20 dfits file1.fits file2.fits | fitsort NAXIS2 NAXIS1 would litterally print out (\t stands for tab, \n for linefeed): file1.fits\t200\t100\n file2.fits\t\t20\n */ /*----------------------------------------------------------------------------*/ /* $Id: fitsort.c,v 1.4 2005/07/04 14:21:31 yjung Exp $ $Author: yjung $ $Date: 2005/07/04 14:21:31 $ $Revision: 1.4 $ */ /*----------------------------------------------------------------------------- Include -----------------------------------------------------------------------------*/ #include #include #include #include /*----------------------------------------------------------------------------- Define -----------------------------------------------------------------------------*/ #define MAX_STRING 128 #define MAX_KEY 512 #define FMT_STRING "%%-%ds\t" /*----------------------------------------------------------------------------- New types -----------------------------------------------------------------------------*/ /* This holds a keyword value and a flag to indicate its presence */ typedef struct _KEYWORD_ { char value[MAX_STRING]; int present; } keyword; /* Each detected file in input has such an associated structure */ typedef struct _RECORD_ { char filename[MAX_STRING]; keyword listkw[MAX_KEY]; } record; /*----------------------------------------------------------------------------- Function prototypes -----------------------------------------------------------------------------*/ static int isfilename (char *string); static void getfilename (char *line, char *word); static char *expand_hierarch_keyword (char *, char *); static int isdetectedkeyword (char *line, char *keywords[], int nkeys); static void getkeywordvalue (char *line, char *word); /*----------------------------------------------------------------------------- Main -----------------------------------------------------------------------------*/ int main (int argc, char *argv[]) { char curline[MAX_STRING]; char word[MAX_STRING]; int i, j; int nfiles; record *allrecords; int kwnum; int len; int max_width[MAX_KEY]; int max_filnam; char fmt[8]; int flag; int printnames; int print_hdr; if (argc < 2) { printf ("\n\nuse : %s [-d] KEY1 KEY2 ... KEYn\n", argv[0]); printf ("Input data is received from stdin\n"); printf ("See man page for more details and examples\n\n"); return 0; } /* Initialize */ printnames = 0; print_hdr = 1; nfiles = 0; allrecords = (record *) calloc (1, sizeof (record)); if (!strcmp (argv[1], "-d")) { print_hdr = 0; argv++; argc--; } argv++; /* Uppercase all inputs */ for (i = 0; i < (argc - 1); i++) { j = 0; while (argv[i][j] != 0) { argv[i][j] = toupper (argv[i][j]); j++; } } while (fgets (curline, MAX_STRING, stdin) != (char *) NULL) { flag = isfilename (curline); if (flag == 1) { /* New file name is detected, get the new file name */ printnames = 1; getfilename (curline, allrecords[nfiles].filename); nfiles++; /* Initialize a new record structure to store data for this file. */ allrecords = (record *) realloc (allrecords, (nfiles + 1) * sizeof (record)); for (i = 0; i < MAX_KEY; i++) allrecords[nfiles].listkw[i].present = 0; } else if (flag == 0) { /* Is not a file name, is it a searched keyword? */ if ((kwnum = isdetectedkeyword (curline, argv, argc - 1)) != -1) { /* Is there anything allocated yet to store this? */ if (nfiles > 0) { /* It has been detected as a searched keyword. */ /* Get its value, store it, present flag up */ getkeywordvalue (curline, word); strcpy (allrecords[nfiles - 1].listkw[kwnum].value, word); allrecords[nfiles - 1].listkw[kwnum].present++; } } } } for (i = 0; i < argc - 1; i++) max_width[i] = (int) strlen (argv[i]); /* Record the maximum width for each column */ max_filnam = 0; for (i = 0; i < nfiles; i++) { len = (int) strlen (allrecords[i].filename); if (len > max_filnam) max_filnam = len; for (kwnum = 0; kwnum < argc - 1; kwnum++) { if (allrecords[i].listkw[kwnum].present) { len = (int) strlen (allrecords[i].listkw[kwnum].value); } else { len = 0; } if (len > max_width[kwnum]) max_width[kwnum] = len; } } /* Print out header line */ if (print_hdr) { sprintf (fmt, FMT_STRING, max_filnam); if (printnames) printf (fmt, "FILE"); for (i = 0; i < argc - 1; i++) { sprintf (fmt, FMT_STRING, max_width[i]); printf (fmt, argv[i]); } printf ("\n"); } /* Now print out stored data */ if (nfiles < 1) { printf ("*** error: no input data corresponding to dfits output\n"); return -1; } for (i = 0; i < nfiles; i++) { if (printnames) { sprintf (fmt, FMT_STRING, max_filnam); printf (fmt, allrecords[i].filename); } for (kwnum = 0; kwnum < argc - 1; kwnum++) { sprintf (fmt, FMT_STRING, max_width[kwnum]); if (allrecords[i].listkw[kwnum].present) printf (fmt, allrecords[i].listkw[kwnum].value); else printf (fmt, " "); } printf ("\n"); } free (allrecords); return 0; } /*----------------------------------------------------------------------------- Functions code -----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /** @brief find out if an input line contains a file name or a FITS magic nb. @param string dfits output line @return int (see below) Filename recognition is based on 'dfits' output. The function returns 1 if the line contains a valid file name as produced by dfits, 2 if it is for an extension, 0 otherwise. */ /*----------------------------------------------------------------------------*/ static int isfilename (char *string) { if (!strncmp (string, "====>", 5)) return 1; if (!strncmp (string, "===>", 4)) return 2; return 0; } /*----------------------------------------------------------------------------*/ /** @brief returns a file name from a dfits output line @param line dfits output line @param word file name @return a file name from a dfits output line This is dfits dependent. */ /*----------------------------------------------------------------------------*/ static void getfilename (char *line, char *word) { /* get filename from a dfits output */ sscanf (line, "%*s %*s %s", word); return; } /*----------------------------------------------------------------------------*/ /** @brief detects a if a keyword is present in a FITS line @param line FITS line @param keywords set of keywords @param nkeys number of kw in the set @return keyword rank, -1 if unidentified Feed this function a FITS line, a set of keywords in the *argv[] fashion (*keywords[]). If the provided line appears to contain one of the keywords registered in the list, the rank of the keyword in the list is returned, otherwise, -1 is returned. */ /*----------------------------------------------------------------------------*/ static int isdetectedkeyword (char *line, char *keywords[], int nkeys) { char kw[MAX_STRING]; char esokw[MAX_STRING]; int i; /* The keyword is up to the equal character, with trailing blanks removed */ strcpy (kw, line); strtok (kw, "="); /* Now remove all trailing blanks (if any) */ i = (int) strlen (kw) - 1; while (kw[i] == ' ') i--; kw[i + 1] = (char) 0; /* Now compare what we got with what's available */ for (i = 0; i < nkeys; i++) { if (strstr (keywords[i], ".") != NULL) { /* * keyword contains a dot, it is a hierarchical keyword that * must be expanded. Pattern is: * A.B.C... becomes HIERARCH ESO A B C ... */ expand_hierarch_keyword (keywords[i], esokw); if (!strcmp (kw, esokw)) { return i; } } else if (!strcmp (kw, keywords[i])) { return i; } } /* Keyword not found */ return -1; } /*----------------------------------------------------------------------------*/ /** @brief Expand a HIERARCH keyword in format A.B.C to HIERARCH ESO A B C @param dotkey Keyword @param hierarchy HIERARCH @return char *, pointer to second input string (modified) */ /*----------------------------------------------------------------------------*/ static char * expand_hierarch_keyword (char *dotkey, char *hierarchy) { char *token; char ws[MAX_STRING]; sprintf (hierarchy, "HIERARCH ESO"); strcpy (ws, dotkey); token = strtok (ws, "."); while (token != NULL) { strcat (hierarchy, " "); strcat (hierarchy, token); token = strtok (NULL, "."); } return hierarchy; } /*----------------------------------------------------------------------------*/ /** @brief Get a keyword value within a FITS line @param line FITS line to process @param word char string to return result @return void, result returned in word No complex value is recognized */ /*----------------------------------------------------------------------------*/ static void getkeywordvalue (char *line, char *word) { int c, w; char tmp[MAX_STRING]; char *begin, *end; int length; int quote = 0; int search = 1; memset (tmp, (char) 0, MAX_STRING); memset (word, (char) 0, MAX_STRING); c = w = 0; /* Parse the line till the equal '=' sign is found */ while (line[c] != '=') c++; c++; /* Copy the line till the slash '/' sign or the end of data is found. */ while (search == 1) { if (c >= 80) search = 0; else if ((line[c] == '/') && (quote == 0)) search = 0; if (line[c] == '\'') quote = !quote; tmp[w++] = line[c++]; } /* NULL termination of the string */ tmp[--w] = (char) 0; /* Return the keyword only : a diff is made between text fields and nbs. */ if ((begin = strchr (tmp, '\'')) != (char *) NULL) { /* A quote has been found: it is a string value */ begin++; end = strrchr (tmp, '\''); length = (int) strlen (begin) - (int) strlen (end); strncpy (word, begin, length); } else { /* No quote, just get the value (only one, no complex supported) */ sscanf (tmp, "%s", word); } return; }