# include # include # include # include "msstat.h" # define SWAP(a,b) temp=(a);(a)=(b);(b)=temp; /* E_LIB -- Some basic functions for: * * - handling compressed HDUs * - string parsing * - range string decoding * - dictionary search * - dictionary extract * - select k-th smallest value * - messaging at stdout * * * Revision history: * ---------------- * 09 Jun 96 - Implementation (IB) * 21 Oct 96 - Revised after code review (IB) * 12 Nov 96 - Support for compressed HDUs (IB) * 06 Mar 97 - Warns when invalid tokens are found in control * strings (IB) * 06 Mar 97 - Support for sections with compressed HDUs (IB) * */ /* This routine replaces the equivalent cvos (ximio) call, and * should be used whenever compressed HDUs in the HSTIO sense * are expected. * */ int e_imglen (IRAFPointer im, int axis) { char str[10]; int size; if (c_imgndim (im) == 0) { if (c_imaccf (im, "PIXVALUE")) { sprintf (str, "NPIX%d", axis); size = c_imgeti (im, str); } else size = 0; } else size = c_imglen (im, axis); return (size); } /* Parse strings into enumerated types and stores results into control * structure. * * This routine is used to parse the "stats", "arrays" and "clarray" * parameters. Commas must be used as separators, embedded blanks are * ignored. The third parameter is used to discriminate in between the * three string types. * */ void e_parseString (Control *con, char *string, int type) { int inp_index; /* Index in input string */ int wk_index; /* Index in work string */ char work[SZ_STR]; /* Work string */ int found, i; char fmt[] = "Ignoring invalid token: %s"; int e_strdic (char *, char *, int, char *); i = 0; inp_index = 0; while (inp_index < strlen(string)) { /* Isolate next token in input string. */ wk_index = 0; while (string[inp_index] != ',' && inp_index < strlen(string)) work[wk_index++] = string[inp_index++]; work[wk_index] = '\0'; inp_index++; /* Look into dictionary. Notice the -2 used to make * the 1-indexed dictionary comply with -1-indexed * enumerated types. */ switch (type) { case TYPE_STAT: found = e_strdic (work, work, SZ_STR, STAT_TYPES); if (found) con->stats[i++] = found-2; /* skip "doall" spec */ else { sprintf (MsgText, fmt, work); e_warn (MsgText); } break; case TYPE_HDU: found = e_strdic (work, work, SZ_STR, HDU_TYPES); if (found) con->hdu[i++] = found-2; /* skip primary header */ else { sprintf (MsgText, fmt, work); e_warn (MsgText); } break; case TYPE_CLHDU: con->cl_hdu = e_strdic (work, work, SZ_STR, HDU_TYPES) - 2; if (con->cl_hdu == -2) { sprintf (MsgText, fmt, work); e_warn (MsgText); } break; } } switch (type) { case TYPE_STAT: con->nstats = i; break; case TYPE_HDU: con->nhdu = i; break; } } /* Parse range string and stores initial group, final group and step * into control structure. * * This routine is used to parse the "groups" parameter. The syntax * is similar to the range string used to specify image sections. * Ex.: * g1 - group g1 * g1-g2 - all groups from g1 to g2 * g1-g2xg3 - every other g3nd group, from g1 to g2 * * - all groups in file * */ void e_parseGroups (Control *con, char *string) { int inp_index; /* Index in input string */ int wk_index; /* Index in work string */ char work[SZ_STR]; /* Work string */ con->group_init = 1; con->group_end = 1; con->group_step = 1; /* Test the all-groups case. */ inp_index = 0; while (string[inp_index] == ' ') inp_index++; if (*string == '*') { con->allGroups = True; return; } else { con->allGroups = False; /* Now go parsing string. */ wk_index = 0; while (string[inp_index] != '-' && inp_index < strlen(string)) work[wk_index++] = string[inp_index++]; work[wk_index] = '\0'; inp_index++; con->group_init = atoi (work); if (string[inp_index-1] != '\0') { wk_index = 0; while (string[inp_index] != 'x' && inp_indexgroup_end = atoi (work); } else { con->group_end = con->group_init; con->group_step = 1; return; } if (string[inp_index-1] != '\0') { wk_index = 0; while (inp_index < strlen(string)) work[wk_index++] = string[inp_index++]; work[wk_index] = '\0'; inp_index++; con->group_step = atoi (work); } else { con->group_step = 1; return; } } } /* E_STRDIC -- Search a dictionary string for a match with an input string. * * The input string may be an abbreviation of a dictionary entry, however, * it is an error if the abbreviation is not unique. The entries in the * dictionary string are separated by a delimiter character which is the * first character of the dictionary string. The full name of the matched * dictionary entry found is returned in out_str; the function value is the * word index of the dictionary entry. The output string may be the same as * the input string. * * * This is an almost plain SPP->C translation of iraf$sys/fmtio/strdic.x * with minor modifications to deal with zero-indexed vectors (5/10/96 IB) * * The output is 1-indexed into the dictionary elements. * */ int e_strdic (char *in_str, char *out_str, int maxchars, char *dict) { /* char in_str[ARB] # Input string char out_str[ARB] # Output string as found in dictionary int maxchars # Maximum length of output string char dict[ARB] # Dictionary string */ char ch, fch; int start, len, ip, i, match, entry; if (dict[0] == '\0') return (0); i = 0; while (in_str[i++] == ' '); start = i-1; match = 0; ip = 1; len = strlen (in_str+start); fch = in_str[start]; /* Search the dictionary string. If the input string matches a * dictionary entry it is either an exact match (len = dictionary * entry length) or a legal abbreviation. If an abbreviation * matches two entries it is ambiguous and an error. */ for (entry=1; dict[ip] != '\0'; entry=entry+1) { if (dict[ip] == fch) { if (strncmp (dict+ip, in_str+start, len) == 0) { for (i=0; i < maxchars; i++) { ch = dict[ip+i]; if ((ch == dict[0]) || (ch == '\0')) break; out_str[i] = ch; } out_str[i] = '\0'; if ((dict[ip+len] == dict[0]) || (dict[ip+len] == '\0')) return (entry); /* exact match */ else { /* If we already have a match and the new match is * not exact, then the abbreviation is ambiguous. */ if (match != 0) return (0); else match = entry; } } } while (dict[ip] != dict[0] && dict[ip+1] != '\0') ip++; ip++; } return (match); } /* E_STREXTRACT -- Extract the Nth string from a dictionary. * * The dictionary string must have the same format as required by e-strdic. * If index points to an inexistent element, nothing happens. * * */ void e_strExtract (int index, char *out_str, char *dict) { char separator; int i, jp, ip, counter; if (index < 1) return; separator = dict[0]; /* separator is the first character in dict */ ip = 0; /* points to first character in dictionary */ counter = 0; /* counts how many separators were found */ /* Locate index-th occurrence of separator. */ while (counter < index) { while (dict[ip] != separator) { if (dict[ip] == '\0') return; ip++; } ip++; counter++; } /* Locate next occurrence of separator. This is why the * dictionary string _must_ be terminated with a separator. */ jp = ip; while (dict[jp] != separator) { if (dict[jp] == '\0') return; jp++; } /* Copy to output string. */ i = 0; while (ip < jp) out_str[i++] = dict[ip++]; out_str[i] = '\0'; } /* * E_SELECT - Selects k-th smallest value in vector. * * From "Numerical Recipes - The Art of Scientific Computing", * Press, W.H., Teukolsky, S.A., Vetterling, W.T. and Flannery, B.P., * 2nd edition, Cambridge University Press, 1995. * * Vectors are 1-indexed, thus the calling sequence should be * something as: * * med = g_select ((long)n/2, (long)n, temp-1); * * where `temp' is a standard, 0-indexed, 1-dimensional C array. * * */ float e_select (unsigned long k, unsigned long n, float arr[]) { unsigned long i, ir, j, l, mid; float a, temp; l = 1; ir = n; for (;;) { if (ir <= l+1) { if (ir == l+1 && arr[ir] < arr[l]) { SWAP(arr[l], arr[ir]) } return arr[k]; } else { mid = (l+ir) >> 1; SWAP(arr[mid], arr[l+1]) if (arr[l] > arr[ir]) { SWAP(arr[l], arr[ir]) } if (arr[l+1] > arr[ir]) { SWAP(arr[l+1], arr[ir]) } if (arr[l] > arr[l+1]) { SWAP(arr[l], arr[l+1]) } i = l+1; j = ir; a = arr[l+1]; for (;;) { do i++; while (arr[i] < a); do j--; while (arr[j] > a); if (j < i) break; SWAP(arr[i], arr[j]) } arr[l+1] = arr[j]; arr[j] = a; if (j >= k) ir = j - 1; if (j <= k) l = i; } } } /* Routines for handling messaging at stdout. * * g_message does NOT issue a newline after the message because * it is used in more sophisticated formatting operations. */ void e_message (char *message) { printf ("%s", message); fflush(stdout); } void e_warn (char *message) { printf ("# *** WARNING: %s\n", message); fflush(stdout); } void e_warn2 (char *message) { printf ("# *** WARNING: %s. Skipping file...\n", message); fflush(stdout); } void e_error (char *message) { printf ("# *** ERROR: %s\n", message); fflush(stdout); } void e_IRAFerror () { printf ("# *** IRAF ERROR: %s (%d)\n", c_iraferrmsg(), c_iraferr()); fflush(stdout); }