void atlKy2hd( AstKeyMap *keymap, HDSLoc *loc, int *status ) { /* * Name: * atlKy2hd * Purpose: * Copies values from an AST KeyMap to a primitive HDS object. * Language: * C. * Invocation: * void atlKy2hd( AstKeyMap *keymap, HDSLoc *loc, int *status ) * Description: * This routine copies the contents of an AST KeyMap into a supplied * HDS structure. * Arguments: * keymap * An AST pointer to the KeyMap. * loc * A locator for the HDS object into which the KeyMap contents * are to be copied. A new component is added to the HDS object for * each entry in the KeyMap. * status * The inherited status. * Copyright: * Copyright (C) 2008, 2010, 2012 Science & Technology Facilities Council. * All Rights Reserved. * Licence: * 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 * Authors: * DSB: David S. Berry * TIMJ: Tim Jenness (JAC, Hawaii) * {enter_new_authors_here} * History: * 29-APR-2008 (DSB): * Original version. * 2010-09-23 (TIMJ): * Fix arrays of strings. * 2010-09-30 (TIMJ): * Make sure that we are using the correct status pointer in AST. * 2010-10-01 (TIMJ): * Sort the keys when writing to HDS structured. * 2010-10-04 (TIMJ): * Support Short ints in keymap * 14-SEP-2012 (DSB): * Moved from kaplibs to atl. * 17-SEP-2012 (DSB): * Add support for undefined values. * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} */ /* Local Varianles: */ AstObject **objArray = NULL; AstObject *obj = NULL; HDSLoc *cloc = NULL; HDSLoc *dloc = NULL; const char *cval = NULL; const char *key; double dval; float fval; int i; int ival; int j; int lenc; int nval; char *oldsortby; int *oldstat = NULL; int size; int type; int veclen; size_t el; void *pntr = NULL; /* Check inherited status */ if( *status != SAI__OK ) return; /* Make sure that we are checking AST status */ oldstat = astWatch( status ); /* If set, save the old SortBy value and then ensure alphabetical sorting. We need to take a copy of the original string since the buffer in which the string is stored may be re-used by subsequent incocations of astGetC. */ if( astTest( keymap, "SortBy" ) ) { int nc = 0; oldsortby = astAppendString( NULL, &nc, astGetC( keymap, "SortBy" ) ); } else { oldsortby = NULL; } astSet( keymap, "SortBy=KeyUp" ); /* Loop round each entry in the KeyMap. */ size = astMapSize( keymap ); for( i = 0; i < size; i++ ) { if (*status != SAI__OK) break; /* Get the key. the data type and the vector length for the current KeyMap entry. */ key = astMapKey( keymap, i ); type = astMapType( keymap, key ); veclen = astMapLength( keymap, key ); /* If the current entry holds one or more nested KeyMaps, then we call this function recursively to add them into a new HDS component. */ if( type == AST__OBJECTTYPE ) { /* First deal with scalar entries holding a single KeyMap. */ if( veclen == 1 ) { datNew( loc, key, "KEYMAP_ENTRY", 0, NULL, status ); datFind( loc, key, &cloc, status ); (void) astMapGet0A( keymap, key, &obj ); if( astIsAKeyMap( obj ) ) { atlKy2hd( (AstKeyMap *) obj, cloc, status ); } else if( *status == SAI__OK ) { *status = SAI__ERROR; errRep( "", "atlKy2hd: Supplied KeyMap contains unusable AST " "objects (programming error).", status ); } datAnnul( &cloc, status ); /* Now deal with vector entries holding multiple KeyMaps. */ } else { datNew( loc, key, "KEYMAP_ENTRY", 1, &veclen, status ); datFind( loc, key, &cloc, status ); objArray = astMalloc( sizeof( AstObject *) * (size_t)veclen ); if( objArray ) { (void) astMapGet1A( keymap, key, veclen, &nval, objArray ); for( j = 1; j <= veclen; j++ ) { datCell( cloc, 1, &j, &dloc, status ); if( astIsAKeyMap( objArray[ j - 1 ] ) ) { atlKy2hd( (AstKeyMap *) objArray[ j - 1 ], dloc, status ); } else if( *status == SAI__OK ) { *status = SAI__ERROR; errRep( "", "atlKy2hd: Supplied KeyMap contains unusable AST " "objects (programming error).", status ); } datAnnul( &dloc, status ); } objArray = astFree( objArray ); } datAnnul( &cloc, status ); } /* For primitive types... */ } else if( type == AST__INTTYPE ) { if( veclen == 1 ) { datNew0I( loc, key, status ); datFind( loc, key, &cloc, status ); (void) astMapGet0I( keymap, key, &ival ); datPut0I( cloc, ival, status ); datAnnul( &cloc, status ); } else { datNew1I( loc, key, veclen, status ); datFind( loc, key, &cloc, status ); datMapV( cloc, "_INTEGER", "WRITE", &pntr, &el, status ); (void) astMapGet1I( keymap, key, veclen, &nval, (int *) pntr ); datUnmap( cloc, status ); datAnnul( &cloc, status ); } } else if( type == AST__SINTTYPE ) { short sval = 0; if( veclen == 1 ) { datNew0W( loc, key, status ); datFind( loc, key, &cloc, status ); (void) astMapGet0S( keymap, key, &sval ); datPut0W( cloc, sval, status ); datAnnul( &cloc, status ); } else { datNew1W( loc, key, veclen, status ); datFind( loc, key, &cloc, status ); datMapV( cloc, "_WORD", "WRITE", &pntr, &el, status ); (void) astMapGet1S( keymap, key, veclen, &nval, (short *) pntr ); datUnmap( cloc, status ); datAnnul( &cloc, status ); } } else if( type == AST__DOUBLETYPE ) { if( veclen == 1 ) { datNew0D( loc, key, status ); datFind( loc, key, &cloc, status ); (void) astMapGet0D( keymap, key, &dval ); datPut0D( cloc, dval, status ); datAnnul( &cloc, status ); } else { datNew1D( loc, key, veclen, status ); datFind( loc, key, &cloc, status ); datMapV( cloc, "_DOUBLE", "WRITE", &pntr, &el, status ); (void) astMapGet1D( keymap, key, veclen, &nval, (double *) pntr ); datUnmap( cloc, status ); datAnnul( &cloc, status ); } } else if( type == AST__FLOATTYPE ) { if( veclen == 1 ) { datNew0R( loc, key, status ); datFind( loc, key, &cloc, status ); (void) astMapGet0F( keymap, key, &fval ); datPut0R( cloc, fval, status ); datAnnul( &cloc, status ); } else { datNew1R( loc, key, veclen, status ); datFind( loc, key, &cloc, status ); datMapV( cloc, "_REAL", "WRITE", &pntr, &el, status ); (void) astMapGet1F( keymap, key, veclen, &nval, (float *) pntr ); datUnmap( cloc, status ); datAnnul( &cloc, status ); } } else if( type == AST__STRINGTYPE ) { lenc = astMapLenC( keymap, key ); if( veclen == 1 ) { datNew0C( loc, key, lenc, status ); datFind( loc, key, &cloc, status ); (void) astMapGet0C( keymap, key, &cval ); datPut0C( cloc, cval, status ); datAnnul( &cloc, status ); } else { datNew1C( loc, key, lenc, veclen, status ); datFind( loc, key, &cloc, status ); datMapV( cloc, "_CHAR", "WRITE", &pntr, &el, status ); (void) atlMapGet1C( keymap, key, veclen*lenc, lenc, &nval, (char *) pntr, status ); datUnmap( cloc, status ); datAnnul( &cloc, status ); } /* KeyMap "UNDEF" values are always scalar and have no corresponding HDS data type. So arbitrarily use an "_INTEGER" primitive with no defined value to represent a KeyMap UNDEF value. */ } else if( type == AST__UNDEFTYPE ) { datNew0L( loc, key, status ); /* Unknown or unsupported data types. */ } else if( *status == SAI__OK ) { *status = SAI__ERROR; msgSeti( "T", type ); errRep( "", "atlKy2hd: Supplied KeyMap contains entries with " "unusable data type (^T) (programming error).", status ); } } /* If it was originally set, re-instate the old SortBy value in the KeyMap, then free the memory. Otherwise, clear the SortBy attribute. */ if( oldsortby ) { astSetC( keymap, "SortBy", oldsortby ); oldsortby = astFree( oldsortby ); } else { astClear( keymap, "SortBy" ); } /* Reset AST status */ astWatch( oldstat ); }
dim_t smf_get_padding( AstKeyMap *keymap, int report, const smfHead *hdr, double steptime, int *status ) { /* Local Variables: */ AstObject *obj; const char *key; dim_t pad; dim_t result; double f_low; double filt_edgehigh; double filt_edgelarge; double filt_edgelow; double filt_edgesmall; double filt_notchlow[ SMF__MXNOTCH ]; int f_nnotch; int iel; int nel; int temp; double scalelen; double downsampscale; double downsampfreq; /* Initialise */ result = 0; /* Main routine */ if (*status != SAI__OK) return result; /* If the keymap contains a PAD value, return it. */ if( astMapGet0I( keymap, "PAD", &temp ) ) { if( temp < 0 && *status == SAI__OK ) { *status = SAI__ERROR; errRep( "", "PAD cannot be < 0.", status ); } else { result = (dim_t) temp; } /* If the keymap contains no PAD value, calculate a default on the basis of the FILT_ values. */ } else { /* If the keymap does not contain a PAD value, not even an "<undef>" value, an error will have been reported by astMapget0I above. In this case, annull the error and continue since the KeyMap may contain FILT_ values that can be used to calculate a default PAD value. */ if( *status == AST__MPKER ) errAnnul( status ); /* Search for filtering parameters in the keymap. None of these parameters represent a number of time clies, so we can set the smfData (the 2nd argument) to NULL. */ f_nnotch = 0; smf_get_cleanpar( keymap, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &filt_edgelow, &filt_edgehigh, &filt_edgesmall, &filt_edgelarge, filt_notchlow, NULL, &f_nnotch, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &downsampscale, &downsampfreq, NULL, status ); if( downsampscale && downsampfreq ) { *status = SAI__ERROR; errRep( "", FUNC_NAME ": both downsampscale and downsampfreq are set", status ); } /* If any were not found, annul the error and continue with those that were found (plus defaults for the others). */ if( *status == AST__MPKER ) errAnnul( status ); if( *status == SAI__OK ) { /* Modify edge filters if spatial scales were requested */ smf_scale2freq( filt_edgesmall, filt_edgelarge, hdr, &filt_edgelow, &filt_edgehigh, status ); if( *status == SMF__TELSTAT ) { errAnnul( status ); } /* Find the lowest of these frequencies. The lowest frequency will give the greatest padding. */ f_low = ( filt_edgehigh > 0.0 ) ? filt_edgehigh : VAL__MAXD; if( filt_edgelow > 0.0 && filt_edgelow < f_low ) f_low = filt_edgelow; for( iel = 0; iel < f_nnotch; iel++ ) { if( filt_notchlow[ iel ] > 0.0 && filt_notchlow[ iel ] < f_low ) f_low = filt_notchlow[ iel ]; } /* If any down-sampling is occurring, set the step time to value implied by the requested downsampling factor. This should match the calculation in smf_grp_related */ if( downsampscale || downsampfreq ) { if( downsampscale ) { scalelen = hdr->steptime * hdr->scanvel / downsampscale; } else { if( hdr->steptime ) { scalelen = downsampfreq / (1./hdr->steptime); } else { *status = SAI__ERROR; scalelen = VAL__BADD; errRep( "", FUNC_NAME ": can't resample because smfData has " "unknown sample rate", status ); } } if( (*status==SAI__OK) && (scalelen<=SMF__DOWNSAMPLIMIT) ) steptime = hdr->steptime/scalelen; /* If no downsampling is happening, use the steptime in the header unless another steptime was supplied. */ } else if( steptime == VAL__BADD ) { steptime = hdr->steptime; } /* Find the corresponding padding. */ if( f_low != VAL__MAXD ) { result = 1.0/( steptime * f_low ); } else { result = 0; } /* Now check the supplied keymap for any nested keymaps. Assumes that each entry in the supplied KeyMap contain either a primitive value or a scalar KeyMap pointer. */ nel = astMapSize( keymap ); for( iel = 0; iel < nel; iel++ ) { key = astMapKey( keymap, iel ); /* If this entry is a KeyMap (assuming no other class of AST object is stored in the KeyMap)... */ if( astMapType( keymap, key ) == AST__OBJECTTYPE ) { /* Get a pointer to the KeyMap. */ (void) astMapGet0A( keymap, key, &obj ); /* Call this function to get the padding implied by the sub-KeyMap. */ pad = smf_get_padding( (AstKeyMap *) obj, report, hdr, steptime, status ); /* Use the larger of the two paddings. */ if( pad > result ) result = pad; } } /* If required, report the default value. */ if( report ) { msgSeti( "P", (int) result ); msgOutif( MSG__VERB, "", "Padding each time stream with ^P zero " "values at start and end.", status ); } } } /* Return the result. */ return result; }
void kpg1Kygp1( AstKeyMap *keymap, Grp **igrp, const char *prefix, int *status ){ /* *+ * Name: * kpg1Kygp1 * Purpose: * Creates a GRP group holding keyword/value pairs read from an AST KeyMap. * Language: * C. * Invocation: * void kpg1Kygp1( AstKeyMap *keymap, Grp **igrp, const char *prefix, * int *status ) * Description: * This function is the inverse of kpg1Kymp1. It extracts the values * from the supplied AST KeyMap and creates a set of "name=value" strings * which it appends to a supplied group (or creates a new group). If * the KeyMap contains nested KeyMaps, then the "name" associated with * each primitive value stored in the returned group is a hierarchical * list of component names separated by dots. * Arguments: * keymap * A pointer to the KeyMap. Numerical entries which have bad values * (VAL__BADI for integer entries or VAL__BADD for floating point * entries) are not copied into the group. * igrp * A location at which is stored a pointer to the Grp structure * to which the name=value strings are to be appended. A new group is * created and a pointer to it is returned if the supplied Grp * structure is not valid. * prefix * A string to append to the start of each key extracted from the * supplied KeyMap. If NULL, no prefix is used. * status * Pointer to the inherited status value. * Notes: * - This function provides a private implementation for the public * KPG1_KYGRP Fortran routine and kpg1Kygrp C function. * - Entries will be stored in the group in alphabetical order * Copyright: * Copyright (C) 2008,2010 Science & Technology Facilities Council. * Copyright (C) 2005 Particle Physics & Astronomy Research Council. * All Rights Reserved. * Licence: * 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 * Authors: * DSB: David S. Berry * TIMJ: Tim Jenness (JAC, Hawaii) * {enter_new_authors_here} * History: * 7-NOV-2005 (DSB): * Original version. * 15-JUL-2008 (TIMJ): * Tweak to GRP C API. * 2010-07-19 (TIMJ): * Handle vector keymap entries. * 2010-08-12 (TIMJ): * Store entries in group in alphabetical order. * 13-AUG-2010 (DSB): * Re-instate the original SortBy value before exiting. * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} *- */ /* Local Variables: */ AstObject *obj; /* Pointer to nested AST Object */ char *oldsortby; /* The old value of the KeyMap's SortBy attribute */ char *text; /* Sum of concatenated strings */ const char *key; /* Key string for current entry in KeyMap */ const char *value; /* Value of current entry in KeyMap */ double dval; /* Double value */ int *old_status; /* Pointer to original status variable */ int bad; /* Is the numerical entry value bad? */ int i; /* Index into supplied KeyMap */ int ival; /* Integer value */ int n; /* Number of entries in the KeyMap */ int nc; /* Length of "text" excluding trailing null */ int type; /* Data type of current entry in KeyMap */ int valid; /* Is the supplied GRP structure valid? */ /* Check the inherited status. */ if( *status != SAI__OK ) return; /* Make AST use the Fortran status variable. */ old_status = astWatch( status ); /* Create a new GRP group if required. */ valid = grpValid( *igrp, status ); if( !valid ) *igrp = grpNew( "Created by kpg1_Kygp1", status ); /* If set, save the old SortBy value and then ensure alphabetical sorting. We need to take a copy of the original string since the buffer in which the string is stored may be re-used by subsequent incocations of astGetC. */ if( astTest( keymap, "SortBy" ) ) { nc = 0; oldsortby = astAppendString( NULL, &nc, astGetC( keymap, "SortBy" ) ); } else { oldsortby = NULL; } astSet( keymap, "SortBy=KeyUp" ); /* Get the number of entries in the KeyMap. */ n = astMapSize( keymap ); /* Loop round all the entries in the KeyMap.*/ for( i = 0; i < n; i++ ) { /* Get the name and type of the current KeyMap entry. */ key = astMapKey( keymap, i ); type = astMapType( keymap, key ); /* If the entry is an AST Object, get a pointer to it.*/ if( type == AST__OBJECTTYPE && astMapGet0A( keymap, key, &obj ) ) { /* If it is a nested KeyMap, update the prefix and call this function recursively. We ignore other forms of AST Objects. */ if( astIsAKeyMap( obj ) ) { nc = 0; text = astAppendString( NULL, &nc, prefix ); text = astAppendString( text, &nc, key ); text = astAppendString( text, &nc, "." ); kpg1Kygp1( (AstKeyMap *) obj, igrp, text, status ); text = astFree( text ); } /* If it is a primitive, format it and add it to the group. */ } else { /* If it is a numerical type, see if it has a bad value. */ bad = 0; if( type == AST__INTTYPE && astMapGet0I( keymap, key, &ival ) ){ if( ival == VAL__BADI ) bad = 1; } else if( type == AST__DOUBLETYPE && astMapGet0D( keymap, key, &dval ) ){ if( dval == VAL__BADD ) bad = 1; } /* If it not bad, get its formatted value. We also make sure that astMapGet0C returns true because we intend to skip undefined values. */ if( !bad && astMapGet0C( keymap, key, &value ) ) { size_t length; /* Write the key and equals sign to a buffer */ nc = 0; text = astAppendString( NULL, &nc, prefix ); text = astAppendString( text, &nc, key ); text = astAppendString( text, &nc, "=" ); length = astMapLength( keymap, key ); if( length > 1 ) { /* Vector so we need to use (a,b,c) syntax */ char thiselem[GRP__SZNAM+1]; size_t l; text = astAppendString( text, &nc, "("); for ( l = 0; l < length; l++) { if( astMapGetElemC( keymap, key, sizeof(thiselem), l, thiselem ) ) { text = astAppendString( text, &nc, thiselem ); } /* always deal with the comma. Even if value was undef we need to put in the comma */ if( l < (length - 1) ) { text = astAppendString( text, &nc, "," ); } } text = astAppendString( text, &nc, ")"); } else { /* Scalar */ text = astAppendString( text, &nc, value ); } /* Put it in the group. */ grpPut1( *igrp, text, 0, status ); text = astFree( text ); } } } /* If it was originally set, re-instate the old SortBy value in the KeyMap, then free the memory. Otherwise, clear the SortBy attribute. */ if( oldsortby ) { astSetC( keymap, "SortBy", oldsortby ); oldsortby = astFree( oldsortby ); } else { astClear( keymap, "SortBy" ); } /* Make AST use its original status variable. */ astWatch( old_status ); }
static void DisplayKeyMap( AstKeyMap *km, int sort, const char *prefix, AstKeyMap *refkm, int *status ){ /* * Name: * DisplayKeyMap * Purpose: * Display the contents of a keymap. * Synopsis: * void DisplayKeyMap( AstKeyMap *km, int sort, const char *prefix, * int *status ) * Arguments: * km * Pointer to the KeyMaps containing the values to display. * sort * If non-zero, sort the values alphabetically by their keys. * prefix * A string to prepend to eack key. * refkm * Reference key map (e.g. values from the supplied configuration * rather than the NDF history), or null if not required. * status * Inherited status pointer. * Description: * This function displays the contents of a supplied KeyMap as * a series of "key = value" strings, one per line. It calls itself * recursively if a nested KeyMap is found, adding a suitable * prefix to the nested keys. If a reference key map is supplied then * the output shows how the main key map differs from it. */ /* Local Variables: */ AstObject *avalue; AstObject *refavalue; char cbuffer[ 255 ]; char newpref[ 255 ]; const char *cvalue; const char *refcvalue; const char *key; int ikey; int ival; int nc; int nkey; int nval; /* Check the inherited status */ if( *status != SAI__OK ) return; if (refkm) astClear(refkm, "KeyError"); /* Sort the supplied KeyMap is required. */ if( sort ) astSetC( km, "SortBy", "KeyUp" ); /* Loop round all keys in the supplied KeyMap. */ nkey = astMapSize( km ); for( ikey = 0; ikey < nkey; ikey++ ) { key = astMapKey( km, ikey ); /* If the current entry is a nest KeyMap, get a pointer to it and call this function recurisvely to display it, modifying the prefix to add to each key so that it includes the key associated with the nest keymap. */ if( astMapType( km, key ) == AST__OBJECTTYPE ) { astMapGet0A( km, key, &avalue ); if (refkm) { if (! astMapGet0A(refkm, key, &refavalue)) { refavalue = (AstObject*) astKeyMap(""); } } else { refavalue = NULL; } sprintf( newpref, "%s%s.", prefix, key ); DisplayKeyMap( (AstKeyMap *) avalue, sort, newpref, (AstKeyMap *) refavalue, status ); avalue = astAnnul( avalue ); if (refavalue) refavalue = astAnnul(refavalue); /* If the current entry is not a nested keymap, we display it now. */ } else { /* Get the vector length of the entry. */ nval = astMapLength( km, key ); /* If it is a scalar, just get its value as a character string using the automatic type conversion provided by the KeyMap class, and display it, putting the supplied prefix at the start of the key. */ if( nval <= 1 ) { cvalue = "<undef>"; astMapGet0C( km, key, &cvalue ); if (refkm) { refcvalue = "<undef>"; if (astMapGet0C(refkm, key, &refcvalue) && ! strcmp(cvalue, refcvalue)) { msgOutf("", "- %s%s = %s", status, prefix, key, cvalue); } else { msgOutf("", "+ %s%s = %s", status, prefix, key, cvalue); } } else { msgOutf( "", "%s%s = %s", status, prefix, key, cvalue ); } /* If it is a vector, we construct a string containing a comma-separated list of elements, enclosed in parentheses. */ } else { nc = 0; cvalue = astAppendString( NULL, &nc, "(" ); for( ival = 0; ival < nval; ival++ ) { if( astMapGetElemC( km, key, sizeof( cbuffer) - 1, ival, cbuffer ) ) { cvalue = astAppendString( (char *) cvalue, &nc, cbuffer ); } if( ival < nval - 1 ) cvalue = astAppendString( (char *) cvalue, &nc, "," ); } cvalue = astAppendString( (char *) cvalue, &nc, ")" ); /* Do the same for the reference KeyMap. */ if (refkm && (nval = astMapLength(refkm, key))) { nc = 0; refcvalue = astAppendString(NULL, &nc, "("); for (ival = 0; ival < nval; ival++) { if (ival) { refcvalue = astAppendString((char*) refcvalue, &nc, "," ); } if (astMapGetElemC(refkm, key, sizeof(cbuffer) - 1, ival, cbuffer)) { refcvalue = astAppendString((char*) refcvalue, &nc, cbuffer); } } refcvalue = astAppendString((char*) refcvalue, &nc, ")"); } else { refcvalue = NULL; } /* Display the total string, with the current key prefix, and free the memory used to store it. */ if (refkm) { if (refcvalue && ! strcmp(cvalue, refcvalue)) { msgOutf("", "- %s%s = %s", status, prefix, key, cvalue); } else { msgOutf("", "+ %s%s = %s", status, prefix, key, cvalue); } } else { msgOutf( "", "%s%s = %s", status, prefix, key, cvalue ); } cvalue = astFree( (void *) cvalue ); if (refcvalue) refcvalue = astFree((void*) refcvalue); } } } }