uves_utils_wrappers.c

00001 /*                                                                              *
00002  *   This file is part of the ESO UVES Pipeline                                 *
00003  *   Copyright (C) 2004,2005 European Southern Observatory                      *
00004  *                                                                              *
00005  *   This library is free software; you can redistribute it and/or modify       *
00006  *   it under the terms of the GNU General Public License as published by       *
00007  *   the Free Software Foundation; either version 2 of the License, or          *
00008  *   (at your option) any later version.                                        *
00009  *                                                                              *
00010  *   This program is distributed in the hope that it will be useful,            *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
00013  *   GNU General Public License for more details.                               *
00014  *                                                                              *
00015  *   You should have received a copy of the GNU General Public License          *
00016  *   along with this program; if not, write to the Free Software                *
00017  *   Foundation, 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA       *
00018  *                                                                              */
00019 
00020 /*
00021  * $Author: jmlarsen $
00022  * $Date: 2007/08/21 13:08:26 $
00023  * $Revision: 1.110 $
00024  * $Name: uves-3_4_5 $
00025  * $Log: uves_utils_wrappers.c,v $
00026  * Revision 1.110  2007/08/21 13:08:26  jmlarsen
00027  * Removed irplib_access module, largely deprecated by CPL-4
00028  *
00029  * Revision 1.109  2007/07/23 12:52:28  jmlarsen
00030  * Make work also with CPL3
00031  *
00032  * Revision 1.108  2007/07/19 09:55:38  jmlarsen
00033  * Renamed cpl_vector_get_median -> cpl_vector_get_median_const
00034  *
00035  * Revision 1.107  2007/06/20 15:34:16  jmlarsen
00036  * Fixed assertion failure if sorting table column with only nulls
00037  *
00038  * Revision 1.106  2007/06/06 08:17:33  amodigli
00039  * replace tab with 4 spaces
00040  *
00041  * Revision 1.105  2007/06/06 06:28:30  jmlarsen
00042  * Renamed non-header file uves_tools_body.h -> uves_tools_body.c
00043  *
00044  * Revision 1.104  2007/05/23 12:50:36  jmlarsen
00045  * Added missing include directive
00046  *
00047  * Revision 1.103  2007/05/23 12:50:07  jmlarsen
00048  * Replace isnan/isinf -> irplib_isnan/irplib_isinf
00049  *
00050  * Revision 1.102  2007/05/11 08:41:20  jmlarsen
00051  * Added support for type float in table selection functions
00052  *
00053  * Revision 1.101  2007/05/08 14:27:18  jmlarsen
00054  * Avoid exporting workaround functions
00055  *
00056  * Revision 1.100  2007/05/07 10:17:44  jmlarsen
00057  * Added uves_image_reject_all
00058  *
00059  * Revision 1.99  2007/05/04 13:14:32  jmlarsen
00060  * Added workaround code
00061  *
00062  * Revision 1.98  2007/05/03 15:24:27  jmlarsen
00063  * Added deallocator functions
00064  *
00065  * Revision 1.97  2007/04/24 12:50:29  jmlarsen
00066  * Replaced cpl_propertylist -> uves_propertylist which is much faster
00067  *
00068  * Revision 1.96  2007/04/24 09:43:17  jmlarsen
00069  * Renamed uves_propertylist_append -> uves_propertylist_append_property
00070  *
00071  * Revision 1.95  2007/04/20 14:45:37  jmlarsen
00072  * Added uves_sort_table_3()
00073  *
00074  * Revision 1.94  2007/04/19 06:26:28  jmlarsen
00075  * Fixed: set slope to input value, not zero in first iteration
00076  *
00077  * Revision 1.93  2007/04/03 11:03:01  jmlarsen
00078  * Added uves_free_float
00079  *
00080  * Revision 1.92  2007/03/19 13:51:02  jmlarsen
00081  * Added workaround for cpl_table_and_selected_invalid
00082  *
00083  * Revision 1.91  2007/03/15 12:34:52  jmlarsen
00084  * Declared functions static
00085  *
00086  * Revision 1.90  2007/03/13 15:36:19  jmlarsen
00087  * Implemented yet another faster and uglier workaround for the slow cpl_table_erase_selected()
00088  *
00089  * Revision 1.89  2007/03/05 10:15:20  jmlarsen
00090  * Support slope parameter in 1d fitting
00091  *
00092  * Revision 1.88  2007/02/26 11:55:52  jmlarsen
00093  * Renamed and generalized function uves_raise_to_median() -> uves_raise_to_median_frac()
00094  *
00095  * Revision 1.87  2007/02/22 15:36:29  jmlarsen
00096  * Don't use workaround for cpl_table_erase_selected with newer CPL versions
00097  *
00098  * Revision 1.86  2007/02/09 09:00:57  jmlarsen
00099  * Added context as parameter of uves_set_parameter_default
00100  *
00101  * Revision 1.85  2007/01/17 13:28:32  jmlarsen
00102  * Added uves_free_frame
00103  *
00104  * Revision 1.84  2007/01/15 08:49:26  jmlarsen
00105  * More accurate Gaussian centering
00106  *
00107  * Revision 1.83  2006/12/08 07:41:43  jmlarsen
00108  * Minor doc. change
00109  *
00110  * Revision 1.82  2006/12/01 12:31:28  jmlarsen
00111  * Added uves_free_string_const
00112  *
00113  * Revision 1.81  2006/11/24 09:37:43  jmlarsen
00114  * Removed inline directive of uves_fit_1d_compare
00115  *
00116  * Revision 1.80  2006/11/15 15:02:15  jmlarsen
00117  * Implemented const safe workarounds for CPL functions
00118  *
00119  * Revision 1.78  2006/11/15 14:04:08  jmlarsen
00120  * Removed non-const version of parameterlist_get_first/last/next which is 
00121  * already in CPL, added const-safe wrapper, unwrapper and deallocator functions
00122  *
00123  * Revision 1.77  2006/11/13 14:23:55  jmlarsen
00124  * Removed workarounds for CPL const bugs
00125  *
00126  * Revision 1.76  2006/11/13 12:50:03  jmlarsen
00127  * Added type-safe wrappers of cpl_free
00128  *
00129  * Revision 1.75  2006/11/07 14:06:02  jmlarsen
00130  * Added cpl_array_delete wrapper
00131  *
00132  * Revision 1.74  2006/11/03 14:56:47  jmlarsen
00133  * uves_table_erase_selected_dfs02356: Support CPL 3d tables
00134  *
00135  * Revision 1.73  2006/09/20 12:53:57  jmlarsen
00136  * Replaced stringcat functions with uves_sprintf()
00137  *
00138  * Revision 1.72  2006/09/19 14:23:33  jmlarsen
00139  * uves_find_frame(): Support returning pointer to frame
00140  *
00141  * Revision 1.71  2006/09/06 14:47:55  jmlarsen
00142  * Added option to easily switch on/off debugging the LM algorithm
00143  *
00144  * Revision 1.70  2006/09/01 14:01:16  jmlarsen
00145  * Exported function uves_fit
00146  *
00147  * Revision 1.69  2006/08/23 15:08:29  jmlarsen
00148  * Added uves_free_bivector()
00149  *
00150  * Revision 1.68  2006/08/17 14:40:06  jmlarsen
00151  * Added missing documentation
00152  *
00153  * Revision 1.67  2006/08/17 14:11:25  jmlarsen
00154  * Use assure_mem macro to check for memory allocation failure
00155  *
00156  * Revision 1.66  2006/08/17 13:56:53  jmlarsen
00157  * Reduced max line length
00158  *
00159  * Revision 1.65  2006/08/14 12:19:32  jmlarsen
00160  * Improved parameter estimation, made workaround for optimization related
00161  * numerical instability in uves_fit
00162  *
00163  * Revision 1.64  2006/08/11 14:36:11  jmlarsen
00164  * Implemented workaround for slow cpl_table_erase_selected
00165  *
00166  * Revision 1.63  2006/08/11 09:42:57  jmlarsen
00167  * Use the new cpl_parameter_set_default to have the correct recipe 
00168  * default parameter values also with Gasgano
00169  *
00170  * Revision 1.62  2006/08/10 10:54:25  jmlarsen
00171  * Removed workaround for cpl_image_get_bpm
00172  *
00173  * Revision 1.61  2006/08/08 11:27:18  amodigli
00174  * upgrade to CPL3
00175  *
00176  * Revision 1.60  2006/07/14 12:43:15  jmlarsen
00177  * Added uves_extract_table_rows_local
00178  *
00179  * Revision 1.59  2006/07/03 13:21:41  jmlarsen
00180  * Changed 1d-fit parameter estimation method when only sky needs to be determined
00181  *
00182  * Revision 1.58  2006/06/16 08:26:41  jmlarsen
00183  * Doc bugfix
00184  *
00185  * Revision 1.57  2006/06/13 12:02:53  jmlarsen
00186  * Renamed y0 -> y_0
00187  *
00188  * Revision 1.56  2006/06/06 08:40:11  jmlarsen
00189  * Shortened max line length
00190  *
00191  * Revision 1.55  2006/06/01 14:43:17  jmlarsen
00192  * Added missing documentation
00193  *
00194  * Revision 1.54  2006/05/12 15:12:43  jmlarsen
00195  * Pass image bpm as extra parameter to fitting routine for efficiency reasons
00196  *
00197  * Revision 1.53  2006/05/05 14:00:03  jmlarsen
00198  * Bugfix: proper handling of bad pixels when fitting image data
00199  *
00200  * Revision 1.52  2006/04/24 09:33:16  jmlarsen
00201  * Added function that factors out profile for 1d gaussian-like fit
00202  *
00203  * Revision 1.51  2006/04/06 08:52:48  jmlarsen
00204  * Added raise-to-median of table column function
00205  *
00206  * Revision 1.50  2006/03/23 14:14:40  jmlarsen
00207  * Corrected spelling mistake causing infinite recursion in uves_get_image_bpm
00208  *
00209  * Revision 1.49  2006/03/03 13:54:11  jmlarsen
00210  * Changed syntax of check macro
00211  *
00212  * Revision 1.48  2006/02/28 09:15:23  jmlarsen
00213  * Minor update
00214  *
00215  * Revision 1.47  2006/02/15 13:19:15  jmlarsen
00216  * Reduced source code max. line length
00217  *
00218  * Revision 1.46  2006/01/31 08:25:08  jmlarsen
00219  * Wrapper for cpl_image_get_bpm
00220  *
00221  * Revision 1.45  2006/01/25 16:13:20  jmlarsen
00222  * Changed interface of gauss.fitting routine
00223  *
00224  * Revision 1.44  2005/12/19 16:17:56  jmlarsen
00225  * Replaced bool -> int
00226  *
00227  */
00228 
00229 #ifdef HAVE_CONFIG_H
00230 #  include <config.h>
00231 #endif
00232 
00233 /*----------------------------------------------------------------------------*/
00241 /*----------------------------------------------------------------------------*/
00242 
00243 #include <uves_utils_wrappers.h>
00244 
00245 #include <uves_utils.h>
00246 #include <uves_utils_cpl.h>
00247 #include <uves_error.h>
00248 #include <uves_dump.h>
00249 #include <cpl.h>
00250 
00251 #include <irplib_utils.h>
00252 #include <stdbool.h>
00253 #include <assert.h>
00254 
00255 /*-----------------------------------------------------------------------------
00256                                    Local functions
00257  -----------------------------------------------------------------------------*/
00258 
00259 static int get_candidate(const double *a, const int ia[],
00260              int M, int N, int D,
00261              double lambda,
00262              int    (*f)(const double x[], const double a[], 
00263                      double *result),
00264              int (*dfda)(const double x[], const double a[], 
00265                      double result[]),
00266              const double *x,
00267              const double *y,
00268              const double *sigma,
00269              double *partials,
00270              cpl_matrix *alpha,
00271              cpl_matrix *beta,
00272              double *a_da);
00273 
00274 static double get_chisq(int N, int D,
00275             int (*f)(const double x[], const double a[], 
00276                  double *result),
00277             const double *a,
00278             const double *x,
00279             const double *y,
00280             const double *sigma);
00281 
00282 /*-----------------------------------------------------------------------------
00283                                    Defines
00284  -----------------------------------------------------------------------------*/
00285 
00287 #define image_is_rejected(badmap, x, y) \
00288   ((badmap) != NULL && (badmap)[((x)-1) + ((y)-1)*nx] == CPL_BINARY_1)
00289 
00290 #ifndef UVES_FIT_MAXITER
00291 #define UVES_FIT_MAXITER 1000
00292 #endif
00293 
00294 /*-----------------------------------------------------------------------------
00295                                    Types
00296  -----------------------------------------------------------------------------*/
00297 /* @cond */
00298 typedef struct {
00299     double x;
00300     double y;
00301 } uves_fit_1d_input;
00302 /* @endcond */
00303 
00304 /*-----------------------------------------------------------------------------
00305                                    Implementation
00306  -----------------------------------------------------------------------------*/
00310 /*----------------------------------------------------------------------------*/
00317 /*----------------------------------------------------------------------------*/
00318 void uves_image_reject_all(cpl_image *image)
00319 {
00320     int nx, ny;
00321     int x, y;
00322 
00323     assure_nomsg( image != NULL, CPL_ERROR_NULL_INPUT );
00324     nx = cpl_image_get_size_x(image);
00325     ny = cpl_image_get_size_y(image);
00326 
00327     for (y = 1; y <= ny; y++) {
00328         for (x = 1; x <= nx; x++) {
00329             cpl_image_reject(image, x, y);
00330         }
00331     }
00332     
00333   cleanup:
00334     return;    
00335 }
00336 
00337 
00338 /*----------------------------------------------------------------------------*/
00397 /*----------------------------------------------------------------------------*/
00398 
00399 cpl_error_code
00400 uves_fit_1d_image(const cpl_image *image, const cpl_image *noise,
00401           const cpl_binary *image_badmap,
00402           bool horizontal, bool fix_back, bool fit_back,
00403           int xlo, int xhi, int y_0,
00404           double *x0, double *sigma, double *norm, double *background,
00405                   double *slope,
00406           double *mse, double *red_chisq,
00407           cpl_matrix **covariance,
00408           int (*f)   (const double x[], const double a[], double *result),
00409           int (*dfda)(const double x[], const double a[], double result[]),
00410           int M)
00411 {
00412     cpl_vector *x = NULL;
00413     cpl_vector *y = NULL;
00414     cpl_vector *sigma_y = NULL;     /* Noise vector          */
00415     
00416     cpl_fit_mode fit_pattern;
00417     int nx, ny;                     /* Image size            */
00418     int N;                          /* Number of good pixels */
00419     int i, j;
00420     cpl_type image_type;
00421 
00422     const double *image_data       = NULL;        /* Pointer to data */
00423     const double *noise_data       = NULL;        /* Pointer to data */
00424 
00425     assure( x0 != NULL        , CPL_ERROR_NULL_INPUT, "Null fit parameter");
00426     assure( sigma != NULL     , CPL_ERROR_NULL_INPUT, "Null fit parameter");
00427     assure( norm != NULL      , CPL_ERROR_NULL_INPUT, "Null fit parameter");
00428     assure( background != NULL, CPL_ERROR_NULL_INPUT, "Null fit parameter");
00429     /* mse, red_chisq, covariance may be NULL */
00430 
00431     assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
00432    
00433     image_type = cpl_image_get_type(image);
00434 
00435     /* To support the following types, use cpl_image_get() or
00436        more multiple type pointers to data buffer.
00437        cpl_ensure_code( image_type == CPL_TYPE_INT ||
00438        image_type == CPL_TYPE_FLOAT ||
00439        image_type == CPL_TYPE_DOUBLE,
00440        CPL_ERROR_TYPE_MISMATCH);
00441     */
00442 
00443     assure( image_type == CPL_TYPE_DOUBLE, CPL_ERROR_UNSUPPORTED_MODE,
00444         "Unsupported type: %s", uves_tostring_cpl_type(image_type));
00445 
00446     image_data = cpl_image_get_data_double_const(image);
00447 
00448     if (noise != NULL)
00449     {
00450         image_type = cpl_image_get_type(noise);
00451         /*  See comment above.
00452           cpl_ensure_code( image_type == CPL_TYPE_INT ||
00453           image_type == CPL_TYPE_FLOAT ||
00454           image_type == CPL_TYPE_DOUBLE,
00455           CPL_ERROR_TYPE_MISMATCH);
00456         */
00457         assure( image_type == CPL_TYPE_DOUBLE, CPL_ERROR_UNSUPPORTED_MODE, 
00458             "Unsupported type: %s", uves_tostring_cpl_type(image_type));
00459 
00460         noise_data = cpl_image_get_data_double_const(noise);
00461     }   
00462 
00463     nx = cpl_image_get_size_x(image);
00464     ny = cpl_image_get_size_y(image);
00465 
00466     if (horizontal)
00467     {
00468         assure( 1 <= xlo && xlo <= xhi && xhi <= nx &&
00469             1 <= y_0  && y_0  <= ny, CPL_ERROR_ACCESS_OUT_OF_RANGE,
00470             "Illegal window (%d, %d)-(%d, %d), image: %dx%d",
00471             xlo, y_0, xhi, y_0,
00472             nx, ny);
00473     }
00474     else
00475     {
00476         assure( 1 <= xlo && xlo <= xhi && xhi <= ny &&
00477             1 <= y_0  && y_0  <= nx,
00478             CPL_ERROR_ACCESS_OUT_OF_RANGE,
00479             "Illegal window (%d, %d)-(%d, %d), image: %dx%d",
00480             y_0, xlo, y_0, xhi,
00481             nx, ny);
00482     }
00483     
00484     /* Noise image must have same size
00485      * as the input image
00486      */
00487     if (noise != NULL)
00488     {
00489         assure( cpl_image_get_size_x(noise) == nx &&
00490             cpl_image_get_size_y(noise) == ny,
00491             CPL_ERROR_INCOMPATIBLE_INPUT, "Noise image: %dx%d, image: %dx%d:",
00492             cpl_image_get_size_x(noise),
00493             cpl_image_get_size_y(noise),
00494             nx, ny);
00495     }
00496    
00497     /* Count good pixels in sub-window, check that noise image is positive */
00498     N = 0;
00499     for (i = xlo; i <= xhi; i++)
00500     {
00501         if ( !image_is_rejected(image_badmap,
00502                     (horizontal) ? i : y_0,
00503                     (horizontal) ? y_0 : i) )
00504         {
00505             if ( noise != NULL)
00506             {
00507                 if( !image_is_rejected(image_badmap,
00508                            (horizontal) ? i : y_0,
00509                            (horizontal) ? y_0 : i) )
00510                 {
00511                     /* Noise image must be positive (only check
00512                        pixels that are actually used) */
00513                     assure( /*cpl_image_get(noise,
00514                           (horizontal) ? i : y_0,
00515                           (horizontal) ? y_0 : i,
00516                           &pis_rejected)*/
00517                     noise_data[(((horizontal) ? i : y_0) - 1) +
00518                            (((horizontal) ? y_0 : i) - 1) * nx]
00519                     > 0,
00520                     CPL_ERROR_ILLEGAL_INPUT,
00521                     "Non-positive noise at (%d, %d): %e",
00522                     (horizontal) ? i : y_0,
00523                     (horizontal) ? y_0 : i,
00524                     noise_data[(((horizontal) ? i : y_0) - 1) +
00525                            (((horizontal) ? y_0 : i) - 1) * nx]
00526                     );
00527                     
00528                     N += 1;
00529                 }
00530                 else
00531                 {
00532                     /* Pixel value is good, but noise pixel is
00533                        bad. Don't use. */
00534                 }
00535             }
00536             else
00537             {
00538                 /* Pixel is good. No noise image */
00539                 N += 1;
00540             }
00541         }
00542     }
00543    
00544     /* Check that there is at least one good pixel */
00545     assure( N >= 1, CPL_ERROR_ILLEGAL_INPUT, "Only %d good pixel(s)", N);
00546 
00547     /* Allocate space */
00548     x = cpl_vector_new(N);
00549     y = cpl_vector_new(N);
00550     if (noise != NULL)
00551     {
00552         sigma_y = cpl_vector_new(N);
00553         assure_mem( sigma_y );
00554     }
00555 
00556     if (fix_back)
00557     {
00558         fit_pattern = CPL_FIT_CENTROID | CPL_FIT_STDEV | CPL_FIT_AREA;
00559     }
00560     else if (fit_back)
00561     {
00562         fit_pattern = CPL_FIT_AREA | CPL_FIT_OFFSET;
00563     }
00564     else
00565     {
00566         fit_pattern = CPL_FIT_ALL;
00567     }
00568    
00569     assure_mem( x );
00570     assure_mem( y );
00571     
00572     /* Copy the N good pixels from the input image to vectors,
00573        j count good pixels */
00574     for (i = xlo, j = 0;
00575      i <= xhi;
00576      i++)
00577     {
00578         double flux;
00579         
00580         /*
00581           flux = cpl_image_get(image,
00582           (horizontal) ? xlo+i : y_0,
00583           (horizontal) ? y_0 : xlo+i,
00584           &pis_rejected);
00585         */
00586         
00587         flux = image_data[(((horizontal) ? i : y_0) - 1) +
00588                   (((horizontal) ? y_0 : i) - 1) * nx];
00589        
00590         //if (!pis_rejected)
00591         if ( !image_is_rejected(image_badmap,
00592                     (horizontal) ? i : y_0,
00593                     (horizontal) ? y_0 : i) )
00594         {
00595             if (noise != NULL)
00596             {
00597                 double flux_noise;
00598                
00599                 /* flux_noise = cpl_image_get(noise,
00600                    (horizontal) ? xlo+i : y_0,
00601                    (horizontal) ? y_0 : xlo+i,
00602                    &pis_rejected);
00603                 */
00604                
00605                 flux_noise = noise_data
00606                 [(((horizontal) ? i : y_0) - 1) +
00607                  (((horizontal) ? y_0 : i) - 1) * nx];
00608                
00609                 //if (!pis_rejected)
00610                 if ( !image_is_rejected(image_badmap,
00611                             (horizontal) ?
00612                             i : y_0,
00613                             (horizontal)
00614                             ? y_0 : i) )
00615                 {
00616                     cpl_vector_set(x,       j, i);
00617                     cpl_vector_set(y,       j, flux);
00618                     cpl_vector_set(sigma_y, j, flux_noise);
00619                     j++;
00620                 }
00621             }
00622             else
00623             {
00624                 cpl_vector_set(x, j, i);
00625                 cpl_vector_set(y, j, flux);
00626                 j++;
00627             }
00628         }
00629     }
00630     passure( j == N, "%d %d", j, N);
00631     
00632     check( uves_fit_1d(x, NULL,      /* x, sigma_x */
00633                y, sigma_y,
00634                fit_pattern, fit_back,
00635                x0, sigma, norm, background,
00636                        slope,
00637                mse, red_chisq,
00638                covariance,
00639                f, dfda, M),
00640        "Fit failed");
00641 
00642     
00643   cleanup:
00644     uves_free_vector(&x);
00645     uves_free_vector(&y);
00646     uves_free_vector(&sigma_y);
00647 
00648     return cpl_error_get_code();
00649 }
00650 
00651 /*----------------------------------------------------------------------------*/
00659 /*----------------------------------------------------------------------------*/
00660 static int uves_fit_1d_compare(const void *left,
00661                    const void *right)
00662 {
00663     return 
00664     (((uves_fit_1d_input *)left )->x <  
00665      ((uves_fit_1d_input *)right)->x) ? -1 :
00666     (((uves_fit_1d_input *)left )->x == 
00667      ((uves_fit_1d_input *)right)->x) ? 0  : 1;
00668 }
00669 
00670 /*----------------------------------------------------------------------------*/
00693 /*----------------------------------------------------------------------------*/
00694 cpl_error_code
00695 uves_fit_1d(const cpl_vector *x, const cpl_vector *sigma_x,
00696             const cpl_vector *y, const cpl_vector *sigma_y,
00697             cpl_fit_mode fit_pars, bool fit_back,
00698             double *x0, double *sigma, double *area, double *offset, double *slope,
00699             double *mse, double *red_chisq,
00700             cpl_matrix **covariance,
00701             int (*f)   (const double x[], const double a[], double *result),
00702             int (*dfda)(const double x[], const double a[], double result[]),
00703             int M)
00704 {
00705     const cpl_matrix *x_matrix = NULL; /* LM algorithm needs a matrix,
00706                       not a vector                 */
00707 
00708     int N;                          /* Number of data points        */
00709     double xlo, xhi;                /* Min/max x                    */
00710 
00711     /* Initial parameter values */
00712     double x0_guess    = 0;  /* Avoid warnings about uninitialized variables */
00713     double sigma_guess = 0;
00714     double area_guess;
00715     double offset_guess;
00716 
00717     cpl_ensure_code( M == 4 || M == 5, CPL_ERROR_UNSUPPORTED_MODE);
00718 
00719     /* Validate input */
00720     cpl_ensure_code( x       != NULL, CPL_ERROR_NULL_INPUT);
00721     cpl_ensure_code( sigma_x == NULL, CPL_ERROR_UNSUPPORTED_MODE);
00722     cpl_ensure_code( y       != NULL, CPL_ERROR_NULL_INPUT);
00723     /* sigma_y may be NULL or non-NULL */
00724     
00725     N = cpl_vector_get_size(x);
00726 
00727     cpl_ensure_code( N == cpl_vector_get_size(y),
00728              CPL_ERROR_INCOMPATIBLE_INPUT);
00729 
00730     if (sigma_x != NULL)
00731     {
00732         cpl_ensure_code( N == cpl_vector_get_size(sigma_x),
00733                  CPL_ERROR_INCOMPATIBLE_INPUT);
00734     }
00735     if (sigma_y != NULL)
00736     {
00737         cpl_ensure_code( N == cpl_vector_get_size(sigma_y),
00738                  CPL_ERROR_INCOMPATIBLE_INPUT);
00739     }
00740 
00741     cpl_ensure_code( x0     != NULL &&
00742              sigma  != NULL &&
00743              area   != NULL &&
00744              offset != NULL &&
00745                      (M != 5 || slope != NULL), CPL_ERROR_NULL_INPUT);
00746 
00747     if (! (fit_pars & CPL_FIT_STDEV))
00748     {
00749         cpl_ensure_code( *sigma > 0, CPL_ERROR_ILLEGAL_INPUT);
00750     }
00751 
00752     cpl_ensure_code( !fit_back || fit_pars == (CPL_FIT_OFFSET | CPL_FIT_AREA),
00753              CPL_ERROR_INCOMPATIBLE_INPUT);
00754 
00755     /* Input area must be positive if fit_back is false */
00756     if (! (fit_pars & CPL_FIT_AREA) && !fit_back)
00757     {
00758         cpl_ensure_code( *area > 0, CPL_ERROR_ILLEGAL_INPUT);
00759     }
00760 
00761     /* mse, red_chisq may be NULL */
00762 
00763     /* Need more than number_of_parameters points to calculate chi^2.
00764      * There are less than 5 parameters. */
00765     cpl_ensure_code( red_chisq == NULL || N >= 5, CPL_ERROR_ILLEGAL_INPUT);
00766     
00767     if (covariance != NULL) *covariance = NULL;
00768     /* If covariance computation is requested, then
00769      * return either the covariance matrix or NULL
00770      * (don't return undefined pointer).
00771      */
00772     
00773     /* Cannot compute chi square & covariance without sigma_y */
00774     cpl_ensure_code( (red_chisq == NULL && covariance == NULL) || 
00775              sigma_y != NULL,
00776              CPL_ERROR_INCOMPATIBLE_INPUT);
00777     
00778     /* Create matrix from x-data */
00779     x_matrix = cpl_matrix_wrap(N, 1, cpl_vector_get_data_const(x));
00780     if (x_matrix == NULL)
00781     {
00782         cpl_ensure_code(
00783                 CPL_FALSE,
00784         CPL_ERROR_ILLEGAL_OUTPUT);
00785     }
00786     
00787     /* Check that any provided sigmas are positive. */
00788     if (sigma_x != NULL && cpl_vector_get_min(sigma_x) <= 0)
00789     {
00790         cpl_matrix_unwrap(x_matrix);
00791         cpl_ensure_code(
00792         CPL_FALSE,
00793         CPL_ERROR_ILLEGAL_INPUT);
00794     }
00795     if (sigma_y != NULL && cpl_vector_get_min(sigma_y) <= 0)
00796     {
00797         cpl_matrix_unwrap(x_matrix);
00798         cpl_ensure_code(
00799         CPL_FALSE,
00800         CPL_ERROR_ILLEGAL_INPUT);
00801     }
00802 
00803     /* Compute guess parameters using robust estimation
00804      * (This step might be improved by taking into account the 
00805      * uncertainties but for simplicity's sake do not)
00806      */
00807     if (fit_back)
00808     {
00809         /* We need to estimate only these two parameters */
00810         assert( fit_pars == CPL_FIT_OFFSET || CPL_FIT_AREA);
00811 
00812 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE >= CPL_VERSION(4, 0, 0)
00813         offset_guess = cpl_vector_get_median_const(y);
00814 #else
00815         offset_guess = cpl_vector_get_median(y);
00816 #endif
00817         area_guess = N*(cpl_vector_get_mean(y) - offset_guess);
00818         /* Sum of (flux-offset) */
00819 
00820         x0_guess = *x0;
00821         sigma_guess = *sigma;
00822     }
00823     else {
00824     double sum  = 0.0;
00825     double quartile[3];
00826     double fraction[3] = {0.25 , 0.50 , 0.75};
00827     const double *y_data = cpl_vector_get_data_const(y);
00828 
00829     if (fit_pars & CPL_FIT_OFFSET)
00830         {
00831         /* Estimate offset as 25% percentile of y-values.
00832            (The minimum value may be too low for noisy input,
00833            the median is too high if there is not much
00834            background in the supplied data, so use
00835            something inbetween).
00836         */
00837 
00838         cpl_vector *y_dup = cpl_vector_duplicate(y);
00839         
00840         if (y_dup == NULL)
00841             {
00842             cpl_matrix_unwrap(x_matrix);
00843             cpl_ensure_code(
00844                 CPL_FALSE,
00845                 CPL_ERROR_ILLEGAL_OUTPUT);
00846             }
00847         
00848         offset_guess = uves_utils_get_kth_double(
00849             cpl_vector_get_data(y_dup), N, N/4);
00850         
00851         cpl_vector_delete(y_dup);
00852         }
00853     else
00854         {
00855         offset_guess = *offset;
00856         }
00857     
00858     /* Get quartiles of distribution
00859        (only bother if it's needed for estimation of x0 or sigma) */
00860     if ( (fit_pars & CPL_FIT_CENTROID) ||
00861          (fit_pars & CPL_FIT_STDEV   )
00862         )
00863         {
00864         /* The algorithm requires the input to be sorted
00865            as function of x, so do that (using qsort), and
00866            work on the sorted copy. Of course, the y-vector
00867            must be re-ordered along with x.
00868            sigma_x and sigma_y are not used, so don't copy those.
00869         */
00870         
00871         uves_fit_1d_input
00872             *sorted_input = cpl_malloc(N * sizeof(*sorted_input));
00873         const double *x_data = cpl_matrix_get_data_const(x_matrix);
00874         cpl_boolean is_sorted = CPL_TRUE;
00875         int i;
00876         
00877         if (sorted_input == NULL)
00878             {
00879             cpl_matrix_unwrap(x_matrix);
00880             cpl_ensure_code(
00881                 CPL_FALSE,
00882                 CPL_ERROR_ILLEGAL_INPUT);
00883             }
00884         
00885         for (i = 0; i < N; i++)
00886             {
00887             sorted_input[i].x = x_data[i];
00888             sorted_input[i].y = y_data[i];
00889             
00890             is_sorted = is_sorted && 
00891                 (i==0 || (x_data[i-1] < x_data[i]));
00892             }            
00893         
00894         if (!is_sorted)
00895             {
00896             qsort(sorted_input, N, sizeof(*sorted_input),
00897                   &uves_fit_1d_compare);
00898             }
00899 
00900         for(i = 0; i < N; i++)
00901             {
00902             double flux = sorted_input[i].y;
00903             
00904             sum += (flux - offset_guess);
00905             }
00906         /* Note that 'sum' must be calculated the same way as
00907            'running_sum' below, Otherwise (due to round-off error)
00908            'running_sum' might end up being different from 'sum'(!).
00909            Specifically, it will not work to calculate 'sum' as
00910            
00911            (flux1 + ... + fluxN)  -  N*offset_guess
00912         */
00913         
00914         if (sum > 0.0)
00915             {
00916             double flux, x1, x2;
00917             double running_sum = 0.0;
00918             int j;
00919             
00920             i = 0;
00921             flux = sorted_input[i].y - offset_guess;
00922             
00923             for (j = 0; j < 3; j++)
00924                 {
00925                 double limit = fraction[j] * sum;
00926                 double k;
00927                 
00928                 while (running_sum + flux < limit && i < N-1)
00929                     {
00930                     running_sum += flux;
00931                     i++;
00932                     flux = sorted_input[i].y - offset_guess;
00933                     }
00934 
00935                 /* Fraction [0;1] of current flux needed
00936                    to reach the quartile */
00937                 k = (limit - running_sum)/flux;
00938                 
00939                 if (k <= 0.5)
00940                     {
00941                     /* Interpolate linearly between
00942                        current and previous position
00943                     */
00944                     if (0 < i)
00945                         {
00946                         x1 = sorted_input[i-1].x;
00947                         x2 = sorted_input[i].x;
00948                         
00949                         quartile[j] = 
00950                             x1*(0.5-k) +
00951                             x2*(0.5+k);
00952                         /*
00953                           k=0   => quartile = midpoint,
00954                           k=0.5 => quartile = x2
00955                         */
00956                         }
00957                     else
00958                         {
00959                         quartile[j] = sorted_input[i].x;
00960                         }
00961                     }
00962                 else
00963                     {
00964                     /* Interpolate linearly between
00965                        current and next position */
00966                     if (i < N-1)
00967                         {
00968                         x1 = sorted_input[i].x;
00969                         x2 = sorted_input[i+1].x;
00970                         
00971                         quartile[j] = 
00972                             x1*( 1.5-k) +
00973                             x2*(-0.5+k);
00974                         /*
00975                           k=0.5 => quartile = x1,
00976                           k=1.0 => quartile = midpoint
00977                         */
00978                         }
00979                     else
00980                         {
00981                         quartile[j] = sorted_input[i].x;
00982                         }
00983                     }
00984                 }
00985             }
00986         else
00987             {
00988             /* If there's no flux (sum = 0) then
00989                set quartiles to something that's not 
00990                completely insensible.
00991             */
00992             quartile[1] = cpl_matrix_get_mean(x_matrix);
00993             
00994             quartile[2] = quartile[1];
00995             quartile[0] = quartile[2] - 1.0;
00996             /* Then sigma_guess = 1.0 */
00997             }
00998 
00999         cpl_free(sorted_input);
01000         } /* If need to compute quartiles */
01001         
01002     /* x0_guess = median of distribution */
01003     x0_guess = (fit_pars & CPL_FIT_CENTROID) ? quartile[1] : *x0;
01004     
01005     /* sigma_guess = median of absolute residuals
01006      *
01007      *  (68% is within 1 sigma, and 50% is within 0.6744
01008      *  sigma,  => quartile3-quartile1 = 2*0.6744 sigma)
01009      */
01010     sigma_guess = (fit_pars & CPL_FIT_STDEV) ? 
01011         (quartile[2] - quartile[0]) / (2*0.6744) : *sigma;
01012     
01013     area_guess  = (fit_pars & CPL_FIT_AREA) ?
01014         (cpl_vector_get_max(y) - offset_guess) * sqrt(2*M_PI) * sigma_guess : *area;
01015     /* This formula makes sense only if the area is positive */
01016     
01017     /* Make sure that the area is a positive number */
01018     if ( area_guess <= 0)  area_guess = 1.0;
01019     if (sigma_guess <= 0) sigma_guess = 1.0;
01020     }
01021     
01022     /* Wrap parameters, fit, unwrap */
01023     {
01024     cpl_vector *a;
01025     int ia[5];            /* The last element
01026                  is ignored if
01027                  M = 4 */
01028     cpl_error_code ec;
01029 
01030     assert(M == 4 || M == 5);
01031     a = cpl_vector_new(M);
01032 
01033     if (a == NULL)
01034         {
01035         cpl_matrix_unwrap(x_matrix);
01036         cpl_ensure_code(
01037             CPL_FALSE,
01038             CPL_ERROR_ILLEGAL_OUTPUT);
01039         }
01040 
01041     cpl_vector_set(a, 0, x0_guess);
01042     cpl_vector_set(a, 1, sigma_guess);
01043     cpl_vector_set(a, 2, area_guess);
01044     cpl_vector_set(a, 3, offset_guess);
01045     
01046     ia[0] = fit_pars & CPL_FIT_CENTROID;
01047     ia[1] = fit_pars & CPL_FIT_STDEV;
01048     ia[2] = fit_pars & CPL_FIT_AREA;
01049     ia[3] = fit_pars & CPL_FIT_OFFSET;
01050 
01051     if (M == 5)
01052         {
01053         /* linear sky-term, first hold it constant,
01054          * then call LM-fitting a second time where
01055          * it is non-constant */
01056         if (fit_pars & CPL_FIT_OFFSET)
01057                     {
01058                         cpl_vector_set(a, 4, 0);
01059                     }
01060                 else
01061                     {
01062                         cpl_vector_set(a, 4, *slope);
01063                     }
01064 
01065         ia[4] = 0;
01066         }
01067     
01068     ec = uves_fit(x_matrix, NULL,
01069             y, sigma_y, 
01070             a, ia, f, dfda,
01071             mse, red_chisq,
01072             covariance);
01073     
01074 //    printf("Sky: e='%s'\n", cpl_error_get_message()); cpl_vector_dump(a, stdout);
01075     if (M == 5)
01076         {
01077         ia[4] = fit_pars & CPL_FIT_OFFSET;
01078 
01079         if (covariance != NULL)
01080             {
01081             uves_free_matrix(covariance);
01082             }
01083 
01084         ec = uves_fit(x_matrix, NULL,
01085                 y, sigma_y, 
01086                 a, ia, f, dfda,
01087                 mse, red_chisq,
01088                 covariance);
01089 //    printf("Sky: e='%s'\n", cpl_error_get_message()); cpl_vector_dump(a, stdout);
01090         }
01091 
01092     cpl_matrix_unwrap(x_matrix);
01093     
01094     /* Check return status of fitting routine */
01095     if (ec == CPL_ERROR_NONE      ||
01096         ec == CPL_ERROR_SINGULAR_MATRIX)
01097         {
01098         /* The LM algorithm converged. The computation
01099          *  of the covariance matrix might have failed.
01100          */
01101         
01102         /* In principle, the LM algorithm might have converged
01103          * to a negative sigma (even if the guess value was
01104          * positive). Make sure that the returned sigma is positive
01105          * (by convention).
01106          */
01107 
01108         if (CPL_FIT_CENTROID) *x0     = cpl_vector_get(a, 0);
01109         if (CPL_FIT_STDEV   ) *sigma  = fabs(cpl_vector_get(a, 1));
01110         if (CPL_FIT_AREA    ) *area   = cpl_vector_get(a, 2);
01111         if (CPL_FIT_OFFSET  ) {
01112                     *offset = cpl_vector_get(a, 3);
01113                     if (M == 5) *slope = cpl_vector_get(a, 4);
01114                 }
01115         }
01116     
01117     cpl_vector_delete(a);
01118     
01119     xlo = cpl_vector_get_min(x);
01120     xhi = cpl_vector_get_max(x);
01121 
01122     if (ec == CPL_ERROR_CONTINUE ||
01123         !(
01124         !irplib_isnan(*x0    ) && !irplib_isinf(*x0    ) &&
01125         !irplib_isnan(*sigma ) && !irplib_isinf(*sigma ) &&
01126         !irplib_isnan(*area  ) && !irplib_isinf(*area  ) &&
01127         !irplib_isnan(*offset) && !irplib_isinf(*offset) &&
01128         ((M != 5) || (!irplib_isnan(*slope ) && !irplib_isinf(*slope ))) &&
01129         xlo <= *x0 && *x0 <= xhi &&
01130         0 < *sigma && *sigma < (xhi - xlo + 1) &&
01131         (fit_back || 0 < *area)
01132         /* This extra check on the background level makes sense
01133            iff the input flux is assumed to be positive
01134            && *offset > - *area  */
01135         )
01136         )
01137         {
01138         /* The LM algorithm did not converge, or it converged to
01139          * a non-sensical result. Return the guess parameter values
01140          * in order to enable the caller to recover. */
01141 
01142         *x0         = x0_guess;
01143         *sigma      = sigma_guess;
01144         *area       = area_guess;
01145         *offset     = offset_guess;
01146                 if (M == 5) *slope = 0;
01147         
01148         /* In this case the covariance matrix will not make sense
01149            (because the LM algorithm failed), so delete it */
01150         if (covariance != NULL && *covariance != NULL)
01151             {
01152             cpl_matrix_delete(*covariance);
01153             *covariance = NULL;
01154             }
01155 
01156         /* Return CPL_ERROR_CONTINUE if the fitting routine failed */
01157         cpl_ensure_code(
01158             CPL_FALSE,
01159             CPL_ERROR_CONTINUE);
01160         }
01161     }
01162     
01163     return CPL_ERROR_NONE;
01164 }
01165 /* @endcond */
01166 
01167 #define DEBUG_LM 0   /* Set to non-zero to print info on the error msg level */
01168 /*----------------------------------------------------------------------------*/
01235 /*----------------------------------------------------------------------------*/
01236 cpl_error_code
01237 uves_fit(const cpl_matrix *x, const cpl_matrix *sigma_x,
01238      const cpl_vector *y, const cpl_vector *sigma_y,
01239      cpl_vector *a, const int ia[],
01240      int    (*f)(const double x[], const double a[], double *result),
01241      int (*dfda)(const double x[], const double a[], double result[]),
01242      double *mse,
01243      double *red_chisq,
01244      cpl_matrix **covariance)
01245 {
01246     const double *x_data     = NULL; /* Pointer to input data                  */
01247     const double *y_data     = NULL; /* Pointer to input data                  */
01248     const double *sigma_data = NULL; /* Pointer to input data                  */
01249     int N    = 0;                    /* Number of data points                  */
01250     int D    = 0;                    /* Dimension of x-points                  */
01251     int M    = 0;                    /* Number of fit parameters               */
01252     int Mfit = 0;                    /* Number of non-constant fit
01253                         parameters                             */
01254 
01255     double lambda    = 0.0;          /* Lambda in L-M algorithm                */
01256     double MAXLAMBDA = 10e40;        /* Parameter to control the graceful exit
01257                     if steepest descent unexpectedly fails */
01258     double chi_sq    = 0.0;          /* Current  chi^2                         */
01259     int count        = 0;            /* Number of successive small improvements
01260                     in chi^2 */
01261     int iterations   = 0;
01262    
01263     cpl_matrix *alpha  = NULL;       /* The MxM ~curvature matrix used in L-M  */
01264     cpl_matrix *beta   = NULL;       /* Mx1 matrix = -.5 grad(chi^2)           */
01265     double *a_data     = NULL;       /* Parameters, a                          */
01266     double *a_da       = NULL;       /* Candidate position a+da                */
01267     double *part       = NULL;       /* The partial derivatives df/da          */
01268     int *ia_local      = NULL;       /* non-NULL version of ia                 */
01269    
01270     /* If covariance computation is requested, then either
01271      * return the covariance matrix or return NULL.
01272      */
01273     if (covariance != NULL) *covariance = NULL;
01274 
01275     /* Validate input */
01276     cpl_ensure_code(x       != NULL, CPL_ERROR_NULL_INPUT);
01277     cpl_ensure_code(sigma_x == NULL, CPL_ERROR_UNSUPPORTED_MODE);
01278     cpl_ensure_code(y       != NULL, CPL_ERROR_NULL_INPUT);
01279     cpl_ensure_code(a       != NULL, CPL_ERROR_NULL_INPUT);
01280     /* ia may be NULL */
01281     cpl_ensure_code(f       != NULL, CPL_ERROR_NULL_INPUT);
01282     cpl_ensure_code(dfda    != NULL, CPL_ERROR_NULL_INPUT);
01283 
01284     /* Chi^2 and covariance computations require sigmas to be known */
01285     cpl_ensure_code( sigma_y != NULL || (red_chisq == NULL && covariance == NULL),
01286              CPL_ERROR_INCOMPATIBLE_INPUT);
01287 
01288     D = cpl_matrix_get_ncol(x);
01289     N = cpl_matrix_get_nrow(x);
01290     M = cpl_vector_get_size(a);
01291     cpl_ensure_code(N > 0 && D > 0 && M > 0, CPL_ERROR_ILLEGAL_INPUT);
01292 
01293     cpl_ensure_code( cpl_vector_get_size(y) == N,
01294              CPL_ERROR_INCOMPATIBLE_INPUT);
01295 
01296     x_data = cpl_matrix_get_data_const(x);
01297     y_data = cpl_vector_get_data_const(y);
01298     a_data = cpl_vector_get_data(a);
01299 
01300     if (sigma_y != NULL)
01301     {
01302         cpl_ensure_code( cpl_vector_get_size(sigma_y) == N,
01303                  CPL_ERROR_INCOMPATIBLE_INPUT);
01304         /* Sigmas must be positive */
01305         cpl_ensure_code( cpl_vector_get_min (sigma_y) > 0,
01306                  CPL_ERROR_ILLEGAL_INPUT);
01307         sigma_data = cpl_vector_get_data_const(sigma_y);
01308     }
01309 
01310     ia_local = cpl_malloc(M * sizeof(int));
01311     cpl_ensure_code(ia_local != NULL, CPL_ERROR_ILLEGAL_OUTPUT);
01312 
01313     /* Count non-constant fit parameters, copy ia */
01314     if (ia != NULL)
01315     {
01316         int i;
01317 
01318         Mfit = 0;
01319         for (i = 0; i < M; i++)
01320         {
01321             ia_local[i] = ia[i];
01322 
01323             if (ia[i] != 0) 
01324             {
01325                 Mfit += 1;
01326             }
01327         }
01328         
01329         if (! (Mfit > 0))
01330         {
01331             cpl_free(ia_local);
01332             cpl_ensure_code( CPL_FALSE,
01333                      CPL_ERROR_ILLEGAL_INPUT);
01334         }
01335     }
01336     else
01337     {
01338         /* All parameters participate */
01339         int i;
01340         
01341         Mfit = M;
01342         
01343         for (i = 0; i < M; i++)
01344         {
01345             ia_local[i] = 1;
01346         }
01347     }
01348 
01349     /* To compute reduced chi^2, we need N > Mfit */
01350     if (! ( red_chisq == NULL || N > Mfit ) )
01351     {
01352         cpl_free(ia_local);
01353         cpl_ensure_code(
01354         CPL_FALSE,
01355         CPL_ERROR_ILLEGAL_INPUT);
01356     }
01357 
01358     /* Create alpha, beta, a_da, part  work space */
01359     alpha = cpl_matrix_new(Mfit, Mfit);
01360     if (alpha == NULL)
01361     {
01362         cpl_free(ia_local);
01363         cpl_ensure_code(
01364         CPL_FALSE,
01365         CPL_ERROR_ILLEGAL_OUTPUT);
01366     }
01367    
01368     beta = cpl_matrix_new(Mfit, 1);
01369     if (beta == NULL)
01370     {
01371         cpl_free(ia_local);
01372         cpl_matrix_delete(alpha);
01373         cpl_ensure_code(
01374         CPL_FALSE,
01375         CPL_ERROR_ILLEGAL_OUTPUT);
01376     }
01377 
01378     a_da = cpl_malloc(M * sizeof(double));
01379     if (a_da == NULL)
01380     {
01381         cpl_free(ia_local);
01382         cpl_matrix_delete(alpha);
01383         cpl_matrix_delete(beta);
01384         cpl_ensure_code(
01385         CPL_FALSE,
01386         CPL_ERROR_ILLEGAL_OUTPUT);
01387     }
01388 
01389     part = cpl_malloc(M * sizeof(double));
01390     if (part == NULL)
01391     {
01392         cpl_free(ia_local);
01393         cpl_matrix_delete(alpha);
01394         cpl_matrix_delete(beta);
01395         cpl_free(a_da);
01396         cpl_ensure_code(
01397         CPL_FALSE,
01398         CPL_ERROR_ILLEGAL_OUTPUT);
01399     }
01400 
01401     /* Initialize loop variables */
01402     lambda = 0.001;
01403     count = 0;
01404     iterations = 0;
01405     if( (chi_sq = get_chisq(N, D, f, a_data, x_data, y_data, sigma_data)) < 0)
01406     {
01407         cpl_free(ia_local);
01408         cpl_matrix_delete(alpha);
01409         cpl_matrix_delete(beta);
01410         cpl_free(a_da);
01411         cpl_free(part);
01412         cpl_ensure_code(
01413         CPL_FALSE,
01414         cpl_error_get_code());
01415     }
01416 
01417 #if DEBUG_LM    
01418      uves_msg_error("Initial chi^2 = %f", chi_sq); 
01419      {int i;
01420      for (i = 0; i < M; i++) 
01421      {
01422          uves_msg_error("Initial a[%d] = %e", i, a_data[i]); 
01423      }
01424      }
01425 #endif
01426 
01427     /* Iterate until chi^2 didn't improve substantially many (say, 5)
01428        times in a row */
01429     while (count < 5 && lambda < MAXLAMBDA && iterations < UVES_FIT_MAXITER)
01430     {
01431         /* In each iteration lambda increases, or chi^2 decreases or
01432            count increases. Because chi^2 is bounded from below
01433            (and lambda and count from above), the loop will terminate */
01434 
01435         double chi_sq_candidate = 0.0;
01436         int returncode = 0;
01437 
01438         /* Get candidate position in parameter space = a+da,
01439          * where  alpha * da = beta .
01440          * Increase lambda until alpha is non-singular
01441          */
01442        
01443         while( (returncode = get_candidate(a_data, ia_local,
01444                            M, N, D,
01445                            lambda, f, dfda,
01446                            x_data, y_data, sigma_data,
01447                            part, alpha, beta, a_da)
01448                ) != 0
01449            && cpl_error_get_code() == CPL_ERROR_SINGULAR_MATRIX
01450            && lambda < MAXLAMBDA)
01451         {
01452 #if DEBUG_LM    
01453             uves_msg_error("Singular matrix. lambda = %e", lambda);
01454 #endif
01455             cpl_error_reset();
01456             lambda *= 9.0;
01457         }
01458        
01459         /* Set error if lambda diverged */
01460         if ( !( lambda < MAXLAMBDA ) )
01461         {
01462             cpl_free(ia_local);
01463             cpl_matrix_delete(alpha);
01464             cpl_matrix_delete(beta);
01465             cpl_free(a_da);
01466             cpl_free(part);
01467             cpl_ensure_code(
01468             CPL_FALSE,
01469             CPL_ERROR_CONTINUE);
01470         }
01471        
01472         if (returncode != 0)
01473         {
01474             cpl_free(ia_local);
01475             cpl_matrix_delete(alpha);
01476             cpl_matrix_delete(beta);
01477             cpl_free(a_da);
01478             cpl_free(part);
01479             cpl_ensure_code(
01480             CPL_FALSE,
01481             cpl_error_get_code());
01482         }
01483 
01484         /* Get chi^2(a+da) */
01485         if ((chi_sq_candidate = get_chisq(N, D, f, a_da,
01486                           x_data, y_data, sigma_data)) < 0)
01487         {
01488             cpl_free(ia_local);
01489             cpl_matrix_delete(alpha);
01490             cpl_matrix_delete(beta);
01491             cpl_free(a_da);
01492             cpl_free(part);
01493             cpl_ensure_code(
01494             CPL_FALSE,
01495             cpl_error_get_code());
01496         }
01497 
01498         if (chi_sq_candidate > 1.000001 * chi_sq)
01499         {
01500             /* Move towards steepest descent */
01501 #if DEBUG_LM
01502             uves_msg_error("Chi^2 = %f  Candidate = %f  Lambda = %e",
01503                chi_sq, chi_sq_candidate, lambda); 
01504 #endif            
01505             lambda *= 9.0;
01506         }
01507         else
01508         {
01509 #if DEBUG_LM
01510             uves_msg_error("Chi^2 = %f  Candidate = %f* Lambda = %e count = %d",
01511                chi_sq, chi_sq_candidate, lambda, count);
01512 #endif
01513        
01514             /* Move towards Newton's algorithm */
01515             lambda /= 10.0;
01516 
01517             /* Count the number of successive improvements in chi^2 of
01518                less than 0.01 relative */
01519             if ( chi_sq == 0 ||
01520              (chi_sq - chi_sq_candidate)/chi_sq < .01)
01521             {
01522                 count += 1;
01523             }
01524             else
01525             {
01526                 /* Chi^2 improved by a significant amount,
01527                    reset counter */
01528                 count = 0;
01529             }
01530 
01531             if (chi_sq_candidate < chi_sq)
01532             {
01533                 /* chi^2 improved, update a and chi^2 */
01534                 int i;
01535                 for (i = 0; i < M; i++) 
01536                 {
01537                     a_data[i] = a_da[i];
01538 #if DEBUG_LM
01539                     uves_msg_error("-> a[%d] = %e", i, a_da[i]); 
01540 #endif
01541                 }
01542                 chi_sq = chi_sq_candidate;
01543             }
01544         }
01545         iterations++;
01546     }
01547 
01548     /* Set error if we didn't converge */
01549     if ( !( lambda < MAXLAMBDA && iterations < UVES_FIT_MAXITER ) )
01550     {
01551 #if DEBUG_LM
01552         uves_msg_error("Failed to converge, lambda=%f iterations=%d",
01553                lambda, iterations);
01554 #endif
01555         cpl_free(ia_local);
01556         cpl_matrix_delete(alpha);
01557         cpl_matrix_delete(beta);
01558         cpl_free(a_da);
01559         cpl_free(part);
01560         cpl_ensure_code(
01561         CPL_FALSE,
01562         CPL_ERROR_CONTINUE);
01563     }
01564 
01565     /* Compute mse if requested */
01566     if (mse != NULL)
01567     {
01568         int i;
01569 
01570         *mse = 0.0;
01571        
01572         for(i = 0; i < N; i++)
01573         {
01574             double fx_i = 0.0;
01575             double residual = 0.0;
01576            
01577             /* Evaluate f(x_i) at the best fit parameters */
01578             if( f(&(x_data[i*D]),
01579               a_data,
01580               &fx_i) != 0)
01581             {
01582                 cpl_free(ia_local);
01583                 cpl_matrix_delete(alpha);
01584                 cpl_matrix_delete(beta);
01585                 cpl_free(a_da);
01586                 cpl_free(part);
01587                 cpl_ensure_code(
01588                 CPL_FALSE,
01589                 CPL_ERROR_ILLEGAL_INPUT);
01590             }
01591 
01592             residual = y_data[i] - fx_i;
01593             *mse += residual * residual;
01594         }
01595         *mse /= N;
01596     }
01597 
01598     /* Compute reduced chi^2 if requested */
01599     if (red_chisq != NULL)
01600     {
01601         /* We already know the optimal chi^2 (and that N > Mfit)*/
01602         *red_chisq = chi_sq / (N-Mfit);
01603     }
01604 
01605     /* Compute covariance matrix if requested
01606      * cov = alpha(lambda=0)^-1              
01607      */
01608     if (covariance != NULL)
01609     {
01610         cpl_matrix *cov;
01611 
01612         if( get_candidate(a_data, ia_local, 
01613                   M, N, D, 0.0, f, dfda, 
01614                   x_data, y_data, sigma_data,
01615                   part, alpha, beta, a_da)
01616         != 0)
01617         {
01618             cpl_free(ia_local);
01619             cpl_matrix_delete(alpha);
01620             cpl_matrix_delete(beta);
01621             cpl_free(a_da);
01622             cpl_free(part);
01623             cpl_ensure_code(
01624             CPL_FALSE,
01625             cpl_error_get_code());
01626         }
01627        
01628         cov = cpl_matrix_invert_create(alpha);
01629         if (cov == NULL)
01630         {
01631             cpl_free(ia_local);
01632             cpl_matrix_delete(alpha);
01633             cpl_matrix_delete(beta);
01634             cpl_free(a_da);
01635             cpl_free(part);
01636             cpl_ensure_code(
01637             CPL_FALSE,
01638             cpl_error_get_code());
01639         }
01640        
01641         /* Make sure that variances are positive */
01642         {
01643         int i;
01644         for (i = 0; i < Mfit; i++)
01645             {
01646             if ( !(cpl_matrix_get(cov, i, i) > 0) )
01647                 {
01648                 cpl_free(ia_local);
01649                 cpl_matrix_delete(alpha);
01650                 cpl_matrix_delete(beta);
01651                 cpl_free(a_da);
01652                 cpl_free(part);
01653                 cpl_matrix_delete(cov);
01654                 *covariance = NULL;
01655                 cpl_ensure_code(
01656                     CPL_FALSE,
01657                     CPL_ERROR_SINGULAR_MATRIX);
01658                 }
01659             }
01660         }
01661 
01662         /* Expand covariance matrix from Mfit x Mfit
01663            to M x M. Set rows/columns corresponding to fixed
01664            parameters to zero */
01665 
01666         *covariance = cpl_matrix_new(M, M);
01667         if (*covariance == NULL)
01668         {
01669             cpl_free(ia_local);
01670             cpl_matrix_delete(alpha);
01671             cpl_matrix_delete(beta);
01672             cpl_free(a_da);
01673             cpl_free(part);
01674             cpl_matrix_delete(cov);
01675             cpl_ensure_code(
01676             CPL_FALSE,
01677             CPL_ERROR_ILLEGAL_OUTPUT);
01678         }
01679 
01680         {
01681         int j, jmfit;
01682 
01683         for (j = 0, jmfit = 0; j < M; j++)
01684             if (ia_local[j] != 0)
01685             {
01686                 int i, imfit;
01687 
01688                 for (i = 0, imfit = 0; i < M; i++)
01689                 if (ia_local[i] != 0)
01690                     {
01691                     cpl_matrix_set(*covariance, i, j,
01692                                cpl_matrix_get(
01693                                cov, imfit, jmfit));
01694                     imfit += 1;
01695                     }
01696                 
01697                 assert( imfit == Mfit );
01698 
01699                 jmfit += 1;
01700             }
01701         
01702         assert( jmfit == Mfit );
01703         }
01704 
01705         cpl_matrix_delete(cov);
01706     }
01707     
01708     cpl_free(ia_local);
01709     cpl_matrix_delete(alpha);
01710     cpl_matrix_delete(beta);
01711     cpl_free(a_da);
01712     cpl_free(part);
01713    
01714     return CPL_ERROR_NONE;
01715 }
01716 
01717 /*----------------------------------------------------------------------------*/
01727 /*----------------------------------------------------------------------------*/
01728 cpl_error_code
01729 uves_cast_image(cpl_image **image, cpl_type to_type)
01730 {
01731     cpl_image *temp = NULL;
01732     
01733     assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
01734 
01735     temp = *image;
01736     
01737     check( *image = cpl_image_cast(temp, to_type), "Couldn't convert image to %s", 
01738        uves_tostring_cpl_type(to_type));
01739     
01740   cleanup:
01741     uves_free_image(&temp);
01742     return cpl_error_get_code();    
01743 }
01744 
01745 
01746 /*-----------------------------------------------------------------------------*/
01761 /*-----------------------------------------------------------------------------*/
01762 cpl_error_code
01763 uves_crop_image(cpl_image **image, int x1, int y_1, int x2, int y2)
01764 {
01765     cpl_image *temp = NULL;
01766     
01767     assure( image != NULL, CPL_ERROR_NULL_INPUT, "Null image");
01768 
01769     temp = *image;
01770     
01771     check( *image = cpl_image_extract(temp, x1, y_1, x2, y2), 
01772        "Could not extract image");
01773     
01774   cleanup:
01775     uves_free_image(&temp);
01776     return cpl_error_get_code();    
01777 }
01778 
01779 /*----------------------------------------------------------------------------*/
01803 /*----------------------------------------------------------------------------*/
01804 cpl_error_code
01805 uves_get_property_value(const uves_propertylist *plist, const char *keyword, 
01806             cpl_type keywordtype, void *result)
01807 {
01808     cpl_type t;
01809     
01810     /* Check input */
01811     assure( plist != NULL  , CPL_ERROR_NULL_INPUT, "Null property list");
01812     assure( keyword != NULL, CPL_ERROR_NULL_INPUT, "Null keyword");
01813     
01814     /* Check for existence... */
01815     assure( uves_propertylist_contains(plist, keyword), CPL_ERROR_DATA_NOT_FOUND,
01816         "Keyword %s does not exist", keyword );
01817     /* ...and type of keyword */
01818     check( t = uves_propertylist_get_type(plist, keyword) ,
01819        "Could not read type of keyword '%s'", keyword );
01820     assure(t == keywordtype , CPL_ERROR_TYPE_MISMATCH, 
01821        "Keyword '%s' has wrong type (%s). %s expected",
01822        keyword, uves_tostring_cpl_type(t), uves_tostring_cpl_type(keywordtype));
01823     
01824     /* Read the keyword */
01825     switch (keywordtype)
01826     {
01827     case CPL_TYPE_INT   : 
01828         check( *((      int    *)result) =
01829         uves_propertylist_get_int(plist, keyword),
01830         "Could not get (integer) value of %s", keyword );
01831         break;
01832     case CPL_TYPE_BOOL  : 
01833         check( *((      bool   *)result) =
01834            uves_propertylist_get_bool(plist, keyword), 
01835            "Could not get (boolean) value of %s", keyword ); 
01836         break;
01837     case CPL_TYPE_DOUBLE:
01838         check( *((      double *)result) = 
01839            uves_propertylist_get_double(plist, keyword), 
01840            "Could not get (double) value of %s" , keyword );
01841         break;
01842     case CPL_TYPE_STRING: 
01843         check( *((const char * *)result) = 
01844            uves_propertylist_get_string(plist, keyword), 
01845            "Could not get (string) value of %s" , keyword ); 
01846         break;
01847     default:
01848         assure( false, CPL_ERROR_INVALID_TYPE, "Unknown type");
01849         break;
01850     }
01851     
01852   cleanup:
01853     return cpl_error_get_code();
01854 }
01855 
01856 
01857 /*----------------------------------------------------------------------------*/
01882 /*----------------------------------------------------------------------------*/
01883 
01884 const char *
01885 uves_find_frame(const cpl_frameset *frames, const char **wanted, int N, int *found,
01886         const cpl_frame **frame)
01887 {
01888     const char *filename = NULL;  /* Return NULL in case of error */
01889     int i;
01890     const cpl_frame *f = NULL;
01891     
01892     /* Return well-defined pointers in case of error */
01893     *found = 0;
01894     if (frame != NULL)
01895     {
01896         *frame = NULL;
01897     }
01898 
01899     for (i = 0; i < N; i++)
01900     {
01901         check( f = cpl_frameset_find_const(frames, wanted[i]), 
01902            "Could not search through frame set");
01903         if (f != NULL) 
01904         {
01905             check( filename = cpl_frame_get_filename(f), 
01906                "Could not read frame filename");
01907             *found = i;
01908             if (frame != NULL)
01909             {
01910                 *frame = f;
01911             }
01912             /* break */
01913             i = N;
01914         }
01915     }
01916     
01917     /* Set an error if a matching frame wasn't found */
01918     assure(filename != NULL, CPL_ERROR_DATA_NOT_FOUND, "No such frame in frame set");
01919 
01920   cleanup:
01921     return filename;
01922 }
01923 
01924 
01925 /*----------------------------------------------------------------------------*/
01932 /*----------------------------------------------------------------------------*/
01933 int
01934 uves_get_nextensions(const char *filename)
01935 {
01936     int result = 0;
01937     cpl_frame *f = NULL;
01938     
01939     /* CPL only supports reading the number of extensions of a FITS
01940        file if this is in a frame, so create a frame for the specified file */
01941       
01942     check(( f = cpl_frame_new(),
01943         cpl_frame_set_filename(f, filename)),
01944       "Could not create frame");
01945 
01946     check( result = cpl_frame_get_nextensions(f),
01947        "Error reading number of extensions of file '%s'", filename);
01948   cleanup:
01949     cpl_frame_delete(f);
01950     return result;
01951 }
01952 
01953 /*----------------------------------------------------------------------------*/
01974 /*----------------------------------------------------------------------------*/
01975 cpl_error_code
01976 uves_get_parameter(const cpl_parameterlist *parameters, const char *context,
01977            const char *recipe_id, const char *name, cpl_type type, 
01978            void *value)
01979 {
01980     char *fullname = NULL;
01981     const cpl_parameter *p = NULL;
01982     
01983     passure( parameters != NULL, " ");
01984     /* 'context' may be NULL */
01985     passure( recipe_id != NULL, " ");
01986     passure( name != NULL, " ");
01987     passure( value != NULL, " ");
01988 
01989     if (context != NULL)
01990     {
01991         check( fullname = uves_sprintf("%s.%s.%s", context, recipe_id, name),
01992            "Error getting full parameter name");
01993     }
01994     else
01995     {
01996         check( fullname = uves_sprintf("%s.%s", recipe_id, name),
01997            "Error getting full parameter name");
01998     }
01999 
02000     /* Const cast */
02001     check( p = cpl_parameterlist_find_const(parameters, fullname), 
02002        "Error searching for parameter '%s'", fullname);
02003     assure( p != NULL, CPL_ERROR_DATA_NOT_FOUND, 
02004         "No parameter '%s' in parameter list", fullname);
02005     
02006     /* Check that parameter has the correct type */
02007     {
02008     cpl_type partype;
02009     check(  partype = cpl_parameter_get_type(p), 
02010         "Could not read type of parameter '%s'", fullname);
02011     assure( partype == type, CPL_ERROR_TYPE_MISMATCH,
02012         "Parameter '%s' has type %s. Expected type was %s", 
02013         fullname,
02014         uves_tostring_cpl_type(partype), uves_tostring_cpl_type(type));    
02015     }
02016 
02017     /* Read the parameter */
02018     switch(type)
02019     {
02020     case CPL_TYPE_INT:
02021         check( *(int *         )value = 
02022            cpl_parameter_get_int   (p),
02023            "Could not read integer parameter '%s'", fullname);  
02024         break;
02025     case CPL_TYPE_BOOL:
02026         check( *(bool *        )value = 
02027            cpl_parameter_get_bool  (p),
02028            "Could not read boolean parameter '%s'", fullname);  
02029         break;
02030     case CPL_TYPE_DOUBLE:    
02031         check( *(double *      )value = 
02032            cpl_parameter_get_double(p),
02033            "Could not read double parameter '%s'" , fullname );  
02034         break;
02035     case CPL_TYPE_STRING:
02036         check( *(const char ** )value = 
02037            cpl_parameter_get_string(p),
02038            "Could not read string parameter '%s'" , fullname );  
02039         break;
02040     default:
02041         assure(false, CPL_ERROR_UNSUPPORTED_MODE,
02042            "Don't know how to read parameter '%s' of type %s",
02043            fullname, uves_tostring_cpl_type(type));
02044         break;
02045     }
02046     
02047   cleanup:
02048     cpl_free(fullname); fullname = NULL;
02049     return cpl_error_get_code();
02050 }
02051 
02052 /*----------------------------------------------------------------------------*/
02068 /*----------------------------------------------------------------------------*/
02069 cpl_error_code
02070 uves_set_parameter(cpl_parameterlist *parameters, 
02071            const char *context,
02072            const char *name, cpl_type type, void *value)
02073 {
02074     char *fullname = NULL;
02075     cpl_parameter *p = NULL;
02076     
02077     check( fullname = uves_sprintf("%s.%s", context, name),
02078        "Error getting full parameter name");
02079 
02080     /* Const cast */
02081     check( p = cpl_parameterlist_find(parameters, fullname), 
02082        "Error searching for parameter '%s'", fullname);
02083     assure( p != NULL, CPL_ERROR_DATA_NOT_FOUND, 
02084         "No parameter '%s' in parameter list", fullname);
02085 
02086     /* Check that parameter has the correct type */
02087     {
02088     cpl_type partype;
02089     check(  partype = cpl_parameter_get_type(p), 
02090         "Could not read type of parameter '%s'", fullname);
02091     assure( partype == type, CPL_ERROR_TYPE_MISMATCH,
02092         "Parameter '%s' has type %s. Expected type was %s", 
02093         fullname, uves_tostring_cpl_type(partype),
02094         uves_tostring_cpl_type(type));    
02095     }
02096 
02097     /* Set the parameter */
02098     switch(type)
02099     {
02100     case CPL_TYPE_INT:
02101         check( cpl_parameter_set_int   (p, *((int *)    value)), 
02102            "Could not set integer parameter '%s'", fullname);  
02103         break;
02104     case CPL_TYPE_BOOL:    
02105         check( cpl_parameter_set_bool  (p, *((bool *)    value)), 
02106            "Could not set boolean parameter '%s'", fullname);
02107         break;
02108     case CPL_TYPE_DOUBLE:
02109         check( cpl_parameter_set_double(p, *((double *) value)), 
02110            "Could not set double parameter '%s'" , fullname);
02111         break;
02112     case CPL_TYPE_STRING:
02113         check( cpl_parameter_set_string(p, *((char **)  value)),
02114            "Could not set string parameter '%s'" , fullname);  
02115         break;
02116     default:
02117         assure(false, CPL_ERROR_UNSUPPORTED_MODE,
02118            "Don't know how to set parameter of type %s", 
02119            uves_tostring_cpl_type(type));
02120         break;
02121     }
02122     
02123   cleanup:
02124     cpl_free(fullname); fullname = NULL;
02125     return cpl_error_get_code();
02126 }
02127 
02128 /*----------------------------------------------------------------------------*/
02142 /*----------------------------------------------------------------------------*/
02143 
02144 cpl_error_code
02145 uves_set_parameter_default(cpl_parameterlist *parameters, const char *context,
02146                const char *parname, 
02147                cpl_type type, void *value)
02148 {
02149     const char *full_name = NULL;
02150     cpl_parameter *p = NULL;
02151     cpl_type partype;
02152 
02153     if (context != NULL)
02154     {
02155         full_name = uves_sprintf("%s.%s", context, parname);
02156     }
02157     else
02158     {
02159         full_name = uves_sprintf("%s", parname);
02160     }
02161 
02162     if (full_name == NULL)
02163     {
02164         return CPL_ERROR_ILLEGAL_OUTPUT;
02165     }
02166 
02167 
02168     if ( (p = cpl_parameterlist_find(parameters, full_name)) == NULL)
02169     {
02170         uves_msg_error("Missing parameter: '%s'", full_name);
02171 
02172         uves_free_string_const(&full_name);
02173         if (cpl_error_get_code() != CPL_ERROR_NONE) return cpl_error_get_code();
02174         else return CPL_ERROR_DATA_NOT_FOUND;
02175     }
02176     
02177     partype = cpl_parameter_get_type(p);
02178     
02179     if (partype != type)
02180     {
02181         uves_msg_error("Parameter '%s' has type %s. Expected type was %s", 
02182               full_name, uves_tostring_cpl_type(partype), 
02183               uves_tostring_cpl_type(type));
02184 
02185         uves_free_string_const(&full_name);
02186         return CPL_ERROR_TYPE_MISMATCH;
02187     }
02188 
02189     switch(type)
02190     {
02191     case CPL_TYPE_INT:
02192         cpl_parameter_set_default_int   (p, *((int *)    value)); 
02193         break;
02194     case CPL_TYPE_BOOL:
02195         cpl_parameter_set_default_bool  (p, *((bool *)   value)); 
02196         break;
02197     case CPL_TYPE_DOUBLE:
02198         cpl_parameter_set_default_double(p, *((double *) value)); 
02199         break;
02200     case CPL_TYPE_STRING:
02201         cpl_parameter_set_default_string(p, *((char **)  value)); 
02202         break;
02203     default:
02204         uves_msg_error("Unknown type: %s", uves_tostring_cpl_type(type));
02205 
02206         uves_free_string_const(&full_name);
02207         return CPL_ERROR_INVALID_TYPE;
02208     }
02209 
02210     if (cpl_error_get_code() != CPL_ERROR_NONE)
02211     {
02212         uves_msg_error("Error changing value of parameter '%s'", 
02213                full_name);
02214 
02215         uves_free_string_const(&full_name);
02216         return cpl_error_get_code();
02217     }
02218 
02219 
02220     uves_free_string_const(&full_name);
02221     return CPL_ERROR_NONE;
02222 }
02223 
02224 
02225 /*----------------------------------------------------------------------------*/
02237 /*----------------------------------------------------------------------------*/
02238 void 
02239 uves_raise_to_median_frac(cpl_table *t, const char *column, double fraction)
02240 {
02241     int i = 0;
02242     double threshold;
02243 
02244     assure_nomsg(t != NULL, CPL_ERROR_NULL_INPUT);
02245     assure(cpl_table_has_column(t, column), CPL_ERROR_DATA_NOT_FOUND,
02246        "No such column: %s", column);
02247 
02248     assure(cpl_table_get_column_type(t, column) == CPL_TYPE_DOUBLE,
02249        CPL_ERROR_UNSUPPORTED_MODE, "Column %s has type %s. %s expected",
02250        column,
02251        uves_tostring_cpl_type(cpl_table_get_column_type(t, column)),
02252        uves_tostring_cpl_type(CPL_TYPE_DOUBLE));
02253 
02254 
02255     threshold = fraction * cpl_table_get_column_median(t, column);
02256     for (i = 0; i < cpl_table_get_nrow(t); i++)
02257     {
02258         if (cpl_table_get_double(t, column, i, NULL) < threshold)
02259         {
02260             cpl_table_set_double(t, column, i, threshold);
02261         }
02262     }
02263 
02264   cleanup:
02265     return;
02266 }
02267 
02268 
02269 /*----------------------------------------------------------------------------*/
02286 /*----------------------------------------------------------------------------*/
02287 
02288 int
02289 uves_select_table_rows(cpl_table *t,  const char *column, 
02290                cpl_table_select_operator operator, double value)
02291 {
02292     int result = 0;
02293     cpl_type type;
02294     
02295     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
02296     assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT, 
02297         "No such column: %s", column);
02298 
02299     type = cpl_table_get_column_type(t, column);
02300 
02301     assure( type == CPL_TYPE_DOUBLE || type == CPL_TYPE_FLOAT ||
02302         type == CPL_TYPE_INT, CPL_ERROR_INVALID_TYPE,
02303         "Column '%s' must be double or int. %s found", column, 
02304         uves_tostring_cpl_type(type));
02305 
02306     check( cpl_table_select_all(t), "Error selecting rows");
02307     
02308     if      (type == CPL_TYPE_DOUBLE)
02309     {
02310         result = cpl_table_and_selected_double(t, column, operator, value);
02311     }
02312     else if (type == CPL_TYPE_FLOAT)
02313     {
02314         result = cpl_table_and_selected_float(t, column, operator, value);
02315     }
02316     else if (type == CPL_TYPE_INT)
02317     {
02318         result = cpl_table_and_selected_int(t, column, operator, 
02319                                                 uves_round_double(value));
02320     }
02321     else { /*impossible*/ passure(false, ""); }
02322     
02323   cleanup:
02324     return result;
02325 
02326 }
02327 
02328 /*----------------------------------------------------------------------------*/
02342 /*----------------------------------------------------------------------------*/
02343 int
02344 uves_extract_table_rows_local(cpl_table *t, const char *column,
02345                   cpl_table_select_operator operator, double value)
02346 {
02347     int result = 0;
02348     
02349     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
02350     assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT, 
02351         "No such column: %s", column);
02352 
02353     check( result = uves_select_table_rows(t, column, operator, value),
02354        "Error selecting rows");
02355 
02356     check( cpl_table_not_selected(t), "Error selecting rows");
02357 
02358     check( uves_table_erase_selected_dfs02356(t), "Error deleting rows");
02359 
02360   cleanup:
02361     return result;
02362 }
02363 
02364 /*----------------------------------------------------------------------------*/
02383 /*----------------------------------------------------------------------------*/
02384 int
02385 uves_erase_table_rows(cpl_table *t, const char *column,
02386               cpl_table_select_operator operator, double value)
02387 {
02388     int result = 0;
02389     
02390     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
02391     assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT, 
02392         "No such column: %s", column);
02393 
02394     check( result = uves_select_table_rows(t, column, operator, value),
02395        "Error selecting rows");
02396 
02397     check( uves_table_erase_selected_dfs02356(t), "Error deleting rows");
02398 
02399   cleanup:
02400     return result;
02401 }
02402 
02403 
02404 
02405 
02406 
02407 /*----------------------------------------------------------------------------*/
02416 /*----------------------------------------------------------------------------*/
02417 
02418 void uves_propertylist_append_property(uves_propertylist *plist, const cpl_property *p)
02419 {
02420     switch(cpl_property_get_type(p)) {
02421     case CPL_TYPE_CHAR:
02422         uves_propertylist_append_char(plist, cpl_property_get_name(p), cpl_property_get_char(p));
02423         break;
02424     case CPL_TYPE_BOOL:
02425         uves_propertylist_append_bool(plist, cpl_property_get_name(p), cpl_property_get_bool(p));
02426         break;
02427     case CPL_TYPE_INT:
02428         uves_propertylist_append_int(plist, cpl_property_get_name(p), cpl_property_get_int(p));
02429         break;
02430     case CPL_TYPE_LONG:
02431         uves_propertylist_append_long(plist, cpl_property_get_name(p), cpl_property_get_long(p));
02432         break;
02433     case CPL_TYPE_FLOAT:
02434         uves_propertylist_append_float(plist, cpl_property_get_name(p), cpl_property_get_float(p));
02435         break;
02436     case CPL_TYPE_DOUBLE:
02437         uves_propertylist_append_double(plist, cpl_property_get_name(p), cpl_property_get_double(p));
02438         break;
02439     case CPL_TYPE_STRING:
02440         uves_propertylist_append_string(plist, cpl_property_get_name(p), cpl_property_get_string(p));
02441         break;
02442     default:
02443         assure( false, CPL_ERROR_UNSUPPORTED_MODE,
02444                 "Type is %s", uves_tostring_cpl_type(cpl_property_get_type(p)));
02445         break;
02446     }
02447   cleanup:
02448     return;
02449 }
02450 
02451 /* This is really, really bad. If CPL realeased their bug-fixes, it wouldn't have been necessary.
02452    The following is duplicated from CPL and renamed cpl->xxx
02453 
02454    Did I mention that this is an ugly workaround. */
02455 
02456 typedef struct _xxx_table_ xxx_table;
02457 typedef int xxx_column_flag;
02458 typedef struct _xxx_column_ xxx_column;
02459 
02460 typedef union _xxx_column_values_ {
02461     int        *i;                          /* CPL_TYPE_INT    */
02462     float      *f;                          /* CPL_TYPE_FLOAT  */
02463     double     *d;                          /* CPL_TYPE_DOUBLE */
02464     char      **s;                          /* CPL_TYPE_STRING */
02465     cpl_array **array;                      /* Array types     */
02466 } xxx_column_values;
02467 
02468 struct _xxx_column_ {
02469     char              *name;
02470     char              *unit;
02471     char              *format;
02472     int                length;
02473     int                depth;
02474     cpl_type           type;
02475     xxx_column_values *values;
02476     xxx_column_flag   *null;       /* NULL flags buffer              */
02477     int                nullcount;  /* Number of NULLs in column      */
02478     cpl_array         *dimensions; /* Number of dimensions in column */
02479 };
02480 
02481 struct _xxx_table_ {
02482     int              nc;
02483     int              nr;
02484     xxx_column     **columns;
02485     xxx_column_flag *select;
02486     int              selectcount;
02487 };
02488 
02489 
02490 
02491 
02492 
02493 
02494 
02495 #define CPL_INT_SWAP(a,b) { register int t=(a);(a)=(b);(b)=t; }
02496 
02497 #define CPL_PIX_STACK_SIZE 50
02498 /*----------------------------------------------------------------------------*/
02509 /*----------------------------------------------------------------------------*/
02510 static cpl_error_code xxx_tools_sort_int(
02511         int     *   pix_arr,
02512         int         n)
02513 {
02514     int         i, ir, j, k, l;
02515     int         i_stack[CPL_PIX_STACK_SIZE] ;
02516     int         j_stack ;
02517     int         a ;
02518 
02519     /* Check entries */
02520     cpl_ensure(pix_arr, CPL_ERROR_NULL_INPUT,
02521             CPL_ERROR_NULL_INPUT) ;
02522 
02523     ir = n ;
02524     l = 1 ;
02525     j_stack = 0 ;
02526     for (;;) {
02527         if (ir-l < 7) {
02528             for (j=l+1 ; j<=ir ; j++) {
02529                 a = pix_arr[j-1];
02530                 for (i=j-1 ; i>=1 ; i--) {
02531                     if (pix_arr[i-1] <= a) break;
02532                     pix_arr[i] = pix_arr[i-1];
02533                 }
02534                 pix_arr[i] = a;
02535             }
02536             if (j_stack == 0) break;
02537             ir = i_stack[j_stack-- -1];
02538             l  = i_stack[j_stack-- -1];
02539         } else {
02540             k = (l+ir) >> 1;
02541             CPL_INT_SWAP(pix_arr[k-1], pix_arr[l])
02542             if (pix_arr[l] > pix_arr[ir-1]) {
02543                 CPL_INT_SWAP(pix_arr[l], pix_arr[ir-1])
02544             }
02545             if (pix_arr[l-1] > pix_arr[ir-1]) {
02546                 CPL_INT_SWAP(pix_arr[l-1], pix_arr[ir-1])
02547             }
02548             if (pix_arr[l] > pix_arr[l-1]) {
02549                 CPL_INT_SWAP(pix_arr[l], pix_arr[l-1])
02550             }
02551             i = l+1;
02552             j = ir;
02553             a = pix_arr[l-1];
02554             for (;;) {
02555                 do i++; while (pix_arr[i-1] < a);
02556                 do j--; while (pix_arr[j-1] > a);
02557                 if (j < i) break;
02558                 CPL_INT_SWAP(pix_arr[i-1], pix_arr[j-1]);
02559             }
02560             pix_arr[l-1] = pix_arr[j-1];
02561             pix_arr[j-1] = a;
02562             j_stack += 2;
02563             if (j_stack > CPL_PIX_STACK_SIZE) {
02564                 /* Should never reach here */
02565                 return CPL_ERROR_ILLEGAL_INPUT ;
02566             }
02567             if (ir-i+1 >= j-l) {
02568                 i_stack[j_stack-1] = ir;
02569                 i_stack[j_stack-2] = i;
02570                 ir = j-1;
02571             } else {
02572                 i_stack[j_stack-1] = j-1;
02573                 i_stack[j_stack-2] = l;
02574                 l = i;
02575             }
02576         }
02577     }
02578     return CPL_ERROR_NONE ;
02579 }
02580 #undef CPL_PIX_STACK_SIZE
02581 
02582 static cpl_error_code xxx_tools_sort_stable_pattern_int(const int *, 
02583                                                int, int, int, int *);
02584 static cpl_error_code xxx_tools_sort_stable_pattern_float(const float *, 
02585                                                  int, int, int, int *);
02586 static cpl_error_code xxx_tools_sort_stable_pattern_double(const double *, 
02587                                                   int, int, int, int *);
02588 static cpl_error_code xxx_tools_sort_stable_pattern_string(char * const *,
02589                                                   int, int, int, int *);
02590 
02591 
02592 #undef CONCAT
02593 #undef CONCAT2X
02594 #define CONCAT(a,b) a ## _ ## b
02595 #define CONCAT2X(a,b) CONCAT(a,b)
02596 
02597 #define CPL_TYPE int
02598 #define CPL_TYPE_NAME int
02599 #define CPL_TOOLS_SORT_LT(x,y) ((x) < (y))
02600 #include "uves_tools_body.c"
02601 #undef CPL_TYPE
02602 #undef CPL_TYPE_NAME
02603 #undef CPL_TOOLS_SORT_LT
02604 
02605 #define CPL_TYPE float
02606 #define CPL_TYPE_NAME float
02607 #define CPL_TOOLS_SORT_LT(x,y) ((x) < (y))
02608 #include "uves_tools_body.c"
02609 #undef CPL_TYPE
02610 #undef CPL_TYPE_NAME
02611 #undef CPL_TOOLS_SORT_LT
02612 
02613 #define CPL_TYPE double
02614 #define CPL_TYPE_NAME double
02615 #define CPL_TOOLS_SORT_LT(x,y) ((x) < (y))
02616 #include "uves_tools_body.c"
02617 #undef CPL_TYPE
02618 #undef CPL_TYPE_NAME
02619 #undef CPL_TOOLS_SORT_LT
02620 
02621 #define CPL_TYPE char *
02622 #define CPL_TYPE_NAME string
02623 #define CPL_TOOLS_SORT_LT(x,y) (((x) == NULL && (y) != NULL) ||  \
02624                                 ((x) != NULL && (y) != NULL &&   \
02625                                  strcmp((x), (y)) < 0))
02626 #include "uves_tools_body.c"
02627 #undef CPL_TYPE
02628 #undef CPL_TYPE_NAME
02629 #undef CPL_TOOLS_SORT_LT
02630 
02631 
02632 
02633 
02634 
02635 
02636 
02637 
02638 void xxx_column_dump_structure(xxx_column *column);
02639 void xxx_column_dump(xxx_column *column, int start, int count);
02640 
02641 /*
02642  * Constructors and destructors:
02643  */
02644 
02645 xxx_column *xxx_column_new_int(int length);
02646 xxx_column *xxx_column_new_float(int length);
02647 xxx_column *xxx_column_new_double(int length);
02648 xxx_column *xxx_column_new_string(int length);
02649 xxx_column *xxx_column_new_array(cpl_type, int, int);
02650 
02651 xxx_column *xxx_column_wrap_int(int *data, int length);
02652 xxx_column *xxx_column_wrap_float(float *data, int length);
02653 xxx_column *xxx_column_wrap_double(double *data, int length);
02654 xxx_column *xxx_column_wrap_string(char **data, int length);
02655 
02656 void *xxx_column_unwrap(xxx_column *);
02657 void xxx_column_delete_but_strings(xxx_column *);
02658 void xxx_column_delete_but_arrays(xxx_column *);
02659 
02660 cpl_error_code xxx_column_copy_data(xxx_column *column, 
02661                                     const double *data);
02662 cpl_error_code xxx_column_copy_data_int(xxx_column *column, 
02663                                     const int *data);
02664 cpl_error_code xxx_column_copy_data_float(xxx_column *column, 
02665                                     const float *data);
02666 cpl_error_code xxx_column_copy_data_double(xxx_column *column, 
02667                                     const double *data);
02668 cpl_error_code xxx_column_copy_data_string(xxx_column *column, 
02669                                     const char **data);
02670 
02671 void xxx_column_delete(xxx_column *);
02672 
02673 
02674 /*
02675  * Methods:
02676  */
02677 
02678 cpl_error_code xxx_column_set_name(xxx_column *, const char *);
02679 const char *xxx_column_get_name(xxx_column *);
02680 
02681 cpl_error_code xxx_column_set_unit(xxx_column *, const char *);
02682 const char *xxx_column_get_unit(xxx_column *);
02683 
02684 cpl_error_code xxx_column_set_format(xxx_column *, const char *);
02685 const char *xxx_column_get_format(xxx_column *);
02686 
02687 int xxx_column_get_depth(xxx_column *);
02688 int xxx_column_get_dimensions(xxx_column *);
02689 cpl_error_code xxx_column_set_dimensions(xxx_column *, cpl_array *);
02690 int xxx_column_get_dimension(xxx_column *, int);
02691 
02692 
02693 int *xxx_column_get_data_int(xxx_column *);
02694 float *xxx_column_get_data_float(xxx_column *);
02695 double *xxx_column_get_data_double(xxx_column *);
02696 char **xxx_column_get_data_string(xxx_column *);
02697 cpl_array **xxx_column_get_data_array(xxx_column *);
02698 xxx_column_flag *xxx_column_get_data_invalid(xxx_column *);
02699 cpl_error_code xxx_column_set_data_invalid(xxx_column *, 
02700                                            xxx_column_flag *, int);
02701 
02702 cpl_error_code xxx_column_set_size(xxx_column *, int);
02703 cpl_error_code xxx_column_set_depth(xxx_column *, int);
02704 
02705 double xxx_column_get(xxx_column *, int, int *null); 
02706 int xxx_column_get_int(xxx_column *, int, int *null); 
02707 float xxx_column_get_float(xxx_column *, int, int *null); 
02708 double xxx_column_get_double(xxx_column *, int, int *null); 
02709 const char *xxx_column_get_string(xxx_column *, int);
02710 const cpl_array *xxx_column_get_array(xxx_column *, int);
02711 
02712 cpl_error_code xxx_column_set(xxx_column *, int, double); 
02713 cpl_error_code xxx_column_set_int(xxx_column *, int, int); 
02714 cpl_error_code xxx_column_set_float(xxx_column *, int, float); 
02715 cpl_error_code xxx_column_set_double(xxx_column *, int, double); 
02716 cpl_error_code xxx_column_set_string(xxx_column *, int, const char *);
02717 cpl_error_code xxx_column_set_array(xxx_column *, int, const cpl_array *);
02718 
02719 cpl_error_code xxx_column_fill(xxx_column *, int, int, double); 
02720 cpl_error_code xxx_column_fill_int(xxx_column *, int, int, int); 
02721 cpl_error_code xxx_column_fill_float(xxx_column *, int, int, float); 
02722 cpl_error_code xxx_column_fill_double(xxx_column *, int, int, double);
02723 cpl_error_code xxx_column_fill_string(xxx_column *, int, int, const char *);
02724 cpl_error_code xxx_column_fill_array(xxx_column *, int, int, const cpl_array *);
02725 
02726 cpl_error_code xxx_column_copy_segment(xxx_column *, int, int, double *);
02727 cpl_error_code xxx_column_copy_segment_int(xxx_column *, int, int, int *);
02728 cpl_error_code xxx_column_copy_segment_float(xxx_column *, int, int, float *);
02729 cpl_error_code xxx_column_copy_segment_double(xxx_column *, int, int, double *);
02730 cpl_error_code xxx_column_copy_segment_string(xxx_column *, int, int, char **);
02731 cpl_error_code xxx_column_copy_segment_array(xxx_column *, int, int, 
02732                                              cpl_array **);
02733 
02734 cpl_error_code xxx_column_shift(xxx_column *, int);
02735 
02736 cpl_error_code xxx_column_set_invalid(xxx_column *, int);
02737 cpl_error_code xxx_column_fill_invalid(xxx_column *, int, int);
02738 int xxx_column_is_invalid(xxx_column *, int);
02739 int xxx_column_has_invalid(xxx_column *);
02740 int xxx_column_has_valid(xxx_column *);
02741 int xxx_column_count_invalid(xxx_column *);
02742 
02743 cpl_error_code xxx_column_fill_invalid_int(xxx_column *, int);
02744 cpl_error_code xxx_column_fill_invalid_float(xxx_column *, float);
02745 cpl_error_code xxx_column_fill_invalid_double(xxx_column *, double);
02746 
02747 cpl_error_code xxx_column_erase_segment(xxx_column *, int, int);
02748 cpl_error_code xxx_column_insert_segment(xxx_column *, int, int);
02749 
02750 xxx_column *xxx_column_duplicate(xxx_column *);
02751 
02752 xxx_column *xxx_column_extract(xxx_column *, int, int);
02753 
02754 xxx_column *xxx_column_cast_to_int(xxx_column *);
02755 xxx_column *xxx_column_cast_to_float(xxx_column *);
02756 xxx_column *xxx_column_cast_to_double(xxx_column *);
02757 
02758 cpl_error_code xxx_column_merge(xxx_column *, xxx_column *, int);
02759 
02760 cpl_error_code xxx_column_add(xxx_column *, xxx_column *);
02761 cpl_error_code xxx_column_subtract(xxx_column *, xxx_column *);
02762 cpl_error_code xxx_column_multiply(xxx_column *, xxx_column *);
02763 cpl_error_code xxx_column_divide(xxx_column *, xxx_column *);
02764 
02765 cpl_error_code xxx_column_add_scalar(xxx_column *, double);
02766 cpl_error_code xxx_column_subtract_scalar(xxx_column *, double);
02767 cpl_error_code xxx_column_multiply_scalar(xxx_column *, double);
02768 cpl_error_code xxx_column_divide_scalar(xxx_column *, double);
02769 cpl_error_code xxx_column_logarithm(xxx_column *, double);
02770 cpl_error_code xxx_column_power(xxx_column *, double);
02771 cpl_error_code xxx_column_exponential(xxx_column *, double);
02772 
02773 double xxx_column_get_mean(xxx_column *);
02774 double xxx_column_get_median(xxx_column *);
02775 double xxx_column_get_stdev(xxx_column *);
02776 
02777 double xxx_column_get_max(xxx_column *);
02778 double xxx_column_get_min(xxx_column *);
02779 cpl_error_code xxx_column_get_maxpos(xxx_column *, int *);
02780 cpl_error_code xxx_column_get_minpos(xxx_column *, int *);
02781 
02782 
02783 
02784 
02785 
02786 
02787 
02788 
02789 
02790 
02791 inline static int xxx_column_type_size(cpl_type type)
02792 {
02793 
02794     switch (type) {
02795     case CPL_TYPE_INT:
02796         return sizeof(int);
02797     case CPL_TYPE_FLOAT:
02798         return sizeof(float);
02799     case CPL_TYPE_DOUBLE:
02800         return sizeof(double);
02801     case CPL_TYPE_STRING:
02802         return sizeof(char *);
02803     case CPL_TYPE_INT | CPL_TYPE_POINTER:
02804     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
02805     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
02806     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
02807         return sizeof(cpl_array *);
02808     default:
02809         return 0;
02810     }
02811 
02812 }
02813 #define CPL_DOUBLE_SWAP(a,b) { register double t=(a);(a)=(b);(b)=t; }
02814 #define CPL_FLOAT_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; }
02815 #define CPL_PIX_SORT(a,b) { if ((a)>(b)) CPL_DOUBLE_SWAP((a),(b)); }
02816 
02817 
02818 static int xxx_column_get_size(xxx_column *column)
02819 {
02820 
02821     if (column)
02822         return column->length;
02823 
02824     cpl_error_set("xxx_column_get_size", CPL_ERROR_NULL_INPUT);
02825 
02826     return 0;
02827 
02828 }
02829 
02830 static cpl_type xxx_column_get_type(xxx_column *column)
02831 {
02832 
02833     if (column)
02834         return column->type;
02835 
02836     cpl_error_set("xxx_column_get_type", CPL_ERROR_NULL_INPUT);
02837 
02838     return CPL_TYPE_INVALID;
02839 
02840 }
02841 
02842 
02843 
02844 static cpl_error_code xxx_column_erase_pattern(xxx_column *column, 
02845                                         int *pattern)
02846 {
02847     
02848     const char     *fid        = "xxx_column_erase_pattern";
02849     cpl_type         type       = xxx_column_get_type(column);
02850     int              old_length = xxx_column_get_size(column);
02851     int              new_length;
02852     int              i;
02853     int              j;
02854     cpl_array      **ap;
02855     char           **sp;
02856     int             *ip;
02857     float           *fp;
02858     double          *dp;
02859 
02860 
02861     if (column == 0x0)
02862         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
02863 
02864     if (pattern == 0x0)
02865         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
02866 
02867     new_length = 0;
02868     for (i = 0; i < old_length; i++)
02869         if (!pattern[i]) 
02870             new_length++;
02871 
02872     if (type == CPL_TYPE_STRING) {
02873 
02874         /*
02875          *  If a column of character strings is shortened, we must
02876          *  free explicitly the extra strings.
02877          */
02878 
02879       for(i = 0; i < old_length; i++)
02880         if (pattern[i])
02881           if (column->values->s[i])
02882             cpl_free(column->values->s[i]);
02883 
02884     }
02885 
02886     if (type & CPL_TYPE_POINTER) {
02887 
02888         /*
02889          *  If a column of arrays is shortened, we must
02890          *  free explicitly the extra arrays.
02891          */
02892 
02893       for(i = 0; i < old_length; i++)
02894         if (pattern[i])
02895           if (column->values->array[i])
02896             cpl_array_delete(column->values->array[i]);
02897 
02898     }
02899 
02900 
02901     /*
02902      *  Shorten the invalid flags buffer, if present, 
02903      *  counting how many invalid elements will be lost.
02904      */
02905     
02906     if (column->null) {
02907         
02908         for (i = 0; i < old_length; i++)
02909             if (pattern[i])
02910                 if (column->null[i])
02911                     column->nullcount--;
02912 
02913         if (column->nullcount == 0 || column->nullcount == new_length) {
02914             
02915             /*
02916              *  Since either no invalid or just invalid elements are left, 
02917              *  the invalid flag buffer can be released.
02918              */
02919             
02920             if (column->null)
02921                 cpl_free(column->null);
02922             column->null = NULL;
02923             
02924         }
02925         else {
02926 
02927             /*
02928              *  Shift up NULL flags.
02929              */
02930             
02931             i = 0;
02932             for (j = 0; j < old_length; j++)
02933                 if (!pattern[j]) {
02934                     column->null[i] = column->null[j];
02935                     i++;
02936                 }
02937             
02938             /*
02939              *  Get rid of extra memory.
02940              */
02941             
02942             column->null = cpl_realloc(column->null,
02943                                        new_length * sizeof(xxx_column_flag));
02944             
02945         }
02946     }
02947     else {
02948 
02949         /*
02950          *  There is no invalid flag buffer, so either there are no 
02951          *  invalid elements or there are just invalid elements. If 
02952          *  there are no invalid elements, nullcount stays zero. If 
02953          *  there are just invalid elements, nullcount must be set 
02954          *  to the new column length.
02955          */
02956 
02957         if (column->nullcount == old_length)
02958             column->nullcount = new_length;
02959 
02960     }
02961 
02962 
02963     /*
02964      *  Now take care of data values
02965      */
02966 
02967     if ((type == CPL_TYPE_STRING) || (type & CPL_TYPE_POINTER))
02968         column->nullcount = 0;
02969 
02970     if (column->nullcount != new_length) {
02971 
02972         /*
02973          *  Column has not just invalid elements. In this case we have to
02974          *  shift also the data to fill the gaps.
02975          */
02976 
02977         ip = column->values->i;
02978         fp = column->values->f;
02979         dp = column->values->d;
02980         sp = column->values->s;
02981         ap = column->values->array;
02982  
02983         switch (type) {
02984         case CPL_TYPE_INT:
02985           i = 0;
02986           for(j = 0; j < old_length; j++)
02987             if (!pattern[j])
02988               ip[i++] = ip[j];
02989           break;
02990         case CPL_TYPE_FLOAT:
02991           i = 0;
02992           for(j = 0; j < old_length; j++)
02993             if (!pattern[j])
02994               fp[i++] = fp[j];
02995             break;
02996         case CPL_TYPE_DOUBLE:
02997           i = 0;
02998           for(j = 0; j < old_length; j++)
02999             if (!pattern[j])
03000               dp[i++] = dp[j];
03001             break;
03002         case CPL_TYPE_STRING:
03003           i = 0;
03004           for(j = 0; j < old_length; j++)
03005             if (!pattern[j])
03006               sp[i++] = sp[j];
03007             break;
03008         default:     /* Array columns */
03009           i = 0;
03010           for(j = 0; j < old_length; j++)
03011             if (!pattern[j])
03012               ap[i++] = ap[j];
03013           break;
03014         }
03015 
03016     }
03017 
03018 
03019     /*
03020      *  Finally, reallocate the data buffer.
03021      */
03022 
03023     column->values->i = cpl_realloc(column->values->i,
03024                         new_length * xxx_column_type_size(type));
03025 
03026     column->length = new_length;
03027 
03028     return 0;
03029 
03030 }
03031 
03032 /* Lots of unsafe casts here */
03033 static cpl_error_code xxx_table_erase_selected(xxx_table *table)
03034 {
03035 
03036     const char     *fid    = "xxx_table_erase_selected";
03037     int              length = cpl_table_get_nrow((cpl_table *)table);
03038     int              i, width;
03039 
03040     if (table == 0x0)
03041         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
03042 
03043     if (table->selectcount == 0)
03044         return cpl_table_select_all((cpl_table *)table);
03045 
03046     if (table->selectcount == length)
03047         return cpl_table_set_size((cpl_table *)table, 0);
03048 
03049     width = cpl_table_get_ncol((cpl_table *)table);
03050 
03051     for (i = 0; i < width; i++)
03052         if (xxx_column_erase_pattern(table->columns[i], table->select)) {
03053             cpl_error_set_where(fid);
03054             return cpl_error_get_code();
03055         }
03056 
03057     table->nr -= table->selectcount;
03058 
03059     return cpl_table_select_all((cpl_table *)table);
03060 }
03061 
03062 /*----------------------------------------------------------------------------*/
03070 /*----------------------------------------------------------------------------*/
03071 cpl_error_code uves_table_erase_selected_dfs02356(cpl_table *t)
03072 {
03073     xxx_table_erase_selected((xxx_table *)t);
03074 
03075     passure( cpl_table_count_selected(t) == cpl_table_get_nrow(t),
03076              "%d %d",
03077              cpl_table_count_selected(t), cpl_table_get_nrow(t) );
03078 
03079 //    cpl_table_erase_selected(t);
03080   cleanup:
03081     return cpl_error_get_code();
03082 }
03083 
03084 /* another major workaround here */
03085 static xxx_column *xxx_table_find_column(const xxx_table *table,
03086                                          const char *name)
03087 {
03088 
03089     xxx_column **column;
03090     const char  *column_name;
03091     int          i;
03092 
03093 
03094     column = table->columns;
03095 
03096     for (i = 0; i < table->nc; i++, column++) {
03097         column_name = xxx_column_get_name(*column);
03098         if (strcmp(name, column_name) == 0) {
03099             return *column;
03100         }
03101     }
03102 
03103     return NULL;
03104 
03105 }
03106 
03107 
03108 
03109 static double xxx_tools_get_kth_double(
03110         double  *   a,
03111         int         n,
03112         int         k)
03113 {
03114     register double x ;
03115     register int    i, j, l, m ;
03116 
03117     cpl_ensure(a, CPL_ERROR_NULL_INPUT, 0.00) ;
03118 
03119     l=0 ; m=n-1 ;
03120     while (l<m) {
03121         x=a[k] ;
03122         i=l ;
03123         j=m ;
03124         do {
03125             while (a[i]<x) i++ ;
03126             while (x<a[j]) j-- ;
03127             if (i<=j) {
03128                 CPL_DOUBLE_SWAP(a[i],a[j]) ;
03129                 i++ ; j-- ;
03130             }
03131         } while (i<=j) ;
03132         if (j<k) l=i ;
03133         if (k<i) m=j ;
03134     }
03135     return a[k] ;
03136 }
03137 
03138 /*----------------------------------------------------------------------------*/
03147 /*----------------------------------------------------------------------------*/
03148 static float xxx_tools_get_kth_float(
03149         float   *   a,
03150         int         n,
03151         int         k)
03152 {
03153     register float  x ;
03154     register int    i, j, l, m ;
03155 
03156     cpl_ensure(a, CPL_ERROR_NULL_INPUT, 0.00) ;
03157 
03158     l=0 ; m=n-1 ;
03159     while (l<m) {
03160         x=a[k] ;
03161         i=l ;
03162         j=m ;
03163         do {
03164             while (a[i]<x) i++ ;
03165             while (x<a[j]) j-- ;
03166             if (i<=j) {
03167                 CPL_FLOAT_SWAP(a[i],a[j]) ;
03168                 i++ ; j-- ;
03169             }
03170         } while (i<=j) ;
03171         if (j<k) l=i ;
03172         if (k<i) m=j ;
03173     }
03174     return a[k] ;
03175 }
03176 
03177 /*----------------------------------------------------------------------------*/
03186 /*----------------------------------------------------------------------------*/
03187 static int xxx_tools_get_kth_int(
03188         int     *   a,
03189         int         n,
03190         int         k)
03191 {
03192     register float  x ;
03193     register int    i, j, l, m ;
03194 
03195     cpl_ensure(a, CPL_ERROR_NULL_INPUT, 0) ;
03196 
03197     l=0 ; m=n-1 ;
03198     while (l<m) {
03199         x=a[k] ;
03200         i=l ;
03201         j=m ;
03202         do {
03203             while (a[i]<x) i++ ;
03204             while (x<a[j]) j-- ;
03205             if (i<=j) {
03206                 CPL_INT_SWAP(a[i],a[j]) ;
03207                 i++ ; j-- ;
03208             }
03209         } while (i<=j) ;
03210         if (j<k) l=i ;
03211         if (k<i) m=j ;
03212     }
03213     return a[k] ;
03214 }
03215 
03216 
03217 #define INT_FORM "% 7d"
03218 #define FLOAT_FORM "% 1.5e"
03219 #define DOUBLE_FORM "% 1.5e"
03220 #define STRING_FORM "%s"
03221 
03222 static cpl_error_code
03223 table_sort(xxx_table *table, const uves_propertylist *reflist, unsigned n,
03224            int *sort_pattern, int *sort_null_pattern)
03225 {
03226     const char     *fid = "table_sort";
03227     cpl_property *info;
03228     const char *name;
03229     int reverse;
03230     const int stable = 1;
03231     xxx_column *column;
03232     xxx_column *column_sorted_null;
03233     cpl_type type;
03234     int i, j;
03235 
03236     int nullcount;
03237     int             *idata;
03238     int             *sorted_idata;
03239     float           *fdata;
03240     float           *sorted_fdata;
03241     double          *ddata;
03242     double          *sorted_ddata;
03243     char           **sdata;
03244     char           **sorted_sdata;
03245     cpl_array      **adata;
03246     cpl_array      **sorted_adata;
03247     xxx_column_flag *ndata;
03248     xxx_column_flag *sorted_ndata;
03249 
03250 
03251     if (n == 0) {
03252         return CPL_ERROR_NONE;
03253     }
03254 
03255 
03256     /*
03257      * Sort after least significant column
03258      */
03259 
03260     info = uves_propertylist_get((uves_propertylist *)reflist, n - 1);
03261     name = cpl_property_get_name(info);
03262     if (cpl_property_get_type(info) == CPL_TYPE_BOOL) {
03263         reverse = cpl_property_get_bool(info);
03264     }
03265     else {
03266         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
03267     }
03268 
03269     if (name == NULL) {
03270         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
03271     }
03272     if ((column = xxx_table_find_column(table, name)) == NULL) {
03273         return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
03274     }
03275 
03276     type = xxx_column_get_type(column);
03277     if (type & CPL_TYPE_POINTER) {   /* Arrays not as reference */
03278         return cpl_error_set(fid, CPL_ERROR_UNSUPPORTED_MODE);
03279     }
03280 
03281 
03282     /*
03283      * Independent of the reverse flag, put rows with invalid values at the
03284      * beginning of the table
03285      */
03286 
03287     nullcount = xxx_column_count_invalid(column);
03288     ndata = xxx_column_get_data_invalid(column);
03289 
03290     j = 0;
03291     for (i = 0; i < table->nr; i++) {
03292         if (nullcount == table->nr || 
03293             (ndata != NULL && ndata[i])) {
03294             sort_null_pattern[j++] = i;
03295         }
03296     }
03297 
03298     assert( j == nullcount );
03299 
03300     for (i = 0; i < table->nr; i++) {
03301         if (!
03302             (nullcount == table->nr || 
03303              (ndata != NULL && ndata[i]))
03304             ) {
03305             sort_null_pattern[j++] = i;
03306         }
03307     }
03308 
03309     assert( j == table->nr );
03310 
03311 
03312     /*
03313      *  Apply NULL pattern
03314      */
03315 
03316     column_sorted_null = xxx_column_duplicate(column);
03317     for (i = 0; i < nullcount; i++) {
03318         xxx_column_set_invalid(column_sorted_null, i);
03319     }
03320     for (i = nullcount; i < table->nr; i++) {
03321         int isnull;
03322 
03323         switch (type) {
03324         case CPL_TYPE_INT:
03325             xxx_column_set_int(
03326                 column_sorted_null, i,
03327                 xxx_column_get_int(column, sort_null_pattern[i], &isnull));
03328             break;
03329         case CPL_TYPE_FLOAT:
03330             xxx_column_set_float(
03331                 column_sorted_null, i,
03332                 xxx_column_get_float(column, sort_null_pattern[i], &isnull));
03333             break;
03334         case CPL_TYPE_DOUBLE:
03335             xxx_column_set_double(
03336                 column_sorted_null, i,
03337                 xxx_column_get_double(column, sort_null_pattern[i], &isnull));
03338             break;
03339         case CPL_TYPE_STRING:
03340             xxx_column_set_string(
03341                 column_sorted_null, i,
03342                 xxx_column_get_string(column, sort_null_pattern[i]));
03343             break;
03344         default:
03345             assert( 0 );
03346             break;
03347         }
03348     }
03349 
03350     /*
03351      * Get remaining sort pattern
03352      */
03353 
03354     for (i = 0; i < nullcount; i++) {
03355         sort_pattern[i] = i;
03356     }
03357     switch (type) {
03358     case CPL_TYPE_INT:
03359         xxx_tools_sort_stable_pattern_int(
03360             xxx_column_get_data_int(column_sorted_null) + nullcount,
03361             table->nr - nullcount,
03362             reverse,
03363             stable,
03364             sort_pattern + nullcount);
03365         break;
03366     case CPL_TYPE_FLOAT:
03367         xxx_tools_sort_stable_pattern_float(
03368             xxx_column_get_data_float(column_sorted_null) + nullcount,
03369             table->nr - nullcount,
03370             reverse,
03371             stable,
03372             sort_pattern + nullcount);
03373         break;
03374     case CPL_TYPE_DOUBLE:
03375         xxx_tools_sort_stable_pattern_double(
03376             xxx_column_get_data_double(column_sorted_null) + nullcount,
03377             table->nr - nullcount,
03378             reverse,
03379             stable,
03380             sort_pattern + nullcount);
03381         break;
03382     case CPL_TYPE_STRING:
03383         xxx_tools_sort_stable_pattern_string(
03384             xxx_column_get_data_string(column_sorted_null) + nullcount,
03385             table->nr - nullcount,
03386             reverse,
03387             stable,
03388             sort_pattern + nullcount);
03389         break;
03390     default:
03391         assert( 0 );
03392         break;
03393     }
03394 
03395     xxx_column_delete(column_sorted_null);
03396 
03397 
03398     /*
03399      *  Transform sort pattern
03400      */
03401 
03402     for (i = nullcount; i < table->nr; i++) {
03403         sort_pattern[i] += nullcount;
03404     }
03405 
03406 
03407     /*
03408      * Now apply the combined sort pattern to each column in the table:
03409      */
03410 
03411     j = 0;
03412     while (j < table->nc) {
03413         xxx_column      *sorted_column;
03414 
03415         switch (xxx_column_get_type(table->columns[j])) {
03416 
03417         case CPL_TYPE_INT:
03418 
03419             sorted_column = xxx_column_new_int(table->nr);
03420 
03421             xxx_column_set_name(sorted_column,
03422                                 xxx_column_get_name(table->columns[j]));
03423 
03424             nullcount = xxx_column_count_invalid(table->columns[j]);
03425 
03426             if (nullcount != table->nr) {
03427 
03428                 /*
03429                  * This is just a trick to make the null column exist,
03430                  * with the right number of nulls:
03431                  */
03432 
03433                 xxx_column_fill_int(sorted_column, 0,
03434                                     table->nr - nullcount, 0);
03435 
03436                 ndata = xxx_column_get_data_invalid(table->columns[j]);
03437 
03438                 if (ndata) {
03439                     sorted_ndata = xxx_column_get_data_invalid(sorted_column);
03440 
03441                     for (i = 0; i < table->nr; i++)
03442                         sorted_ndata[i] = 
03443                         ndata[sort_null_pattern[sort_pattern[i]]];
03444 
03445                 }
03446 
03447             }
03448 
03449             sorted_idata = xxx_column_get_data_int(sorted_column);
03450             idata = xxx_column_get_data_int(table->columns[j]);
03451 
03452             for (i = 0; i < table->nr; i++)
03453                 sorted_idata[i] = idata[sort_null_pattern[sort_pattern[i]]];
03454 
03455             xxx_column_delete(table->columns[j]);
03456             table->columns[j] = sorted_column;
03457             break;
03458 
03459         case CPL_TYPE_FLOAT:
03460 
03461             sorted_column = xxx_column_new_float(table->nr);
03462 
03463             xxx_column_set_name(sorted_column,
03464                                 xxx_column_get_name(table->columns[j]));
03465 
03466             nullcount = xxx_column_count_invalid(table->columns[j]);
03467 
03468             if (nullcount != table->nr) {
03469 
03470                 /*
03471                  * This is just a trick to make the null column exist,
03472                  * with the right number of nulls:
03473                  */
03474 
03475                 xxx_column_fill_float(sorted_column, 0,
03476                                       table->nr - nullcount, 0.0);
03477 
03478                 ndata = xxx_column_get_data_invalid(table->columns[j]);
03479 
03480                 if (ndata) {
03481                     sorted_ndata = xxx_column_get_data_invalid(sorted_column);
03482 
03483                     for (i = 0; i < table->nr; i++)
03484                         sorted_ndata[i] = 
03485                         ndata[sort_null_pattern[sort_pattern[i]]];
03486 
03487                 }
03488 
03489             }
03490 
03491             sorted_fdata = xxx_column_get_data_float(sorted_column);
03492             fdata = xxx_column_get_data_float(table->columns[j]);
03493 
03494             for (i = 0; i < table->nr; i++)
03495                 sorted_fdata[i] = fdata[sort_null_pattern[sort_pattern[i]]];
03496 
03497 
03498             xxx_column_delete(table->columns[j]);
03499             table->columns[j] = sorted_column;
03500             break;
03501 
03502         case CPL_TYPE_DOUBLE:
03503 
03504             sorted_column = xxx_column_new_double(table->nr);
03505 
03506             xxx_column_set_name(sorted_column,
03507                                 xxx_column_get_name(table->columns[j]));
03508 
03509             nullcount = xxx_column_count_invalid(table->columns[j]);
03510 
03511             if (nullcount != table->nr) {
03512 
03513                 /*
03514                  * This is just a trick to make the null column exist,
03515                  * with the right number of nulls:
03516                  */
03517 
03518                 xxx_column_fill_double(sorted_column, 0,
03519                                        table->nr - nullcount, 0.0);
03520 
03521                 ndata = xxx_column_get_data_invalid(table->columns[j]);
03522 
03523                 if (ndata) {
03524                     sorted_ndata = xxx_column_get_data_invalid(sorted_column);
03525 
03526                     for (i = 0; i < table->nr; i++)
03527                         sorted_ndata[i] = 
03528                         ndata[sort_null_pattern[sort_pattern[i]]];
03529 
03530                 }
03531 
03532             }
03533 
03534             sorted_ddata = xxx_column_get_data_double(sorted_column);
03535             ddata = xxx_column_get_data_double(table->columns[j]);
03536 
03537             for (i = 0; i < table->nr; i++)
03538                 sorted_ddata[i] = ddata[sort_null_pattern[sort_pattern[i]]];
03539 
03540             xxx_column_delete(table->columns[j]);
03541             table->columns[j] = sorted_column;
03542             break;
03543 
03544         case CPL_TYPE_STRING:
03545 
03546             sorted_column = xxx_column_new_string(table->nr);
03547 
03548             xxx_column_set_name(sorted_column,
03549                                 xxx_column_get_name(table->columns[j]));
03550 
03551             sorted_sdata = xxx_column_get_data_string(sorted_column);
03552             sdata = xxx_column_get_data_string(table->columns[j]);
03553 
03554             for (i = 0; i < table->nr; i++)
03555                 sorted_sdata[i] = sdata[sort_null_pattern[sort_pattern[i]]];
03556 
03557             xxx_column_delete_but_strings(table->columns[j]);
03558             table->columns[j] = sorted_column;
03559             break;
03560 
03561         case CPL_TYPE_INT | CPL_TYPE_POINTER:
03562         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
03563         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
03564         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
03565 
03566             sorted_column =
03567             xxx_column_new_array(xxx_column_get_type(table->columns[j]),
03568                                  table->nr,
03569                                  xxx_column_get_depth(table->columns[j]));
03570 
03571             xxx_column_set_name(sorted_column,
03572                                 xxx_column_get_name(table->columns[j]));
03573 
03574             sorted_adata = xxx_column_get_data_array(sorted_column);
03575             adata = xxx_column_get_data_array(table->columns[j]);
03576 
03577             for (i = 0; i < table->nr; i++)
03578                 sorted_adata[i] = adata[sort_null_pattern[sort_pattern[i]]];
03579 
03580             xxx_column_delete_but_arrays(table->columns[j]);
03581             table->columns[j] = sorted_column;
03582             break;
03583 
03584         default:
03585 
03586             break;      /* Should never get here */
03587 
03588         }
03589 
03590         j++;
03591 
03592     }
03593 
03594 
03595     /*
03596      * Finished sorting after least significant column.
03597      * Sort after remaining columns
03598      */
03599 
03600     return table_sort(table, reflist, n - 1, sort_pattern, sort_null_pattern);
03601 }
03602 static 
03603 cpl_error_code xxx_table_sort(xxx_table *table, const uves_propertylist *reflist)
03604 {
03605     const char     *fid = "xxx_table_sort";
03606     int *sort_pattern, *sort_null_pattern;
03607     cpl_error_code ec;
03608 
03609     if (table == NULL || reflist == NULL)
03610         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
03611 
03612     if (uves_propertylist_get_size(reflist) == 0)
03613         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
03614 
03615     if (table->nr < 2)
03616         return CPL_ERROR_NONE;
03617 
03618     sort_pattern      = cpl_malloc(table->nr * sizeof(int));
03619     sort_null_pattern = cpl_malloc(table->nr * sizeof(int));
03620 
03621     ec = table_sort(table, reflist, uves_propertylist_get_size(reflist),
03622                     sort_pattern, sort_null_pattern);
03623 
03624     cpl_free(sort_pattern);
03625     cpl_free(sort_null_pattern);
03626 
03627     return ec;
03628 }
03629 
03630 
03631 
03632 
03633 
03634 
03635 
03636 /*
03637  * @brief
03638  *   Create a column values container (private).
03639  *
03640  * @return Pointer to column values container.
03641  *
03642  * This private function allocates and initializes a container of
03643  * column values.
03644  */
03645 
03646 static xxx_column_values *xxx_column_values_new(void)
03647 {
03648 
03649     xxx_column_values *value = cpl_calloc(1, sizeof(xxx_column_values));
03650 
03651 
03652     value->i = NULL;
03653 
03654     return value;
03655 
03656 }
03657 
03658 /*
03659  * @brief
03660  *   Returns the values container of a column (private).
03661  *
03662  * @return Pointer to column values container, or @em NULL.
03663  */
03664 
03665 static xxx_column_values *xxx_column_get_values(xxx_column *column)
03666 {
03667 
03668     if (column)
03669         return column->values;
03670 
03671     return NULL;
03672 
03673 }
03674 
03675 
03676 /*
03677  * @brief
03678  *   Destructor of the container of column values (private).
03679  *
03680  * @param values  Pointer to container of column values.
03681  * @param length  Column length.
03682  * @param type    Column type.
03683  *
03684  * @return Nothing.
03685  *
03686  * This is a private function used to free all the column data and their
03687  * container.
03688  */
03689 
03690 static void xxx_column_values_delete(xxx_column_values *values, 
03691                                      int length, cpl_type type)
03692 {
03693 
03694     int i;
03695 
03696 
03697     if (values) {
03698         switch (type) {
03699         case CPL_TYPE_INT | CPL_TYPE_POINTER:
03700         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
03701         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
03702         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
03703 
03704             for (i = 0; i < length; i++)
03705                 cpl_array_delete(values->array[i]);
03706 
03707             cpl_free((void *)values->array);
03708             cpl_free(values);
03709 
03710             break;
03711 
03712         case CPL_TYPE_STRING:
03713 
03714             for (i = 0; i < length; i++)
03715                 if (values->s[i])
03716                     cpl_free(values->s[i]);
03717 
03718         default:
03719 
03720             if (values->s)
03721                 cpl_free((void *)values->s);
03722 
03723             cpl_free(values);
03724 
03725             break;
03726 
03727         }
03728     }
03729 
03730 }
03731 
03732 
03733 /*
03734  * @brief
03735  *   Unset a NULL flag (private).
03736  *
03737  * @param column  Column to be accessed.
03738  * @param row     Position where to unset the NULL.
03739  *
03740  * @return 0 on success.
03741  *
03742  * This function is private: the only way for a user to unset a
03743  * null flag, is to write to the corresponding column element a
03744  * valid value. This function cannot be used for string or array 
03745  * columns.
03746  * Being this function private, all safety checks are removed to
03747  * make this function faster, assuming that all checks has been
03748  * already performed by the caller.
03749  */
03750 
03751 static int xxx_column_unset_null(xxx_column *column, int row)
03752 {
03753 
03754     int length;
03755 
03756 
03757     if (column->nullcount == 0)       /* There are no nulls to unset */
03758         return 0;
03759 
03760     if (!column->null)                /* There are just nulls        */
03761         column->null = cpl_malloc(column->length * sizeof(xxx_column_flag));
03762 
03763     length = column->length;
03764 
03765     if (column->nullcount == length)
03766         while (length--)
03767             column->null[length] = 1;
03768 
03769     if (column->null[row] == 1) {
03770         column->null[row] = 0;
03771         column->nullcount--;
03772     }
03773 
03774     if (column->nullcount == 0) {
03775         if (column->null)
03776             cpl_free(column->null);
03777         column->null = NULL;
03778     }
03779 
03780     return 0;
03781 
03782 }
03783 
03784 
03785 /*
03786  * @brief
03787  *   Unset an interval of NULL flags (private).
03788  *
03789  * @param column  Column to be accessed.
03790  * @param start   Position where to start unsetting NULLs.
03791  * @param count   Number of column elements to unset.
03792  *
03793  * @return 0 on success.
03794  *
03795  * This function is private: the only way for a user to unset a
03796  * null flag, is to write to the corresponding column element a
03797  * valid value. This function cannot be used for string or array columns.
03798  * Being this function private, all safety checks are removed to
03799  * make this function faster, assuming that all checks has been
03800  * already performed by the caller.
03801  */
03802 
03803 static int xxx_column_unset_null_segment(xxx_column *column, 
03804                                          int start, int count)
03805 {
03806 
03807     int length = xxx_column_get_size(column);
03808 
03809 
03810     if (start == 0 && count == length) {
03811         if (column->null)
03812             cpl_free(column->null);
03813         column->null = NULL;
03814         column->nullcount = 0;
03815     }
03816 
03817     if (column->nullcount == 0)
03818         return 0;
03819 
03820     if (!column->null)
03821         column->null = cpl_malloc(length * sizeof(xxx_column_flag));
03822 
03823     if (column->nullcount == length) {
03824         while (length--)
03825             column->null[length] = 1;
03826         memset(column->null + start, 0, count * sizeof(xxx_column_flag));
03827         column->nullcount -= count;
03828     }
03829     else {
03830         while (count--) {
03831             if (column->null[start] == 1) {
03832                 column->null[start] = 0;
03833                 column->nullcount--;
03834             }
03835             start++;
03836         }
03837     }
03838 
03839     if (column->nullcount == 0) {
03840         if (column->null)
03841             cpl_free(column->null);
03842         column->null = NULL;
03843     }
03844 
03845     return 0;
03846 
03847 }
03848 
03849 
03850 void xxx_column_dump_structure(xxx_column *column)
03851 {
03852 
03853     const char *name   = xxx_column_get_name(column);
03854     const char *unit   = xxx_column_get_unit(column);
03855     const char *format = xxx_column_get_format(column);
03856     cpl_type    type   = xxx_column_get_type(column);
03857     int         length = xxx_column_get_size(column);
03858 
03859 
03860     if (column) {
03861 
03862         printf("Column name   : ");
03863 
03864         if (name)
03865             printf("\"%s\"\n", name);
03866         else
03867             printf("NONE\n");
03868 
03869         printf("Column unit   : ");
03870 
03871         if (unit)
03872             printf("\"%s\"\n", unit);
03873         else
03874             printf("NONE\n");
03875 
03876         printf("Column format : ");
03877 
03878         if (format)
03879             printf("\"%s\"\n", format);
03880         else
03881             printf("NONE\n");
03882 
03883         printf("Column type   : ");
03884 
03885         switch (type) {
03886         case CPL_TYPE_INT:
03887             printf("int\n");
03888             break;
03889         case CPL_TYPE_FLOAT:
03890             printf("float\n");
03891             break;
03892         case CPL_TYPE_DOUBLE:
03893             printf("double\n");
03894             break;
03895         case CPL_TYPE_STRING:
03896             printf("string\n");
03897             break;
03898         default:
03899             printf("UNDEFINED\n");
03900         }
03901 
03902         printf("Column length : %d\n", length);
03903 
03904         printf("Column nulls  : %d\n", xxx_column_count_invalid(column));
03905         printf("                (the NULL column %sexists)\n", 
03906                       column->null ? "" : "does not ");
03907 
03908     }
03909     else {
03910         printf("Column is NULL\n");
03911         cpl_error_reset();
03912     }
03913         
03914 }
03915 
03916 
03917 void xxx_column_dump(xxx_column *column, int start, int count)
03918 {
03919 
03920     cpl_type type   = xxx_column_get_type(column);
03921     int      length = xxx_column_get_size(column);
03922     int      nulls  = xxx_column_count_invalid(column);
03923     int      i      = start;
03924 
03925 
03926     if (column) {
03927         if (start < length) {
03928 
03929             if (count > length - start)
03930                 count = length - start;
03931 
03932             switch (type) {
03933             case CPL_TYPE_INT:
03934                 if (nulls == 0) {
03935                     while (count--) {
03936                         printf("%d %d\n", i, column->values->i[i]);
03937                         i++;
03938                     }
03939                 }
03940                 else if (nulls == length) {
03941                     while (count--) {
03942                         printf("%d %d NULL\n", i, column->values->i[i]);
03943                         i++;
03944                     }
03945                 }
03946                 else {
03947                     while (count--) {
03948                         printf("%d %d %d\n", i, 
03949                         column->values->i[i], column->null[i]);
03950                         i++;
03951                     }
03952                 }
03953                 break;
03954             case CPL_TYPE_FLOAT:
03955                 if (nulls == 0) {
03956                     while (count--) {
03957                         printf("%d %f\n", i, column->values->f[i]);
03958                         i++;
03959                     }
03960                 }
03961                 else if (nulls == length) {
03962                     while (count--) {
03963                         printf("%d %f NULL\n", i, column->values->f[i]);
03964                         i++;
03965                     }
03966                 }
03967                 else {
03968                     while (count--) {
03969                         printf("%d %f %d\n", i, 
03970                         column->values->f[i], column->null[i]);
03971                         i++;
03972                     } 
03973                 } 
03974                 break;
03975             case CPL_TYPE_DOUBLE:
03976                 if (nulls == 0) {
03977                     while (count--) {
03978                         printf("%d %f\n", i, column->values->d[i]);
03979                         i++;
03980                     }
03981                 }
03982                 else if (nulls == length) {
03983                     while (count--) {
03984                         printf("%d %f NULL\n", i, column->values->d[i]);
03985                         i++;
03986                     }
03987                 }
03988                 else {
03989                     while (count--) {
03990                         printf("%d %f %d\n", i, 
03991                         column->values->d[i], column->null[i]);
03992                         i++;
03993                     } 
03994                 } 
03995                 break;
03996             case CPL_TYPE_STRING:
03997                 while (count--) {
03998                     printf("%d %s\n", i, 
03999                     column->values->s[i] ? column->values->s[i] : "NULL");
04000                     i++;
04001                 } 
04002                 break;
04003             default:
04004                 break;
04005             }
04006         }
04007     }
04008     else {
04009         printf("Column is NULL\n");
04010         cpl_error_reset();
04011     }
04012     
04013 }
04014 
04015 
04016 /*
04017  * @brief
04018  *   Create a new empty column (private).
04019  *
04020  * @param type    Column type.
04021  *
04022  * @return Pointer to the new column, or @c NULL.
04023  *
04024  * This private function allocates memory for a column, its type is 
04025  * assigned, and the container of column values is initialized together 
04026  * with all the other column properties.
04027  */
04028 
04029 static xxx_column *xxx_column_new(cpl_type type)
04030 {
04031 
04032     xxx_column *column = cpl_calloc(1, sizeof(xxx_column));
04033 
04034 
04035     column->values     = xxx_column_values_new();
04036     column->name       = NULL;
04037     column->unit       = NULL;
04038     column->format     = NULL;
04039     column->length     = 0;
04040     column->depth      = 0;
04041     column->type       = type;
04042     column->null       = NULL;
04043     column->nullcount  = 0;
04044     column->dimensions = NULL;
04045 
04046     return column;
04047 
04048 }
04049 
04050 
04051 /* 
04052  * @brief
04053  *   Create a new @em integer column.
04054  *
04055  * @param length    Number of elements in column.
04056  *
04057  * @return Pointer to the new column, or @c NULL in case of error.
04058  *
04059  * The function allocates memory for a column, its type is assigned,
04060  * and its number of elements is allocated. All column elements are 
04061  * flagged as invalid. If a negative length is specified, an error 
04062  * @c CPL_ERROR_ILLEGAL_INPUT is set. Zero length columns are allowed.
04063  */
04064 
04065 xxx_column *xxx_column_new_int(int length)
04066 {
04067 
04068     const char *fid = "xxx_column_new_int";
04069     xxx_column  *column;
04070 
04071 
04072     if (length < 0) {
04073         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04074         return NULL;
04075     }
04076 
04077     column = xxx_column_new(CPL_TYPE_INT);
04078 
04079     if (length)
04080         column->values->i = (int *)cpl_malloc(length * sizeof(int));
04081     else
04082         column->values->i = NULL;
04083 
04084     column->format    = cpl_strdup(INT_FORM);
04085     column->length    = length;
04086     column->nullcount = length;
04087 
04088     return column;
04089 
04090 }
04091 
04092 
04093 /* 
04094  * @brief
04095  *   Create a new @em float column.
04096  *
04097  * @param length    Number of elements in column.
04098  *
04099  * @return Pointer to the new column, or @c NULL in case of error.
04100  *
04101  * See documentation of @c xxx_column_new_int().
04102  */
04103 
04104 xxx_column *xxx_column_new_float(int length)
04105 {
04106 
04107     const char *fid = "xxx_column_new_float";
04108     xxx_column  *column;
04109 
04110 
04111     if (length < 0) {
04112         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04113         return NULL;
04114     }
04115 
04116     column = xxx_column_new(CPL_TYPE_FLOAT);
04117 
04118     if (length)
04119         column->values->f = (float *)cpl_malloc(length * sizeof(float));
04120     else
04121         column->values->f = NULL;
04122 
04123     column->format    = cpl_strdup(FLOAT_FORM);
04124     column->length    = length;
04125     column->nullcount = length;
04126 
04127     return column;
04128 
04129 }
04130 
04131 
04132 /* 
04133  * @brief
04134  *   Create a new @em double column.
04135  *
04136  * @param length    Number of elements in column.
04137  *
04138  * @return Pointer to the new column, or @c NULL in case of error.
04139  *
04140  * See documentation of @c xxx_column_new_int().
04141  */
04142 
04143 xxx_column *xxx_column_new_double(int length)
04144 {
04145 
04146     const char *fid = "xxx_column_new_double";
04147     xxx_column  *column;
04148 
04149 
04150     if (length < 0) {
04151         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04152         return NULL;
04153     }
04154 
04155     column = xxx_column_new(CPL_TYPE_DOUBLE);
04156 
04157     if (length)
04158         column->values->d = (double *)cpl_malloc(length * sizeof(double));
04159     else
04160         column->values->d = NULL;
04161 
04162     column->format    = cpl_strdup(DOUBLE_FORM);
04163     column->length    = length;
04164     column->nullcount = length;
04165 
04166     return column;
04167 
04168 }
04169 
04170 
04171 /* 
04172  * @brief
04173  *   Create a new string column.
04174  *
04175  * @param length    Number of elements in column.
04176  *
04177  * @return Pointer to the new column, or @c NULL in case of error.
04178  *
04179  * The function allocates memory for a column of pointers to @em char,
04180  * all initialized to @c NULL pointers. No memory is allocated for the 
04181  * single column elements. If a negative length is specified, an error 
04182  * @c CPL_ERROR_ILLEGAL_INPUT is set. Zero length columns are allowed. 
04183  * No memory is allocated for the single column elements.
04184  */
04185 
04186 xxx_column *xxx_column_new_string(int length)
04187 {
04188 
04189     const char *fid = "xxx_column_new_string";
04190     xxx_column  *column;
04191 
04192 
04193     if (length < 0) {
04194         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04195         return NULL;
04196     }
04197 
04198     column = xxx_column_new(CPL_TYPE_STRING);
04199 
04200     if (length)
04201         column->values->s = (char **)cpl_calloc(length, sizeof (char *));
04202     else
04203         column->values->s = NULL;
04204 
04205     column->format = cpl_strdup(STRING_FORM);
04206     column->length = length;
04207 
04208     return column;
04209 
04210 }
04211 
04212 
04213 /*
04214  * @brief
04215  *   Create a new @em integer array column.
04216  *
04217  * @param type      Column type
04218  * @param length    Number of arrays in column.
04219  * @param depth     Number of elements per array in column.
04220  *
04221  * @return Pointer to the new column, or @c NULL in case of error.
04222  *
04223  * The function allocates memory for a column, its type is assigned,
04224  * and its number of elements is allocated. All column elements are
04225  * flagged as invalid. If a negative length is specified, an error
04226  * @c CPL_ERROR_ILLEGAL_INPUT is set. Zero length columns are allowed.
04227  */
04228 
04229 xxx_column *xxx_column_new_array(cpl_type type, int length, int depth)
04230 {
04231 
04232     const char *fid = "xxx_column_new_array";
04233     xxx_column  *column;
04234 
04235 
04236     if (length < 0 || depth < 0) {
04237         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04238         return NULL;
04239     }
04240 
04241     column = xxx_column_new(type | CPL_TYPE_POINTER);
04242 
04243     if (length)
04244         column->values->array = cpl_calloc(length, sizeof (cpl_array *));
04245     else
04246         column->values->array = NULL;
04247 
04248     switch(type) {
04249     case CPL_TYPE_INT: 
04250     case CPL_TYPE_INT | CPL_TYPE_POINTER:
04251         column->format = cpl_strdup(INT_FORM);
04252         break;
04253     case CPL_TYPE_FLOAT:
04254     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
04255         column->format = cpl_strdup(FLOAT_FORM);
04256         break;
04257     case CPL_TYPE_DOUBLE: 
04258     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
04259         column->format = cpl_strdup(DOUBLE_FORM);
04260         break;
04261     case CPL_TYPE_STRING:
04262     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
04263         column->format = cpl_strdup(STRING_FORM);
04264         break;
04265     default:
04266         xxx_column_delete(column);
04267         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
04268         return NULL;
04269     }
04270 
04271     column->length = length;
04272     column->depth = depth;
04273 
04274     return column;
04275 
04276 }
04277 
04278 
04279 /*
04280  * @brief
04281  *   Create a new @em integer column from existing data.
04282  *
04283  * @param data      Existing data buffer.
04284  * @param length    Number of elements in column.
04285  *
04286  * @return Pointer to the new column, or @c NULL in case of error.
04287  *
04288  * This function creates a new @em integer column that will encapsulate 
04289  * the given data. Note that the size of the data array is not checked in
04290  * any way, and that the data values are all considered valid: invalid
04291  * values should be marked using the functions @c xxx_column_set_invalid()
04292  * and @c xxx_column_fill_invalid(). The data array is not copied,
04293  * so it should never be deallocated: to deallocate it, the function
04294  * @c xxx_column_delete() should be called instead. Alternatively, the
04295  * function @c xxx_column_unwrap() might be used, and the data array
04296  * deallocated afterwards. A zero or negative length is illegal, and
04297  * would cause an error @c CPL_ERROR_ILLEGAL_INPUT to be set. An input
04298  * @c NULL pointer would set an error @c CPL_ERROR_NULL_INPUT.
04299  *
04300  * @note
04301  *   Functions that handle columns assume that a column data array
04302  *   is dinamically allocated: with a statically allocated array
04303  *   any function implying memory handling (@c xxx_column_set_size(),
04304  *   @c xxx_column_delete(), etc.) would crash the program. This means
04305  *   that a static array should never be passed to this function if
04306  *   memory handling is planned. In case of a static array, only the
04307  *   @c xxx_column_unwrap() destructor can be used.
04308  */
04309 
04310 xxx_column *xxx_column_wrap_int(int *data, int length)
04311 {
04312 
04313     const char *fid = "xxx_column_wrap_int";
04314     xxx_column  *column;
04315 
04316 
04317     if (data == 0x0) {
04318         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04319         return NULL;
04320     }
04321 
04322     if (length <= 0) {
04323         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04324         return NULL;
04325     }
04326 
04327     column = xxx_column_new(CPL_TYPE_INT);
04328 
04329     column->format    = cpl_strdup(INT_FORM);
04330     column->length    = length;
04331     column->values->i = data;
04332 
04333     return column;
04334 
04335 }
04336 
04337 
04338 /* 
04339  * @brief
04340  *   Create a new @em float column from existing data.
04341  *
04342  * @param data      Existing data buffer.
04343  * @param length    Number of elements in column.
04344  *
04345  * @return Pointer to the new column, or @c NULL in case of error.
04346  *
04347  * See documentation of function @c xxx_column_wrap_int().
04348  */
04349 
04350 xxx_column *xxx_column_wrap_float(float *data, int length)
04351 {
04352 
04353     const char *fid = "xxx_column_wrap_float";
04354     xxx_column  *column;
04355 
04356 
04357     if (data == 0x0) {
04358         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04359         return NULL;
04360     }
04361 
04362     if (length <= 0) {
04363         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04364         return NULL;
04365     }
04366 
04367     column = xxx_column_new(CPL_TYPE_FLOAT);
04368 
04369     column->format    = cpl_strdup(FLOAT_FORM);
04370     column->length    = length;
04371     column->values->f = data;
04372 
04373     return column;
04374 
04375 }
04376 
04377 
04378 /* 
04379  * @brief
04380  *   Create a new @em double column from existing data.
04381  *
04382  * @param data      Existing data buffer.
04383  * @param length    Number of elements in column.
04384  *
04385  * @return Pointer to the new column, or @c NULL in case of error.
04386  *
04387  * See documentation of function @c xxx_column_wrap_int().
04388  */
04389 
04390 xxx_column *xxx_column_wrap_double(double *data, int length)
04391 {
04392 
04393     const char *fid = "xxx_column_wrap_double";
04394     xxx_column  *column;
04395 
04396 
04397     if (data == 0x0) {
04398         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04399         return NULL;
04400     }
04401 
04402     if (length <= 0) {
04403         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04404         return NULL;
04405     }
04406 
04407     column = xxx_column_new(CPL_TYPE_DOUBLE);
04408 
04409     column->format    = cpl_strdup(DOUBLE_FORM);
04410     column->length    = length;
04411     column->values->d = data;
04412 
04413     return column;
04414 
04415 }
04416 
04417 
04418 /* 
04419  * @brief
04420  *   Create a new character string column from existing data.
04421  *
04422  * @param data      Existing data buffer.
04423  * @param length    Number of elements in column.
04424  *
04425  * @return Pointer to the new column, or @c NULL in case of error.
04426  *
04427  * See documentation of function @c xxx_column_wrap_int().
04428  */
04429 
04430 xxx_column *xxx_column_wrap_string(char **data, int length)
04431 {
04432 
04433     const char *fid = "xxx_column_wrap_string";
04434     xxx_column  *column;
04435 
04436 
04437     if (data == 0x0) {
04438         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04439         return NULL;
04440     }
04441 
04442     if (length <= 0) {
04443         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
04444         return NULL;
04445     }
04446 
04447     column = xxx_column_new(CPL_TYPE_STRING);
04448 
04449     column->format    = cpl_strdup(STRING_FORM);
04450     column->length    = length;
04451     column->values->s = data;
04452 
04453     return column;
04454 
04455 }
04456 
04457 
04458 /* 
04459  * @brief
04460  *   Copy array of numerical data to a numerical column.
04461  *
04462  * @param column    Existing column.
04463  * @param data      Existing data buffer.
04464  *
04465  * @return @c CPL_ERROR_NONE on success. If the column is not a numerical 
04466  *   column, a @c CPL_ERROR_INVALID_TYPE is returned. At any @c NULL input
04467  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04468  *
04469  * The input data are copied into the specified column. If the type of the
04470  * accessed column is not double, data values will be truncated according
04471  * to C casting rules. The size of the input array is not checked in any 
04472  * way, and the data values are all considered valid: invalid values 
04473  * should be marked using the functions @c xxx_column_set_invalid() and 
04474  * @c xxx_column_fill_invalid(). If @em N is the length of the column,
04475  * the first @em N values of the input data buffer would be copied to
04476  * the column buffer. If the column had length zero, no values would
04477  * be copied.
04478  */
04479 
04480 cpl_error_code xxx_column_copy_data(xxx_column *column, const double *data)
04481 {
04482 
04483     const char *fid = "xxx_column_copy_data";
04484     int       length = xxx_column_get_size(column);
04485     cpl_type  type   = xxx_column_get_type(column);
04486     int      *idata;
04487     float    *fdata;
04488 
04489 
04490     if (data == 0x0 || column == 0x0)
04491         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04492 
04493     if (length == 0)
04494         return CPL_ERROR_NONE;
04495 
04496 
04497     switch (type) {
04498     case CPL_TYPE_INT:
04499         idata = xxx_column_get_data_int(column);
04500         while (length--)
04501             *idata++ = *data++;
04502         break;
04503     case CPL_TYPE_FLOAT:
04504         fdata = xxx_column_get_data_float(column);
04505         while (length--)
04506             *fdata++ = *data++;
04507         break;
04508     case CPL_TYPE_DOUBLE:
04509         memcpy(column->values->d, data, column->length * sizeof(double));
04510         break;
04511     default:
04512         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
04513     }
04514 
04515     if (column->null)
04516         cpl_free(column->null);
04517     column->null = NULL;
04518     column->nullcount = 0;
04519 
04520     return CPL_ERROR_NONE;
04521 
04522 }
04523 
04524 
04525 /* 
04526  * @brief
04527  *   Copy existing data to an @em integer column.
04528  *
04529  * @param column    Existing column.
04530  * @param data      Existing data buffer.
04531  *
04532  * @return 0 on success. If the input column is not integer, a 
04533  *   @c CPL_ERROR_TYPE_MISMATCH is returned. At any @c NULL input
04534  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04535  *
04536  * The input data are copied into the specified column. The size of the 
04537  * input array is not checked in any way, and the data values are all 
04538  * considered valid: invalid values should be marked using the functions 
04539  * @c xxx_column_set_invalid() and @c xxx_column_fill_invalid(). If @em N 
04540  * is the length of the column, the first @em N values of the input data 
04541  * buffer would be copied to the column buffer. If the column had length 
04542  * zero, no values would be copied.
04543  */
04544 
04545 cpl_error_code xxx_column_copy_data_int(xxx_column *column, const int *data)
04546 {
04547 
04548     const char *fid  = "xxx_column_copy_data_int";
04549     cpl_type     type = xxx_column_get_type(column);
04550 
04551 
04552     if (data == 0x0 || column == 0x0)
04553         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04554 
04555     if (type != CPL_TYPE_INT)
04556         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
04557 
04558     if (column->length == 0)
04559         return CPL_ERROR_NONE;
04560 
04561     memcpy(column->values->i, data, column->length * sizeof(int));
04562 
04563     if (column->null)
04564         cpl_free(column->null);
04565     column->null = NULL;
04566     column->nullcount = 0;
04567 
04568     return CPL_ERROR_NONE;
04569 
04570 }
04571 
04572 
04573 /* 
04574  * @brief
04575  *   Copy existing data to a @em float column.
04576  *
04577  * @param column    Existing column.
04578  * @param data      Existing data buffer.
04579  *
04580  * @return 0 on success.  If the input column is not float, a
04581  *   @c CPL_ERROR_TYPE_MISMATCH is returned. At any @c NULL input
04582  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04583  *
04584  * See documentation of function @c xxx_column_copy_data_int().
04585  */
04586 
04587 cpl_error_code xxx_column_copy_data_float(xxx_column *column, 
04588                                           const float *data)
04589 {
04590 
04591     const char *fid  = "xxx_column_copy_data_float";
04592     cpl_type     type = xxx_column_get_type(column);
04593 
04594 
04595     if (data == 0x0 || column == 0x0)
04596         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04597 
04598     if (type != CPL_TYPE_FLOAT)
04599         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
04600 
04601     if (column->length == 0)
04602         return CPL_ERROR_NONE;
04603 
04604     memcpy(column->values->f, data, column->length * sizeof(float));
04605 
04606     if (column->null)
04607         cpl_free(column->null);
04608     column->null = NULL;
04609     column->nullcount = 0;
04610 
04611     return CPL_ERROR_NONE;
04612 
04613 }
04614 
04615 
04616 /* 
04617  * @brief
04618  *   Copy existing data to a @em double column.
04619  *
04620  * @param column    Existing column.
04621  * @param data      Existing data buffer.
04622  *   
04623  * @return 0 on success. If the input column is not double, a
04624  *   @c CPL_ERROR_TYPE_MISMATCH is returned. At any @c NULL input
04625  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04626  *
04627  * See documentation of function @c xxx_column_copy_data_int().
04628  */
04629 
04630 cpl_error_code xxx_column_copy_data_double(xxx_column *column, 
04631                                            const double *data)
04632 {
04633 
04634     const char *fid  = "xxx_column_copy_data_double";
04635     cpl_type     type = xxx_column_get_type(column); 
04636 
04637 
04638     if (data == 0x0 || column == 0x0)
04639         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04640 
04641     if (type != CPL_TYPE_DOUBLE)
04642         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
04643 
04644     if (column->length == 0)
04645         return CPL_ERROR_NONE;
04646 
04647     memcpy(column->values->d, data, column->length * sizeof(double));
04648 
04649     if (column->null)
04650         cpl_free(column->null);
04651     column->null = NULL;
04652     column->nullcount = 0;
04653 
04654     return CPL_ERROR_NONE;
04655 
04656 }
04657 
04658 
04659 /* 
04660  * @brief
04661  *   Copy existing data to a @em string column.
04662  *
04663  * @param column    Existing column.
04664  * @param data      Existing data buffer.
04665  *   
04666  * @return 0 on success. If the input column is not of type string, a
04667  *   @c CPL_ERROR_TYPE_MISMATCH is returned. At any @c NULL input
04668  *   pointer a @c CPL_ERROR_NULL_INPUT would be returned.
04669  *
04670  * See documentation of function @c xxx_column_copy_data_int().
04671  * 
04672  * The input data are copied into the specified column. The size of the
04673  * input array is not checked in any way. The strings pointed by the input
04674  * buffer are all duplicated, while the strings contained in the column 
04675  * are released before being overwritten. If @em N is the length of the 
04676  * column, the first @em N values of the input data buffer would be copied 
04677  * to the column buffer. If the column had length zero, no values would be 
04678  * copied.
04679  */
04680 
04681 cpl_error_code xxx_column_copy_data_string(xxx_column *column, 
04682                                            const char **data)
04683 {
04684 
04685     const char *fid    = "xxx_column_copy_data_string";
04686     cpl_type     type   = xxx_column_get_type(column); 
04687     int          length = xxx_column_get_size(column);
04688 
04689 
04690     if (data == 0x0 || column == 0x0)
04691         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04692 
04693     if (type != CPL_TYPE_STRING)
04694         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
04695 
04696 
04697     while (length--) {
04698         if (column->values->s[length])
04699             cpl_free(column->values->s[length]);
04700         if (data[length])
04701             column->values->s[length] = cpl_strdup((char *)data[length]);
04702         else
04703             column->values->s[length] = NULL;
04704     }
04705 
04706     return CPL_ERROR_NONE;
04707 
04708 }
04709 
04710 
04711 /* 
04712  * @brief
04713  *   Delete a column.
04714  *
04715  * @param column  Column to be deleted.
04716  *
04717  * @return Nothing.
04718  *
04719  * This function deletes a column. If the input column is @c NULL, 
04720  * nothing is done, and no error is set.
04721  */
04722 
04723 void xxx_column_delete(xxx_column *column)
04724 {
04725 
04726     cpl_type           type;
04727     xxx_column_values *values;
04728     int                length;
04729 
04730 
04731     if (column != NULL) {
04732         type   = xxx_column_get_type(column);
04733         values = xxx_column_get_values(column);
04734         length = xxx_column_get_size(column);
04735 
04736         xxx_column_values_delete(values, length, type);
04737         if (column->name)
04738             cpl_free(column->name);
04739         if (column->unit)
04740             cpl_free(column->unit);
04741         if (column->format)
04742             cpl_free(column->format);
04743         if (column->null)
04744             cpl_free(column->null);
04745         if (column->dimensions)
04746             cpl_array_delete(column->dimensions);
04747         cpl_free(column);
04748     }
04749 
04750 }
04751 
04752 
04753 /* 
04754  * @brief
04755  *   Delete a column, without losing the data.
04756  *
04757  * @param column  Column to be deleted.
04758  *
04759  * @return Pointer to the internal data buffer.
04760  *
04761  * This function deletes a column, but the data buffer is not destroyed.
04762  * Supposedly, the developer knows that the data are static, or the
04763  * developer holds the pointer to the data obtained with the functions
04764  * @c xxx_column_get_data_int(), @c xxx_column_get_data_float(), etc.
04765  * If the input column is @c NULL, nothing is done, and no error is set.
04766  */
04767 
04768 void *xxx_column_unwrap(xxx_column *column)
04769 {
04770  
04771     cpl_type           type;
04772     xxx_column_values *values;
04773     void              *d = NULL;
04774  
04775  
04776     if (column != NULL) {
04777         type = xxx_column_get_type(column);
04778         values = xxx_column_get_values(column);
04779         d = (void *)values->i;
04780         cpl_free(values);
04781         if (column->name)
04782             cpl_free(column->name);
04783         if (column->unit)
04784             cpl_free(column->unit);
04785         if (column->format)
04786             cpl_free(column->format);
04787         if (column->null)
04788             cpl_free(column->null);
04789         if (column->dimensions)
04790             cpl_array_delete(column->dimensions);
04791         cpl_free(column);
04792     }
04793 
04794     return d;
04795 
04796 }
04797 
04798 
04799 /* 
04800  * @brief
04801  *   Delete a string column, without losing the single strings.
04802  *
04803  * @param column  Column to be deleted.
04804  *
04805  * @return Nothing, but if the column is not of string type, a 
04806  * @c CPL_ERROR_INVALID_TYPE is set.
04807  *
04808  * This function deletes a string column, but the single strings pointed
04809  * by the data buffer are not destroyed. Supposedly, the developer knows
04810  * that the strings are static, or the developer holds the pointers to the
04811  * strings somewhere else. If the input column is @c NULL, or the input
04812  * column is not a string column, nothing is done.
04813  */
04814 
04815 void xxx_column_delete_but_strings(xxx_column *column)
04816 {
04817 
04818     cpl_type           type;
04819     xxx_column_values *values;
04820 
04821 
04822     if (column == NULL)
04823         return;
04824 
04825     type = xxx_column_get_type(column);
04826 
04827     if (type == CPL_TYPE_STRING) {
04828         values = xxx_column_get_values(column);
04829         if (values->s)
04830             cpl_free(values->s);
04831         if (values)
04832             cpl_free(values);
04833         if (column->name)
04834             cpl_free(column->name);
04835         if (column->unit)
04836             cpl_free(column->unit);
04837         if (column->format)
04838             cpl_free(column->format);
04839         if (column->null)
04840             cpl_free(column->null);
04841         cpl_free(column);
04842     }
04843     else
04844         cpl_error_set("xxx_column_delete_but_strings", CPL_ERROR_INVALID_TYPE);
04845 
04846 }
04847 
04848 
04849 /*
04850  * @brief
04851  *   Delete an array column, without losing the single arrays.
04852  *
04853  * @param column  Column to be deleted.
04854  *
04855  * @return Nothing, but if the column is not of array type, a
04856  * @c CPL_ERROR_INVALID_TYPE is set.
04857  *   
04858  * This function deletes an array column, but the single arrays pointed
04859  * by the data buffer are not destroyed. Supposedly, the developer knows
04860  * that the arrays are static, or the developer holds the pointers to the
04861  * arrays somewhere else. If the input column is @c NULL, or the input
04862  * column is not an array column, nothing is done.
04863  */
04864 
04865 void xxx_column_delete_but_arrays(xxx_column *column)
04866 {
04867 
04868     cpl_type           type;
04869     xxx_column_values *values;
04870 
04871 
04872     if (column == NULL)
04873         return;
04874 
04875     type = xxx_column_get_type(column);
04876 
04877     if (type & CPL_TYPE_POINTER) {
04878         values = xxx_column_get_values(column);
04879         if (values->array)
04880             cpl_free(values->array);
04881         if (values)
04882             cpl_free(values);
04883         if (column->name)
04884             cpl_free(column->name);
04885         if (column->unit)
04886             cpl_free(column->unit);
04887         if (column->format)
04888             cpl_free(column->format);
04889         if (column->null)
04890             cpl_free(column->null);
04891         if (column->dimensions)
04892             cpl_array_delete(column->dimensions);
04893         cpl_free(column);
04894     }
04895     else
04896         cpl_error_set("xxx_column_delete_but_arrays", CPL_ERROR_INVALID_TYPE);
04897 
04898 }
04899 
04900 
04901 /* 
04902  * @brief
04903  *   Give a new name to a column.
04904  *
04905  * @param column  Column to be named.
04906  * @param name    New column name.
04907  *
04908  * @return @c CPL_ERROR_NONE on success. If the input column is @c NULL,
04909  *   a @c CPL_ERROR_NULL_INPUT is returned.
04910  *
04911  * The input name is duplicated before being used as the column name. 
04912  * If the new name is a @c NULL pointer the column will be nameless.
04913  */
04914 
04915 cpl_error_code xxx_column_set_name(xxx_column *column, const char *name)
04916 {
04917 
04918     const char *fid = "xxx_column_set_name";
04919 
04920 
04921     if (column == 0x0)
04922         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
04923 
04924     if (column->name)
04925         cpl_free(column->name);
04926 
04927     if (name)
04928         column->name = cpl_strdup((char *)name);
04929     else
04930         column->name = NULL;
04931 
04932     return CPL_ERROR_NONE;
04933 
04934 }
04935 
04936 
04937 /* 
04938  * @brief
04939  *   Get the name of a column.
04940  *
04941  * @param column  Column to get the name from.
04942  *
04943  * @return Name of column, or @em NULL if the column is nameless, or 
04944  *   if the input column is a @c NULL pointer. In the latter case, a 
04945  *   @c CPL_ERROR_NULL_INPUT is set.
04946  *
04947  * Return the name of a column, if present. Note that the returned 
04948  * string is a pointer to the column name, not its copy. Its manipulation
04949  * will directly affect the column name, while changing the column name
04950  * using @c xxx_column_set_name() will turn it into garbage. Therefore,
04951  * if a real copy of a column name is required, this function should be
04952  * called as an argument of the function @c cpl_strdup(). If the input column 
04953  * has no name, a @c NULL is returned.
04954  */
04955 
04956 const char *xxx_column_get_name(xxx_column *column)
04957 {
04958 
04959     if (column)
04960         return column->name;
04961 
04962     cpl_error_set("xxx_column_get_name", CPL_ERROR_NULL_INPUT);
04963 
04964     return NULL;
04965 
04966 }
04967 
04968 
04969 /* 
04970  * @brief
04971  *   Give a new unit to a column.
04972  * 
04973  * @param column  Column to access.
04974  * @param unit    New column unit.
04975  *
04976  * @return 0 on success. Currently this function always succeeds.
04977  * 
04978  * The input unit is duplicated before being used as the column unit.
04979  * If the new unit is a @c NULL pointer the column will be unitless. 
04980  * The unit string associated to a column has no effect on any operation 
04981  * performed on columns, and it must be considered just an optional 
04982  * description of the content of a column.
04983  */ 
04984 
04985 cpl_error_code xxx_column_set_unit(xxx_column *column, const char *unit)
04986 {
04987 
04988     if (column == 0x0)
04989         return cpl_error_set("xxx_column_set_unit", CPL_ERROR_NULL_INPUT);
04990 
04991     if (column->unit)
04992         cpl_free(column->unit);
04993 
04994     if (unit)
04995         column->unit = cpl_strdup((char *)unit);
04996     else
04997         column->unit = NULL;
04998 
04999     return CPL_ERROR_NONE;
05000 
05001 }
05002 
05003 
05004 /* 
05005  * @brief
05006  *   Get the unit of a column.
05007  *
05008  * @param column  Column to get the unit from.
05009  *
05010  * @return Unit of column, or @c NULL if the column is unitless, or if the
05011  * input column is a @c NULL. In the latter case, a @c CPL_ERROR_NULL_INPUT is
05012  * set.
05013  *
05014  * Return the unit of a column, if present. Note that the returned
05015  * string is a pointer to the column unit, not its copy. Its manipulation
05016  * will directly affect the column unit, while changing the column unit
05017  * using @c xxx_column_set_unit() will turn it into garbage. Therefore,
05018  * if a real copy of a column unit is required, this function should be
05019  * called as an argument of the function @c cpl_strdup(). If the input column
05020  * has no unit, a @c NULL is returned.
05021  */
05022 
05023 const char *xxx_column_get_unit(xxx_column *column)
05024 {
05025 
05026     if (column)
05027         return column->unit;
05028 
05029     cpl_error_set("xxx_column_get_unit", CPL_ERROR_NULL_INPUT);
05030 
05031     return NULL;
05032 
05033 }
05034 
05035 
05036 /* 
05037  * @brief
05038  *   Give a new format to a column.
05039  *
05040  * @param column  Column to access.
05041  * @param format  New column format.
05042  *
05043  * @return 0 on success. Currently this function always succeeds.
05044  *
05045  * The input format is duplicated before being used as the column format.
05046  * If a @c NULL @em format is given, "%s" will be used if the column is
05047  * of type string, "% 1.5e" if the column is of type float or double, and 
05048  * "% 7d" if it is of type integer. The format string associated to a column 
05049  * has no effect on any operation performed on columns, and it is used
05050  * just while printing a column. The given format string must conform to
05051  * the legal standard C formats.
05052  */
05053 
05054 cpl_error_code xxx_column_set_format(xxx_column *column, const char *format)
05055 {
05056 
05057     const char *fid = "xxx_column_set_format";
05058     cpl_type type;
05059 
05060 
05061     if (column == 0x0)
05062         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05063 
05064     type = xxx_column_get_type(column);
05065 
05066     if (column->format)
05067         cpl_free(column->format);
05068 
05069     if (format)
05070         column->format = cpl_strdup((char *)format);
05071     else
05072         switch (type) {
05073         case CPL_TYPE_INT:
05074         case CPL_TYPE_INT | CPL_TYPE_POINTER:
05075             column->format = cpl_strdup(INT_FORM);
05076             break;
05077         case CPL_TYPE_FLOAT:
05078         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
05079             column->format = cpl_strdup(FLOAT_FORM);
05080             break;
05081         case CPL_TYPE_DOUBLE:
05082         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
05083             column->format = cpl_strdup(DOUBLE_FORM);
05084             break;
05085         case CPL_TYPE_STRING:
05086         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
05087             column->format = cpl_strdup(STRING_FORM);
05088             break;
05089         default:
05090             return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
05091         }
05092 
05093     return CPL_ERROR_NONE;
05094     
05095 }
05096 
05097 
05098 /*  
05099  * @brief
05100  *   Get the format of a column.
05101  *  
05102  * @param column  Column to get the format from.
05103  *
05104  * @return Column format, or @c NULL. The latter case can occur only if a
05105  *   @c NULL column is passed to the function, and a @c CPL_ERROR_NULL_INPUT 
05106  *   is set.
05107  *
05108  * Return the format string of a column. Note that the returned string 
05109  * is a pointer to the column format, not its copy. Its manipulation
05110  * will directly affect the column format, while changing the column format
05111  * using @c xxx_column_set_format() will turn it into garbage. Therefore,
05112  * if a real copy of a column format is required, this function should be
05113  * called as an argument of the function @c cpl_strdup(). The function accepts 
05114  * also a @c NULL input column.
05115  */
05116 
05117 const char *xxx_column_get_format(xxx_column *column)
05118 {
05119 
05120     if (column)
05121         return column->format;
05122 
05123     cpl_error_set("xxx_column_get_format", CPL_ERROR_NULL_INPUT);
05124 
05125     return NULL;
05126 
05127 }
05128 /*
05129  * @brief
05130  *   Get the depth of a column.
05131  *
05132  * @param column  Column to get the depth from.
05133  *
05134  * @return Depth of column, or zero. The latter case can occur either
05135  * with a non-array column, or if a NULL column is passed to this
05136  * function, but in the latter case a @c CPL_ERROR_NULL_INPUT is set.
05137  *
05138  * If the column is @em NULL, zero is returned.
05139  */
05140 
05141 int xxx_column_get_depth(xxx_column *column)
05142 {
05143 
05144     if (column)
05145         return column->depth;
05146 
05147     cpl_error_set("xxx_column_get_depth", CPL_ERROR_NULL_INPUT);
05148 
05149     return 0;
05150 
05151 }
05152 
05153 
05154 /*
05155  * @brief
05156  *   Get the number of dimensions of a column.
05157  *
05158  * @param column  Column to get the number of dimensions from.
05159  *
05160  * @return Number of dimensions of column, or zero. The latter case can 
05161  * occur if a NULL column is passed to this function, and in that case
05162  * @c CPL_ERROR_NULL_INPUT is also set. If a column is not an array
05163  * column, or if it has no dimensions, 1 is returned.
05164  *
05165  * If the column is @em NULL, zero is returned. 
05166  */
05167 
05168 int xxx_column_get_dimensions(xxx_column *column)
05169 {
05170 
05171     if (column) {
05172         if (xxx_column_get_type(column) & CPL_TYPE_POINTER)
05173             if (column->dimensions)
05174                 return cpl_array_get_size(column->dimensions);
05175         return 1;
05176     }
05177 
05178     cpl_error_set("xxx_column_get_dimensions", CPL_ERROR_NULL_INPUT);
05179 
05180     return 0;
05181 
05182 }
05183 
05184 
05185 /*
05186  * @brief
05187  *   Set the dimensions of a column.
05188  *
05189  * @param column      Column to be assigned the dimensions.
05190  * @param dimensions  Integer array containing the sizes of the column
05191  *
05192  * @return The column must be of type array, and all of its elements
05193  * must be valid, or a @c CPL_ERROR_ILLEGAL_INPUT is returned. 
05194  * A @c CPL_ERROR_INCOMPATIBLE_INPUT is returned if the specified 
05195  * sizes are incompatible with the total number of elements in the column.
05196  * If the input array @em dimensions is not an integer array a
05197  * @c CPL_ERROR_TYPE_MISMATCH is returned. If this array has size less 
05198  * than 2, nothing is done and no error is returned. If a NULL column is 
05199  * passed to this function, a @c CPL_ERROR_NULL_INPUT is set. 
05200  *
05201  * Set the dimensions of a column. 
05202  */
05203 
05204 cpl_error_code xxx_column_set_dimensions(xxx_column *column, 
05205                                          cpl_array *dimensions)
05206 {
05207     const char *fid = "xxx_column_set_dimensions";
05208 
05209     cpl_type type;
05210     int      ndim;
05211     int      size = 1;
05212 
05213     if (column == NULL || dimensions == NULL)
05214         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05215 
05216     type = xxx_column_get_type(column);
05217 
05218     if (type & CPL_TYPE_POINTER) {
05219         type = cpl_array_get_type(dimensions);
05220 
05221         if (!(type & CPL_TYPE_INT))
05222             return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05223 
05224         ndim = cpl_array_get_size(dimensions);
05225 
05226         if (ndim < 2)
05227             return CPL_ERROR_NONE;
05228 
05229         if (cpl_array_has_invalid(dimensions))
05230             return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
05231 
05232         while (ndim--)
05233             size *= cpl_array_get(dimensions, ndim, NULL);
05234 
05235         if (size != column->depth)
05236             return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
05237 
05238         if (column->dimensions)
05239             cpl_array_delete(column->dimensions);
05240 
05241         column->dimensions = cpl_array_duplicate(dimensions);
05242     }
05243     else
05244         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
05245 
05246     return CPL_ERROR_NONE;
05247 
05248 }
05249 
05250 
05251 /*
05252  * @brief
05253  *   Get size of one dimension of the column.
05254  *
05255  * @param column  Column.
05256  * @param indx    Indicate dimension to query (0 = x, 1 = y, 2 = z, etc.)
05257  *
05258  * @return Size of queried dimension of the column, or zero in case of error.
05259  *
05260  * If the column is not of type array, a @c CPL_ERROR_UNSUPPORTED_MODE is set.
05261  * A @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set if the specified @em indx
05262  * is not compatible with the column dimensions. If the column has no
05263  * dimensions, 1 is returned.
05264  *
05265  * Get size of one dimension of the column.
05266  */
05267 
05268 int xxx_column_get_dimension(xxx_column *column, int indx)
05269 {
05270     const char *fid = "xxx_column_get_dimension";
05271     
05272     cpl_type type;
05273     int      ndim;
05274     
05275 
05276     if (column == NULL) {
05277         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05278         return 0;
05279     }
05280 
05281     if (indx < 0) {
05282         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
05283         return 0;
05284     }
05285 
05286     type = xxx_column_get_type(column);
05287 
05288     if (type & CPL_TYPE_POINTER) {
05289 
05290         if (column->dimensions)
05291             ndim = cpl_array_get_size(column->dimensions);
05292         else
05293             ndim = 1;
05294 
05295         if (indx >= ndim) {
05296             cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
05297             return 0;
05298         }
05299 
05300         if (ndim > 1)
05301             return cpl_array_get(column->dimensions, indx, NULL);
05302         else
05303             return column->depth;
05304 
05305     }
05306 
05307     return cpl_error_set(fid, CPL_ERROR_UNSUPPORTED_MODE);
05308 
05309 
05310 
05311 }
05312 
05313 
05314 /* 
05315  * @brief
05316  *   Check if a column element is invalid.
05317  *
05318  * @param column  Column to inquire.
05319  * @param indx    Column element to inquire.
05320  *
05321  * @return 1 if the column element is invalid, 0 if not, or in case
05322  *   of error.
05323  *
05324  * Check if a column element is invalid. Column elements are counted 
05325  * starting from zero. An out of range index would cause an error 
05326  * @c CPL_ERROR_ACCESS_OUT_OF_RANGE to be set. If the input column
05327  * has zero length, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE would always be
05328  * set. If the input column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT 
05329  * is set.
05330  */
05331 
05332 int xxx_column_is_invalid(xxx_column *column, int indx)
05333 {
05334 
05335     const char  *fid    = "xxx_column_is_invalid";
05336     cpl_type     type   = xxx_column_get_type(column);
05337     int          length = xxx_column_get_size(column);
05338 
05339 
05340     if (column == 0x0) {
05341         cpl_error_set_where(fid);
05342         return 0;
05343     }
05344 
05345     if (indx < 0 || indx >= length) {
05346         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
05347         return 0;
05348     }
05349 
05350     if (type == CPL_TYPE_STRING)
05351         return (column->values->s[indx] == NULL);
05352     if (type & CPL_TYPE_POINTER)
05353         return (column->values->array[indx] == NULL);
05354     if (column->nullcount == 0)
05355         return 0;
05356     if (column->nullcount == length)
05357         return 1;
05358 
05359     return column->null[indx];
05360 
05361 }
05362 
05363 
05364 /* 
05365  * @brief
05366  *   Check if a column contains at least one invalid element.
05367  *
05368  * @param column  Column to inquire.
05369  *
05370  * @return 1 if the column contains at least one invalid element, 0 if not,
05371  *   -1 in case of error.
05372  *
05373  * Check if there are invalid elements in a column. This function does
05374  * not report the presence of invalid elements within an array type
05375  * column, but in that case reports just if an array is allocated or
05376  * not (just like is done for strings). If the input column is a
05377  * @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is set.
05378  */
05379 
05380 int xxx_column_has_invalid(xxx_column *column)
05381 {
05382 
05383     cpl_type type   = xxx_column_get_type(column);
05384     int      length = xxx_column_get_size(column);
05385 
05386 
05387     if (column == 0x0) {
05388         cpl_error_set_where("xxx_column_has_invalid");
05389         return -1;
05390     }
05391 
05392     if (type == CPL_TYPE_STRING) {
05393         while (length--)
05394             if (column->values->s[length] == NULL)
05395                 return 1;
05396         return 0;
05397     }
05398     if (type & CPL_TYPE_POINTER) {
05399         while (length--)
05400             if (column->values->array[length] == NULL)
05401                 return 1;
05402         return 0;
05403     }
05404 
05405     return (column->nullcount > 0 ? 1 : 0);
05406 
05407 }
05408 
05409 
05410 /* 
05411  * @brief
05412  *   Check if a column contains at least one valid value.
05413  *
05414  * @param column  Column to inquire.
05415  *
05416  * @return 1 if the column contains at least one valid value, 0 if not
05417  *   -1 in case of error.
05418  *
05419  * Check if there are valid values in a column. If the input column is a
05420  * @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is set.
05421  */
05422 
05423 int xxx_column_has_valid(xxx_column *column)
05424 {
05425 
05426     const char *fid    = "xxx_column_has_valid";
05427     cpl_type     type   = xxx_column_get_type(column);
05428     int          length = xxx_column_get_size(column);
05429 
05430 
05431     if (column == 0x0) {
05432         cpl_error_set_where(fid);
05433         return -1;
05434     }
05435 
05436     if (type == CPL_TYPE_STRING) {
05437 
05438         while (length--)
05439             if (column->values->s[length])
05440                 return 1;
05441         return 0;
05442 
05443     }
05444     if (type & CPL_TYPE_POINTER) {
05445 
05446         while (length--)
05447             if (column->values->array[length])
05448                 return 1;
05449         return 0;
05450 
05451     }
05452 
05453     return (column->nullcount < length ? 1 : 0);
05454 
05455 }
05456 
05457 
05458 /* 
05459  * @brief
05460  *   Count number of invalid elements in a column.
05461  *
05462  * @param column  Column to inquire.
05463  *
05464  * @return Number of invalid elements in a column. -1 is always returned
05465  *   in case of error.
05466  *
05467  * Count number of invalid elements in a column. This function does
05468  * not report the presence of invalid elements within an array type
05469  * column, but in that case reports just if an array is allocated or
05470  * not (just like is done for strings). If the column itself is 
05471  * a @c NULL pointer, an error @c CPL_ERROR_NULL_INPUT is set.
05472  */
05473 
05474 int xxx_column_count_invalid(xxx_column *column)
05475 {
05476 
05477     cpl_type    type   = xxx_column_get_type(column);
05478     int         length = xxx_column_get_size(column);
05479     char      **p;
05480     cpl_array **a;
05481 
05482 
05483     if (column == 0x0) {
05484         cpl_error_set_where("xxx_column_count_invalid");
05485         return -1;
05486     }
05487 
05488     if (type == CPL_TYPE_STRING) {
05489 
05490         p = column->values->s;
05491 
05492         column->nullcount = 0;
05493         while (length--)
05494             if (*p++ == NULL)
05495                 column->nullcount++;
05496 
05497     }
05498 
05499     if (type & CPL_TYPE_POINTER) {
05500 
05501         a = column->values->array;
05502 
05503         column->nullcount = 0;
05504         while (length--)
05505             if (*a++ == NULL)
05506                 column->nullcount++;
05507  
05508     }
05509 
05510     return column->nullcount;
05511 
05512 }
05513 
05514 
05515 /*
05516  * @brief
05517  *   Get a pointer to @c integer column data. 
05518  *
05519  * @param column  Column to get the data from.
05520  *
05521  * @return Pointer to @c integer column data. If @em column contains no
05522  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05523  *   a @c NULL is returned, and an error is set.
05524  *
05525  * If the column is not of type @c CPL_TYPE_INT, a
05526  * @c CPL_ERROR_TYPE_MISMATCH is set.
05527  *
05528  * @note
05529  *   Use at your own risk: direct manipulation of column data rules 
05530  *   out any check performed by the column object interface, and may 
05531  *   introduce inconsistencies between the column information maintained 
05532  *   internally and the actual column data.
05533  */
05534 
05535 int *xxx_column_get_data_int(xxx_column *column)
05536 {
05537 
05538     const char *fid  = "xxx_column_get_data_int";
05539     cpl_type     type = xxx_column_get_type(column);
05540 
05541 
05542     if (column == 0x0) {
05543         cpl_error_set_where(fid);
05544         return NULL;
05545     }
05546 
05547     if (type == CPL_TYPE_INT)
05548         return column->values->i;
05549 
05550     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05551 
05552     return NULL;
05553 
05554 }
05555 
05556 
05557 /* 
05558  * @brief
05559  *   Get a pointer to @em float column data. 
05560  *
05561  * @param column  Column to get the data from.
05562  *
05563  * @return Pointer to @em float column data. If @em column contains no
05564  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05565  *   a @c NULL is returned, and an error is set.
05566  * 
05567  * If the column is not of type @c CPL_TYPE_FLOAT, a 
05568  * @c CPL_ERROR_TYPE_MISMATCH is set.
05569  *
05570  * See documentation of function xxx_column_get_data_int().
05571  */
05572 
05573 float *xxx_column_get_data_float(xxx_column *column)
05574 {
05575 
05576     const char *fid  = "xxx_column_get_data_float";
05577     cpl_type     type = xxx_column_get_type(column);
05578 
05579 
05580     if (column == 0x0) {
05581         cpl_error_set_where(fid);
05582         return NULL;
05583     }
05584 
05585     if (type == CPL_TYPE_FLOAT)
05586         return column->values->f;
05587 
05588     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05589 
05590     return NULL;
05591 
05592 }
05593 
05594 
05595 /* 
05596  * @brief
05597  *   Get a pointer to @em double column data. 
05598  *
05599  * @param column  Column to get the data from.
05600  *
05601  * @return Pointer to @em double column data. If @em column contains no
05602  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05603  *   a @c NULL is returned, and an error is set. 
05604  *
05605  * If the column is not of type @c CPL_TYPE_DOUBLE, 
05606  * a @c CPL_ERROR_TYPE_MISMATCH is set.
05607  *
05608  * See documentation of function xxx_column_get_data_int().
05609  */
05610 
05611 double *xxx_column_get_data_double(xxx_column *column)
05612 {
05613 
05614     const char *fid  = "xxx_column_get_data_double";
05615     cpl_type     type =  xxx_column_get_type(column);
05616 
05617 
05618     if (column == 0x0) {
05619         cpl_error_set_where(fid);
05620         return NULL;
05621     }
05622 
05623     if (type == CPL_TYPE_DOUBLE)
05624         return column->values->d;
05625 
05626     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05627 
05628     return NULL;
05629 
05630 }
05631 
05632 
05633 /* 
05634  * @brief
05635  *   Get a pointer to string column data. 
05636  *
05637  * @param column  Column to get the data from.
05638  *
05639  * @return Pointer to string column data.  If @em column contains no
05640  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05641  *   a @c NULL is returned, and an error is set. 
05642  *
05643  * If the column is not of type @c CPL_TYPE_STRING, 
05644  * a @c CPL_ERROR_TYPE_MISMATCH is set.
05645  *
05646  * See documentation of function xxx_column_get_data_int().
05647  */
05648 
05649 char **xxx_column_get_data_string(xxx_column *column)
05650 {
05651 
05652     const char *fid  = "xxx_column_get_data_string";
05653     cpl_type     type =  xxx_column_get_type(column);
05654 
05655 
05656     if (column == 0x0) {
05657         cpl_error_set_where(fid);
05658         return NULL;
05659     }
05660 
05661     if (type == CPL_TYPE_STRING)
05662         return column->values->s;
05663 
05664     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05665 
05666     return NULL;
05667 
05668 }
05669 
05670 
05671 /*
05672  * @brief
05673  *   Get a pointer to array column data.
05674  *
05675  * @param column  Column to get the data from.
05676  *
05677  * @return Pointer to array column data.  If @em column contains no
05678  *   data (zero length), a @c NULL is returned. If @em column is a @c NULL,
05679  *   a @c NULL is returned and an error is set.
05680  *
05681  * If the column is not an array type
05682  * a @c CPL_ERROR_TYPE_MISMATCH is set.
05683  *
05684  * See documentation of function xxx_column_get_data_int().
05685  */
05686 
05687 cpl_array **xxx_column_get_data_array(xxx_column *column)
05688 {
05689 
05690     const char *fid  = "xxx_column_get_data_array";
05691     cpl_type     type =  xxx_column_get_type(column);
05692 
05693 
05694     if (column == 0x0) {
05695         cpl_error_set_where(fid);
05696         return NULL;
05697     }
05698 
05699     if (type & CPL_TYPE_POINTER)
05700         return column->values->array;
05701 
05702     cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
05703 
05704     return NULL;
05705 
05706 }
05707 
05708 
05709 /* 
05710  * @brief
05711  *   Get a pointer to a column invalid flags buffer.
05712  *
05713  * @param column  Column from where to get the data.
05714  *
05715  * @return Pointer to the column buffer containing the flagging of the
05716  *   invalid elements, or @c NULL if it is missing.
05717  *
05718  * If all or no column elements are invalid, a @c NULL pointer is returned. 
05719  * A @c NULL is returned also if the column is of type @c CPL_TYPE_STRING 
05720  * or of type array (no buffer marking the invalid elements is present in 
05721  * this case).
05722  *
05723  * @note
05724  *   Use at your own risk: direct manipulation of column data rules out 
05725  *   any check performed by the column object interface, and may introduce 
05726  *   inconsistencies between the column information maintained internally
05727  *   and the actual column data.
05728  */
05729 
05730 xxx_column_flag *xxx_column_get_data_invalid(xxx_column *column)
05731 {
05732 
05733     if (column == 0x0) {
05734         cpl_error_set("xxx_column_get_data_invalid", CPL_ERROR_NULL_INPUT);
05735         return NULL;
05736     }
05737 
05738     return column->null;
05739 
05740 }
05741 
05742 
05743 /* 
05744  * @brief
05745  *   Plug a new invalid flag buffer into a numerical column.
05746  *
05747  * @param column      Column to access.
05748  * @param nulls       Array of null flags.
05749  * @param nullcount   Total number of nulls.
05750  *
05751  * @return CPL_ERROR_NONE on success. If the column type is not
05752  *   numerical, an invalid flag buffer is not used, and an attempt 
05753  *   to plug it in will cause a @c CPL_ERROR_INVALID_TYPE to be 
05754  *   returned. A @c CPL_ERROR_INCOMPATIBLE_INPUT is returned if 
05755  *   an impossible @em nullcount value is passed. If the input 
05756  *   @em nulls buffer does not contains just 1s or 0s, a 
05757  *   @c CPL_ERROR_ILLEGAL_INPUT is returned. A @c CPL_ERROR_NULL_INPUT
05758  *   is returned if a @c NULL column pointer is passed.
05759  *
05760  * This function is used to assign a new set of flags marking invalid
05761  * elements within a column. If a flag buffer already exists, this is 
05762  * deallocated before being replaced by the new one. If @em nullcount 
05763  * is either 0 or equal to the column length, the passed flag buffer 
05764  * is ignored, but the internal buffer is deallocated. If @em nullcount 
05765  * is negative, it will be evaluated internally, or set to zero if no 
05766  * flag buffer was passed. This function cannot be use either for array
05767  * columns or @c CPL_TYPE_STRING columns.
05768  *
05769  * @note
05770  *   Use at your own risk: direct manipulation of column data rules out 
05771  *   any check performed by the column object interface, and may introduce 
05772  *   inconsistencies between the column information maintained internally 
05773  *   and the actual column data.
05774  */
05775 
05776 cpl_error_code xxx_column_set_data_invalid(xxx_column *column, 
05777                              xxx_column_flag *nulls, int nullcount)
05778 {
05779 
05780     const char *fid    = "xxx_column_set_data_invalid";
05781     cpl_type     type   = xxx_column_get_type(column);
05782     int          length = xxx_column_get_size(column);
05783 
05784 
05785     if (column == 0x0)
05786         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05787 
05788     if (type == CPL_TYPE_STRING)
05789         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
05790 
05791     if (type & CPL_TYPE_POINTER)
05792         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
05793 
05794     if (nullcount > length)
05795         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
05796 
05797     if (nulls)
05798         while (length--)
05799             if (nulls[length] != 0)
05800                 if (nulls[length] != 1)
05801                     return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
05802 
05803     length = xxx_column_get_size(column);
05804 
05805     if (nullcount < 0) {
05806 
05807         /*
05808          *  The total number of NULLs must be evaluated internally. If a 
05809          *  null flag buffer was not passed, the total number of NULLs is
05810          *  assumed to be zero.
05811          */
05812 
05813         if (nulls) {
05814             nullcount = 0;
05815             while (length--)
05816                 nullcount += nulls[length];
05817         }
05818         else {
05819             nullcount = 0;
05820         }
05821     }
05822 
05823 
05824     /*
05825      *  If no null buffer was passed, and a wrong null count was specified,
05826      *  return a failure (wrong input).
05827      */
05828 
05829     if (!nulls)
05830         if (nullcount != length && nullcount != 0)
05831             return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
05832 
05833 
05834     /*
05835      *  Replace the old buffer with the new one if necessary.
05836      */
05837 
05838     if (nullcount == length || nullcount == 0)
05839         nulls = NULL;
05840 
05841     if (column->null)
05842         cpl_free(column->null);
05843 
05844     column->null = nulls;
05845     column->nullcount = nullcount;
05846 
05847     return 0;
05848 
05849 }
05850 
05851 
05852 /*
05853  * @brief
05854  *   Reallocate a column of arrays to a new depth.
05855  *
05856  * @param column  Column to be resized.
05857  * @param depth   New depth of column.
05858  *
05859  * @return @c CPL_ERROR_NONE on success. The new column depth must not 
05860  *   be negative, or a @c CPL_ERROR_ILLEGAL_INPUT is returned. The input
05861  *   column pointer should not be @c NULL, or a @c CPL_ERROR_NULL_INPUT
05862  *   is returned.
05863  *
05864  * Reallocate a column of arrays to a new depth. The contents of the
05865  * arrays data buffer will be unchanged up to the lesser of the new and
05866  * old sizes. If the column depth is increased, the new arrays elements
05867  * are flagged as invalid. The pointer to array data may change, therefore
05868  * pointers previously retrieved by calling @c xxx_column_get_data_array(),
05869  * @c xxx_column_get_data_string(), etc. should be discarded). Resizing
05870  * to zero is allowed, and would produce a zero-depth column. In case
05871  * of failure, the old data buffer is left intact. Changing column
05872  * depth implies removing any information about column dimensions.
05873  */
05874 
05875 
05876 /* 
05877  * @brief
05878  *   Reallocate a column to a new number of elements.
05879  *
05880  * @param column      Column to be resized.
05881  * @param new_length  New number of elements in column.
05882  *
05883  * @return @c CPL_ERROR_NONE on success. The new column size must not be
05884  *   negative, or a @c CPL_ERROR_ILLEGAL_INPUT is returned. The input
05885  *   column pointer should not be @c NULL, or a @c CPL_ERROR_NULL_INPUT
05886  *   is returned.
05887  *
05888  * Reallocate a column to a new number of elements. The contents of the 
05889  * column data buffer will be unchanged up to the lesser of the new and 
05890  * old sizes. If the column size is increased, the new column elements 
05891  * are flagged as invalid. The pointer to data may change, therefore 
05892  * pointers previously retrieved by calling @c xxx_column_get_data_int(), 
05893  * @c xxx_column_get_data_string(), etc. should be discarded). Resizing 
05894  * to zero is allowed, and would produce a zero-length column. In case 
05895  * of failure, the old data buffer is left intact.
05896  */
05897 
05898 cpl_error_code xxx_column_set_size(xxx_column *column, int new_length)
05899 {
05900 
05901     const char *fid          = "xxx_column_set_size";
05902     cpl_type     type         = xxx_column_get_type(column);
05903     int          old_length   = xxx_column_get_size(column);
05904     int          element_size = xxx_column_type_size(type);
05905     int          null_size    = old_length * sizeof(xxx_column_flag);
05906     int          new_size     = element_size * new_length;
05907     int          i            = 0;
05908 
05909     xxx_column_flag *np       = NULL;
05910     char           **sp;
05911     cpl_array      **ap;
05912 
05913 
05914     if (column == 0x0)
05915         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
05916 
05917     if (new_length < 0)
05918         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
05919 
05920     if (new_length == old_length)     /* Resizing is unnecessary */
05921         return CPL_ERROR_NONE;
05922 
05923     if (new_length == 0) {            /* Resizing to zero        */
05924 
05925         switch (type) {
05926         case CPL_TYPE_INT | CPL_TYPE_POINTER:
05927         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
05928         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
05929         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
05930 
05931             for (i = 0; i < old_length; i++)
05932                 if (column->values->array[i])
05933                     cpl_array_delete(column->values->array[i]);
05934 
05935             cpl_free((void *)column->values->array);
05936 
05937             break;
05938 
05939         case CPL_TYPE_STRING:
05940 
05941             for (i = 0; i < old_length; i++)
05942                 if (column->values->s[i])
05943                     cpl_free(column->values->s[i]);
05944 
05945         default:
05946 
05947             if (column->values->s)
05948                 cpl_free((void *)column->values->s);
05949 
05950             break;
05951 
05952         }
05953 
05954         column->values->i = NULL;
05955         if (column->null)
05956             cpl_free(column->null);
05957         column->null = NULL;
05958         column->nullcount = 0;
05959         column->length = 0;
05960 
05961         return CPL_ERROR_NONE;
05962     }
05963 
05964     if (old_length == 0) {            /* Resizing from zero      */
05965 
05966         switch (type) {
05967         case CPL_TYPE_INT:
05968             column->values->i = cpl_malloc(new_length * sizeof(int));
05969             break;
05970         case CPL_TYPE_FLOAT:
05971             column->values->f = cpl_malloc(new_length * sizeof(float));
05972             break;
05973         case CPL_TYPE_DOUBLE:
05974             column->values->d = cpl_malloc(new_length * sizeof(double));
05975             break;
05976         case CPL_TYPE_STRING:
05977             column->values->s = cpl_calloc(new_length, sizeof(char *));
05978             break;
05979         case CPL_TYPE_INT | CPL_TYPE_POINTER:
05980         case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
05981         case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
05982         case CPL_TYPE_STRING | CPL_TYPE_POINTER:
05983             column->values->array = cpl_calloc(new_length, sizeof(cpl_array *));
05984             break;
05985         default:
05986             return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
05987         }
05988 
05989         column->length = new_length;
05990 
05991         if (type != CPL_TYPE_STRING && !(type & CPL_TYPE_POINTER))
05992             column->nullcount = new_length;
05993 
05994         return CPL_ERROR_NONE;
05995     }
05996 
05997 
05998     /*
05999      * In the following the generic case is handled
06000      */
06001 
06002     if (column->null) {
06003 
06004         /*
06005          *  If the null flags buffer exists, it should be reallocated 
06006          *  first. 
06007          */
06008 
06009         null_size = new_length * sizeof(xxx_column_flag);
06010         column->null = cpl_realloc((void *)column->null, null_size);
06011 
06012         if (new_length < old_length) {
06013 
06014             /*
06015              *  If the column was shortened, check whether some 
06016              *  NULLs are still present in column. If no NULL is 
06017              *  found, then the null flags buffer can be deallocated.
06018              */
06019 
06020             column->nullcount = 0;
06021             np = column->null;
06022             for (i = 0; i < new_length; i++)
06023                 if (*np++)
06024                     column->nullcount++;
06025 
06026             if (column->nullcount == new_length || 
06027                 column->nullcount == 0) {
06028                 if (column->null)
06029                     cpl_free(column->null);
06030                 column->null = NULL;
06031             }
06032         }
06033         else {
06034 
06035             /*
06036              *  Pad with 1s the extra space (by definition, extra space
06037              *  in the column data buffer is not initialized, therefore
06038              *  it is a NULL value; the case of string columns doesn't 
06039              *  need to be treated, since in that case the null flags 
06040              *  are not used).
06041              */
06042 
06043             np = column->null + old_length;
06044             for (i = old_length; i < new_length; i++)
06045                 *np++ = 1;
06046 
06047             column->nullcount += new_length - old_length;
06048 
06049         }
06050     }
06051     else {
06052 
06053         /*
06054          *  We don't need to take care of string columns here, because
06055          *  they take automatically care of their own NULLs.
06056          */
06057 
06058         if (type != CPL_TYPE_STRING) {
06059 
06060             if (new_length > old_length) {
06061 
06062                 /*
06063                  *  If the null flags buffer doesn't exist, it is 
06064                  *  either because there were no NULLs, or there 
06065                  *  were just NULLs. In the latter case we do not 
06066                  *  need to allocate any new buffer, because the
06067                  *  expansion just added extra NULLs. In the former 
06068                  *  case, we have to allocate a null flags column 
06069                  *  buffer in case the column is expanded, because 
06070                  *  the expanded part contains NULLs:
06071                  */
06072 
06073                 if (column->nullcount == 0) {
06074 
06075                     column->null = cpl_calloc(new_length, 
06076                                               sizeof(xxx_column_flag));
06077 
06078                     np = column->null + old_length;
06079                     for (i = old_length; i < new_length; i++)
06080                         *np++ = 1;
06081 
06082                     column->nullcount = new_length - old_length;
06083                 }
06084                 else                       /* There were just nulls     */
06085                     column->nullcount = new_length;
06086             }
06087             else if (column->nullcount)    /* Column of nulls shortened */
06088                 column->nullcount = new_length;
06089 
06090         }
06091     }
06092 
06093     /*
06094      *  If a column of character strings or of arrays is shortened,
06095      *  we must explicitly free the extra strings.
06096      */
06097 
06098     if (type == CPL_TYPE_STRING)
06099         for (i = new_length; i < old_length; i++)
06100             if (column->values->s[i])
06101                 cpl_free(column->values->s[i]);
06102 
06103     if (type & CPL_TYPE_POINTER)
06104         for (i = new_length; i < old_length; i++)
06105             if (column->values->array[i])
06106                 cpl_array_delete(column->values->array[i]);
06107 
06108     /*
06109      *  Finally, we realloc the column data buffer:
06110      */
06111 
06112     column->values->i = cpl_realloc((void *)column->values->i, new_size);
06113     column->length = new_length;
06114 
06115     /*
06116      *  We don't initialize the extra memory, since it is NULL flagged,
06117      *  with the exception of string and array columns:
06118      */
06119 
06120     if (type == CPL_TYPE_STRING) {
06121         sp = column->values->s + old_length;
06122         for (i = old_length; i < new_length; i++)
06123             *sp++ = 0x0;
06124     }
06125 
06126     if (type & CPL_TYPE_POINTER) {
06127         ap = column->values->array + old_length;
06128         for (i = old_length; i < new_length; i++)
06129             *ap++ = 0x0;
06130     }
06131 
06132     return CPL_ERROR_NONE;
06133 
06134 }
06135 
06136 
06137 /* 
06138  * @brief
06139  *   Read a value from a numerical column.
06140  *
06141  * @param column  Column to be accessed.
06142  * @param indx    Position of element to be read.
06143  * @param null    Flag indicating null values, or error condition.
06144  *
06145  * @return Value read. In case of an invalid column element, or in
06146  *   case of error, 0.0 is always returned. 
06147  *
06148  * Read a value from a numerical column. A @c CPL_ERROR_NULL_INPUT is set in
06149  * case @em column is a @c NULL pointer. A @c CPL_ERROR_INVALID_TYPE is set 
06150  * in case a non-numerical column is accessed. @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06151  * is set if the @em indx is outside the column range. Indexes are 
06152  * counted starting from 0. If the input column has length zero, 
06153  * @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set. The @em null 
06154  * flag is used to indicate whether the accessed column element is 
06155  * valid (0) or invalid (1). The null flag also signals an error 
06156  * condition (-1). The @em null argument can be left to @c NULL.
06157  * This function cannot be used for the access of array elements in
06158  * array columns.
06159  */
06160 
06161 double xxx_column_get(xxx_column *column, int indx, int *null)
06162 {
06163 
06164     const char *fid  = "xxx_column_get";
06165     cpl_type     type = xxx_column_get_type(column);
06166 
06167 
06168     if (null)
06169         *null = -1;
06170 
06171     switch (type) {
06172     case CPL_TYPE_INT:
06173         return (double)xxx_column_get_int(column, indx, null);
06174     case CPL_TYPE_FLOAT:
06175         return (double)xxx_column_get_float(column, indx, null);
06176     case CPL_TYPE_DOUBLE:
06177         return xxx_column_get_double(column, indx, null);
06178     case CPL_TYPE_INT | CPL_TYPE_POINTER:
06179     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
06180     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
06181     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
06182     case CPL_TYPE_STRING:
06183         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
06184         break;
06185     default:
06186         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06187     }
06188 
06189     return 0.0;
06190 
06191 }
06192 
06193 
06194 /* 
06195  * @brief
06196  *   Read a value from an @em integer column.
06197  *
06198  * @param column  Column to be accessed.
06199  * @param indx    Position of element to be read.
06200  * @param null    Flag indicating null values, or error condition.
06201  *
06202  * @return Integer value read. In case of an invalid column element, or in
06203  *   case of error, 0 is always returned.
06204  *
06205  * Read a value from a column of type @c CPL_TYPE_INT. If @em column is a
06206  * @c NULL pointer a @c CPL_ERROR_NULL_INPUT is set. If the column is not
06207  * of the expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx 
06208  * is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set. 
06209  * Indexes are counted starting from 0. If the input column has length zero, 
06210  * the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set. If the @em null 
06211  * flag is a valid pointer, it is used to indicate whether the accessed 
06212  * column element is valid (0) or invalid (1). The null flag also signals 
06213  * an error condition (-1).
06214  */
06215 
06216 int xxx_column_get_int(xxx_column *column, int indx, int *null)
06217 {
06218 
06219     const char *fid    = "xxx_column_get_int";
06220     int          isnull = xxx_column_is_invalid(column, indx);
06221     int          length = xxx_column_get_size(column);
06222     cpl_type     type   = xxx_column_get_type(column);
06223 
06224 
06225     if (null)
06226         *null = -1;
06227 
06228     if (column == 0x0) {
06229         cpl_error_set_where(fid);
06230         return 0;
06231     }
06232 
06233     if (indx < 0 || indx >= length) {
06234         cpl_error_set_where(fid);
06235         return 0;
06236     }
06237 
06238     if (type != CPL_TYPE_INT) {
06239         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06240         return 0;
06241     }
06242 
06243     if (null)
06244         *null = isnull;
06245 
06246     if (isnull)
06247         return 0;
06248 
06249     return column->values->i[indx];
06250 
06251 }
06252 
06253 
06254 /* 
06255  * @brief
06256  *   Read a value from a @em float column.
06257  *
06258  * @param column  Column to be accessed.
06259  * @param indx    Position of element to be read.
06260  * @param null    Flag indicating null values, or error condition.
06261  *
06262  * @return Float value read. In case of an invalid column element, or in
06263  *   case of error, 0.0 is always returned.
06264  *
06265  * Read a value from a column of type @c CPL_TYPE_FLOAT. See the
06266  * documentation of the function xxx_column_get_int().
06267  */
06268 
06269 float xxx_column_get_float(xxx_column *column, int indx, int *null)
06270 {
06271 
06272     const char *fid    = "xxx_column_get_float";
06273     int          isnull = xxx_column_is_invalid(column, indx);
06274     int          length = xxx_column_get_size(column);
06275     cpl_type     type   = xxx_column_get_type(column);
06276 
06277 
06278     if (null)
06279         *null = -1;
06280 
06281     if (column == 0x0) {
06282         cpl_error_set_where(fid);
06283         return 0; 
06284     }
06285 
06286     if (indx < 0 || indx >= length) {
06287         cpl_error_set_where(fid);
06288         return 0; 
06289     }
06290 
06291     if (type != CPL_TYPE_FLOAT) {
06292         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06293         return 0;
06294     }
06295     
06296     if (null)
06297         *null = isnull;
06298 
06299     if (isnull)
06300         return 0;
06301 
06302     return column->values->f[indx];
06303 
06304 }
06305 
06306 
06307 
06308 /* 
06309  * @brief
06310  *   Read a value from a @em double column.
06311  *
06312  * @param column  Column to be accessed.
06313  * @param indx    Position of element to be read.
06314  * @param null    Flag indicating null values, or error condition.
06315  *
06316  * @return Double value read. In case of an invalid column element, or in
06317  *   case of error, 0.0 is always returned.
06318  *
06319  * Read a value from a column of type @c CPL_TYPE_DOUBLE. See the
06320  * documentation of the function xxx_column_get_int().
06321  */
06322 
06323 double xxx_column_get_double(xxx_column *column, int indx, int *null)
06324 {
06325 
06326     const char *fid    = "xxx_column_get_double";
06327     int          isnull = xxx_column_is_invalid(column, indx);
06328     int          length = xxx_column_get_size(column);
06329     cpl_type     type   = xxx_column_get_type(column);
06330 
06331 
06332     if (null)
06333         *null = -1;
06334 
06335     if (column == 0x0) {
06336         cpl_error_set_where(fid);
06337         return 0; 
06338     }
06339 
06340     if (indx < 0 || indx >= length) {
06341         cpl_error_set_where(fid);
06342         return 0; 
06343     }
06344 
06345     if (type != CPL_TYPE_DOUBLE) {
06346         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06347         return 0;
06348     }
06349     
06350     if (null)
06351         *null = isnull;
06352 
06353     if (isnull)
06354         return 0;
06355 
06356     return column->values->d[indx];
06357 
06358 }
06359 
06360 
06361 /* 
06362  * @brief
06363  *   Read a value from a string column.
06364  *
06365  * @param column  Column to be accessed.
06366  * @param indx    Position of element to be read.
06367  *
06368  * @return Character string read. In case of an invalid column element,
06369  *   or in case of error, a @c NULL pointer is always returned.
06370  *
06371  * Read a value from a column of type @c CPL_TYPE_STRING. If @em column is a
06372  * @c NULL pointer a @c CPL_ERROR_NULL_INPUT is set. If the column is not
06373  * of the expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx
06374  * is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set.
06375  * Indexes are counted starting from 0. If the input column has length zero,
06376  * the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set.
06377  * 
06378  * @note
06379  *   The returned string is a pointer to a column element, not its 
06380  *   copy. Its manipulation will directly affect that column element, 
06381  *   while changing that column element using @c xxx_column_set_string() 
06382  *   will turn it into garbage. Therefore, if a real copy of a string 
06383  *   column element is required, this function should be called as an 
06384  *   argument of the function @c cpl_strdup().
06385  */
06386 
06387 const char *xxx_column_get_string(xxx_column *column, int indx)
06388 {
06389 
06390     const char *fid    = "xxx_column_get_string";
06391     int          length = xxx_column_get_size(column);
06392     cpl_type     type   = xxx_column_get_type(column);
06393 
06394 
06395     if (column == 0x0) {
06396         cpl_error_set_where(fid);
06397         return NULL; 
06398     }
06399 
06400     if (indx < 0 || indx >= length) {
06401         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06402         return NULL; 
06403     }
06404 
06405     if (type != CPL_TYPE_STRING) {
06406         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06407         return NULL;
06408     }
06409     
06410     return column->values->s[indx];
06411 
06412 }
06413 
06414 
06415 /*
06416  * @brief
06417  *   Read an array from an array column.
06418  *
06419  * @param column  Column to be accessed.
06420  * @param indx    Position of array to be read.
06421  *
06422  * @return CPL array read. In case of an invalid column element,
06423  *   or in case of error, a @c NULL pointer is always returned.
06424  *
06425  * Read an array from a column of type array. If @em column is a
06426  * @c NULL pointer a @c CPL_ERROR_NULL_INPUT is set. If the column is not
06427  * of the expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx
06428  * is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set.
06429  * Indexes are counted starting from 0. If the input column has length zero,
06430  * the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set.
06431  *
06432  * @note
06433  *   The returned array is a pointer to a column element, not its
06434  *   copy. Its manipulation will directly affect that column element,
06435  *   while changing that column element using @c xxx_column_set_array()
06436  *   will turn it into garbage. Therefore, if a real copy of an array
06437  *   column element is required, this function should be called as an
06438  *   argument of the function @c cpl_array_duplicate().
06439  */
06440 
06441 const cpl_array *xxx_column_get_array(xxx_column *column, int indx)
06442 {
06443 
06444     const char *fid    = "xxx_column_get_array";
06445     int          length = xxx_column_get_size(column);
06446     cpl_type     type   = xxx_column_get_type(column);
06447 
06448 
06449     if (column == 0x0) {
06450         cpl_error_set_where(fid);
06451         return NULL;
06452     }
06453 
06454     if (indx < 0 || indx >= length) {
06455         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06456         return NULL;
06457     }
06458 
06459     if (!(type & CPL_TYPE_POINTER)) {
06460         cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06461         return NULL;
06462     }
06463 
06464     return column->values->array[indx];
06465 
06466 }
06467 
06468 
06469 /* 
06470  * @brief
06471  *   Write a value to a numerical column element.
06472  *
06473  * @param column  Column to be accessed.
06474  * @param indx    Position where to write value.
06475  * @param value   Value to write.
06476  *
06477  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer 
06478  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of numerical 
06479  *   type, a @c CPL_ERROR_INVALID_TYPE is returned. If @em indx is outside 
06480  *   the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If 
06481  *   the input column has length zero, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
06482  *   is always returned.
06483  *
06484  * Write a value to a numerical column element. The value is cast to the
06485  * accessed column type. The written value is automatically flagged as
06486  * valid. To invalidate a column value use @c xxx_column_set_invalid().
06487  * Column elements are counted starting from 0. This function cannot
06488  * be used on array columns.
06489  */
06490 
06491 cpl_error_code xxx_column_set(xxx_column *column, int indx, double value)
06492 {
06493 
06494     const char *fid  = "xxx_column_set";
06495     cpl_type     type = xxx_column_get_type(column);
06496 
06497 
06498     switch (type) {
06499     case CPL_TYPE_INT:
06500         return xxx_column_set_int(column, indx, value);
06501     case CPL_TYPE_FLOAT:
06502         return xxx_column_set_float(column, indx, value);
06503     case CPL_TYPE_DOUBLE:
06504         return xxx_column_set_double(column, indx, value);
06505     case CPL_TYPE_INT | CPL_TYPE_POINTER:
06506     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
06507     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
06508     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
06509     case CPL_TYPE_STRING:
06510         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
06511     default:
06512         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06513     }
06514 
06515 }
06516 
06517 
06518 /* 
06519  * @brief
06520  *   Write a value to an @em integer column element.
06521  *
06522  * @param column  Column to be accessed.
06523  * @param indx    Position where to write value.
06524  * @param value   Value to write.
06525  *
06526  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer 
06527  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the 
06528  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx is 
06529  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned.
06530  *   If the input column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
06531  *   is always returned.
06532  *
06533  * Write a value to an @em integer column element. The written value 
06534  * is automatically flagged as valid. To invalidate a column value use 
06535  * @c xxx_column_set_invalid(). Column elements are counted starting 
06536  * from 0.
06537  */
06538 
06539 cpl_error_code xxx_column_set_int(xxx_column *column, int indx, int value)
06540 {
06541 
06542     const char *fid    = "xxx_column_set_int";
06543     int          length = xxx_column_get_size(column);
06544     cpl_type     type   = xxx_column_get_type(column);
06545 
06546 
06547     if (column == 0x0)
06548         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06549     
06550     if (indx < 0 || indx >= length)
06551         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06552 
06553     if (type != CPL_TYPE_INT)
06554         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06555 
06556     column->values->i[indx] = value;
06557     xxx_column_unset_null(column, indx);
06558 
06559     return CPL_ERROR_NONE;
06560 
06561 }
06562 
06563 
06564 /* 
06565  * @brief
06566  *   Write a value to a @em float column element.
06567  *
06568  * @param column  Column to be accessed.
06569  * @param indx    Position where to write value.
06570  * @param value   Value to write.
06571  *
06572  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06573  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06574  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx is
06575  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned.
06576  *   If the input column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06577  *   is always returned.
06578  *
06579  * Write a value to a @em float column element. The written value
06580  * is automatically flagged as valid. To invalidate a column value use
06581  * @c xxx_column_set_invalid(). Column elements are counted starting
06582  * from 0.
06583  */
06584 
06585 cpl_error_code xxx_column_set_float(xxx_column *column, int indx, float value)
06586 {
06587 
06588     const char *fid    = "xxx_column_set_float";
06589     int          length = xxx_column_get_size(column);
06590     cpl_type     type   = xxx_column_get_type(column);
06591 
06592 
06593     if (column == 0x0)
06594         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06595 
06596     if (indx < 0 || indx >= length)
06597         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06598 
06599     if (type != CPL_TYPE_FLOAT)
06600         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06601 
06602     column->values->f[indx] = value;
06603     xxx_column_unset_null(column, indx);
06604 
06605     return CPL_ERROR_NONE;
06606 
06607 }
06608 
06609 
06610 /* 
06611  * @brief
06612  *   Write a value to a @em double column element.
06613  *
06614  * @param column  Column to be accessed.
06615  * @param indx    Position where to write value.
06616  * @param value   Value to write.
06617  *
06618  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06619  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06620  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is set. If @em indx is
06621  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned.
06622  *   If the input column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06623  *   is always returned.
06624  *
06625  * Write a value to a @em double column element. The written value
06626  * is automatically flagged as valid. To invalidate a column value use
06627  * @c xxx_column_set_invalid(). Column elements are counted starting
06628  * from 0.
06629  */
06630 
06631 cpl_error_code xxx_column_set_double(xxx_column *column, int indx, 
06632                                      double value)
06633 {
06634 
06635     const char *fid    = "xxx_column_set_double";
06636     int          length = xxx_column_get_size(column);
06637     cpl_type     type   = xxx_column_get_type(column);
06638 
06639 
06640     if (column == 0x0)
06641         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06642 
06643     if (indx < 0 || indx >= length)
06644         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06645 
06646     if (type != CPL_TYPE_DOUBLE)
06647         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06648 
06649     column->values->d[indx] = value;
06650     xxx_column_unset_null(column, indx);
06651 
06652     return CPL_ERROR_NONE;
06653 
06654 }
06655 
06656 
06657 /* 
06658  * @brief
06659  *   Write a character string to a string column element.
06660  *
06661  * @param column  Column to be accessed.
06662  * @param indx    Position where to write character string.
06663  * @param string  Character string to write.
06664  *
06665  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06666  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06667  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em indx is
06668  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned.
06669  *   If the input column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06670  *   is always returned.
06671  *
06672  * Copy a character string to a @em string column element. The written 
06673  * value can also be a @c NULL pointer. Note that the input character 
06674  * string is copied, therefore the original can be modified without 
06675  * affecting the column content. To "plug" a character string directly 
06676  * into a column element, use the function @c xxx_column_get_data_string(). 
06677  * Column elements are counted starting from zero.
06678  */
06679 
06680 cpl_error_code xxx_column_set_string(xxx_column *column, 
06681                                      int indx, const char *string)
06682 {
06683 
06684     const char *fid    = "xxx_column_set_string";
06685     int          length = xxx_column_get_size(column);
06686     cpl_type     type   = xxx_column_get_type(column);
06687 
06688 
06689     if (column == 0x0)
06690         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06691 
06692     if (indx < 0 || indx >= length)
06693         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06694 
06695     if (type != CPL_TYPE_STRING)
06696         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06697 
06698     if (column->values->s[indx])
06699         cpl_free(column->values->s[indx]);
06700 
06701     if (string)
06702         column->values->s[indx] = cpl_strdup((char *)string);
06703     else
06704         column->values->s[indx] = NULL;
06705 
06706     return CPL_ERROR_NONE;
06707 
06708 }
06709 
06710 
06711 /*
06712  * @brief
06713  *   Write an array to an array column element.
06714  *
06715  * @param column  Column to be accessed.
06716  * @param indx    Position where to write array.
06717  * @param array   CPL array to write.
06718  *
06719  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL 
06720  *   pointer a @c CPL_ERROR_NULL_INPUT is returned. If the column 
06721  *   does not match the type of the input @em array, or if the column 
06722  *   is not made of arrays, a @c CPL_ERROR_TYPE_MISMATCH is returned. 
06723  *   If the input @em array size is different from the column depth, 
06724  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned. If @em indx is 
06725  *   outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is 
06726  *   returned.
06727  *
06728  * Copy a CPL array to an array column element. The written value 
06729  * can also be a @c NULL pointer. Note that the input array
06730  * is copied, therefore the original can be modified without
06731  * affecting the column content. To "plug" an array directly
06732  * into a column element, use the function @c xxx_column_get_data_array().
06733  * Column elements are counted starting from zero.
06734  */
06735 
06736 cpl_error_code xxx_column_set_array(xxx_column *column,
06737                                     int indx, const cpl_array *array)
06738 {
06739 
06740     const char *fid    = "xxx_column_set_array";
06741     int          length = xxx_column_get_size(column);
06742     cpl_type     type   = xxx_column_get_type(column);
06743     cpl_type     atype;
06744 
06745 
06746     if (column == 0x0)
06747         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06748 
06749     if (indx < 0 || indx >= length)
06750         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06751 
06752     if (!(type & CPL_TYPE_POINTER))
06753         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06754 
06755     if (array) {
06756         atype = cpl_array_get_type(array);
06757         if (type != (atype | CPL_TYPE_POINTER))
06758             return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06759         if (xxx_column_get_depth(column) != cpl_array_get_size(array))
06760             return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
06761     }
06762 
06763     if (column->values->array[indx])
06764         cpl_array_delete(column->values->array[indx]);
06765 
06766     if (array)
06767         column->values->array[indx] = cpl_array_duplicate((cpl_array *)array);
06768     else
06769         column->values->array[indx] = NULL;
06770 
06771     return CPL_ERROR_NONE;
06772 
06773 }
06774 
06775 
06776 /* 
06777  * @brief
06778  *   Set a column element to NULL;
06779  *
06780  * @param column  Column to be accessed.
06781  * @param indx    Position where to write a NULL.
06782  *
06783  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06784  *   a @c CPL_ERROR_NULL_INPUT is returned. If @em indx is outside the 
06785  *   column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is set. If the input 
06786  *   column has length 0, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always set.
06787  *
06788  * In the case of a string or array column, the string or array is set free 
06789  * and its pointer is set to @c NULL; for other data types, the corresponding
06790  * element of the null flags buffer is flagged. Column elements are counted 
06791  * starting from zero.
06792  */
06793 
06794 cpl_error_code xxx_column_set_invalid(xxx_column *column, int indx)
06795 {
06796 
06797     const char *fid    = "xxx_column_set_invalid";
06798     int          length = xxx_column_get_size(column);
06799     cpl_type     type   = xxx_column_get_type(column);
06800 
06801 
06802     if (column == 0x0)
06803         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06804 
06805     if (indx < 0 || indx >= length)
06806         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06807 
06808 
06809     if (type == CPL_TYPE_STRING) {
06810         if (column->values->s[indx]) {
06811             cpl_free(column->values->s[indx]);
06812             column->values->s[indx] = NULL;
06813         }
06814         return CPL_ERROR_NONE;
06815     }
06816 
06817     if (type & CPL_TYPE_POINTER) {
06818         if (column->values->array[indx]) {
06819             cpl_array_delete(column->values->array[indx]);
06820             column->values->array[indx] = NULL;
06821         }
06822         return CPL_ERROR_NONE;
06823     }
06824 
06825     if (column->nullcount == column->length)
06826         return CPL_ERROR_NONE;
06827 
06828     if (!column->null)
06829         column->null = cpl_calloc(column->length, sizeof(xxx_column_flag));
06830 
06831     if (column->null[indx] == 0) {
06832 
06833         column->null[indx] = 1;
06834         column->nullcount++;
06835 
06836         if (column->nullcount == column->length) {
06837             if (column->null)
06838                 cpl_free(column->null);
06839             column->null = NULL;
06840         }
06841 
06842     }
06843 
06844     return CPL_ERROR_NONE;
06845 
06846 }
06847 
06848 
06849 /*
06850  * @brief
06851  *   Write the same a value within a numerical column segment.
06852  *
06853  * @param column  Column to be accessed.
06854  * @param start   Position where to begin write value.
06855  * @param count   Number of values to write.
06856  * @param value   Value to write.
06857  *
06858  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06859  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of numerical
06860  *   type, a @c CPL_ERROR_INVALID_TYPE is returned. If @em start is outside
06861  *   the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If
06862  *   the input column has length zero, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06863  *   is always returned.
06864  *
06865  * Write the same value to a numerical column segment. The value is cast to
06866  * the accessed column type. The written values are automatically flagged as
06867  * valid. To invalidate a column interval use @c xxx_column_fill_invalid().
06868  */
06869 
06870 cpl_error_code xxx_column_fill(xxx_column *column, 
06871                                int start, int count, double value)
06872 {
06873 
06874     const char *fid  = "xxx_column_fill";
06875     cpl_type     type = xxx_column_get_type(column);
06876 
06877 
06878     switch (type) {
06879     case CPL_TYPE_INT:
06880         return xxx_column_fill_int(column, start, count, value);
06881     case CPL_TYPE_FLOAT:
06882         return xxx_column_fill_float(column, start, count, value);
06883     case CPL_TYPE_DOUBLE:
06884         return xxx_column_fill_double(column, start, count, value);
06885     case CPL_TYPE_INT | CPL_TYPE_POINTER:
06886     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
06887     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
06888     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
06889     case CPL_TYPE_STRING:
06890         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
06891     default:
06892         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06893     }
06894 
06895 }
06896 
06897 
06898 /* 
06899  * @brief
06900  *   Write the same value within an @em integer column segment.
06901  *
06902  * @param column  Column to be accessed.
06903  * @param start   Position where to begin write value.
06904  * @param count   Number of values to write.
06905  * @param value   Value to write.
06906  *
06907  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06908  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06909  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start 
06910  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
06911  *   is returned. If the input column has length zero, the error 
06912  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
06913  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
06914  *
06915  * Write the same value to an @em integer column segment. The written 
06916  * values are automatically flagged as valid. To invalidate a column 
06917  * interval use @c xxx_column_fill_invalid(). The @em count argument
06918  * can go beyond the column end, and in that case the specified @em value
06919  * will be written just up to the end of the column. If @em count is zero,
06920  * the column is not modified and no error is set.
06921  */
06922 
06923 cpl_error_code xxx_column_fill_int(xxx_column *column, 
06924                                    int start, int count, int value)
06925 {
06926 
06927     const char *fid    = "xxx_column_fill_int";
06928     int          length = xxx_column_get_size(column);
06929     cpl_type     type   = xxx_column_get_type(column);
06930     int         *ip;
06931 
06932 
06933     if (column == 0x0)
06934         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
06935 
06936     if (start < 0 || start >= length)
06937         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
06938 
06939     if (count < 0)
06940         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
06941 
06942     if (type != CPL_TYPE_INT)
06943         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
06944 
06945     if (count == 0)
06946         return CPL_ERROR_NONE;
06947 
06948     if (count > length - start)
06949         count = length - start;
06950 
06951     xxx_column_unset_null_segment(column, start, count);
06952 
06953     ip = column->values->i + start;
06954 
06955     while (count--)
06956         *ip++ = value;
06957 
06958     return CPL_ERROR_NONE;
06959 
06960 }
06961 
06962 
06963 /* 
06964  * @brief
06965  *   Write a value to a @em float column segment.
06966  *
06967  * @param column  Column to be accessed.
06968  * @param start   Position where to begin write value.
06969  * @param count   Number of values to write.
06970  * @param value   Value to write.
06971  *
06972  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
06973  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
06974  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
06975  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
06976  *   is returned. If the input column has length zero, the error
06977  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
06978  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
06979  *
06980  * Write the same value to a @em float column segment. The written
06981  * values are automatically flagged as valid. To invalidate a column
06982  * interval use @c xxx_column_fill_invalid(). The @em count argument
06983  * can go beyond the column end, and in that case the specified @em value
06984  * will be written just up to the end of the column. If @em count is zero,
06985  * the column is not modified and no error is set.
06986  */
06987 
06988 cpl_error_code xxx_column_fill_float(xxx_column *column, int start, 
06989                                      int count, float value)
06990 {
06991 
06992     const char *fid    = "xxx_column_fill_float";
06993     int          length = xxx_column_get_size(column);
06994     cpl_type     type   = xxx_column_get_type(column);
06995     float       *fp;
06996 
06997 
06998     if (column == 0x0)
06999         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07000 
07001     if (start < 0 || start >= length)
07002         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07003 
07004     if (count < 0)
07005         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07006 
07007     if (type != CPL_TYPE_FLOAT)
07008         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07009 
07010     if (count == 0)
07011         return CPL_ERROR_NONE;
07012 
07013     if (count > length - start)
07014         count = length - start;
07015 
07016     xxx_column_unset_null_segment(column, start, count);
07017 
07018     fp = column->values->f + start;
07019 
07020     while (count--)
07021         *fp++ = value;
07022 
07023     return CPL_ERROR_NONE;
07024 
07025 }
07026 
07027 
07028 /* 
07029  * @brief
07030  *   Write a value to a @em double column segment.
07031  *
07032  * @param column  Column to be accessed.
07033  * @param start   Position where to begin write value.
07034  * @param count   Number of values to write.
07035  * @param value   Value to write.
07036  *
07037  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07038  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07039  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07040  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07041  *   is returned. If the input column has length zero, the error
07042  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07043  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07044  *
07045  * Write the same value to a @em double column segment. The written
07046  * values are automatically flagged as valid. To invalidate a column
07047  * interval use @c xxx_column_fill_invalid(). The @em count argument
07048  * can go beyond the column end, and in that case the specified @em value
07049  * will be written just up to the end of the column. If @em count is zero,
07050  * the column is not modified and no error is set.
07051  */
07052 
07053 cpl_error_code xxx_column_fill_double(xxx_column *column, int start, 
07054                                       int count, double value)
07055 {
07056 
07057     const char *fid    = "xxx_column_fill_double";
07058     int          length = xxx_column_get_size(column);
07059     cpl_type     type   = xxx_column_get_type(column);
07060     double      *dp;
07061 
07062 
07063     if (column == 0x0)
07064         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07065 
07066     if (start < 0 || start >= length)
07067         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07068 
07069     if (count < 0)
07070         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07071 
07072     if (type != CPL_TYPE_DOUBLE)
07073         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07074 
07075     if (count == 0)
07076         return CPL_ERROR_NONE;
07077 
07078     if (count > length - start)
07079         count = length - start;
07080 
07081     xxx_column_unset_null_segment(column, start, count);
07082 
07083     dp = column->values->d + start;
07084 
07085     while (count--)
07086         *dp++ = value;
07087 
07088     return CPL_ERROR_NONE;
07089 
07090 }
07091 
07092 
07093 /* 
07094  * @brief
07095  *   Write a string to a string column segment.
07096  *
07097  * @param column  Column to be accessed.
07098  * @param start   Position where to begin write value.
07099  * @param count   Number of values to write.
07100  * @param value   Value to write.
07101  *
07102  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07103  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07104  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07105  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07106  *   is returned. If the input column has length zero, the error
07107  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07108  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07109  *
07110  * Copy the same string to a string column segment. If the input string 
07111  * is not a @c NULL pointer, it is duplicated for each accessed column 
07112  * element. If the input string is @c NULL, this call is equivalent to 
07113  * @c xxx_column_fill_invalid(). The @em count argument can go beyond 
07114  * the column end, and in that case the specified @em value will be 
07115  * copied just up to the end of the column. If @em count is zero,
07116  * the column is not modified and no error is set.
07117  */
07118 
07119 cpl_error_code xxx_column_fill_string(xxx_column *column, int start,
07120                                       int count, const char *value)
07121 {
07122 
07123     const char *fid    = "xxx_column_fill_string";
07124     int          length = xxx_column_get_size(column);
07125     cpl_type     type   = xxx_column_get_type(column);
07126     char       **sp;
07127 
07128 
07129     if (column == 0x0)
07130         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07131 
07132     if (start < 0 || start >= length)
07133         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07134 
07135     if (count < 0)
07136         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07137 
07138     if (type != CPL_TYPE_STRING)
07139         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07140 
07141     if (count == 0)
07142         return CPL_ERROR_NONE;
07143 
07144     if (count > length - start)
07145         count = length - start;
07146 
07147     if (value == NULL)
07148         return xxx_column_fill_invalid(column, start, count);
07149 
07150     sp = column->values->s + start;
07151     while (count--) {
07152         if (*sp)
07153             cpl_free(*sp);
07154         *sp++ = cpl_strdup((char *)value);
07155     }
07156 
07157     return CPL_ERROR_NONE;
07158 
07159 }
07160 
07161 
07162 /*
07163  * @brief
07164  *   Write the same array to an array column segment.
07165  *   
07166  * @param column  Column to be accessed.
07167  * @param start   Position where to begin write value.
07168  * @param count   Number of values to write.
07169  * @param array   Array to write.
07170  * 
07171  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL
07172  *   pointer a @c CPL_ERROR_NULL_INPUT is returned. If the column
07173  *   does not match the type of the input @em array, or if the column
07174  *   is not made of arrays, a @c CPL_ERROR_TYPE_MISMATCH is returned.
07175  *   If the input @em array size is different from the column depth,
07176  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned. If @em start
07177  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
07178  *   is returned. If the input column has length zero, the error
07179  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07180  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07181  *   
07182  * Copy the same array to an array column segment. If the input array
07183  * is not a @c NULL pointer, it is duplicated for each accessed column 
07184  * element. If the input array is @c NULL, this call is equivalent to
07185  * @c xxx_column_fill_invalid(). The @em count argument can go beyond 
07186  * the column end, and in that case the specified @em value will be 
07187  * copied just up to the end of the column. If @em count is zero,
07188  * the column is not modified and no error is set. 
07189  */
07190 
07191 cpl_error_code xxx_column_fill_array(xxx_column *column, int start,
07192                                      int count, const cpl_array *array)
07193 {
07194 
07195     const char *fid    = "xxx_column_fill_array";
07196     int          length = xxx_column_get_size(column);
07197     cpl_type     type   = xxx_column_get_type(column);
07198     cpl_type     atype;
07199     cpl_array  **ap;
07200     
07201 
07202     if (column == 0x0)
07203         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07204 
07205     if (start < 0 || start >= length)
07206         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07207 
07208     if (count < 0)
07209         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07210 
07211     if (!(type & CPL_TYPE_POINTER))
07212         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07213 
07214     if (array) {
07215         atype = cpl_array_get_type(array);
07216         if (type != (atype | CPL_TYPE_POINTER))
07217             return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07218         if (xxx_column_get_depth(column) != cpl_array_get_size(array))
07219             return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
07220     }
07221 
07222     if (count == 0)
07223         return CPL_ERROR_NONE;
07224 
07225     if (count > length - start)
07226         count = length - start;
07227 
07228     if (array == NULL)
07229         return xxx_column_fill_invalid(column, start, count);
07230 
07231     ap = column->values->array + start;
07232     while (count--) {
07233         if (*ap)
07234             cpl_array_delete(*ap);
07235         *ap++ = cpl_array_duplicate(array);
07236     }
07237 
07238     return CPL_ERROR_NONE;
07239 
07240 }
07241 
07242 
07243 /*
07244  * @brief
07245  *   Set a column segment to NULL.
07246  *
07247  * @param column  Column to be accessed.
07248  * @param start   Position where to start writing NULLs.
07249  * @param count   Number of column elements to set to NULL.
07250  *
07251  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07252  *   a @c CPL_ERROR_NULL_INPUT is returned. If @em start is outside the 
07253  *   column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If the 
07254  *   input column has length zero, the error @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
07255  *   is always returned. If @em count is negative, a @c CPL_ERROR_ILLEGAL_INPUT 
07256  *   is returned.
07257  *
07258  * Invalidate values contained in a column segment. The @em count argument 
07259  * can go beyond the column end, and in that case the values will be
07260  * invalidated up to the end of the column. If @em count is zero, the 
07261  * column is not modified and no error is set. In the case of a @em string 
07262  * or @em array column, the invalidated strings or arrays are set free and 
07263  * their pointers are set to @c NULL; for other data types, the corresponding 
07264  * elements are flagged as invalid.
07265  */
07266 
07267 cpl_error_code xxx_column_fill_invalid(xxx_column *column, int start, int count)
07268 {
07269 
07270     const char *fid    = "xxx_column_fill_invalid";
07271     cpl_type     type   = xxx_column_get_type(column);
07272     int          length = xxx_column_get_size(column);
07273     int          c;
07274     int         *np;
07275     char       **sp;
07276     cpl_array  **ap;
07277 
07278 
07279     if (column == 0x0)
07280         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07281 
07282     if (start < 0 || start >= length)
07283         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07284 
07285     if (count < 0) 
07286         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07287 
07288     if (count == 0)
07289         return CPL_ERROR_NONE;
07290 
07291     if (count > length - start)
07292         count = length - start;
07293 
07294     if (count == length) {
07295         if (type != CPL_TYPE_STRING && !(type & CPL_TYPE_POINTER)) {
07296             if (column->null)
07297                 cpl_free(column->null);
07298             column->null = NULL;
07299             column->nullcount = length;
07300             return CPL_ERROR_NONE;
07301         }
07302     }
07303 
07304     c = count;
07305 
07306     if (type == CPL_TYPE_STRING) {
07307 
07308         sp = column->values->s + start;
07309 
07310         while (c--) {
07311             if (*sp)
07312                 cpl_free(*sp);
07313             sp++;
07314         }
07315 
07316         memset(column->values->s + start, 0, count * sizeof(char *));
07317 
07318         return CPL_ERROR_NONE;
07319     }
07320 
07321     if (type & CPL_TYPE_POINTER) {
07322  
07323         ap = column->values->array + start;
07324  
07325         while (c--) { 
07326             if (*ap)
07327                 cpl_array_delete(*ap);
07328             ap++;
07329         }
07330 
07331         memset(column->values->array + start, 0, count * sizeof(cpl_array *));
07332 
07333         return CPL_ERROR_NONE;
07334     }
07335 
07336     if (column->nullcount == length)
07337         return CPL_ERROR_NONE;
07338 
07339     if (!column->null)
07340         column->null = cpl_calloc(length, sizeof(xxx_column_flag));
07341 
07342     np = column->null + start;
07343 
07344     if (column->nullcount == 0) {
07345         column->nullcount = count;
07346         while (c--)
07347             *np++ = 1;
07348     }
07349     else {
07350         while (c--) {
07351             if (*np == 0) {
07352                 *np = 1;
07353                 column->nullcount++;
07354             }
07355             np++;
07356         }
07357 
07358         if (column->nullcount == length) {
07359             if (column->null)
07360                 cpl_free(column->null);
07361             column->null = NULL;
07362         }
07363     }
07364 
07365     return CPL_ERROR_NONE;
07366     
07367 }
07368 
07369 
07370 /*
07371  * @brief
07372  *   Copy an array of values to a numerical column segment.
07373  *
07374  * @param column  Column to be accessed.
07375  * @param start   Position where to begin write values.
07376  * @param count   Number of values to write.
07377  * @param values  Values to write.
07378  *
07379  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07380  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of numerical
07381  *   type, a @c CPL_ERROR_INVALID_TYPE is returned. If @em start is outside
07382  *   the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If
07383  *   the input column has length zero, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07384  *   is always returned. If @em count is not greater than zero, a 
07385  *   @c CPL_ERROR_ILLEGAL_INPUT is returned.
07386  *
07387  * Write the values to a numerical column segment. The values are cast to
07388  * the accessed column type. The written values are automatically flagged 
07389  * as valid. The @em count argument can go beyond the column end, and in 
07390  * that case values will be transferred just up to the end of the column.
07391  * This function doesn't apply to array column types.
07392  */
07393 
07394 cpl_error_code xxx_column_copy_segment(xxx_column *column, 
07395                                        int start, int count, double *values)
07396 {
07397 
07398     const char *fid    = "xxx_column_copy_segment";
07399     int          length = xxx_column_get_size(column);
07400     cpl_type     type   = xxx_column_get_type(column);
07401     int         *idata;
07402     float       *fdata;
07403 
07404 
07405     if (column == 0x0)
07406         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07407 
07408     if (start < 0 || start >= length)
07409         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07410 
07411     if (count <= 0)
07412         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07413 
07414     if (count > length - start)
07415         count = length - start;
07416 
07417     xxx_column_unset_null_segment(column, start, count);
07418 
07419     switch (type) {
07420     case CPL_TYPE_INT:
07421         idata = xxx_column_get_data_int(column);
07422         idata += start;
07423         while (count--)
07424             *idata++ = *values++;
07425         break;
07426     case CPL_TYPE_FLOAT:
07427         fdata = xxx_column_get_data_float(column);
07428         fdata += start;
07429         while (count--)
07430             *fdata++ = *values++;
07431         break;
07432     case CPL_TYPE_DOUBLE:
07433         memcpy(column->values->d + start, values, count * sizeof(double));
07434         break;
07435     default:
07436         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
07437     }
07438 
07439     return CPL_ERROR_NONE;
07440 
07441 }
07442 static double xxx_tools_get_median_9double(double * p)
07443 {
07444     cpl_ensure(p, CPL_ERROR_NULL_INPUT, 0.00) ;
07445 
07446     CPL_PIX_SORT(p[1], p[2]); CPL_PIX_SORT(p[4], p[5]); CPL_PIX_SORT(p[7],p[8]);
07447     CPL_PIX_SORT(p[0], p[1]); CPL_PIX_SORT(p[3], p[4]); CPL_PIX_SORT(p[6],p[7]);
07448     CPL_PIX_SORT(p[1], p[2]); CPL_PIX_SORT(p[4], p[5]); CPL_PIX_SORT(p[7],p[8]);
07449     CPL_PIX_SORT(p[0], p[3]); CPL_PIX_SORT(p[5], p[8]); CPL_PIX_SORT(p[4],p[7]);
07450     CPL_PIX_SORT(p[3], p[6]); CPL_PIX_SORT(p[1], p[4]); CPL_PIX_SORT(p[2],p[5]);
07451     CPL_PIX_SORT(p[4], p[7]); CPL_PIX_SORT(p[4], p[2]); CPL_PIX_SORT(p[6],p[4]);
07452     CPL_PIX_SORT(p[4], p[2]); return(p[4]) ;
07453 }
07454 static double xxx_tools_get_median_double(
07455         double  *   a,
07456         int         n)
07457 {
07458     if (n==9) return xxx_tools_get_median_9double(a) ;
07459     return xxx_tools_get_kth_double(a,n,(((n)&1)?((n)/2):(((n)/2)-1))) ;
07460 }
07461 
07462 
07463 /*----------------------------------------------------------------------------*/
07471 /*----------------------------------------------------------------------------*/
07472 static float xxx_tools_get_median_float(
07473         float   *   a,
07474         int         n)
07475 {
07476     return xxx_tools_get_kth_float(a,n,(((n)&1)?((n)/2):(((n)/2)-1))) ;
07477 }
07478 
07479 /*----------------------------------------------------------------------------*/
07487 /*----------------------------------------------------------------------------*/
07488 static int xxx_tools_get_median_int(
07489         int     *   a,
07490         int         n)
07491 {
07492     return xxx_tools_get_kth_int(a,n,(((n)&1)?((n)/2):(((n)/2)-1))) ;
07493 }
07494 
07495 static double xxx_tools_ipow(double x, int y)
07496 {
07497 
07498     double result;
07499     double pow2 = x;
07500     int p = abs(y);
07501 
07502     /* Compute the result as a product of powers of 2 of x.
07503        - this method may produce (slightly) different results than pow(x,y) */
07504 
07505     /* Handle least significant bit in p here in order to avoid an unnecessary
07506        multiplication of pow2 - which could cause an over- or underflow */
07507     /* Also, 0^0 is 1, while any other power of 0 is 0 */
07508     result = p & 1 ? x : 1.0;
07509 
07510     while (p >>= 1) {
07511         pow2 *= pow2;
07512         /* Process least significant bit in p */
07513         if (p & 1) result *= pow2;
07514     }
07515 
07516     /* It is left to the caller to ensure that no division by zero occurs */
07517     return y < 0 ? 1.0/result : result;
07518 }
07519 
07520 
07521 /* 
07522  * @brief
07523  *   Copy a list of integer values to an @em integer column segment.
07524  *
07525  * @param column  Column to be accessed.
07526  * @param start   Position where to begin write values.
07527  * @param count   Number of values to write.
07528  * @param values  Values to write.
07529  *
07530  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07531  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the 
07532  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start 
07533  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
07534  *   is returned. If the input column has length zero, the 
07535  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count 
07536  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07537  *
07538  * Write a list of integer values to an @em integer column segment. 
07539  * The written values are automatically flagged as valid. The @em count 
07540  * argument can go beyond the column end, and in that case values will 
07541  * be transferred just up to the end of the column.
07542  */
07543 
07544 cpl_error_code xxx_column_copy_segment_int(xxx_column *column, 
07545                                            int start, int count, int *values)
07546 {
07547 
07548     const char *fid    = "xxx_column_copy_segment_int";
07549     int          length = xxx_column_get_size(column);
07550     cpl_type     type   = xxx_column_get_type(column);
07551 
07552 
07553     if (column == 0x0)
07554         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07555 
07556     if (start < 0 || start >= length)
07557         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07558 
07559     if (count <= 0)
07560         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07561 
07562     if (type != CPL_TYPE_INT)
07563         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07564 
07565     if (count > length - start)
07566         count = length - start;
07567 
07568     memcpy(column->values->i + start, values, count * sizeof(int));
07569 
07570     xxx_column_unset_null_segment(column, start, count);
07571 
07572     return CPL_ERROR_NONE;
07573 
07574 }
07575 
07576 
07577 /* 
07578  * @brief
07579  *   Copy a list of float values to a @em float column segment.
07580  *
07581  * @param column  Column to be accessed.
07582  * @param start   Position where to begin write values.
07583  * @param count   Number of values to write.
07584  * @param values  Values to write.
07585  *
07586  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07587  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07588  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07589  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07590  *   is returned. If the input column has length zero, the
07591  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07592  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07593  *
07594  * Write a list of float values to a @em float column segment.
07595  * The written values are automatically flagged as valid. The @em count 
07596  * argument can go beyond the column end, and in that case values will 
07597  * be transferred just up to the end of the column.
07598  */
07599 
07600 cpl_error_code xxx_column_copy_segment_float(xxx_column *column, int start,
07601                                              int count, float *values)
07602 {
07603 
07604     const char *fid    = "xxx_column_copy_segment_float";
07605     int          length = xxx_column_get_size(column);
07606     cpl_type     type   = xxx_column_get_type(column);
07607 
07608 
07609     if (column == 0x0)
07610         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07611 
07612     if (start < 0 || start >= length)
07613         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07614 
07615     if (count <= 0)
07616         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07617 
07618     if (type != CPL_TYPE_FLOAT)
07619         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07620 
07621     if (count > length - start)
07622         count = length - start;
07623 
07624     memcpy(column->values->f + start, values, count * sizeof(float));
07625 
07626     xxx_column_unset_null_segment(column, start, count);
07627 
07628     return CPL_ERROR_NONE;
07629 
07630 }
07631 
07632 
07633 /* 
07634  * @brief
07635  *   Copy a list of @em double values to a @em double column segment.
07636  *
07637  * @param column  Column to be accessed.
07638  * @param start   Position where to begin write values.
07639  * @param count   Number of values to write.
07640  * @param values  Values to write.
07641  *
07642  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07643  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07644  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07645  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07646  *   is returned. If the input column has length zero, the
07647  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07648  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07649  *
07650  * Write a list of double values to a @em double column segment.
07651  * The written values are automatically flagged as valid. The @em count 
07652  * argument can go beyond the column end, and in that case values will 
07653  * be transferred just up to the end of the column.
07654  */
07655 
07656 cpl_error_code xxx_column_copy_segment_double(xxx_column *column, int start,
07657                                               int count, double *values)
07658 {
07659 
07660     const char *fid    = "xxx_column_copy_segment_double";
07661     int          length = xxx_column_get_size(column);
07662     cpl_type     type   = xxx_column_get_type(column);
07663 
07664 
07665     if (column == 0x0)
07666         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07667 
07668     if (start < 0 || start >= length)
07669         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07670 
07671     if (count <= 0)
07672         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07673 
07674     if (type != CPL_TYPE_DOUBLE)
07675         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07676 
07677     if (count > length - start)
07678         count = length - start;
07679 
07680     memcpy(column->values->d + start, values, count * sizeof(double));
07681  
07682     xxx_column_unset_null_segment(column, start, count);
07683  
07684     return CPL_ERROR_NONE;
07685 
07686 }
07687 
07688 
07689 /* 
07690  * @brief
07691  *   Copy a list of strings to a @em string column segment.
07692  *
07693  * @param column  Column to be accessed.
07694  * @param start   Position where to begin write strings.
07695  * @param count   Number of strings to write.
07696  * @param strings Strings to write.
07697  *
07698  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL pointer
07699  *   a @c CPL_ERROR_NULL_INPUT is returned. If the column is not of the
07700  *   expected type, a @c CPL_ERROR_TYPE_MISMATCH is returned. If @em start
07701  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07702  *   is returned. If the input column has length zero, the
07703  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07704  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07705  *
07706  * Write a list of strings to a @em string column segment. The written 
07707  * values are automatically flagged as valid. The input strings are
07708  * duplicated before being assigned to the corresponding column elements.
07709  * The @em count argument can go beyond the column end, and in that case 
07710  * values will be transferred just up to the end of the column.
07711  */
07712 
07713 cpl_error_code xxx_column_copy_segment_string(xxx_column *column, int start,
07714                                               int count, char **strings)
07715 {
07716 
07717     const char *fid    = "xxx_column_copy_segment_string";
07718     cpl_type     type   = xxx_column_get_type(column);
07719     int          length = xxx_column_get_size(column);
07720     int          i;
07721     char       **sp;
07722 
07723 
07724     if (column == 0x0)
07725         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07726 
07727     if (start < 0 || start >= length)
07728         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07729 
07730     if (count <= 0)
07731         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07732 
07733     if (type != CPL_TYPE_STRING)
07734         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07735 
07736     if (count > length - start)
07737         count = length - start;
07738 
07739     sp = column->values->s + start;
07740 
07741     if (strings) {
07742         for (i = 0; i < count; i++) {
07743             if (*sp)
07744                 cpl_free(*sp);
07745             if (*strings)
07746                 *sp++ = cpl_strdup(*strings++);
07747             else
07748                 *sp++ = NULL;
07749         }
07750     }
07751     else {
07752         for (i = 0; i < count; i++) {
07753             if (*sp)
07754                 cpl_free(*sp);
07755             *sp++ = NULL;
07756         }
07757     }
07758 
07759     return CPL_ERROR_NONE;
07760 
07761 }
07762 
07763 
07764 /*
07765  * @brief
07766  *   Copy a list of CPL arrays to an @em array column segment.
07767  *
07768  * @param column  Column to be accessed.
07769  * @param start   Position where to begin write strings.
07770  * @param count   Number of strings to write.
07771  * @param arrays  Arrays to write.
07772  *
07773  * @return @c CPL_ERROR_NONE on success. If @em column is a @c NULL 
07774  *   pointer a @c CPL_ERROR_NULL_INPUT is returned. If the column
07775  *   does not match the type of any of the input arrays, or if the column
07776  *   is not made of arrays, a @c CPL_ERROR_TYPE_MISMATCH is returned.
07777  *   If the size of any of the input arrays is different from the column 
07778  *   depth a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned. If @em start
07779  *   is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE
07780  *   is returned. If the input column has length zero, the
07781  *   @c CPL_ERROR_ACCESS_OUT_OF_RANGE is always returned. If @em count
07782  *   is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
07783  *
07784  * Write a list of arrays to an @em array column segment. The written
07785  * values are automatically flagged as valid. The input arrays are
07786  * duplicated before being assigned to the corresponding column elements.
07787  * The @em count argument can go beyond the column end, and in that case
07788  * values will be transferred just up to the end of the column.
07789  */
07790 
07791 cpl_error_code xxx_column_copy_segment_array(xxx_column *column, int start,
07792                                              int count, cpl_array **arrays)
07793 {
07794 
07795     const char *fid    = "xxx_column_copy_segment_array";
07796     cpl_type     type   = xxx_column_get_type(column);
07797     cpl_type     atype;
07798     int          length = xxx_column_get_size(column);
07799     int          i;
07800     cpl_array  **ap;
07801     cpl_array  **keep;
07802     
07803 
07804     if (column == 0x0)
07805         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
07806 
07807     if (start < 0 || start >= length)
07808         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
07809 
07810     if (count <= 0)
07811         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
07812 
07813     if (!(type & CPL_TYPE_POINTER))
07814         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07815 
07816     if (count > length - start)
07817         count = length - start;
07818 
07819     ap = column->values->array + start;
07820 
07821     if (arrays) {
07822 
07823         /*
07824          * Check the compatibility of all the input arrays first
07825          */
07826 
07827         keep = arrays;
07828 
07829         for (i = 0; i < count; i++) {
07830             if (*arrays) {
07831                 atype = cpl_array_get_type(*arrays);
07832                 if (type != (atype | CPL_TYPE_POINTER))
07833                     return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
07834                 if (xxx_column_get_depth(column) != cpl_array_get_size(*arrays))
07835                     return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
07836                 arrays++;
07837             }
07838         }
07839 
07840         arrays = keep;
07841 
07842         for (i = 0; i < count; i++) {
07843             if (*ap)
07844                 cpl_array_delete(*ap);
07845             if (*arrays)
07846                 *ap++ = cpl_array_duplicate(*arrays++);
07847             else
07848                 *ap++ = NULL;
07849         }
07850     }
07851     else {
07852         for (i = 0; i < count; i++) {
07853             if (*ap)
07854                 cpl_array_delete(*ap);
07855             *ap++ = NULL;
07856         }
07857     }
07858 
07859     return CPL_ERROR_NONE;
07860 
07861 }
07862 
07863 /*************** TODO ******************/
07864 /*  
07865  * @brief
07866  *   Copy a segment of a column into another column.
07867  *
07868  * @param to_column   Column to be modified.
07869  * @param to_start    Position where to begin write values.
07870  * @param from_column Source column.
07871  * @param from_start  Position where to begin copy values.
07872  * @param count       Number of values to copy.
07873  *
07874  * @return 0 on success.
07875  *
07876  * Both columns must be of the same type.
07877  */
07878 
07879 /*************** TODO ******************
07880 
07881 cpl_error_code xxx_column_extract_from_column(xxx_column *to_column, 
07882                                               size_t to_start,
07883                                               xxx_column *from_column, 
07884                                               size_t from_start, 
07885                                               size_t count)
07886 {
07887 
07888     size_t   i           = 0;
07889     size_t   nullcount   = 0;
07890     size_t   to_length   = xxx_column_get_size(to_column);
07891     size_t   from_length = xxx_column_get_size(from_column);
07892     cpl_type to_type     = xxx_column_get_type(to_column);
07893     cpl_type from_type   = xxx_column_get_type(from_column);
07894 
07895 
07896     assert(to_column != 0x0);
07897     assert(from_column != 0x0);
07898 
07899 
07900     if (to_type != from_type)
07901         return 1;
07902 
07903     if (to_start > to_length || from_start > from_length)
07904         return 1;
07905 
07906     if (to_start + count > to_length || from_start + count > from_length)
07907         return 1;
07908 
07909     if (from_column->nullcount == from_length)
07910         return xxx_column_fill_invalid(to_column, to_start, count);
07911 
07912     if (from_column->nullcount) {
07913         while (i < count) {
07914             nullcount += from_column->null[from_start + i];
07915             i++;
07916         }
07917     }
07918 
07919     if (nullcount == count)
07920         return xxx_column_fill_invalid(to_column, to_start, count);
07921 
07922     if (nullcount) {
07923         if (to_column->nullcount == to_length) {
07924             to_column->null = cpl_malloc(to_length * sizeof(xxx_column_flag));
07925         }
07926     }
07927 
07928     switch (to_type) {
07929 
07930     case CPL_TYPE_INT:
07931         memcpy(to_column->values->i + to_start, 
07932                from_column->values->i + from_start, count * sizeof(int));
07933     case CPL_TYPE_FLOAT:
07934     case CPL_TYPE_DOUBLE:
07935     case CPL_TYPE_STRING:
07936     default:
07937 
07938     }
07939 
07940     if (start < length) {
07941 
07942         if (count > length - start)
07943             count = length - start;
07944 
07945         if (type == CPL_TYPE_INT) {
07946 
07947             memcpy(column->values->i + start, 
07948                    values, count * sizeof(int));
07949 
07950             return xxx_column_unset_null_segment(column, start, count);
07951 
07952         }
07953     }
07954 
07955 }
07956 
07957 **********************************/
07958 
07959 
07960 /* 
07961  * @brief
07962  *   Delete a column segment.
07963  *
07964  * @param column  Column to be accessed.
07965  * @param start   Position of first column element to delete.
07966  * @param count   Number of column elements to delete.
07967  *
07968  * @return @c CPL_ERROR_NONE on success. If @em start is outside the 
07969  *   column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If the 
07970  *   input column has length zero, the @c CPL_ERROR_ACCESS_OUT_OF_RANGE is
07971  *   always returned. If @em count is negative, a @c CPL_ERROR_ILLEGAL_INPUT 
07972  *   is returned.
07973  *
07974  * Delete a column segment. This is different from invalidating a column 
07975  * segment, as done by @c xxx_column_fill_invalid(): here a portion of 
07976  * the data is physically removed, and the column data buffer shortened 
07977  * proportionally. The pointer to data may change (therefore pointers 
07978  * previously retrieved by calling @c xxx_column_get_data_int(), 
07979  * @c xxx_column_get_data_string(), etc., should be discarded). The 
07980  * specified segment can go beyond the end of the column, and even all 
07981  * of the column data elements can be removed.
07982  */
07983 
07984 cpl_error_code xxx_column_erase_segment(xxx_column *column, 
07985                                         int start, int count)
07986 {
07987 
07988     const char     *fid        = "xxx_column_erase_segment";
07989     cpl_type         type       = xxx_column_get_type(column);
07990     int              old_length = xxx_column_get_size(column);
07991     int              new_length;
07992     int              end;
07993     int              i;
07994     int              j;
07995     cpl_array      **ap1;
07996     cpl_array      **ap2;
07997     char           **sp1;
07998     char           **sp2;
07999     int             *ip1;
08000     int             *ip2;
08001     float           *fp1;
08002     float           *fp2;
08003     double          *dp1;
08004     double          *dp2;
08005 
08006 
08007     if (column == 0x0)
08008         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
08009 
08010     if (start < 0 || start >= old_length)
08011         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
08012 
08013     if (count < 0)
08014         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
08015 
08016     if (count == 0)
08017         return CPL_ERROR_NONE;
08018 
08019     if (count > old_length - start)
08020         count = old_length - start;
08021 
08022     new_length = old_length - count; 
08023     end = start + count;
08024 
08025     if (end == old_length)
08026         return xxx_column_set_size(column, start);
08027 
08028     if (type == CPL_TYPE_STRING) {
08029 
08030         /*
08031          *  If a column of character strings is shortened, we must
08032          *  free explicitly the extra strings.
08033          */
08034 
08035         sp1 = column->values->s + start;
08036 
08037         for (i = start; i < end; i++, sp1++)
08038             if (*sp1)
08039                 cpl_free(*sp1);
08040     }
08041 
08042     if (type & CPL_TYPE_POINTER) {
08043 
08044         /*
08045          *  If a column of arrays is shortened, we must
08046          *  free explicitly the extra arrays.
08047          */
08048 
08049         ap1 = column->values->array + start;
08050 
08051         for (i = start; i < end; i++, ap1++)
08052             if (*ap1)
08053                 cpl_array_delete(*ap1);
08054     }
08055 
08056 
08057     /*
08058      *  Cut the slice from the invalid flags buffer, if present, 
08059      *  counting how many invalid elements will be lost.
08060      */
08061 
08062     if (column->null) {
08063 
08064         i = start;
08065         while (i < end) {
08066             if (column->null[i])
08067                 column->nullcount--;
08068             i++;
08069         }
08070 
08071         if (column->nullcount == 0 || column->nullcount == new_length) {
08072 
08073             /*
08074              *  Since either no invalid or just invalid elements are left, 
08075              *  the invalid flag buffer can be released.
08076              */
08077 
08078             if (column->null)
08079                 cpl_free(column->null);
08080             column->null = NULL;
08081 
08082         }
08083         else {
08084 
08085             /*
08086              *  Shift up NULL flags that are after the slice.
08087              */
08088 
08089             i = start;
08090             j = end;
08091             while (j < old_length) {
08092                 column->null[i] = column->null[j];
08093                 i++;
08094                 j++;
08095             }
08096 
08097             /*
08098              *  Get rid of extra memory.
08099              */
08100 
08101             column->null = cpl_realloc(column->null,
08102                            new_length * sizeof(xxx_column_flag));
08103 
08104         }
08105     }
08106     else {
08107 
08108         /*
08109          *  There is no invalid flag buffer, so either there are no 
08110          *  invalid elements or there are just invalid elements. If 
08111          *  there are no invalid elements, nullcount stays zero. If 
08112          *  there are just invalid elements, nullcount must be set 
08113          *  to the new column length.
08114          */
08115 
08116         if (column->nullcount == old_length)
08117             column->nullcount = new_length;
08118 
08119     }
08120 
08121 
08122     /*
08123      *  Now take care of data values
08124      */
08125 
08126     if ((type == CPL_TYPE_STRING) || (type & CPL_TYPE_POINTER))
08127         column->nullcount = 0;
08128 
08129     if (column->nullcount != new_length) {
08130 
08131         /*
08132          *  Column has not just invalid elements. In this case we have to
08133          *  shift also the data to fill the gap.
08134          */
08135 
08136         ip1 = column->values->i + start;
08137         ip2 = column->values->i + end;
08138         fp1 = column->values->f + start;
08139         fp2 = column->values->f + end;
08140         dp1 = column->values->d + start;
08141         dp2 = column->values->d + end;
08142         sp1 = column->values->s + start;
08143         sp2 = column->values->s + end;
08144         ap1 = column->values->array + start;
08145         ap2 = column->values->array + end;
08146 
08147         switch (type) {
08148         case CPL_TYPE_INT:
08149             for (j = end; j < old_length; j++)
08150                 *ip1++ = *ip2++;
08151             break;
08152         case CPL_TYPE_FLOAT:
08153             for (j = end; j < old_length; j++)
08154                 *fp1++ = *fp2++;
08155             break;
08156         case CPL_TYPE_DOUBLE:
08157             for (j = end; j < old_length; j++)
08158                 *dp1++ = *dp2++;
08159             break;
08160         case CPL_TYPE_STRING:
08161             for (j = end; j < old_length; j++)
08162                 *sp1++ = *sp2++;
08163             break;
08164         default:     /* Array columns */
08165             for (j = end; j < old_length; j++)
08166                 *ap1++ = *ap2++;
08167             break;
08168         }
08169 
08170     }
08171 
08172 
08173     /*
08174      *  Finally, reallocate the data buffer.
08175      */
08176 
08177     column->values->i = cpl_realloc(column->values->i,
08178                         new_length * xxx_column_type_size(type));
08179 
08180     column->length = new_length;
08181 
08182     return 0;
08183 
08184 }
08185 
08186 
08187 
08188 /*
08189  * @brief
08190  *   Insert a segment into column data.
08191  *
08192  * @param column  Column to be accessed.
08193  * @param start   Column element where to insert the segment.
08194  * @param count   Length of segment.
08195  *
08196  * @return @c CPL_ERROR_NONE on success. If @em start is negative,
08197  *   a @c CPL_ERROR_ACCESS_OUT_OF_RANGE is returned. If @em count 
08198  *   is negative, a @c CPL_ERROR_ILLEGAL_INPUT is returned.
08199  *
08200  * Insert a segment of new values in the column data buffer. The
08201  * new segment consists of a sequence of invalid (not initialised)
08202  * column elements. This is different from invalidating a column data 
08203  * segment, as done by @c xxx_column_fill_invalid(): here a portion 
08204  * of new data is physically inserted, and the column data buffer 
08205  * is made proportionally longer. Setting @em start to a number 
08206  * not less than the column length is legal, and has the effect of 
08207  * appending at the end of the column as many invalid elements as 
08208  * specified by the @em count argument (this is equivalent to expanding 
08209  * a column using @c xxx_column_set_size() ). The input @em column may
08210  * also have zero length. The pointer to data may change, therefore 
08211  * pointers previously retrieved by calling @c xxx_column_get_data_int(), 
08212  * @c xxx_column_get_data_string(), etc., should be discarded.
08213  */
08214 
08215 cpl_error_code xxx_column_insert_segment(xxx_column *column, 
08216                                          int start, int count)
08217 {
08218 
08219     const char *fid        = "xxx_column_insert_segment";
08220     cpl_type     type       = xxx_column_get_type(column);
08221     int          old_length = xxx_column_get_size(column);
08222     int          new_length = old_length + count;
08223     int          i;
08224     cpl_array  **ap1;
08225     cpl_array  **ap2;
08226     char       **sp1;
08227     char       **sp2;
08228     int         *ip1;
08229     int         *ip2;
08230     float       *fp1;
08231     float       *fp2;
08232     double      *dp1;
08233     double      *dp2;
08234     int         *np1;
08235     int         *np2;
08236 
08237 
08238     if (column == 0x0)
08239         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
08240 
08241     if (start < 0)
08242         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
08243 
08244     if (count < 0)
08245         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
08246 
08247     if (count == 0)
08248         return CPL_ERROR_NONE;
08249 
08250     if (xxx_column_set_size(column, new_length)) {
08251         cpl_error_set_where(fid);
08252         return cpl_error_get_code();
08253     }
08254 
08255     if (start > old_length)
08256         return CPL_ERROR_NONE;
08257 
08258     ip1 = column->values->i + new_length;
08259     ip2 = column->values->i + old_length;
08260     fp1 = column->values->f + new_length;
08261     fp2 = column->values->f + old_length;
08262     dp1 = column->values->d + new_length;
08263     dp2 = column->values->d + old_length;
08264     sp1 = column->values->s + new_length;
08265     sp2 = column->values->s + old_length;
08266     ap1 = column->values->array + new_length;
08267     ap2 = column->values->array + old_length;
08268 
08269     switch (type) {
08270     case CPL_TYPE_INT:
08271         for (i = old_length; i > start; i--) {
08272             *--ip1 = *--ip2;
08273             *ip2 = 0;
08274         }
08275         break;
08276 
08277     case CPL_TYPE_FLOAT:
08278         for (i = old_length; i > start; i--) {
08279             *--fp1 = *--fp2;
08280             *fp2 = 0.0;
08281         }
08282         break;
08283 
08284     case CPL_TYPE_DOUBLE:
08285         for (i = old_length; i > start; i--) {
08286             *--dp1 = *--dp2;
08287             *dp2 = 0.0;
08288         }
08289         break;
08290 
08291     case CPL_TYPE_STRING:
08292         for (i = old_length; i > start; i--) {
08293             *--sp1 = *--sp2;
08294             *sp2 = 0x0;
08295         }
08296         break;
08297 
08298     default:                   /* Array columns */
08299         for (i = old_length; i > start; i--) {
08300             *--ap1 = *--ap2;
08301             *ap2 = 0x0;
08302         }
08303         break;
08304     }
08305 
08306 
08307     /*
08308      *  Handling the invalid flags it's simple: all the hard work
08309      *  was actually done by xxx_column_set_size(). If the invalid
08310      *  flags buffer exists, we have just to shift the flags to
08311      *  the proper place.
08312      */
08313 
08314     if (column->null) {
08315 
08316         np1 = column->null + new_length;
08317         np2 = column->null + old_length;
08318 
08319         for (i = old_length; i > start; i--) {
08320             *--np1 = *--np2;
08321             *np2 = 1;
08322         }
08323 
08324     }
08325 
08326     return CPL_ERROR_NONE;
08327 
08328 }
08329 
08330 
08331 /*
08332  * @brief
08333  *   Make a copy of a column.
08334  *
08335  * @param column  Column to be duplicated.
08336  *
08337  * @return Pointer to the new column, or @c NULL in case of error.
08338  *
08339  * If the input @em column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT
08340  * is returned. Copy is "in depth": in the case of a @em string column, 
08341  * also the string elements are duplicated.
08342  */
08343 
08344 xxx_column *xxx_column_duplicate(xxx_column *column)
08345 {
08346 
08347     const char *fid        = "xxx_column_duplicate";
08348     cpl_type     type       = xxx_column_get_type(column);
08349     int          length     = xxx_column_get_size(column);
08350     int          depth      = xxx_column_get_depth(column);
08351     xxx_column  *new_column = NULL;
08352 
08353 
08354     if (column == 0x0) {
08355         cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
08356         return NULL;
08357     }
08358 
08359     switch (type) {
08360     case CPL_TYPE_INT:
08361         new_column = xxx_column_new_int(length);
08362         break;
08363     case CPL_TYPE_FLOAT:
08364         new_column = xxx_column_new_float(length);
08365         break;
08366     case CPL_TYPE_DOUBLE:
08367         new_column = xxx_column_new_double(length);
08368         break;
08369     case CPL_TYPE_STRING:
08370         new_column = xxx_column_new_string(length);
08371         break;
08372     case CPL_TYPE_INT | CPL_TYPE_POINTER:
08373     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
08374     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
08375     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
08376         new_column = xxx_column_new_array(type, length, depth);
08377         break;
08378     default:
08379         cpl_error_set(fid, CPL_ERROR_UNSPECIFIED);
08380         return NULL;
08381     }
08382 
08383     xxx_column_set_name(new_column, xxx_column_get_name(column));
08384     xxx_column_set_unit(new_column, xxx_column_get_unit(column));
08385     xxx_column_set_format(new_column, xxx_column_get_format(column));
08386 
08387     if (length == 0)
08388         return new_column;
08389 
08390     if (type == CPL_TYPE_STRING) {
08391         while (length--) {
08392             if (column->values->s[length]) {
08393                 new_column->values->s[length] = 
08394                                    cpl_strdup(column->values->s[length]);
08395             }
08396             else {
08397                 new_column->values->s[length] = NULL;
08398             }
08399         }
08400         return new_column;
08401     }
08402 
08403     if (type & CPL_TYPE_POINTER) {
08404         while (length--) {
08405             if (column->values->array[length]) {
08406                 new_column->values->array[length] =
08407                     cpl_array_duplicate(column->values->array[length]);
08408             }
08409             else {
08410                 new_column->values->array[length] = NULL;
08411             }
08412         }
08413 
08414         if (column->dimensions)
08415             new_column->dimensions = cpl_array_duplicate(column->dimensions);
08416 
08417         return new_column;
08418     }
08419 
08420     memcpy(new_column->values->i, column->values->i, 
08421            length * xxx_column_type_size(type));
08422 
08423     new_column->nullcount = column->nullcount;
08424 
08425     if (column->null) {
08426         new_column->null = cpl_malloc(length * sizeof(xxx_column_flag));
08427         memcpy(new_column->null, column->null, 
08428                length * sizeof(xxx_column_flag));
08429     }
08430 
08431     return new_column;
08432 
08433 }
08434 
08435 
08436 /*
08437  * @brief
08438  *   Cast a numerical column to a new @em integer column.
08439  *
08440  * @param column  Column to be cast.
08441  *
08442  * @return Pointer to the new columnm, or @em NULL in case of error.
08443  *
08444  * If the accessed column is of type either string or array of strings, 
08445  * a @c CPL_ERROR_INVALID_TYPE is set. If the input is a @c NULL pointer, 
08446  * a @c CPL_ERROR_NULL_INPUT is set. The output column is nameless, 
08447  * and with the default format for its type (see function 
08448  * @c xxx_column_set_format() ). However, if the input column is 
08449  * also @em integer, a simple copy is made and the column format 
08450  * is inherited. The input column units are always preserved in the
08451  * output column. Note that a column of arrays is always cast to 
08452  * another column of @em integer arrays. It is not allowed to cast 
08453  * a column of arrays into a column of plain integers.
08454  */
08455 
08456 
08457 
08458 /*
08459  * @brief
08460  *   Cast a numeric column to a new @em float column.
08461  *
08462  * @param column  Column to be cast.
08463  *
08464  * @return Pointer to the new columnm, or @em NULL in case of error. 
08465  *
08466  * If the accessed column is of type either string or array of strings,
08467  * a @c CPL_ERROR_INVALID_TYPE is set. If the input is a @c NULL 
08468  * pointer, a @c CPL_ERROR_NULL_INPUT is set. The output column is 
08469  * nameless, and with the default format for its type (see function
08470  * @c xxx_column_set_format() ). However, if the input column is
08471  * also @em float, a simple copy is made and the column format
08472  * is inherited. The input column units are always preserved in the
08473  * output column. Note that a column of arrays is always cast to
08474  * another column of @em float arrays. It is not allowed to cast
08475  * a column of arrays into a column of plain floats.
08476  */
08477 
08478 
08479 
08480 /* 
08481  * @brief
08482  *   Create a column from an interval of another column.
08483  *
08484  * @param column  Input column.
08485  * @param start   First element to be copied to new column.
08486  * @param count   Number of elements to be copied.
08487  *
08488  * @return Pointer to the new column, or @c NULL in case of error.
08489  *
08490  * If the input column is @c NULL, @c CPL_ERROR_NULL_INPUT is set. If 
08491  * @em start is outside the column range, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
08492  * is set. If the input column has length zero, this error is always 
08493  * set. If @em count is negative, a @c CPL_ERROR_ILLEGAL_INPUT is set. 
08494  * If @em count is zero, a zero-length column is created. 
08495  * If @em start + @em count goes beyond the end of the input column, 
08496  * elements are always copied up to the end. The new column is nameless, 
08497  * but it inherits the unit and the format of the source column. Existing 
08498  * invalid element flags are also transferred to the new column.
08499  */
08500 
08501 xxx_column *xxx_column_extract(xxx_column *column, int start, int count)
08502 {
08503 
08504     const char *fid        = "xxx_column_extract";
08505     xxx_column  *new_column = NULL;
08506     cpl_type     type       = xxx_column_get_type(column);
08507     int          length     = xxx_column_get_size(column);
08508     int          depth      = xxx_column_get_depth(column);
08509     int          byte_count;
08510     int          i;
08511     int          j;
08512 
08513 
08514     if (column == 0x0) {
08515         cpl_error_set_where(fid);
08516         return NULL;
08517     }
08518 
08519     if (start < 0 || start >= length) {
08520         cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
08521         return NULL;
08522     }
08523 
08524     if (count < 0) {
08525         cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
08526         return NULL;
08527     }
08528 
08529     if (count > length - start)
08530         count = length - start;
08531 
08532     byte_count  = count * xxx_column_type_size(type);
08533 
08534     switch (type) {
08535 
08536     case CPL_TYPE_INT:
08537         new_column = xxx_column_new_int(count);
08538         if (count)
08539             memcpy(new_column->values->i, 
08540                    column->values->i + start, byte_count);
08541         break;
08542 
08543     case CPL_TYPE_FLOAT:
08544         new_column = xxx_column_new_float(count);
08545         if (count)
08546             memcpy(new_column->values->f, 
08547                    column->values->f + start, byte_count);
08548         break;
08549 
08550     case CPL_TYPE_DOUBLE:
08551         new_column = xxx_column_new_double(count);
08552         if (count)
08553             memcpy(new_column->values->d, 
08554                    column->values->d + start, byte_count);
08555         break;
08556 
08557     case CPL_TYPE_STRING:
08558         new_column = xxx_column_new_string(count);
08559         for (i = 0, j = start; i < count; i++, j++)
08560             if (column->values->s[j])
08561                 new_column->values->s[i] = cpl_strdup(column->values->s[j]);
08562             else
08563                 new_column->values->s[i] = NULL;
08564         break;
08565 
08566     case CPL_TYPE_INT | CPL_TYPE_POINTER:
08567     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
08568     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
08569     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
08570 
08571         new_column = xxx_column_new_array(type, count, depth);
08572         for (i = 0, j = start; i < count; i++, j++) {
08573             if (column->values->array[j])
08574                 new_column->values->array[i] = 
08575                       cpl_array_duplicate(column->values->array[j]);
08576             else
08577                 new_column->values->array[i] = NULL;
08578         }
08579 
08580         if (column->dimensions)
08581             new_column->dimensions = cpl_array_duplicate(column->dimensions);
08582 
08583         break;
08584 
08585     default:
08586         cpl_error_set(fid, CPL_ERROR_UNSPECIFIED);
08587         return NULL;
08588         break;
08589     }
08590 
08591     xxx_column_set_unit(new_column, xxx_column_get_unit(column));
08592     xxx_column_set_format(new_column, xxx_column_get_format(column));
08593 
08594     if (column->null) {
08595 
08596         /*
08597          *  If an invalid flags buffer exists in the original column,
08598          *  we have to take care of the (possible) duplication of
08599          *  the appropriate segment.
08600          */
08601 
08602         new_column->nullcount = 0;
08603         for (i = 0, j = start; i < count; i++, j++)
08604             if (column->null[j])
08605                 new_column->nullcount++;
08606 
08607         if (new_column->nullcount != 0 && 
08608             new_column->nullcount != count) {
08609             new_column->null = cpl_calloc(count, sizeof(xxx_column_flag));
08610             for (i = 0, j = start; i < count; i++, j++)
08611                 if (column->null[j])
08612                     new_column->null[i] = 1;
08613         }
08614 
08615     }
08616     else {
08617 
08618       /* 
08619        *  An invalid flag buffer doesn't exist in the original column,
08620        *  and this means no invalid elements, or all elements are invalid, 
08621        *  also for the subcolumn.
08622        */
08623 
08624       if (column->nullcount == 0)
08625           new_column->nullcount = 0;
08626       else
08627           new_column->nullcount = xxx_column_get_size(new_column);
08628           
08629     }
08630 
08631     return new_column;
08632 
08633 }
08634 
08635   
08636 /*
08637  * @brief
08638  *   Insert a column into another column of the same type.
08639  *
08640  * @param target_column Target column.
08641  * @param insert_column Column to be inserted in target column.
08642  * @param position      Position of target where to insert.
08643  *
08644  * @return @c CPL_ERROR_NONE on success. If any input column is a @c NULL 
08645  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the columns are 
08646  *   not of the same type, a @c CPL_ERROR_TYPE_MISMATCH is returned.
08647  *   If @em position is negative, a @c CPL_ERROR_ACCESS_OUT_OF_RANGE 
08648  *   is returned.
08649  *
08650  * The first element of the column to be inserted will be at the 
08651  * specified @em position. If the specified @em position is not 
08652  * less than the target column length, the second column will be 
08653  * appended to the target column. The output column is expanded 
08654  * to host the values copied from the input column, that is left 
08655  * untouched. In the @em target column the pointer to target data 
08656  * may change, therefore pointers previously retrieved by calling 
08657  * @c xxx_column_get_data_int(), @c xxx_column_get_data_string(), 
08658  * etc., should be discarded). Information about columns dimensions 
08659  * (in case of array columns) is ignored.
08660  */
08661 
08662 cpl_error_code xxx_column_merge(xxx_column *target_column, 
08663                                 xxx_column *insert_column, int position)
08664 {
08665 
08666     const char *fid      = "xxx_column_merge";
08667     int          t_length = xxx_column_get_size(target_column);
08668     int          i_length = xxx_column_get_size(insert_column);
08669     cpl_type     t_type   = xxx_column_get_type(target_column);
08670     cpl_type     i_type   = xxx_column_get_type(insert_column);
08671     int          i_size   = i_length * xxx_column_type_size(i_type);
08672     int          i;
08673     int          j;
08674 
08675 
08676     if (target_column == 0x0 || insert_column == 0x0)
08677         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
08678 
08679     if (position < 0) 
08680         return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE);
08681 
08682     if (t_type != i_type)
08683         return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH);
08684 
08685     if (i_length == 0)
08686         return CPL_ERROR_NONE;
08687 
08688     if (position > t_length)
08689         position = t_length;
08690 
08691 
08692     /*
08693      *  First of all, a segment of invalid elements is inserted at the
08694      *  right position.
08695      */
08696 
08697     xxx_column_insert_segment(target_column, position, i_length);
08698 
08699 
08700     /*
08701      *  If the column to be inserted just consists of invalid elements, 
08702      *  the job is already completed.
08703      */
08704 
08705     if (xxx_column_count_invalid(insert_column) == i_length)
08706         return CPL_ERROR_NONE;
08707 
08708 
08709     /*
08710      *  Transferring the data from the column to be inserted,
08711      *  to the expanded part of the target column:
08712      */
08713 
08714     t_length = xxx_column_get_size(target_column);     /* It got longer */
08715 
08716     switch (i_type) {
08717 
08718     case CPL_TYPE_INT:
08719         memcpy(target_column->values->i + position, 
08720                insert_column->values->i, i_size);
08721         break;
08722 
08723     case CPL_TYPE_FLOAT:
08724         memcpy(target_column->values->f + position, 
08725                insert_column->values->f, i_size);
08726         break;
08727 
08728     case CPL_TYPE_DOUBLE:
08729         memcpy(target_column->values->d + position, 
08730                insert_column->values->d, i_size);
08731         break;
08732 
08733     case CPL_TYPE_STRING:
08734         for (i = 0, j = position; i < i_length; i++, j++)
08735             if (insert_column->values->s[i])
08736                 target_column->values->s[j] = 
08737                                        cpl_strdup(insert_column->values->s[i]);
08738         break;
08739 
08740     case CPL_TYPE_INT | CPL_TYPE_POINTER:
08741     case CPL_TYPE_FLOAT | CPL_TYPE_POINTER:
08742     case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER:
08743     case CPL_TYPE_STRING | CPL_TYPE_POINTER:
08744         for (i = 0, j = position; i < i_length; i++, j++)
08745             if (insert_column->values->array[i])
08746                 target_column->values->array[j] =
08747                     cpl_array_duplicate(insert_column->values->array[i]);
08748         break;
08749 
08750     default:
08751         return cpl_error_set(fid, CPL_ERROR_UNSPECIFIED);
08752 
08753     }
08754 
08755     if ((i_type == CPL_TYPE_STRING) || (i_type & CPL_TYPE_POINTER))
08756         return CPL_ERROR_NONE;
08757 
08758 
08759     /*
08760      *  Now also the null flags buffer must be upgraded.
08761      */
08762 
08763     if (target_column->null) {
08764 
08765         if (insert_column->null) {
08766 
08767             /*
08768              *  Both null flags buffers exist. The expanded part of
08769              *  the target column already consists of invalid elements, 
08770              *  so just overwrite valid elements from the first column:
08771              */
08772 
08773             for (i = 0, j = position; i < i_length; i++, j++) {
08774                 if (!insert_column->null[i]) {
08775                     target_column->null[j] = 0;
08776                     target_column->nullcount--;
08777                 } 
08778             } 
08779         }
08780         else {
08781 
08782 
08783             /*
08784              *  Just the target column has the invalid flag buffer. This
08785              *  means necessarily that the column to insert has no invalid
08786              *  elements (the other possibility, that the column to insert
08787              *  just consists of invalid elements, was already handled at
08788              *  the beginning). Then we must turn all the invalid elements
08789              *  of the target expanded interval of the null flag buffer 
08790              *  into valid.
08791              */
08792 
08793             if (target_column->nullcount > i_length) {
08794 
08795 
08796                 /*
08797                  *  Surely target_column->nullcount is at least i_length,
08798                  *  i.e., the number of invalid elements added by the
08799                  *  expansion. If target_column->nullcount is equal to 
08800                  *  i_length, then these are the only invalid elements 
08801                  *  existing, and they would be all unset, therefore it 
08802                  *  would be enough to free the null flags buffer skipping 
08803                  *  this loop.
08804                  */
08805 
08806                 for (i = 0, j = position; i < i_length; i++, j++)
08807                     target_column->null[j] = 0;
08808             }
08809 
08810             target_column->nullcount -= i_length;
08811 
08812         }
08813     }
08814     else {
08815 
08816         /*
08817          *  The target column invalid flags buffer doesn't exist. 
08818          *  Excluding the case of array or string columns, this is
08819          *  necessarily because it just contains invalid elements, 
08820          *  since to expand it means just to add extra invalid elements. 
08821          *  The inserted column instead has some valid elements, that 
08822          *  must be transferred - therefore the target column invalid 
08823          *  flag buffer must be allocated.
08824          */
08825 
08826         target_column->null = cpl_malloc(t_length * sizeof(xxx_column_flag));
08827 
08828         i = t_length;
08829         while (i--)
08830             target_column->null[i] = 1;
08831 
08832         if (insert_column->null) {
08833 
08834            /*
08835             *  Some invalid elements:
08836             */
08837 
08838             for (i = 0, j = position; i < i_length; i++, j++) {
08839                 if (!insert_column->null[i]) {
08840                     target_column->null[j] = 0;
08841                     target_column->nullcount--;
08842                 }
08843             }
08844 
08845         }
08846         else {
08847 
08848             /*
08849              *  No invalid elements:
08850              */
08851 
08852             for (i = 0, j = position; i < i_length; i++, j++)
08853                 target_column->null[j] = 0;
08854 
08855             target_column->nullcount -= i_length;
08856         }
08857     }
08858 
08859 
08860     /*
08861      *  If no invalid elements are left, free the invalid flags buffer
08862      */
08863 
08864     if (target_column->nullcount == 0) {
08865         if (target_column->null)
08866             cpl_free(target_column->null);
08867         target_column->null = NULL;
08868     }
08869 
08870     return 0;
08871 
08872 }
08873 
08874 
08875 /*
08876  * @brief
08877  *   Add two numerical columns.
08878  *
08879  * @param to_column   Target column.
08880  * @param from_column Column to be summed to target column.
08881  * 
08882  * @return @c CPL_ERROR_NONE on success. If any of the input columns
08883  *   is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If 
08884  *   any of the input columns is of type string, a @c CPL_ERROR_INVALID_TYPE
08885  *   is returned. If the input columns do not have the same length, 
08886  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned. 
08887  *
08888  * The result of the sum is stored in the target colum. The type of the
08889  * columns may differ, and in that case the operation would be performed 
08890  * according to the C upcasting rules, with a final cast of the result to
08891  * the target column type. Invalid elements are propagated consistently: 
08892  * if either or both members of the sum are invalid, the result will be
08893  * invalid too. Underflows and overflows are ignored. This function is
08894  * not applicable to array columns.
08895  */
08896 
08897 cpl_error_code xxx_column_add(xxx_column *to_column, xxx_column *from_column)
08898 {
08899 
08900     const char *fid         = "xxx_column_add";
08901     int          i;
08902     int          to_length   = xxx_column_get_size(to_column);
08903     int          from_length = xxx_column_get_size(from_column);
08904     cpl_type     to_type     = xxx_column_get_type(to_column);
08905     cpl_type     from_type   = xxx_column_get_type(from_column);
08906 
08907     int         *fip;
08908     float       *ffp;
08909     double      *fdp;
08910     int         *tip;
08911     float       *tfp;
08912     double      *tdp;
08913     int         *tnp;
08914 
08915 
08916     if (to_column == 0x0 || from_column == 0x0)
08917         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
08918 
08919     if ((to_type == CPL_TYPE_STRING) || (from_type == CPL_TYPE_STRING) ||
08920         (to_type & CPL_TYPE_POINTER) || (from_type & CPL_TYPE_POINTER))
08921         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
08922 
08923     if (to_length != from_length)
08924         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
08925 
08926     if (to_length == 0)
08927         return CPL_ERROR_NONE;
08928 
08929     if (to_column->nullcount == to_length)
08930         return CPL_ERROR_NONE;
08931 
08932     if (from_column->nullcount == from_length)
08933         return xxx_column_fill_invalid(to_column, 0, to_length);
08934 
08935 
08936     fip = from_column->values->i;
08937     ffp = from_column->values->f;
08938     fdp = from_column->values->d;
08939     tip = to_column->values->i;
08940     tfp = to_column->values->f;
08941     tdp = to_column->values->d;
08942 
08943     if (to_column->nullcount == 0 && from_column->nullcount == 0) {
08944 
08945         /*
08946          * If there are no invalid elements in both columns, the operation 
08947          * can be performed without any check:
08948          */
08949 
08950         switch (to_type) {
08951 
08952         case CPL_TYPE_INT:
08953 
08954             switch (from_type) {
08955 
08956             case CPL_TYPE_INT:
08957                 while (to_length--)
08958                     *tip++ += *fip++;
08959                 break;
08960 
08961             case CPL_TYPE_FLOAT:
08962                 while (to_length--)
08963                     *tip++ += *ffp++;
08964                 break;
08965 
08966             case CPL_TYPE_DOUBLE:
08967                 while (to_length--)
08968                     *tip++ += *fdp++;
08969                 break;
08970 
08971             default:
08972                 break;
08973             }
08974             break;
08975 
08976         case CPL_TYPE_FLOAT:
08977 
08978             switch (from_type) {
08979 
08980             case CPL_TYPE_INT:
08981                 while (to_length--)
08982                     *tfp++ += (double)*fip++;
08983                 break;
08984 
08985             case CPL_TYPE_FLOAT:
08986                 while (to_length--)
08987                     *tfp++ += (double)*ffp++;
08988                 break;
08989 
08990             case CPL_TYPE_DOUBLE:
08991                 while (to_length--)
08992                     *tfp++ += *fdp++;
08993                 break;
08994             
08995             default:
08996                 break;
08997             }
08998             break;
08999 
09000         case CPL_TYPE_DOUBLE:
09001 
09002             switch (from_type) {
09003 
09004             case CPL_TYPE_INT:
09005                 while (to_length--)
09006                     *tdp++ += *fip++;
09007                 break;
09008 
09009             case CPL_TYPE_FLOAT:
09010                 while (to_length--)
09011                     *tdp++ += *ffp++;
09012                 break;
09013 
09014             case CPL_TYPE_DOUBLE:
09015                 while (to_length--)
09016                     *tdp++ += *fdp++;
09017                 break;
09018             
09019             default:
09020                 break;
09021             }
09022             break;
09023 
09024         default:
09025             break;
09026         }
09027     }
09028     else {
09029 
09030         /*
09031          * Here there are some invalid elements, so the operation needs to be
09032          * performed with some checks. As a first thing, take care of the
09033          * invalid elements in the target column:
09034          */
09035 
09036         if (to_column->nullcount == 0 || from_column->nullcount == 0) {
09037 
09038             /*
09039              * Here there are some invalid elements in just one of the two 
09040              * columns. If they are just in the column to add, an identical 
09041              * invalid flags buffer must be created for the target column.
09042              */
09043 
09044             if (from_column->nullcount) {
09045                 to_column->null = cpl_calloc(to_length, 
09046                                              sizeof(xxx_column_flag));
09047 
09048                 i = to_length;
09049                 while (i--)
09050                     if (from_column->null[i])
09051                         to_column->null[i] = 1;
09052 
09053                 to_column->nullcount = from_column->nullcount;
09054 
09055             }
09056         }
09057         else {
09058 
09059             /*
09060              *  Here there are some invalid elements in both columns.
09061              */
09062 
09063             i = to_length;
09064             while (i--) {
09065                 if (from_column->null[i]) {
09066                     if (!to_column->null[i]) {
09067                         to_column->null[i] = 1;
09068                         to_column->nullcount++;
09069                     }
09070                 }
09071             }
09072 
09073             if (to_column->nullcount == to_length) {
09074 
09075                 /*
09076                  * Just invalid elements in the result: no need to perform 
09077                  * any further operation, and the invalid flag buffer of the 
09078                  * target column can be disabled.
09079                  */
09080 
09081                 if (to_column->null)
09082                     cpl_free(to_column->null);
09083                 to_column->null = NULL;
09084                 return 0;
09085             }
09086 
09087         }
09088 
09089         /*
09090          * The operation can be performed while checking the already
09091          * computed result invalid flags buffer of the target column.
09092          */
09093 
09094         tnp = to_column->null;
09095 
09096         switch (to_type) {
09097 
09098         case CPL_TYPE_INT:
09099 
09100             switch (from_type) {
09101 
09102             case CPL_TYPE_INT:
09103                 while (to_length--) {
09104                     if (*tnp++ == 0)
09105                         *tip += *fip;
09106                     tip++;
09107                     fip++;
09108                 }
09109                 break;
09110 
09111             case CPL_TYPE_FLOAT:
09112                 while (to_length--) {
09113                     if (*tnp++ == 0)
09114                         *tip += *ffp;
09115                     tip++;
09116                     ffp++;
09117                 }
09118                 break;
09119 
09120             case CPL_TYPE_DOUBLE:
09121                 while (to_length--) {
09122                     if (*tnp++ == 0)
09123                         *tip += *fdp;
09124                     tip++;
09125                     fdp++;
09126                 }
09127                 break;
09128 
09129             default:
09130                 break;
09131             }
09132             break;
09133 
09134         case CPL_TYPE_FLOAT:
09135 
09136             switch (from_type) {
09137 
09138             case CPL_TYPE_INT:
09139                 while (to_length--) {
09140                     if (*tnp++ == 0)
09141                         *tfp += (double)*fip;
09142                     tfp++;
09143                     fip++;
09144                 }
09145                 break;
09146 
09147             case CPL_TYPE_FLOAT:
09148                 while (to_length--) {
09149                     if (*tnp++ == 0)
09150                         *tfp += (double)*ffp;
09151                     tfp++;
09152                     ffp++;
09153                 }
09154                 break;
09155 
09156             case CPL_TYPE_DOUBLE:
09157                 while (to_length--) {
09158                     if (*tnp++ == 0)
09159                         *tfp += *fdp;
09160                     tfp++;
09161                     fdp++;
09162                 }
09163                 break;
09164             
09165             default:
09166                 break;
09167             }
09168             break;
09169 
09170         case CPL_TYPE_DOUBLE:
09171 
09172             switch (from_type) {
09173 
09174             case CPL_TYPE_INT:
09175                 while (to_length--) {
09176                     if (*tnp++ == 0)
09177                         *tdp += *fip;
09178                     tdp++;
09179                     fip++;
09180                 }
09181                 break;
09182 
09183             case CPL_TYPE_FLOAT:
09184                 while (to_length--) {
09185                     if (*tnp++ == 0)
09186                         *tdp += *ffp;
09187                     tdp++;
09188                     ffp++;
09189                 }
09190                 break;
09191 
09192             case CPL_TYPE_DOUBLE:
09193                 while (to_length--) {
09194                     if (*tnp++ == 0)
09195                         *tdp += *fdp;
09196                     tdp++;
09197                     fdp++;
09198                 }
09199                 break;
09200             
09201             default:
09202                 break;
09203             }
09204             break;
09205 
09206         default:
09207             break;
09208         }
09209     }
09210 
09211     return CPL_ERROR_NONE;
09212 
09213 }
09214 
09215 
09216 /* 
09217  * @brief
09218  *   Subtract two numeric columns.
09219  *
09220  * @param to_column   Target column.
09221  * @param from_column Column to subtract from target column.
09222  *
09223  * @return @c CPL_ERROR_NONE on success. If any of the input columns
09224  *   is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If
09225  *   any of the input columns is of type string, a @c CPL_ERROR_INVALID_TYPE
09226  *   is returned. If the input columns do not have the same length,
09227  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned.
09228  *
09229  * The result of the subtraction is stored in the target colum. The type of 
09230  * the columns may differ, and in that case the operation would be performed 
09231  * according to the C upcasting rules, with a final cast of the result to
09232  * the target column type. Invalid elements are propagated consistently: 
09233  * if either or both members of the subtraction are invalid, the result 
09234  * will be invalid too. Underflows and overflows are ignored. This function
09235  * is not applicable to array columns.
09236  */
09237 
09238 cpl_error_code xxx_column_subtract(xxx_column *to_column, 
09239                                    xxx_column *from_column)
09240 {
09241 
09242     const char *fid         = "xxx_column_subtract";
09243     int          i;
09244     int          to_length   = xxx_column_get_size(to_column);
09245     int          from_length = xxx_column_get_size(from_column);
09246     cpl_type     to_type     = xxx_column_get_type(to_column);
09247     cpl_type     from_type   = xxx_column_get_type(from_column);
09248 
09249     int         *fip;
09250     float       *ffp;
09251     double      *fdp;
09252     int         *tip;
09253     float       *tfp;
09254     double      *tdp;
09255     int         *tnp;
09256 
09257 
09258     if (to_column == 0x0 || from_column == 0x0)
09259         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
09260 
09261     if ((to_type == CPL_TYPE_STRING) || (from_type == CPL_TYPE_STRING) ||
09262         (to_type & CPL_TYPE_POINTER) || (from_type & CPL_TYPE_POINTER))
09263         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
09264 
09265     if (to_length != from_length)
09266         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
09267 
09268     if (to_length == 0)
09269         return CPL_ERROR_NONE;
09270 
09271     if (to_column->nullcount == to_length)
09272         return CPL_ERROR_NONE;
09273 
09274     if (from_column->nullcount == from_length)
09275         return xxx_column_fill_invalid(to_column, 0, to_length);
09276 
09277 
09278     fip = from_column->values->i;
09279     ffp = from_column->values->f;
09280     fdp = from_column->values->d;
09281     tip = to_column->values->i;
09282     tfp = to_column->values->f;
09283     tdp = to_column->values->d;
09284 
09285     if (to_column->nullcount == 0 && from_column->nullcount == 0) {
09286 
09287         /*
09288          * If there are no invalid elements in both columns, the operation 
09289          * can be performed without any check:
09290          */
09291 
09292         switch (to_type) {
09293 
09294         case CPL_TYPE_INT:
09295 
09296             switch (from_type) {
09297 
09298             case CPL_TYPE_INT:
09299                 while (to_length--)
09300                     *tip++ -= *fip++;
09301                 break;
09302 
09303             case CPL_TYPE_FLOAT:
09304                 while (to_length--)
09305                     *tip++ -= *ffp++;
09306                 break;
09307 
09308             case CPL_TYPE_DOUBLE:
09309                 while (to_length--)
09310                     *tip++ -= *fdp++;
09311                 break;
09312 
09313             default:
09314                 break;
09315             }
09316             break;
09317 
09318         case CPL_TYPE_FLOAT:
09319 
09320             switch (from_type) {
09321 
09322             case CPL_TYPE_INT:
09323                 while (to_length--)
09324                     *tfp++ -= (double)*fip++;
09325                 break;
09326 
09327             case CPL_TYPE_FLOAT:
09328                 while (to_length--)
09329                     *tfp++ -= (double)*ffp++;
09330                 break;
09331 
09332             case CPL_TYPE_DOUBLE:
09333                 while (to_length--)
09334                     *tfp++ -= *fdp++;
09335                 break;
09336             
09337             default:
09338                 break;
09339             }
09340             break;
09341 
09342         case CPL_TYPE_DOUBLE:
09343 
09344             switch (from_type) {
09345 
09346             case CPL_TYPE_INT:
09347                 while (to_length--)
09348                     *tdp++ -= *fip++;
09349                 break;
09350 
09351             case CPL_TYPE_FLOAT:
09352                 while (to_length--)
09353                     *tdp++ -= *ffp++;
09354                 break;
09355 
09356             case CPL_TYPE_DOUBLE:
09357                 while (to_length--)
09358                     *tdp++ -= *fdp++;
09359                 break;
09360             
09361             default:
09362                 break;
09363             }
09364             break;
09365 
09366         default:
09367             break;
09368         }
09369     }
09370     else {
09371 
09372         /*
09373          * Here there are some invalid elements, so the operation needs to be
09374          * performed with some checks. As a first thing, take care of the
09375          * invalid elements in the target column:
09376          */
09377 
09378         if (to_column->nullcount == 0 || from_column->nullcount == 0) {
09379 
09380             /*
09381              * Here there are some invalids in just one of the two columns.
09382              * If they are just in the column to add, an identical invalid
09383              * flags buffer must be created for the target column.
09384              */
09385 
09386             if (from_column->nullcount) {
09387                 to_column->null = cpl_calloc(to_length, sizeof(xxx_column_flag));
09388 
09389                 i = to_length;
09390                 while (i--)
09391                     if (from_column->null[i])
09392                         to_column->null[i] = 1;
09393 
09394                 to_column->nullcount = from_column->nullcount;
09395 
09396             }
09397         }
09398         else {
09399 
09400             /*
09401              *  Here there are some invalids in both columns.
09402              */
09403 
09404             i = to_length;
09405             while (i--) {
09406                 if (from_column->null[i]) {
09407                     if (!to_column->null[i]) {
09408                         to_column->null[i] = 1;
09409                         to_column->nullcount++;
09410                     }
09411                 }
09412             }
09413 
09414             if (to_column->nullcount == to_length) {
09415 
09416                 /*
09417                  * Just invalids in the result: no need to perform any further
09418                  * operation, and the invalid buffer of the target column can
09419                  * be disabled.
09420                  */
09421 
09422                 if (to_column->null)
09423                     cpl_free(to_column->null);
09424                 to_column->null = NULL;
09425                 return 0;
09426             }
09427 
09428         }
09429 
09430         /*
09431          * The operation can be performed while checking the already
09432          * computed result invalid flags buffer of the target column.
09433          */
09434 
09435         tnp = to_column->null;
09436 
09437         switch (to_type) {
09438 
09439         case CPL_TYPE_INT:
09440 
09441             switch (from_type) {
09442 
09443             case CPL_TYPE_INT:
09444                 while (to_length--) {
09445                     if (*tnp++ == 0)
09446                         *tip -= *fip;
09447                     tip++;
09448                     fip++;
09449                 }
09450                 break;
09451 
09452             case CPL_TYPE_FLOAT:
09453                 while (to_length--) {
09454                     if (*tnp++ == 0)
09455                         *tip -= *ffp;
09456                     tip++;
09457                     ffp++;
09458                 }
09459                 break;
09460 
09461             case CPL_TYPE_DOUBLE:
09462                 while (to_length--) {
09463                     if (*tnp++ == 0)
09464                         *tip -= *fdp;
09465                     tip++;
09466                     fdp++;
09467                 }
09468                 break;
09469 
09470             default:
09471                 break;
09472             }
09473             break;
09474 
09475         case CPL_TYPE_FLOAT:
09476 
09477             switch (from_type) {
09478 
09479             case CPL_TYPE_INT:
09480                 while (to_length--) {
09481                     if (*tnp++ == 0)
09482                         *tfp -= (double)*fip;
09483                     tfp++;
09484                     fip++;
09485                 }
09486                 break;
09487 
09488             case CPL_TYPE_FLOAT:
09489                 while (to_length--) {
09490                     if (*tnp++ == 0)
09491                         *tfp -= (double)*ffp;
09492                     tfp++;
09493                     ffp++;
09494                 }
09495                 break;
09496 
09497             case CPL_TYPE_DOUBLE:
09498                 while (to_length--) {
09499                     if (*tnp++ == 0)
09500                         *tfp -= *fdp;
09501                     tfp++;
09502                     fdp++;
09503                 }
09504                 break;
09505             
09506             default:
09507                 break;
09508             }
09509             break;
09510 
09511         case CPL_TYPE_DOUBLE:
09512 
09513             switch (from_type) {
09514 
09515             case CPL_TYPE_INT:
09516                 while (to_length--) {
09517                     if (*tnp++ == 0)
09518                         *tdp -= *fip;
09519                     tdp++;
09520                     fip++;
09521                 }
09522                 break;
09523 
09524             case CPL_TYPE_FLOAT:
09525                 while (to_length--) {
09526                     if (*tnp++ == 0)
09527                         *tdp -= *ffp;
09528                     tdp++;
09529                     ffp++;
09530                 }
09531                 break;
09532 
09533             case CPL_TYPE_DOUBLE:
09534                 while (to_length--) {
09535                     if (*tnp++ == 0)
09536                         *tdp -= *fdp;
09537                     tdp++;
09538                     fdp++;
09539                 }
09540                 break;
09541             
09542             default:
09543                 break;
09544             }
09545             break;
09546 
09547         default:
09548             break;
09549         }
09550     }
09551 
09552     return CPL_ERROR_NONE;
09553 
09554 }
09555 
09556 
09557 /*
09558  * @brief
09559  *   Multiply two numeric columns.
09560  *
09561  * @param to_column   Target column.
09562  * @param from_column Multiplier column.
09563  *
09564  * @return @c CPL_ERROR_NONE on success. If any of the input columns
09565  *   is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If
09566  *   any of the input columns is of type string, a @c CPL_ERROR_INVALID_TYPE
09567  *   is returned. If the input columns do not have the same length,
09568  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned.
09569  *
09570  * The result of the multiplication is stored in the target colum. The type of
09571  * the columns may differ, and in that case the operation would be performed
09572  * according to the C upcasting rules, with a final cast of the result to
09573  * the target column type. Invalid elements are propagated consistently:
09574  * if either or both members of the multiplication are invalid, the result
09575  * will be invalid too. Underflows and overflows are ignored. This function
09576  * is not applicable to array columns.
09577  */
09578 
09579 cpl_error_code xxx_column_multiply(xxx_column *to_column, 
09580                                    xxx_column *from_column)
09581 {
09582 
09583     const char *fid         = "xxx_column_multiply";
09584     int          i;
09585     int          to_length   = xxx_column_get_size(to_column);
09586     int          from_length = xxx_column_get_size(from_column);
09587     cpl_type     to_type     = xxx_column_get_type(to_column);
09588     cpl_type     from_type   = xxx_column_get_type(from_column);
09589 
09590     int         *fip;
09591     float       *ffp;
09592     double      *fdp;
09593     int         *tip;
09594     float       *tfp;
09595     double      *tdp;
09596     int         *tnp;
09597 
09598 
09599     if (to_column == 0x0 || from_column == 0x0)
09600         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
09601 
09602     if ((to_type == CPL_TYPE_STRING) || (from_type == CPL_TYPE_STRING) ||
09603         (to_type & CPL_TYPE_POINTER) || (from_type & CPL_TYPE_POINTER))
09604         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
09605 
09606     if (to_length != from_length)
09607         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
09608 
09609     if (to_length == 0)
09610         return CPL_ERROR_NONE;
09611 
09612     if (to_column->nullcount == to_length)
09613         return CPL_ERROR_NONE;
09614 
09615     if (from_column->nullcount == from_length)
09616         return xxx_column_fill_invalid(to_column, 0, to_length);
09617 
09618 
09619     fip = from_column->values->i;
09620     ffp = from_column->values->f;
09621     fdp = from_column->values->d;
09622     tip = to_column->values->i;
09623     tfp = to_column->values->f;
09624     tdp = to_column->values->d;
09625 
09626     if (to_column->nullcount == 0 && from_column->nullcount == 0) {
09627 
09628         /*
09629          * If there are no invalids in both columns, the operation can
09630          * be performed without any check:
09631          */
09632 
09633         switch (to_type) {
09634 
09635         case CPL_TYPE_INT:
09636 
09637             switch (from_type) {
09638 
09639             case CPL_TYPE_INT:
09640                 while (to_length--)
09641                     *tip++ *= *fip++;
09642                 break;
09643 
09644             case CPL_TYPE_FLOAT:
09645                 while (to_length--)
09646                     *tip++ *= *ffp++;
09647                 break;
09648 
09649             case CPL_TYPE_DOUBLE:
09650                 while (to_length--)
09651                     *tip++ *= *fdp++;
09652                 break;
09653 
09654             default:
09655                 break;
09656             }
09657             break;
09658 
09659         case CPL_TYPE_FLOAT:
09660 
09661             switch (from_type) {
09662 
09663             case CPL_TYPE_INT:
09664                 while (to_length--)
09665                     *tfp++ *= (double)*fip++;
09666                 break;
09667 
09668             case CPL_TYPE_FLOAT:
09669                 while (to_length--)
09670                     *tfp++ *= (double)*ffp++;
09671                 break;
09672 
09673             case CPL_TYPE_DOUBLE:
09674                 while (to_length--)
09675                     *tfp++ *= *fdp++;
09676                 break;
09677             
09678             default:
09679                 break;
09680             }
09681             break;
09682 
09683         case CPL_TYPE_DOUBLE:
09684 
09685             switch (from_type) {
09686 
09687             case CPL_TYPE_INT:
09688                 while (to_length--)
09689                     *tdp++ *= *fip++;
09690                 break;
09691 
09692             case CPL_TYPE_FLOAT:
09693                 while (to_length--)
09694                     *tdp++ *= *ffp++;
09695                 break;
09696 
09697             case CPL_TYPE_DOUBLE:
09698                 while (to_length--)
09699                     *tdp++ *= *fdp++;
09700                 break;
09701             
09702             default:
09703                 break;
09704             }
09705             break;
09706 
09707         default:
09708             break;
09709         }
09710     }
09711     else {
09712 
09713         /*
09714          * Here there are some invalids around, so the operation needs to be
09715          * performed with some checks. As a first thing, take care of the
09716          * invalids pattern in the target column:
09717          */
09718 
09719         if (to_column->nullcount == 0 || from_column->nullcount == 0) {
09720 
09721             /*
09722              * Here there are some invalids in just one of the two columns.
09723              * If they are just in the column to add, an identical invalid
09724              * flags buffer must be created for the target column.
09725              */
09726 
09727             if (from_column->nullcount) {
09728                 to_column->null = cpl_calloc(to_length, sizeof(xxx_column_flag));
09729 
09730                 i = to_length;
09731                 while (i--)
09732                     if (from_column->null[i])
09733                         to_column->null[i] = 1;
09734 
09735                 to_column->nullcount = from_column->nullcount;
09736 
09737             }
09738         }
09739         else {
09740 
09741             /*
09742              *  Here there are some invalids in both columns.
09743              */
09744 
09745             i = to_length;
09746             while (i--) {
09747                 if (from_column->null[i]) {
09748                     if (!to_column->null[i]) {
09749                         to_column->null[i] = 1;
09750                         to_column->nullcount++;
09751                     }
09752                 }
09753             }
09754 
09755             if (to_column->nullcount == to_length) {
09756 
09757                 /*
09758                  * Just invalids in the result: no need to perform any further
09759                  * operation, and the invalid buffer of the target column can
09760                  * be disabled.
09761                  */
09762 
09763                 if (to_column->null)
09764                     cpl_free(to_column->null);
09765                 to_column->null = NULL;
09766                 return 0;
09767             }
09768 
09769         }
09770 
09771         /*
09772          * The operation can be performed while checking the already
09773          * computed result invalid flags buffer of the target column.
09774          */
09775 
09776         tnp = to_column->null;
09777 
09778         switch (to_type) {
09779 
09780         case CPL_TYPE_INT:
09781 
09782             switch (from_type) {
09783 
09784             case CPL_TYPE_INT:
09785                 while (to_length--) {
09786                     if (*tnp++ == 0)
09787                         *tip *= *fip;
09788                     tip++;
09789                     fip++;
09790                 }
09791                 break;
09792 
09793             case CPL_TYPE_FLOAT:
09794                 while (to_length--) {
09795                     if (*tnp++ == 0)
09796                         *tip *= *ffp;
09797                     tip++;
09798                     ffp++;
09799                 }
09800                 break;
09801 
09802             case CPL_TYPE_DOUBLE:
09803                 while (to_length--) {
09804                     if (*tnp++ == 0)
09805                         *tip *= *fdp;
09806                     tip++;
09807                     fdp++;
09808                 }
09809                 break;
09810 
09811             default:
09812                 break;
09813             }
09814             break;
09815 
09816         case CPL_TYPE_FLOAT:
09817 
09818             switch (from_type) {
09819 
09820             case CPL_TYPE_INT:
09821                 while (to_length--) {
09822                     if (*tnp++ == 0)
09823                         *tfp *= (double)*fip;
09824                     tfp++;
09825                     fip++;
09826                 }
09827                 break;
09828 
09829             case CPL_TYPE_FLOAT:
09830                 while (to_length--) {
09831                     if (*tnp++ == 0)
09832                         *tfp *= (double)*ffp;
09833                     tfp++;
09834                     ffp++;
09835                 }
09836                 break;
09837 
09838             case CPL_TYPE_DOUBLE:
09839                 while (to_length--) {
09840                     if (*tnp++ == 0)
09841                         *tfp *= *fdp;
09842                     tfp++;
09843                     fdp++;
09844                 }
09845                 break;
09846             
09847             default:
09848                 break;
09849             }
09850             break;
09851 
09852         case CPL_TYPE_DOUBLE:
09853 
09854             switch (from_type) {
09855 
09856             case CPL_TYPE_INT:
09857                 while (to_length--) {
09858                     if (*tnp++ == 0)
09859                         *tdp *= *fip;
09860                     tdp++;
09861                     fip++;
09862                 }
09863                 break;
09864 
09865             case CPL_TYPE_FLOAT:
09866                 while (to_length--) {
09867                     if (*tnp++ == 0)
09868                         *tdp *= *ffp;
09869                     tdp++;
09870                     ffp++;
09871                 }
09872                 break;
09873 
09874             case CPL_TYPE_DOUBLE:
09875                 while (to_length--) {
09876                     if (*tnp++ == 0)
09877                         *tdp *= *fdp;
09878                     tdp++;
09879                     fdp++;
09880                 }
09881                 break;
09882             
09883             default:
09884                 break;
09885             }
09886             break;
09887 
09888         default:
09889             break;
09890         }
09891     }
09892 
09893     return CPL_ERROR_NONE;
09894 
09895 }
09896 
09897 
09898 /*
09899  * @brief
09900  *   Divide two numeric columns.
09901  *
09902  * @param to_column   Target column.
09903  * @param from_column Divisor column.
09904  *
09905  * @return @c CPL_ERROR_NONE on success. If any of the input columns
09906  *   is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If
09907  *   any of the input columns is of type string, a @c CPL_ERROR_INVALID_TYPE
09908  *   is returned. If the input columns do not have the same length,
09909  *   a @c CPL_ERROR_INCOMPATIBLE_INPUT is returned.
09910  *
09911  * The result of the multiplication is stored in the target colum. The type of
09912  * the columns may differ, and in that case the operation would be performed
09913  * according to the C upcasting rules, with a final cast of the result to
09914  * the target column type. Invalid elements are propagated consistently:
09915  * if either or both members of the multiplication are invalid, the result
09916  * will be invalid too. Underflows and overflows are ignored, but a division 
09917  * by zero is producing an invalid element in the target column. This function
09918  * is not applicable to array columns.
09919  */
09920 
09921 cpl_error_code xxx_column_divide(xxx_column *to_column, 
09922                                  xxx_column *from_column)
09923 {
09924 
09925     const char *fid         = "xxx_column_divide";
09926     int          i;
09927     int          to_length   = xxx_column_get_size(to_column);
09928     int          from_length = xxx_column_get_size(from_column);
09929     cpl_type     to_type     = xxx_column_get_type(to_column);
09930     cpl_type     from_type   = xxx_column_get_type(from_column);
09931 
09932     int         *fip;
09933     float       *ffp;
09934     double      *fdp;
09935     int         *tip;
09936     float       *tfp;
09937     double      *tdp;
09938     int         *fnp;
09939     int         *tnp;
09940 
09941 
09942     if (to_column == 0x0 || from_column == 0x0)
09943         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
09944 
09945     if ((to_type == CPL_TYPE_STRING) || (from_type == CPL_TYPE_STRING) ||
09946         (to_type & CPL_TYPE_POINTER) || (from_type & CPL_TYPE_POINTER))
09947         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
09948 
09949     if (to_length != from_length)
09950         return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT);
09951 
09952     if (to_length == 0)
09953         return CPL_ERROR_NONE;
09954 
09955     if (from_column->nullcount == from_length)
09956         return xxx_column_fill_invalid(to_column, 0, to_length);
09957 
09958 
09959     /*
09960      *  Look for zeroes in the divisor column, and mark them as
09961      *  invalid in the target column in advance.
09962      */
09963 
09964     if (from_column->nullcount == 0) {
09965 
09966         switch (from_type) {
09967 
09968         case CPL_TYPE_INT:
09969             fip = from_column->values->i;
09970             for (i = 0; i < to_length; i++)
09971                 if (*fip++ == 0)
09972                     xxx_column_set_invalid(to_column, i);
09973             break;
09974     
09975         case CPL_TYPE_FLOAT:
09976             ffp = from_column->values->f;
09977             for (i = 0; i < to_length; i++)
09978                 if (*ffp++ == 0.0)
09979                     xxx_column_set_invalid(to_column, i);
09980             break;
09981     
09982         case CPL_TYPE_DOUBLE:
09983             fdp = from_column->values->d;
09984             for (i = 0; i < to_length; i++)
09985                 if (*fdp++ == 0.0)
09986                     xxx_column_set_invalid(to_column, i);
09987             break;
09988     
09989         default:
09990             break;
09991     
09992         }
09993     }
09994     else {
09995 
09996         fnp = from_column->null;
09997 
09998         switch (from_type) {
09999 
10000         case CPL_TYPE_INT:
10001             fip = from_column->values->i;
10002             for (i = 0; i < to_length; i++, fip++)
10003                 if (*fnp++ == 0)
10004                     if (*fip == 0)
10005                         xxx_column_set_invalid(to_column, i);
10006             break;
10007 
10008         case CPL_TYPE_FLOAT:
10009             ffp = from_column->values->f;
10010             for (i = 0; i < to_length; i++, ffp++)
10011                 if (*fnp++ == 0)
10012                     if (*ffp == 0.0)
10013                         xxx_column_set_invalid(to_column, i);
10014             break;
10015 
10016         case CPL_TYPE_DOUBLE:
10017             fdp = from_column->values->d;
10018             for (i = 0; i < to_length; i++, fdp++)
10019                 if (*fnp++ == 0)
10020                     if (*fdp == 0.0)
10021                         xxx_column_set_invalid(to_column, i);
10022             break;
10023 
10024         default:
10025             break;
10026 
10027         }
10028 
10029     }
10030 
10031 
10032    /*
10033     * If there are just NULLs in the target column, no need to
10034     * perform any further operation:
10035     */
10036 
10037     if (to_column->nullcount == to_length)
10038         return CPL_ERROR_NONE;
10039 
10040 
10041     fip = from_column->values->i;
10042     ffp = from_column->values->f;
10043     fdp = from_column->values->d;
10044     tip = to_column->values->i;
10045     tfp = to_column->values->f;
10046     tdp = to_column->values->d;
10047 
10048     if (to_column->nullcount == 0 && from_column->nullcount == 0) {
10049 
10050         /*
10051          * If there are no invalids in both columns, the operation can
10052          * be performed without any check:
10053          */
10054 
10055         switch (to_type) {
10056 
10057         case CPL_TYPE_INT:
10058 
10059             switch (from_type) {
10060 
10061             case CPL_TYPE_INT:
10062                 while (to_length--)
10063                     *tip++ /= *fip++;
10064                 break;
10065 
10066             case CPL_TYPE_FLOAT:
10067                 while (to_length--)
10068                     *tip++ /= *ffp++;
10069                 break;
10070 
10071             case CPL_TYPE_DOUBLE:
10072                 while (to_length--)
10073                     *tip++ /= *fdp++;
10074                 break;
10075 
10076             default:
10077                 break;
10078             }
10079             break;
10080 
10081         case CPL_TYPE_FLOAT:
10082 
10083             switch (from_type) {
10084 
10085             case CPL_TYPE_INT:
10086                 while (to_length--)
10087                     *tfp++ /= (double)*fip++;
10088                 break;
10089 
10090             case CPL_TYPE_FLOAT:
10091                 while (to_length--)
10092                     *tfp++ /= (double)*ffp++;
10093                 break;
10094 
10095             case CPL_TYPE_DOUBLE:
10096                 while (to_length--)
10097                     *tfp++ /= *fdp++;
10098                 break;
10099             
10100             default:
10101                 break;
10102             }
10103             break;
10104 
10105         case CPL_TYPE_DOUBLE:
10106 
10107             switch (from_type) {
10108 
10109             case CPL_TYPE_INT:
10110                 while (to_length--)
10111                     *tdp++ /= *fip++;
10112                 break;
10113 
10114             case CPL_TYPE_FLOAT:
10115                 while (to_length--)
10116                     *tdp++ /= *ffp++;
10117                 break;
10118 
10119             case CPL_TYPE_DOUBLE:
10120                 while (to_length--)
10121                     *tdp++ /= *fdp++;
10122                 break;
10123             
10124             default:
10125                 break;
10126             }
10127             break;
10128 
10129         default:
10130             break;
10131         }
10132     }
10133     else {
10134 
10135         /*
10136          * Here there are some invalids around, so the operation needs to be
10137          * performed with some checks. As a first thing, take care of the
10138          * invalids pattern in the target column:
10139          */
10140 
10141         if (to_column->nullcount == 0 || from_column->nullcount == 0) {
10142 
10143             /*
10144              * Here there are some invalids in just one of the two columns.
10145              * If they are just in the column to subtract, an identical
10146              * invalid flags buffer must be created for the target column.
10147              */
10148 
10149             if (from_column->nullcount) {
10150                 to_column->null = cpl_calloc(to_length, 
10151                                              sizeof(xxx_column_flag));
10152 
10153                 i = to_length;
10154                 while (i--)
10155                     if (from_column->null[i])
10156                         to_column->null[i] = 1;
10157 
10158                 to_column->nullcount = from_column->nullcount;
10159 
10160             }
10161         }
10162         else {
10163 
10164             /*
10165              *  Here there are some invalids in both columns.
10166              */
10167 
10168             i = to_length;
10169             while (i--) {
10170                 if (from_column->null[i]) {
10171                     if (!to_column->null[i]) {
10172                         to_column->null[i] = 1;
10173                         to_column->nullcount++;
10174                     }
10175                 }
10176             }
10177 
10178             if (to_column->nullcount == to_length) {
10179 
10180                 /*
10181                  * Just invalids in the result: no need to perform any further
10182                  * operation, and the invalid buffer of the target column can
10183                  * be disabled.
10184                  */
10185 
10186                 if (to_column->null)
10187                     cpl_free(to_column->null);
10188                 to_column->null = NULL;
10189                 return 0;
10190             }
10191 
10192         }
10193 
10194 
10195         /*
10196          * The operation can be performed while checking the already
10197          * computed result invalid flags buffer of the target column.
10198          */
10199 
10200         tnp = to_column->null;
10201 
10202         switch (to_type) {
10203 
10204         case CPL_TYPE_INT:
10205 
10206             switch (from_type) {
10207 
10208             case CPL_TYPE_INT:
10209                 for (i = 0; i < to_length; i++, tip++, fip++, tnp++)
10210                     if (*tnp == 0)
10211                         *tip /= *fip;
10212                 break;
10213 
10214             case CPL_TYPE_FLOAT:
10215                 for (i = 0; i < to_length; i++, tip++, ffp++, tnp++)
10216                     if (*tnp == 0)
10217                         *tip /= *ffp;
10218                 break;
10219 
10220             case CPL_TYPE_DOUBLE:
10221                 for (i = 0; i < to_length; i++, tip++, fdp++, tnp++)
10222                     if (*tnp == 0)
10223                         *tip /= *fdp;
10224                 break;
10225 
10226             default:
10227                 break;
10228             }
10229             break;
10230 
10231         case CPL_TYPE_FLOAT:
10232 
10233             switch (from_type) {
10234 
10235             case CPL_TYPE_INT:
10236                 for (i = 0; i < to_length; i++, tfp++, fip++, tnp++)
10237                     if (*tnp == 0)
10238                         *tfp /= (double)*fip;
10239                 break;
10240 
10241             case CPL_TYPE_FLOAT:
10242                 for (i = 0; i < to_length; i++, tfp++, ffp++, tnp++)
10243                     if (*tnp == 0)
10244                         *tfp /= (double)*ffp;
10245                 break;
10246 
10247             case CPL_TYPE_DOUBLE:
10248                 for (i = 0; i < to_length; i++, tfp++, fdp++, tnp++)
10249                     if (*tnp == 0)
10250                         *tfp /= *fdp;
10251                 break;
10252             
10253             default:
10254                 break;
10255             }
10256             break;
10257 
10258         case CPL_TYPE_DOUBLE:
10259 
10260             switch (from_type) {
10261 
10262             case CPL_TYPE_INT:
10263                 for (i = 0; i < to_length; i++, tdp++, fip++, tnp++)
10264                     if (*tnp == 0)
10265                         *tdp /= *fip;
10266                 break;
10267 
10268             case CPL_TYPE_FLOAT:
10269                 for (i = 0; i < to_length; i++, tdp++, ffp++, tnp++)
10270                     if (*tnp == 0)
10271                         *tdp /= *ffp;
10272                 break;
10273 
10274             case CPL_TYPE_DOUBLE:
10275                 for (i = 0; i < to_length; i++, tdp++, fdp++, tnp++)
10276                     if (*tnp == 0)
10277                         *tdp /= *fdp;
10278                 break;
10279             
10280             default:
10281                 break;
10282             }
10283             break;
10284 
10285         default:
10286             break;
10287         }
10288     }
10289 
10290     return CPL_ERROR_NONE;
10291 
10292 }
10293 
10294 
10295 /*
10296  * @brief
10297  *   Private function to make the exponential of an integer column.
10298  *
10299  * @param column  Target column.
10300  * @param base    Constant base.
10301  *
10302  * @return Nothing
10303  *
10304  * This private function is just a way to compact the code of other
10305  * higher level functions. No check is performed on input, assuming
10306  * that this was done elsewhere.
10307  */
10308 
10309 static void xxx_column_exp_int(xxx_column *column, double base)
10310 {
10311 
10312     int    nullcount = xxx_column_count_invalid(column);
10313     int    length    = xxx_column_get_size(column);
10314     int   *ip        = xxx_column_get_data_int(column);
10315     int   *np        = xxx_column_get_data_invalid(column);
10316     int    i;
10317 
10318 
10319     if (nullcount == length)
10320         return;
10321 
10322     if (nullcount == 0) {
10323         for (i = 0; i < length; i++, ip++)
10324             *ip = xxx_tools_ipow(base, *ip);
10325     }
10326     else {
10327         for (i = 0; i < length; i++, ip++, np++)
10328             if (*np == 0)
10329                 *ip = xxx_tools_ipow(base, *ip);
10330     }
10331 
10332 }
10333 
10334 
10335 /*
10336  * @brief
10337  *   Private function to make the exponential of a float column.
10338  *
10339  * @param column  Target column.
10340  * @param base    Constant base.
10341  *
10342  * @return Nothing
10343  *
10344  * This private function is just a way to compact the code of other
10345  * higher level functions. No check is performed on input, assuming
10346  * that this was done elsewhere.
10347  */
10348 
10349 static void xxx_column_exp_float(xxx_column *column, double base)
10350 {
10351 
10352     int    nullcount = xxx_column_count_invalid(column);
10353     int    length    = xxx_column_get_size(column);
10354     float *fp        = xxx_column_get_data_float(column);
10355     int   *np        = xxx_column_get_data_invalid(column);
10356     int    i;
10357 
10358 
10359     if (nullcount == length)
10360         return;
10361 
10362     if (nullcount == 0) {
10363         for (i = 0; i < length; i++, fp++)
10364             *fp = pow(base, *fp);
10365     }
10366     else {
10367         for (i = 0; i < length; i++, fp++, np++)
10368             if (*np == 0)
10369                 *fp = pow(base, *fp);
10370     }
10371 
10372 }
10373 
10374 
10375 /*
10376  * @brief
10377  *   Private function to make the exponential of a double column.
10378  *
10379  * @param column  Target column.
10380  * @param base    Constant base.
10381  *
10382  * @return Nothing
10383  *
10384  * This private function is just a way to compact the code of other
10385  * higher level functions. No check is performed on input, assuming
10386  * that this was done elsewhere.
10387  */
10388 
10389 static void xxx_column_exp_double(xxx_column *column, double base)
10390 {
10391 
10392     int     nullcount = xxx_column_count_invalid(column);
10393     int     length    = xxx_column_get_size(column);
10394     double *dp        = xxx_column_get_data_double(column);
10395     int    *np        = xxx_column_get_data_invalid(column);
10396     int     i;
10397 
10398 
10399     if (nullcount == length)
10400         return;
10401 
10402     if (nullcount == 0) {
10403         for (i = 0; i < length; i++, dp++)
10404             *dp = pow(base, *dp);
10405     }
10406     else {
10407         for (i = 0; i < length; i++, dp++, np++)
10408             if (*np == 0)
10409                 *dp = pow(base, *dp);
10410     }
10411 
10412 }
10413 
10414 
10415 /*
10416  * @brief
10417  *   Private function to make the power of an integer column.
10418  *
10419  * @param column   Target column.
10420  * @param exponent Constant exponent.
10421  *
10422  * @return Nothing
10423  *
10424  * This private function is just a way to compact the code of other
10425  * higher level functions. No check is performed on input, assuming
10426  * that this was done elsewhere.
10427  */
10428 
10429 static void xxx_column_pow_int(xxx_column *column, double exponent)
10430 {
10431 
10432     int    nullcount = xxx_column_count_invalid(column);
10433     int    length    = xxx_column_get_size(column);
10434     int   *ip        = xxx_column_get_data_int(column);
10435     int   *np        = xxx_column_get_data_invalid(column);
10436     int    negative  = exponent < 0.0;
10437     int    i;
10438 
10439 
10440     if (nullcount == length)
10441         return;
10442 
10443     if (negative)
10444         exponent = -exponent;
10445 
10446     if (exponent != 1.0) {
10447         if (nullcount == 0) {
10448             if (negative) {
10449                 for (i = 0; i < length; i++, ip++) {
10450                     if (*ip > 0)
10451                         *ip = floor(1 / pow(*ip, exponent) + 0.5);
10452                     else
10453                         xxx_column_set_invalid(column, i);
10454                 }
10455             }
10456             else {
10457                 for (i = 0; i < length; i++, ip++) {
10458                     if (*ip >= 0)
10459                         *ip = floor(pow(*ip, exponent) + 0.5);
10460                     else
10461                         xxx_column_set_invalid(column, i);
10462                 }
10463             }
10464         }
10465         else {
10466             for (i = 0; i < length; i++, ip++, np++) {
10467                 if (negative) {
10468                     if (*np == 0) {
10469                         if (*ip > 0)
10470                             *ip = floor(1 / pow(*ip, exponent) + 0.5);
10471                         else
10472                             xxx_column_set_invalid(column, i);
10473                     }
10474                 }
10475                 else {
10476                     if (*np == 0) {
10477                         if (*ip >= 0)
10478                             *ip = floor(pow(*ip, exponent) + 0.5);
10479                         else
10480                             xxx_column_set_invalid(column, i);
10481                     }
10482                 }
10483             }
10484         }
10485     }
10486 }
10487 
10488 
10489 /*
10490  * @brief
10491  *   Private function to make the power of a float column.
10492  *
10493  * @param column   Target column.
10494  * @param exponent Constant exponent.
10495  *
10496  * @return Nothing
10497  *
10498  * This private function is just a way to compact the code of other
10499  * higher level functions. No check is performed on input, assuming
10500  * that this was done elsewhere.
10501  */
10502 
10503 static void xxx_column_pow_float(xxx_column *column, double exponent)
10504 {
10505 
10506     int    nullcount = xxx_column_count_invalid(column);
10507     int    length    = xxx_column_get_size(column);
10508     float *fp        = xxx_column_get_data_float(column);
10509     int   *np        = xxx_column_get_data_invalid(column);
10510     int    negative  = exponent < 0.0;
10511     int    i;
10512 
10513 
10514     if (nullcount == length)
10515         return;
10516 
10517     if (negative)
10518         exponent = -exponent;
10519 
10520     if (exponent != 1.0) {
10521         if (nullcount == 0) {
10522             if (negative) {
10523                 for (i = 0; i < length; i++, fp++) {
10524                     if (*fp > 0.0)
10525                         *fp = 1 / pow(*fp, exponent);
10526                     else
10527                         xxx_column_set_invalid(column, i);
10528                 }
10529             }
10530             else {
10531                 for (i = 0; i < length; i++, fp++) {
10532                     if (*fp >= 0.0)
10533                         *fp = pow(*fp, exponent);
10534                     else
10535                         xxx_column_set_invalid(column, i);
10536                 }
10537             }
10538         }
10539         else {
10540             for (i = 0; i < length; i++, fp++, np++) {
10541                 if (negative) {
10542                     if (*np == 0) {
10543                         if (*fp > 0.0)
10544                             *fp = 1 / pow(*fp, exponent);
10545                         else
10546                             xxx_column_set_invalid(column, i);
10547                     }
10548                 }
10549                 else {
10550                     if (*np == 0) {
10551                         if (*fp >= 0.0)
10552                             *fp = pow(*fp, exponent);
10553                         else
10554                             xxx_column_set_invalid(column, i);
10555                     }
10556                 }
10557             }
10558         }
10559     }
10560 }
10561 
10562 
10563 /*
10564  * @brief
10565  *   Private function to make the power of a double column.
10566  *
10567  * @param column   Target column.
10568  * @param exponent Constant exponent.
10569  *
10570  * @return Nothing
10571  *
10572  * This private function is just a way to compact the code of other
10573  * higher level functions. No check is performed on input, assuming
10574  * that this was done elsewhere.
10575  */
10576 
10577 static void xxx_column_pow_double(xxx_column *column, double exponent)
10578 {
10579 
10580     int     nullcount = xxx_column_count_invalid(column);
10581     int     length    = xxx_column_get_size(column);
10582     double *dp        = xxx_column_get_data_double(column);
10583     int    *np        = xxx_column_get_data_invalid(column);
10584     int     negative  = exponent < 0.0;
10585     int     i;
10586 
10587 
10588     if (nullcount == length)
10589         return; 
10590 
10591     if (negative)
10592         exponent = -exponent;
10593 
10594     if (nullcount == 0) {
10595         if (negative) {
10596             for (i = 0; i < length; i++, dp++) {
10597                 if (*dp > 0.0)
10598                     *dp = 1 / pow(*dp, exponent);
10599                 else
10600                     xxx_column_set_invalid(column, i);
10601             }
10602         }
10603         else {
10604             for (i = 0; i < length; i++, dp++) {
10605                 if (*dp >= 0.0)
10606                     *dp = pow(*dp, exponent);
10607                 else
10608                     xxx_column_set_invalid(column, i);
10609             }
10610         }
10611     }
10612     else {
10613         for (i = 0; i < length; i++, dp++, np++) {
10614             if (negative) {
10615                 if (*np == 0) {
10616                     if (*dp > 0.0)
10617                         *dp = 1 / pow(*dp, exponent);
10618                     else
10619                         xxx_column_set_invalid(column, i);
10620                 }
10621             }
10622             else {
10623                 if (*np == 0) {
10624                     if (*dp >= 0.0)
10625                         *dp = pow(*dp, exponent);
10626                     else
10627                         xxx_column_set_invalid(column, i);
10628                 }
10629             }
10630         }
10631     }
10632 }
10633 
10634 
10635 /*
10636  * @brief
10637  *   Private function to make the log of an integer column.
10638  *
10639  * @param column   Target column.
10640  * @param base     Logarithm base.
10641  *
10642  * @return Nothing
10643  *
10644  * This private function is just a way to compact the code of other
10645  * higher level functions. No check is performed on input, assuming
10646  * that this was done elsewhere.
10647  */
10648 
10649 static void xxx_column_log_int(xxx_column *column, double base)
10650 {
10651 
10652     int    nullcount = xxx_column_count_invalid(column);
10653     int    length    = xxx_column_get_size(column);
10654     int   *ip        = xxx_column_get_data_int(column);
10655     int   *np        = xxx_column_get_data_invalid(column);
10656     int    i;
10657     double invlog    = 1 / log(base);
10658 
10659 
10660     if (nullcount == length)
10661         return;
10662 
10663     if (nullcount == 0) {
10664         for (i = 0; i < length; i++, ip++) {
10665             if (*ip > 0)
10666                 *ip = floor(log(*ip) * invlog + 0.5);
10667             else 
10668                 xxx_column_set_invalid(column, i);
10669         }
10670     }
10671     else {
10672         for (i = 0; i < length; i++, ip++, np++) {
10673             if (*np == 0) {
10674                 if (*ip > 0)
10675                     *ip = floor(log(*ip) * invlog + 0.5);
10676                 else
10677                     xxx_column_set_invalid(column, i);
10678             }
10679         }
10680     }
10681 }
10682 
10683 
10684 /*
10685  * @brief
10686  *   Private function to make the log of a float column.
10687  *
10688  * @param column   Target column.
10689  * @param base     Logarithm base.
10690  *
10691  * @return Nothing
10692  *
10693  * This private function is just a way to compact the code of other
10694  * higher level functions. No check is performed on input, assuming
10695  * that this was done elsewhere.
10696  */
10697 
10698 static void xxx_column_log_float(xxx_column *column, double base)
10699 {
10700 
10701     int    nullcount = xxx_column_count_invalid(column);
10702     int    length    = xxx_column_get_size(column);
10703     float *fp        = xxx_column_get_data_float(column);
10704     int   *np        = xxx_column_get_data_invalid(column);
10705     int    i;
10706     double invlog    = 1 / log(base);
10707 
10708 
10709     if (nullcount == length)
10710         return;
10711 
10712     if (nullcount == 0) {
10713         for (i = 0; i < length; i++, fp++) {
10714             if (*fp > 0.0)
10715                 *fp = log(*fp) * invlog;
10716             else
10717                 xxx_column_set_invalid(column, i);
10718         }
10719     }
10720     else {
10721         for (i = 0; i < length; i++, fp++, np++) {
10722             if (*np == 0) {
10723                 if (*fp > 0.0)
10724                     *fp = log(*fp) * invlog;
10725                 else
10726                     xxx_column_set_invalid(column, i);
10727             }
10728         }
10729     }
10730 }
10731 
10732 
10733 /*
10734  * @brief
10735  *   Private function to make the log of a double column.
10736  *
10737  * @param column   Target column.
10738  * @param base     Logarithm base.
10739  *
10740  * @return Nothing
10741  *
10742  * This private function is just a way to compact the code of other
10743  * higher level functions. No check is performed on input, assuming
10744  * that this was done elsewhere.
10745  */
10746 
10747 static void xxx_column_log_double(xxx_column *column, double base)
10748 {
10749 
10750     int     nullcount = xxx_column_count_invalid(column);
10751     int     length    = xxx_column_get_size(column);
10752     double *dp        = xxx_column_get_data_double(column);
10753     int    *np        = xxx_column_get_data_invalid(column);
10754     int     i;
10755     double  invlog    = 1 / log(base);
10756 
10757 
10758     if (nullcount == length)
10759         return;
10760 
10761     if (nullcount == 0) {
10762         for (i = 0; i < length; i++, dp++) {
10763             if (*dp > 0.0)
10764                 *dp = log(*dp) * invlog;
10765             else
10766                 xxx_column_set_invalid(column, i);
10767         }
10768     }
10769     else {
10770         for (i = 0; i < length; i++, dp++, np++) {
10771             if (*np == 0) {
10772                 if (*dp > 0.0)
10773                     *dp = log(*dp) * invlog;
10774                 else
10775                     xxx_column_set_invalid(column, i);
10776             }
10777         }
10778     }
10779 }
10780 
10781 
10782 /*
10783  * @brief
10784  *   Private function to add an @em integer constant to an @em integer column.
10785  *
10786  * @param column   Target column.
10787  * @param value    Value to add.
10788  *
10789  * @return Nothing
10790  *
10791  * This private function is just a way to compact the code of other
10792  * higher level functions. No check is performed on input, assuming
10793  * that this was done elsewhere.
10794  */
10795 
10796 static void xxx_column_add_to_int(xxx_column *column, int value)
10797 {
10798 
10799     int  nullcount = xxx_column_count_invalid(column);
10800     int  length    = xxx_column_get_size(column);
10801     int *ip        = xxx_column_get_data_int(column);
10802     int *np        = xxx_column_get_data_invalid(column);
10803     int  i;
10804 
10805 
10806     if (value == 0)
10807         return;
10808 
10809     if (nullcount == length)
10810         return;
10811 
10812     if (nullcount == 0)
10813         for (i = 0; i < length; i++)
10814             *ip++ += value;
10815     else
10816         for (i = 0; i < length; i++, ip++, np++)
10817             if (*np == 0)
10818                 *ip += value;
10819 
10820 }
10821 
10822 
10823 /*
10824  * @brief
10825  *   Private function to add a @em float constant to a @em float column.
10826  *
10827  * @param column   Target column.
10828  * @param value    Value to add.
10829  *
10830  * @return Nothing
10831  *
10832  * This private function is just a way to compact the code of other
10833  * higher level functions. No check is performed on input, assuming
10834  * that this was done elsewhere.
10835  */ 
10836 
10837 static void xxx_column_add_to_float(xxx_column *column, double value)
10838 {
10839 
10840     int    nullcount = xxx_column_count_invalid(column);
10841     int    length    = xxx_column_get_size(column);
10842     float *fp        = xxx_column_get_data_float(column);
10843     int   *np        = xxx_column_get_data_invalid(column);
10844     int    i;
10845 
10846 
10847     if (value == 0.0)
10848         return;
10849 
10850     if (nullcount == length)
10851         return;
10852 
10853     if (nullcount == 0) 
10854         for (i = 0; i < length; i++)
10855             *fp++ += value;
10856     else
10857         for (i = 0; i < length; i++, fp++, np++)
10858             if (*np == 0)
10859                 *fp += value;
10860 
10861 }
10862 
10863 
10864 /*
10865  * @brief
10866  *   Private function to add a @em double constant to a @em double column.
10867  *
10868  * @param column   Target column.
10869  * @param value    Value to add.
10870  *
10871  * @return Nothing
10872  *
10873  * This private function is just a way to compact the code of other
10874  * higher level functions. No check is performed on input, assuming
10875  * that this was done elsewhere.
10876  */
10877 
10878 static void xxx_column_add_to_double(xxx_column *column, double value)
10879 {
10880 
10881     int     nullcount = xxx_column_count_invalid(column);
10882     int     length    = xxx_column_get_size(column);
10883     double *dp        = xxx_column_get_data_double(column);
10884     int    *np        = xxx_column_get_data_invalid(column);
10885     int     i;
10886 
10887 
10888     if (value == 0.0)
10889         return;
10890 
10891     if (nullcount == length)
10892         return;
10893 
10894     if (nullcount == 0) 
10895         for (i = 0; i < length; i++)
10896             *dp++ += value;
10897     else
10898         for (i = 0; i < length; i++, dp++, np++)
10899             if (*np == 0)
10900                 *dp += value;
10901 
10902 }
10903 
10904 
10905 /*
10906  * @brief
10907  *   Private function to multiply a @em double column by a @em double constant.
10908  *
10909  * @param column   Target column.
10910  * @param value    Value to add.
10911  *
10912  * @return Nothing
10913  *
10914  * This private function is just a way to compact the code of other
10915  * higher level functions. No check is performed on input, assuming
10916  * that this was done elsewhere.
10917  */
10918 
10919 static void xxx_column_mul_to_double(xxx_column *column, double value)
10920 {
10921 
10922     int     nullcount = xxx_column_count_invalid(column);
10923     int     length    = xxx_column_get_size(column);
10924     double *dp        = xxx_column_get_data_double(column);
10925     int    *np        = xxx_column_get_data_invalid(column);
10926     int     i;
10927 
10928 
10929     if (value == 1.0)
10930         return;
10931 
10932     if (nullcount == length)
10933         return;
10934 
10935     if (nullcount == 0)
10936         for (i = 0; i < length; i++)
10937             *dp++ *= value;
10938     else
10939         for (i = 0; i < length; i++, dp++, np++)
10940             if (*np == 0)
10941                 *dp *= value;
10942 
10943 }
10944 
10945 
10946 /*
10947  * @brief
10948  *   Private function to multiply a @em integer column by a @em double constant.
10949  *
10950  * @param column   Target column.
10951  * @param value    Value to add.
10952  *
10953  * @return Nothing.
10954  *
10955  * This private function is just a way to compact the code of other
10956  * higher level functions. No check is performed on input, assuming
10957  * that this was done elsewhere.
10958  */
10959 
10960 static void xxx_column_mul_double_to_int(xxx_column *column, double value)
10961 {
10962 
10963     int  nullcount = xxx_column_count_invalid(column);
10964     int  length    = xxx_column_get_size(column);
10965     int *ip        = xxx_column_get_data_int(column);
10966     int *np        = xxx_column_get_data_invalid(column);
10967     int  i;
10968 
10969 
10970     if (value == 1.0)
10971         return;
10972 
10973     if (nullcount == length)
10974         return;
10975 
10976     if (nullcount == 0)
10977         for (i = 0; i < length; i++)
10978             *ip++ *= value;
10979     else
10980         for (i = 0; i < length; i++, ip++, np++)
10981             if (*np == 0)
10982                 *ip *= value;
10983 
10984 }
10985 
10986 
10987 /*
10988  * @brief
10989  *   Private function to multiply a @em float column by a @em double constant.
10990  *
10991  * @param column   Target column.
10992  * @param value    Value to add.
10993  *
10994  * @return Nothing.
10995  *
10996  * This private function is just a way to compact the code of other
10997  * higher level functions. No check is performed on input, assuming
10998  * that this was done elsewhere.
10999  */
11000 
11001 static void xxx_column_mul_double_to_float(xxx_column *column, double value)
11002 {
11003 
11004     int    nullcount = xxx_column_count_invalid(column);
11005     int    length    = xxx_column_get_size(column);
11006     float *fp        = xxx_column_get_data_float(column);
11007     int   *np        = xxx_column_get_data_invalid(column);
11008     int    i;
11009 
11010 
11011     if (value == 1.0)
11012         return;
11013 
11014     if (nullcount == length)
11015         return;
11016 
11017     if (nullcount == 0)
11018         for (i = 0; i < length; i++)
11019             *fp++ *= value;
11020     else
11021         for (i = 0; i < length; i++, fp++, np++)
11022             if (*np == 0)
11023                 *fp *= value;
11024 
11025 }
11026 
11027 
11028 /* 
11029  * @brief
11030  *   Compute the logarithm of column values.
11031  *
11032  * @param column   Target column.
11033  * @param base     Logarithm base.
11034  *
11035  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL 
11036  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column 
11037  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned. If the
11038  *   @em base is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is
11039  *   returned.
11040  *
11041  * The operation is always performed in double precision, with a final
11042  * cast of the result to the target column type. Non-positive column
11043  * values will be marked as invalid. Columns of strings or arrays are
11044  * not allowed.
11045  */
11046 
11047 cpl_error_code xxx_column_logarithm(xxx_column *column, double base)
11048 {
11049 
11050     const char *fid  = "xxx_column_logarithm";
11051     cpl_type     type = xxx_column_get_type(column);
11052 
11053 
11054     if (column == 0x0)
11055         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11056 
11057     if (base <= 0.0)
11058         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
11059 
11060 
11061     switch (type) {
11062 
11063     case CPL_TYPE_INT:
11064         xxx_column_log_int(column, base);
11065         break;
11066     case CPL_TYPE_FLOAT:
11067         xxx_column_log_float(column, base);
11068         break;
11069     case CPL_TYPE_DOUBLE:
11070         xxx_column_log_double(column, base);
11071         break;
11072     default:
11073         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11074 
11075     }
11076 
11077     return CPL_ERROR_NONE;
11078 
11079 }
11080 
11081 
11082 /* 
11083  * @brief
11084  *   Compute the exponential of column values.
11085  *
11086  * @param column   Target column.
11087  * @param base     Exponential base.
11088  *
11089  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11090  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11091  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned. If the
11092  *   @em base is not greater than zero, a @c CPL_ERROR_ILLEGAL_INPUT is
11093  *   returned.
11094  *
11095  * The operation is always performed in double precision, with a final
11096  * cast of the result to the target column type. Columns of strings or 
11097  * arrays are not allowed.
11098  */
11099 
11100 cpl_error_code xxx_column_exponential(xxx_column *column, double base)
11101 {
11102 
11103     const char *fid  = "xxx_column_exponential";
11104     cpl_type     type = xxx_column_get_type(column);
11105 
11106 
11107     if (column == 0x0)
11108         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11109 
11110     if (base <= 0.0)
11111         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
11112 
11113 
11114     switch (type) {
11115 
11116     case CPL_TYPE_INT:
11117         xxx_column_exp_int(column, base);
11118         break;
11119     case CPL_TYPE_FLOAT:
11120         xxx_column_exp_float(column, base);
11121         break;
11122     case CPL_TYPE_DOUBLE:
11123         xxx_column_exp_double(column, base);
11124         break;
11125     default:
11126         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11127 
11128     }
11129 
11130     return CPL_ERROR_NONE;
11131 
11132 }
11133 
11134 
11135 /* 
11136  * @brief
11137  *   Compute a power of column values.
11138  *
11139  * @param column   Target column.
11140  * @param exponent Constant exponent.
11141  *
11142  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11143  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11144  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned.
11145  *
11146  * The operation is always performed in double precision, with a final
11147  * cast of the result to the target column type. Non-positive column
11148  * values will be marked as invalid. Columns of strings or arrays are 
11149  * not allowed.
11150  */
11151 
11152 cpl_error_code xxx_column_power(xxx_column *column, double exponent)
11153 {
11154 
11155     const char *fid  = "xxx_column_power";
11156     cpl_type     type = xxx_column_get_type(column);
11157 
11158 
11159     if (column == 0x0)
11160         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11161 
11162 
11163     switch (type) {
11164 
11165     case CPL_TYPE_INT:  
11166         xxx_column_pow_int(column, exponent);
11167         break;
11168     case CPL_TYPE_FLOAT:
11169         xxx_column_pow_float(column, exponent);
11170         break;
11171     case CPL_TYPE_DOUBLE:
11172         xxx_column_pow_double(column, exponent);
11173         break;
11174     default:
11175         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11176 
11177     }
11178 
11179     return CPL_ERROR_NONE;
11180 
11181 }
11182 
11183 
11184 /* 
11185  * @brief
11186  *   Add a constant value to a numerical column.
11187  *
11188  * @param column   Target column.
11189  * @param value    Value to add.
11190  * 
11191  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11192  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11193  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned.
11194  * 
11195  * The operation is always performed in double precision, with a final   
11196  * cast of the result to the target column type. Invalid flags are not
11197  * modified by this operation. Columns of strings or arrays are not allowed.
11198  */
11199 
11200 cpl_error_code xxx_column_add_scalar(xxx_column *column, double value)
11201 {
11202 
11203     const char *fid  = "xxx_column_add_scalar";
11204     cpl_type     type = xxx_column_get_type(column);
11205 
11206 
11207     if (column == 0x0)
11208         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11209 
11210 
11211     switch (type) {
11212 
11213     case CPL_TYPE_INT:
11214         xxx_column_add_to_int(column, value);
11215         break;
11216     case CPL_TYPE_FLOAT:
11217         xxx_column_add_to_float(column, value);
11218         break;
11219     case CPL_TYPE_DOUBLE:
11220         xxx_column_add_to_double(column, value);
11221         break;
11222     default:
11223         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11224 
11225     }
11226 
11227     return CPL_ERROR_NONE;
11228 
11229 }
11230 
11231 
11232 /* 
11233  * @brief
11234  *   Subtract a constant value from a numerical column.
11235  *
11236  * @param column   Target column.
11237  * @param value    Value to subtract.
11238  *
11239  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11240  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11241  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned.
11242  *
11243  * The operation is always performed in double precision, with a final
11244  * cast of the result to the target column type. Invalid flags are not
11245  * modified by this operation. Columns of strings or arrays are not allowed.
11246  */
11247 
11248 cpl_error_code xxx_column_subtract_scalar(xxx_column *column, double value)
11249 {
11250 
11251     return xxx_column_add_scalar(column, -value);
11252 
11253 }
11254 
11255 
11256 /* 
11257  * @brief
11258  *   Multiply by a constant a numerical column.
11259  *
11260  * @param column   Target column.
11261  * @param value    Multiplier.
11262  *
11263  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11264  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11265  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned.
11266  *
11267  * The operation is always performed in double precision, with a final
11268  * cast of the result to the target column type. Invalid flags are not
11269  * modified by this operation. Columns of strings or arrays are not allowed.
11270  */
11271 
11272 cpl_error_code xxx_column_multiply_scalar(xxx_column *column, double value)
11273 {
11274 
11275     const char *fid  = "xxx_column_multiply_scalar";
11276     cpl_type     type = xxx_column_get_type(column);
11277 
11278 
11279     if (column == 0x0)
11280         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11281 
11282 
11283     switch (type) {
11284 
11285     case CPL_TYPE_INT:
11286         xxx_column_mul_double_to_int(column, value);
11287         break;
11288     case CPL_TYPE_FLOAT:
11289         xxx_column_mul_double_to_float(column, value);
11290         break;
11291     case CPL_TYPE_DOUBLE:
11292         xxx_column_mul_to_double(column, value);
11293         break;
11294     default:
11295         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11296 
11297     }
11298 
11299     return CPL_ERROR_NONE;
11300 
11301 }
11302 
11303 
11304 /* 
11305  * @brief
11306  *   Divide by a constant a numerical column.
11307  *
11308  * @param column   Target column.
11309  * @param value    Divisor.
11310  *
11311  * @return @c CPL_ERROR_NONE on success. If the input column is a @c NULL
11312  *   pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the accessed column
11313  *   is not numerical, a @c CPL_ERROR_INVALID_TYPE is returned. If the input 
11314  *   @em value is zero, a @c CPL_ERROR_DIVISION_BY_ZERO is returned.
11315  *
11316  * The operation is always performed in double precision, with a final
11317  * cast of the result to the target column type. Invalid flags are not
11318  * modified by this operation. Columns of strings or arrays are not allowed.
11319  */
11320 
11321 cpl_error_code xxx_column_divide_scalar(xxx_column *column, double value)
11322 {
11323 
11324     const char *fid  = "xxx_column_divide_scalar";
11325     cpl_type     type = xxx_column_get_type(column);
11326 
11327     
11328     if (column == 0x0)
11329         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11330 
11331 
11332     if (value == 0.0)
11333         return cpl_error_set(fid, CPL_ERROR_DIVISION_BY_ZERO);
11334 
11335     value = 1 / value;
11336 
11337     switch (type) {
11338 
11339     case CPL_TYPE_INT:
11340         xxx_column_mul_double_to_int(column, value);
11341         break;
11342     case CPL_TYPE_FLOAT:
11343         xxx_column_mul_double_to_float(column, value);
11344         break;
11345     case CPL_TYPE_DOUBLE:
11346         xxx_column_mul_to_double(column, value);
11347         break;
11348     default:
11349         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11350 
11351     }
11352 
11353     return CPL_ERROR_NONE;
11354 
11355 }
11356 
11357 
11358 /* 
11359  * @brief
11360  *   Compute the mean value of a numeric column.
11361  *
11362  * @param column   Input column.
11363  *
11364  * @return Mean value. In case of error, this is set to 0.0.
11365  * 
11366  * If the input @em column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is
11367  * set. If the accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE 
11368  * is set. If the input column elements are all invalid, or the column has
11369  * zero length, a @c CPL_ERROR_DATA_NOT_FOUND is set.
11370  *
11371  * Column values marked as invalid are excluded from the computation. 
11372  * The column must contain at least one valid value. Columns of strings or
11373  * arrays are not allowed.
11374  */
11375 
11376 double xxx_column_get_mean(xxx_column *column)
11377 {
11378 
11379     const char *fid       = "xxx_column_get_mean";
11380     int          length    = xxx_column_get_size(column);
11381     int          nullcount = xxx_column_count_invalid(column);
11382     cpl_type     type      = xxx_column_get_type(column);
11383     double       mean      = 0.0;
11384     int          count     = length - nullcount;
11385     int          i;
11386 
11387     int         *np;
11388     int         *ip;
11389     float       *fp;
11390     double      *dp;
11391 
11392     
11393     if (column == 0x0) {
11394         cpl_error_set_where(fid);
11395         return 0.0;
11396     }
11397 
11398 
11399     if (nullcount == length || length == 0) {
11400         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11401         return 0.0;
11402     }
11403 
11404     np = column->null;
11405 
11406     switch (type) {
11407 
11408     case CPL_TYPE_INT:
11409         ip = column->values->i;
11410         if (nullcount == 0)
11411             for (i = 0; i < length; i++)
11412                 mean += *ip++;
11413         else
11414             for (i = 0; i < length; i++, ip++, np++)
11415                 if (*np == 0)
11416                     mean += *ip;
11417         break;
11418 
11419     case CPL_TYPE_FLOAT:
11420         fp = column->values->f;
11421         if (nullcount == 0)
11422             for (i = 0; i < length; i++)
11423                 mean += *fp++;
11424         else
11425             for (i = 0; i < length; i++, fp++, np++)
11426                 if (*np == 0)
11427                     mean += *fp;
11428         break;
11429 
11430     case CPL_TYPE_DOUBLE:
11431         dp = column->values->d;
11432         if (nullcount == 0)
11433             for (i = 0; i < length; i++)
11434                 mean += *dp++;
11435         else
11436             for (i = 0; i < length; i++, dp++, np++)
11437                 if (*np == 0)
11438                     mean += *dp;
11439         break;
11440 
11441     default:
11442         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11443 
11444     }
11445 
11446     return (mean / count);
11447 
11448 }
11449 
11450 
11451 double xxx_column_get_stdev(xxx_column *column)
11452 {
11453 
11454     const char *fid       = "xxx_column_get_stdev";
11455     int          length    = xxx_column_get_size(column);
11456     int          nullcount = xxx_column_count_invalid(column);
11457     cpl_type     type      = xxx_column_get_type(column);
11458     double       stdev     = 0.0;
11459     double       mean;
11460     int          count     = length - nullcount;
11461     int          i;
11462 
11463     int         *np;
11464     int         *ip;
11465     float       *fp;
11466     double      *dp;
11467 
11468 
11469     if (column == 0x0) {
11470         cpl_error_set_where(fid);
11471         return 0.0;
11472     }
11473 
11474 
11475     if (nullcount == length || length == 0) {
11476         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11477         return 0.0;
11478     }
11479 
11480     if (count == 1)
11481       return 0.0;
11482 
11483     mean = xxx_column_get_mean(column);
11484 
11485     np = column->null;
11486 
11487     switch (type) {
11488 
11489     case CPL_TYPE_INT:
11490         ip = column->values->i;
11491         if (nullcount == 0)
11492             for (i = 0; i < length; i++, ip++)
11493                 stdev += (*ip - mean) * (*ip - mean);
11494         else
11495             for (i = 0; i < length; i++, ip++, np++)
11496                 if (*np == 0)
11497                     stdev += (*ip - mean) * (*ip - mean);
11498         break;
11499 
11500     case CPL_TYPE_FLOAT:
11501         fp = column->values->f;
11502         if (nullcount == 0)
11503             for (i = 0; i < length; i++, fp++)
11504                 stdev += (*fp - mean) * (*fp - mean);
11505         else
11506             for (i = 0; i < length; i++, fp++, np++)
11507                 if (*np == 0)
11508                     stdev += (*fp - mean) * (*fp - mean);
11509         break;
11510 
11511     case CPL_TYPE_DOUBLE:
11512         dp = column->values->d;
11513         if (nullcount == 0)
11514             for (i = 0; i < length; i++, dp++)
11515                 stdev += (*dp - mean) * (*dp - mean);
11516         else
11517             for (i = 0; i < length; i++, dp++, np++)
11518                 if (*np == 0)
11519                     stdev += (*dp - mean) * (*dp - mean);
11520         break;
11521 
11522     default:
11523         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11524 
11525     }
11526 
11527     return sqrt(stdev / (count - 1));
11528 
11529 }
11530 
11531 
11532 /* 
11533  * @brief
11534  *   Get maximum value in a numerical column.
11535  *
11536  * @param column   Input column.
11537  *
11538  * @return Maximum value. In case of error, this is set to 0.0.
11539  *
11540  * If the input @em column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is
11541  * set. If the accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
11542  * is set. If the input column elements are all invalid, or the column has
11543  * zero length, a @c CPL_ERROR_DATA_NOT_FOUND is set.
11544  *
11545  * Column values marked as invalid are excluded from the search. 
11546  * The column must contain at least one valid value. Columns of strings or
11547  * arrays are not allowed.
11548  */
11549 
11550 double xxx_column_get_max(xxx_column *column)
11551 {
11552 
11553     const char *fid       = "xxx_column_get_max";
11554     int          length    = xxx_column_get_size(column);
11555     int          nullcount = xxx_column_count_invalid(column);
11556     cpl_type     type      = xxx_column_get_type(column);
11557     int          first     = 1;
11558     int         *ip;
11559     float       *fp;
11560     double      *dp;
11561     int         *np;
11562     double       maximum = 0;
11563     int          i;
11564 
11565 
11566     if (column == 0x0) {
11567         cpl_error_set_where(fid);
11568         return 0.0;
11569     }
11570 
11571     if (nullcount == length || length == 0) {
11572         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11573         return 0.0;
11574     }
11575 
11576     np = column->null;
11577 
11578     switch (type) {
11579     case CPL_TYPE_INT:
11580         ip = column->values->i;
11581         if (length == 1)
11582             return *ip;
11583         if (nullcount == 0) {
11584             maximum = *ip++;
11585             for (i = 1; i < length; i++, ip++)
11586                 if (maximum < *ip)
11587                     maximum = *ip;
11588         }
11589         else {
11590             for (i = 0; i < length; i++, ip++, np++) {
11591                 if (*np == 0) {
11592                     if (first) {
11593                         first = 0;
11594                         maximum = *ip;
11595                     }
11596                     else
11597                         if (maximum < *ip)
11598                             maximum = *ip;
11599                 }
11600             }
11601         }
11602         break;
11603     case CPL_TYPE_FLOAT:
11604         fp = column->values->f;
11605         if (length == 1)
11606             return *fp;
11607         if (nullcount == 0) {
11608             maximum = *fp++;
11609             for (i = 1; i < length; i++, fp++)
11610                 if (maximum < *fp)
11611                     maximum = *fp;
11612         }
11613         else {
11614             for (i = 0; i < length; i++, fp++, np++) {
11615                 if (*np == 0) {
11616                     if (first) {
11617                         first = 0;
11618                         maximum = *fp;
11619                     }
11620                     else
11621                         if (maximum < *fp)
11622                             maximum = *fp;
11623                 }
11624             }
11625         }
11626         break;
11627     case CPL_TYPE_DOUBLE:
11628         dp = column->values->d;
11629         if (length == 1)
11630             return *dp;
11631         if (nullcount == 0) {
11632             maximum = *dp++;
11633             for (i = 1; i < length; i++, dp++) 
11634                 if (maximum < *dp) 
11635                     maximum = *dp;
11636         }
11637         else {
11638             for (i = 0; i < length; i++, dp++, np++) {
11639                 if (*np == 0) {
11640                     if (first) {
11641                         first = 0;
11642                         maximum = *dp;
11643                     }
11644                     else 
11645                         if (maximum < *dp) 
11646                             maximum = *dp;
11647                 }
11648             }
11649         }
11650         break;
11651     default:
11652         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11653         return 0.0;
11654     }
11655 
11656     return maximum;
11657 
11658 }
11659 
11660 
11661 /* 
11662  * @brief
11663  *   Get minimum value in a numerical column.
11664  *
11665  * @param column   Input column.
11666  *
11667  * @return Minimum value. In case of error, this is set to 0.0.
11668  *
11669  * If the input @em column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is
11670  * set. If the accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
11671  * is set. If the input column elements are all invalid, or the column has
11672  * zero length, a @c CPL_ERROR_DATA_NOT_FOUND is set.
11673  *
11674  * Column values marked as invalid are excluded from the search.
11675  * The column must contain at least one valid value. Columns of strings or
11676  * arrays are not allowed.
11677  */ 
11678 
11679 double xxx_column_get_min(xxx_column *column)
11680 {
11681 
11682     const char *fid       = "xxx_column_get_min";
11683     int          length    = xxx_column_get_size(column);
11684     int          nullcount = xxx_column_count_invalid(column);
11685     cpl_type     type      = xxx_column_get_type(column);
11686     int          first     = 1;
11687     int         *ip;
11688     float       *fp;
11689     double      *dp;
11690     int         *np;
11691     double       minimum= 0;
11692     int          i;
11693 
11694 
11695     if (column == 0x0) {
11696         cpl_error_set_where(fid);
11697         return 0.0;
11698     }
11699 
11700     if (nullcount == length || length == 0) {
11701         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11702         return 0.0;
11703     }
11704 
11705     np = column->null;
11706 
11707     switch (type) {
11708     case CPL_TYPE_INT:
11709         ip = column->values->i;
11710         if (length == 1)
11711             return *ip;
11712         if (nullcount == 0) {
11713             minimum = *ip++;
11714             for (i = 1; i < length; i++, ip++) 
11715                 if (minimum > *ip) 
11716                     minimum = *ip;
11717         }
11718         else {
11719             for (i = 0; i < length; i++, ip++, np++) {
11720                 if (*np == 0) {
11721                     if (first) {
11722                         first = 0;
11723                         minimum = *ip;
11724                     }
11725                     else 
11726                         if (minimum > *ip) 
11727                             minimum = *ip;
11728                 }
11729             }
11730         }
11731         break;
11732     case CPL_TYPE_FLOAT:
11733         fp = column->values->f;
11734         if (length == 1)
11735             return *fp;
11736         if (nullcount == 0) {
11737             minimum = *fp++;
11738             for (i = 1; i < length; i++, fp++) 
11739                 if (minimum > *fp) 
11740                     minimum = *fp;
11741         }
11742         else {
11743             for (i = 0; i < length; i++, fp++, np++) {
11744                 if (*np == 0) {
11745                     if (first) {
11746                         first = 0;
11747                         minimum = *fp;
11748                     }
11749                     else 
11750                         if (minimum > *fp) 
11751                             minimum = *fp;
11752                 }
11753             }
11754         }
11755         break;
11756     case CPL_TYPE_DOUBLE:
11757         dp = column->values->d;
11758         if (length == 1)
11759             return *dp;
11760         if (nullcount == 0) {
11761             minimum = *dp++;
11762             for (i = 1; i < length; i++, dp++) 
11763                 if (minimum > *dp) 
11764                     minimum = *dp;
11765         }
11766         else {
11767             for (i = 0; i < length; i++, dp++, np++) {
11768                 if (*np == 0) {
11769                     if (first) {
11770                         first = 0;
11771                         minimum = *dp;
11772                     }
11773                     else 
11774                         if (minimum > *dp) 
11775                             minimum = *dp;
11776                 }
11777             }
11778         }
11779         break;
11780     default:
11781         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11782         return 0.0;
11783     }
11784 
11785     return minimum;
11786 
11787 }
11788 
11789 
11790 /* 
11791  * @brief
11792  *   Get position of maximum in a numerical column.
11793  *
11794  * @param column   Input column.
11795  * @param indx     Returned position of maximum value.
11796  *
11797  * @return @c CPL_ERROR_NONE on success. If any input argument is a 
11798  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the 
11799  *   accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
11800  *   is returned. If the input column elements are all invalid, or 
11801  *   the column has zero length, a @c CPL_ERROR_DATA_NOT_FOUND is 
11802  *   returned.
11803  *
11804  * Column values marked as invalid are excluded from the search.
11805  * The @em indx argument will be assigned the position of the maximum 
11806  * value. Indexes are counted starting from 0. If more than one column 
11807  * element correspond to the max value, the position with the lowest 
11808  * indx is returned. In case of error, @em indx is set to zero. 
11809  * Columns of strings or arrays are not allowed.
11810  */ 
11811     
11812 cpl_error_code xxx_column_get_maxpos(xxx_column *column, int *indx)
11813 {
11814 
11815     const char *fid       = "xxx_column_get_maxpos";
11816     int          length    = xxx_column_get_size(column);
11817     int          nullcount = xxx_column_count_invalid(column);
11818     cpl_type     type      = xxx_column_get_type(column);
11819     int          first     = 1;
11820     int         *ip;
11821     float       *fp;
11822     double      *dp;
11823     int         *np;
11824     double       maximum=0;
11825     int          i;
11826 
11827 
11828     if (column == 0x0 || indx == 0x0)
11829         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11830 
11831     if (nullcount == length || length == 0)
11832         return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11833 
11834     *indx = 0;
11835 
11836     if (length == 1)
11837         return CPL_ERROR_NONE;
11838 
11839     np = column->null;
11840 
11841     switch (type) {
11842     case CPL_TYPE_INT:
11843         ip = column->values->i;
11844         if (nullcount == 0) {
11845             maximum = *ip++;
11846             for (i = 1; i < length; i++, ip++) {
11847                 if (maximum < *ip) {
11848                     maximum = *ip;
11849                     *indx = i;
11850                 }
11851             }
11852         }
11853         else {
11854             for (i = 0; i < length; i++, ip++, np++) {
11855                 if (*np == 0) {
11856                     if (first) {
11857                         first = 0;
11858                         maximum = *ip;
11859                         *indx = i;
11860                     }
11861                     else {
11862                         if (maximum < *ip) {
11863                             maximum = *ip;
11864                             *indx = i;
11865                         }
11866                     }
11867                 }
11868             }
11869         }
11870         break;
11871     case CPL_TYPE_FLOAT:
11872         fp = column->values->f;
11873         if (nullcount == 0) {
11874             maximum = *fp++;
11875             for (i = 1; i < length; i++, fp++) {
11876                 if (maximum < *fp) {
11877                     maximum = *fp;
11878                     *indx = i;
11879                 }
11880             }
11881         }
11882         else {
11883             for (i = 0; i < length; i++, fp++, np++) {
11884                 if (*np == 0) {
11885                     if (first) {
11886                         first = 0;
11887                         maximum = *fp;
11888                         *indx = i;
11889                     }
11890                     else {
11891                         if (maximum < *fp) {
11892                             maximum = *fp;
11893                             *indx = i;
11894                         }
11895                     }
11896                 }
11897             }
11898         }
11899         break;
11900     case CPL_TYPE_DOUBLE:
11901         dp = column->values->d;
11902         if (nullcount == 0) {
11903             maximum = *dp++;
11904             for (i = 1; i < length; i++, dp++) {
11905                 if (maximum < *dp) {
11906                     maximum = *dp;
11907                     *indx = i;
11908                 }
11909             }
11910         }
11911         else {
11912             for (i = 0; i < length; i++, dp++, np++) {
11913                 if (*np == 0) {
11914                     if (first) {
11915                         first = 0;
11916                         maximum = *dp;
11917                         *indx = i;
11918                     }
11919                     else {
11920                         if (maximum < *dp) {
11921                             maximum = *dp;
11922                             *indx = i;
11923                         }
11924                     }
11925                 }
11926             }
11927         }
11928         break;
11929     default:
11930         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
11931     }
11932 
11933     return CPL_ERROR_NONE;
11934 
11935 }
11936 
11937 
11938 /* 
11939  * @brief
11940  *   Get position of minimum in a numerical column.
11941  *
11942  * @param column   Input column.
11943  * @param indx     Returned position of minimum value.
11944  *
11945  * @return @c CPL_ERROR_NONE on success. If any input argument is a
11946  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
11947  *   accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
11948  *   is returned. If the input column elements are all invalid, or
11949  *   the column has zero length, a @c CPL_ERROR_DATA_NOT_FOUND is
11950  *   returned.
11951  *
11952  * Column values marked as invalid are excluded from the search.
11953  * The @em indx argument will be assigned the position of the minimum
11954  * value. Indexes are counted starting from 0. If more than one column
11955  * element correspond to the min value, the position with the lowest
11956  * index is returned. In case of error, @em indx is set to zero.
11957  * Columns of strings or arrays are not allowed.
11958  */
11959 
11960 cpl_error_code xxx_column_get_minpos(xxx_column *column, int *indx)
11961 {
11962 
11963     const char *fid       = "xxx_column_get_minpos";
11964     int          length    = xxx_column_get_size(column);
11965     int          nullcount = xxx_column_count_invalid(column);
11966     cpl_type     type      = xxx_column_get_type(column);
11967     int          first     = 1;
11968     int         *ip;
11969     float       *fp;
11970     double      *dp;
11971     int         *np;
11972     double       minimum=0;
11973     int          i;
11974 
11975 
11976     if (column == 0x0 || indx == 0x0)
11977         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
11978 
11979     if (nullcount == length || length == 0)
11980         return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
11981 
11982     *indx = 0;
11983 
11984     if (length == 1)
11985         return CPL_ERROR_NONE;
11986 
11987     np = column->null;
11988 
11989     switch (type) {
11990     case CPL_TYPE_INT:
11991         ip = column->values->i;
11992         if (nullcount == 0) {
11993             minimum = *ip++;
11994             for (i = 1; i < length; i++, ip++) {
11995                 if (minimum > *ip) {
11996                     minimum = *ip;
11997                     *indx = i;
11998                 }
11999             }
12000         }
12001         else {
12002             for (i = 0; i < length; i++, ip++, np++) {
12003                 if (*np == 0) {
12004                     if (first) {
12005                         first = 0;
12006                         minimum = *ip;
12007                         *indx = i;
12008                     }
12009                     else {
12010                         if (minimum > *ip) {
12011                             minimum = *ip;
12012                             *indx = i;
12013                         }
12014                     }
12015                 }
12016             }
12017         }
12018         break;
12019     case CPL_TYPE_FLOAT:
12020         fp = column->values->f;
12021         if (nullcount == 0) {
12022             minimum = *fp++;
12023             for (i = 1; i < length; i++, fp++) {
12024                 if (minimum > *fp) {
12025                     minimum = *fp;
12026                     *indx = i;
12027                 }
12028             }
12029         }
12030         else {
12031             for (i = 0; i < length; i++, fp++, np++) {
12032                 if (*np == 0) {
12033                     if (first) {
12034                         first = 0;
12035                         minimum = *fp;
12036                         *indx = i;
12037                     }
12038                     else {
12039                         if (minimum > *fp) {
12040                             minimum = *fp;
12041                             *indx = i;
12042                         }
12043                     }
12044                 }
12045             }
12046         }
12047         break;
12048     case CPL_TYPE_DOUBLE:
12049         dp = column->values->d;
12050         if (nullcount == 0) {
12051             minimum = *dp++;
12052             for (i = 1; i < length; i++, dp++) {
12053                 if (minimum > *dp) {
12054                     minimum = *dp;
12055                     *indx = i;
12056                 }
12057             }
12058         }
12059         else {
12060             for (i = 0; i < length; i++, dp++, np++) {
12061                 if (*np == 0) {
12062                     if (first) {
12063                         first = 0;
12064                         minimum = *dp;
12065                         *indx = i;
12066                     }
12067                     else {
12068                         if (minimum > *dp) {
12069                             minimum = *dp;
12070                             *indx = i;
12071                         }
12072                     }
12073                 }
12074             }
12075         }
12076         break;
12077     default:
12078         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
12079     }
12080 
12081     return CPL_ERROR_NONE;
12082 
12083 }
12084 
12085 
12086 /*
12087  * @brief
12088  *   Find the median of an integer column.
12089  *
12090  * @param column   Input column.
12091  *
12092  * @return Median.
12093  *
12094  * Invalid column values are excluded from the search. 
12095  * The column must contain at least one valid value.
12096  * In case of failure, zero is returned. Columns of strings or
12097  * arrays are not allowed.
12098  */
12099 
12100 static int xxx_column_median_int(xxx_column *column)
12101 {
12102 
12103     int          length    = xxx_column_get_size(column);
12104     int          nullcount = xxx_column_count_invalid(column);
12105     int          median    = 0;
12106     int          i, n;
12107     int         *np;
12108     int         *ip;
12109     int         *cip;
12110     int         *copybuf;
12111 
12112 
12113     n = length - nullcount;
12114     cip = copybuf = cpl_malloc(n * sizeof(int));
12115     ip = column->values->i;
12116     np = column->null;
12117 
12118     if (nullcount) {
12119         for (i = 0; i < length; i++, np++, ip++) {
12120             if (*np == 0) {
12121                 *cip = *ip;
12122                 cip++;
12123             }
12124         }
12125     }
12126     else
12127         memcpy(copybuf, ip, length * sizeof(int));
12128 
12129     median = xxx_tools_get_median_int(copybuf, n);
12130     cpl_free(copybuf);
12131 
12132     return median;
12133 
12134 }
12135 
12136 
12137 /*
12138  * @brief
12139  *   Find the median of a float column.
12140  *
12141  * @param column   Input column.
12142  *
12143  * @return Median.
12144  *
12145  * Column values flagged as NULLs are excluded from the search. 
12146  * The column must contain at least one non-NULL value.
12147  * In case of failure, zero is returned. Columns of strings or
12148  * arrays are not allowed.
12149  */
12150 
12151 static float xxx_column_median_float(xxx_column *column)
12152 {
12153 
12154     int             length    = xxx_column_get_size(column);
12155     int             nullcount = xxx_column_count_invalid(column);
12156     float           median    = 0;
12157     int             i, n;
12158     int            *np;
12159     float          *fp;
12160     float          *cfp;
12161     float          *copybuf;
12162 
12163 
12164     n = length - nullcount;
12165     cfp = copybuf = cpl_malloc(n * sizeof(float));
12166     fp = column->values->f;
12167     np = column->null;
12168 
12169     if (nullcount) {
12170         for (i = 0; i < length; i++, np++, fp++) {
12171             if (*np == 0) {
12172                 *cfp = *fp;
12173                 cfp++;
12174             }
12175         }
12176     }
12177     else
12178         memcpy(copybuf, fp, length * sizeof(float));
12179 
12180     median = xxx_tools_get_median_float(copybuf, n);
12181     cpl_free(copybuf);
12182 
12183     return median;
12184 
12185 }
12186 
12187 
12188 /*
12189  * @brief
12190  *   Find the median of a double column.
12191  *
12192  * @param column   Input column.
12193  *
12194  * @return Median.
12195  *
12196  * Column values flagged as NULLs are excluded from the search. 
12197  * The column must contain at least one non-NULL value.
12198  * In case of failure, zero is returned.
12199  */
12200 
12201 static double xxx_column_median_double(xxx_column *column)
12202 {
12203 
12204     int             length    = xxx_column_get_size(column);
12205     int             nullcount = xxx_column_count_invalid(column);
12206     double          median    = 0;
12207     int             i, n;
12208     int            *np;
12209     double         *dp;
12210     double         *cdp;
12211     double         *copybuf;
12212 
12213 
12214     n = length - nullcount;
12215     cdp = copybuf = cpl_malloc(n * sizeof(double));
12216     dp = column->values->d;
12217     np = column->null;
12218 
12219     if (nullcount) {
12220         for (i = 0; i < length; i++, np++, dp++) {
12221             if (*np == 0) {
12222                 *cdp = *dp;
12223                 cdp++;
12224             }
12225         }
12226     }
12227     else
12228         memcpy(copybuf, dp, length * sizeof(double));
12229 
12230     median = xxx_tools_get_median_double(copybuf, n);
12231     cpl_free(copybuf);
12232 
12233     return median;
12234 
12235 }
12236 
12237 
12238 /* 
12239  * @brief
12240  *   Find the median of a numerical column.
12241  *
12242  * @param column   Input column.
12243  *
12244  * @return Median. In case of error, 0.0 is always returned.
12245  *
12246  * If the input column is a @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is set.
12247  * If the accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE is 
12248  * set. If the input column elements are all invalid, or the column has zero 
12249  * length, a @c CPL_ERROR_DATA_NOT_FOUND is returned. Invalid column elements 
12250  * are excluded from the computation. The column must contain at least one 
12251  * valid elements. Columns of strings or arrays are not allowed.
12252  */
12253 
12254 double xxx_column_get_median(xxx_column *column)
12255 {
12256 
12257     const char *fid       = "xxx_column_get_median";
12258     cpl_type     type      = xxx_column_get_type(column);
12259     int          length    = xxx_column_get_size(column);
12260     int          nullcount = xxx_column_count_invalid(column);
12261 
12262 
12263     if (column == 0x0) {
12264         cpl_error_set_where(fid);
12265         return 0.0;
12266     }
12267 
12268     if (nullcount == length || length == 0) {
12269         cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND);
12270         return 0.0;
12271     }
12272 
12273     switch (type) {
12274     case CPL_TYPE_INT:
12275         return (double)xxx_column_median_int(column);
12276     case CPL_TYPE_FLOAT:
12277         return (double)xxx_column_median_float(column);
12278     case CPL_TYPE_DOUBLE:
12279         return xxx_column_median_double(column);
12280     default:
12281         cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
12282     }
12283 
12284     return 0.0;
12285 
12286 }
12287 
12288 
12289 /*
12290  * @brief
12291  *   Shift numeric column elements.
12292  *
12293  * @param column   Input column.
12294  * @param shift    Shift column values by so many elements.
12295  *
12296  * @return @c CPL_ERROR_NONE on success. If the input @em column is a
12297  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
12298  *   accessed column is not numerical, a @c CPL_ERROR_INVALID_TYPE
12299  *   is returned. The specified shift must be in module less than 
12300  *   the column length, or a @c CPL_ERROR_ILLEGAL_INPUT is returned.
12301  *
12302  * All column elements are shifted by the specified amount. If @em shift 
12303  * is positive, all elements will be moved toward the bottom of the column, 
12304  * otherwise toward its top. The column elements that are left undefined 
12305  * at either end of the column are marked as invalid. Columns of strings or
12306  * arrays are not allowed.
12307  */
12308 
12309 cpl_error_code xxx_column_shift(xxx_column *column, int shift)
12310 {
12311     
12312     const char *fid    = "xxx_column_shift";
12313     cpl_type     type   = xxx_column_get_type(column);
12314     int          length = xxx_column_get_size(column);
12315     int          j;
12316     int          status;
12317     int         *np1;
12318     int         *np2;
12319     int         *ip1;
12320     int         *ip2;
12321     float       *fp1;
12322     float       *fp2;
12323     double      *dp1;
12324     double      *dp2;
12325 
12326 
12327     if (column == 0x0)
12328         return cpl_error_set(fid, CPL_ERROR_NULL_INPUT);
12329 
12330 
12331     /*
12332      *  Allowed column types:
12333      */
12334 
12335     switch (type) {
12336     case CPL_TYPE_INT:
12337     case CPL_TYPE_FLOAT:
12338     case CPL_TYPE_DOUBLE:
12339         break;
12340     default:
12341         return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE);
12342     }
12343 
12344     if (abs(shift) >= length)
12345         return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT);
12346 
12347     if (shift == 0)
12348         return CPL_ERROR_NONE;
12349 
12350     if (column->nullcount == length)
12351         return CPL_ERROR_NONE;
12352 
12353 
12354     /*
12355      *  Invalid flags buffer handling first (because it may fail...)
12356      */
12357 
12358     if (column->nullcount) {
12359         if (shift > 0) {
12360             j = length - shift;
12361             np1 = column->null + length;
12362             np2 = np1 - shift;
12363             while (j--)
12364                 *--np1 = *--np2;
12365         }
12366         else {
12367             j = -shift;
12368             np1 = column->null;
12369             np2 = np1 - shift;
12370             while(j++ < length)
12371                 *np1++ = *np2++;
12372         }
12373 
12374     }
12375 
12376 
12377    /*
12378     *  Invalidate the leftovers
12379     */
12380 
12381     if (shift > 0)
12382         status = xxx_column_fill_invalid(column, 0, shift);
12383     else
12384         status = xxx_column_fill_invalid(column, length + shift, -shift);
12385 
12386     if (status)
12387         return status;
12388 
12389 
12390    /*
12391     *  Now shift the data.
12392     */
12393 
12394     switch (type) {
12395 
12396     case CPL_TYPE_INT:
12397         if (shift > 0) {
12398             j = length - shift;
12399             ip1 = column->values->i + length;
12400             ip2 = ip1 - shift;
12401             while (j--)
12402                 *--ip1 = *--ip2;
12403         }
12404         else {
12405             j = -shift;
12406             ip1 = column->values->i;
12407             ip2 = ip1 - shift;
12408             while(j++ < length)
12409                 *ip1++ = *ip2++;
12410         }
12411         break;
12412 
12413     case CPL_TYPE_FLOAT:
12414         if (shift > 0) {
12415             j = length - shift;
12416             fp1 = column->values->f + length;
12417             fp2 = fp1 - shift;
12418             while (j--)
12419                 *--fp1 = *--fp2;
12420         }
12421         else {  
12422             j = -shift;
12423             fp1 = column->values->f;
12424             fp2 = fp1 - shift;
12425             while(j++ < length)
12426                 *fp1++ = *fp2++;
12427         }
12428         break;
12429 
12430     case CPL_TYPE_DOUBLE:
12431         if (shift > 0) {
12432             j = length - shift;
12433             dp1 = column->values->d + length;
12434             dp2 = dp1 - shift;
12435             while (j--)
12436                 *--dp1 = *--dp2;
12437         }
12438         else {  
12439             j = -shift;
12440             dp1 = column->values->d;
12441             dp2 = dp1 - shift;
12442             while(j++ < length)
12443                 *dp1++ = *dp2++;
12444         }
12445         break;
12446 
12447     default:
12448         break;
12449     }
12450 
12451     return CPL_ERROR_NONE;
12452 
12453 }
12454 
12455 
12456 /* 
12457  * @brief
12458  *   Assign to invalid @em integer column elements a numeric code.
12459  *
12460  * @param column   Input column.
12461  * @param code     Code to write at invalid column elements.
12462  *
12463  * @return @c CPL_ERROR_NONE on success.  If the input @em column is a
12464  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
12465  *   accessed column is not @em integer or arrays of integers, 
12466  *   a @c CPL_ERROR_TYPE_MISMATCH is returned.
12467  *
12468  * In general the column elements that are marked as invalid
12469  * may contain any value, that should not be given any meaning
12470  * whatsoever. In order to export the column data (using a call
12471  * to @c xxx_column_get_data_int() ) to procedures that are external
12472  * to the CPL column system, it may turn out to be appropriate
12473  * assigning to all the invalid elements a special code value.
12474  * This code value will supposedly be recognized and handled
12475  * properly by the foreign method. Note that only existing invalid
12476  * elements will be coded as indicated: new invalid column elements 
12477  * would still have their actual values undefined. Also, any further 
12478  * processing of the column would not take care of maintaining the 
12479  * assigned code to a given invalid column element: therefore the 
12480  * code should be set just before it is actually needed.
12481  *
12482  * @note
12483  *   Assigning a code to an invalid element doesn't make it valid.
12484  */
12485 
12486 
12487 /* 
12488  * @brief
12489  *   Assign to invalid @em float column elements a numeric code.
12490  *
12491  * @param column   Input column.
12492  * @param code     Code to write at invalid column elements.
12493  *
12494  * @return @c CPL_ERROR_NONE on success.  If the input @em column is a
12495  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
12496  *   accessed column is not @em float or array of floats, 
12497  *   a @c CPL_ERROR_TYPE_MISMATCH is returned.
12498  *
12499  * In general the column elements that are marked as invalid
12500  * may contain any value, that should not be given any meaning
12501  * whatsoever. In order to export the column data (using a call
12502  * to @c xxx_column_get_data_float() ) to procedures that are external
12503  * to the CPL column system, it may turn out to be appropriate
12504  * assigning to all the invalid elements a special code value.
12505  * This code value will supposedly be recognized and handled
12506  * properly by the foreign method. Note that only existing invalid
12507  * elements will be coded as indicated: new invalid column elements
12508  * would still have their actual values undefined. Also, any further
12509  * processing of the column would not take care of maintaining the
12510  * assigned code to a given invalid column element: therefore the
12511  * code should be set just before it is actually needed.
12512  *
12513  * @note
12514  *   Assigning a code to an invalid element doesn't make it valid.
12515  */
12516 
12517 
12518 
12519 /* 
12520  * @brief
12521  *   Assign to invalid @em double column elements a numeric code.
12522  *
12523  * @param column   Input column.
12524  * @param code     Code to write at invalid column elements.
12525  *
12526  * @return @c CPL_ERROR_NONE on success.  If the input @em column is a
12527  *   @c NULL pointer, a @c CPL_ERROR_NULL_INPUT is returned. If the
12528  *   accessed column is not @em doubleor array of doubles, 
12529  *   a @c CPL_ERROR_TYPE_MISMATCH is returned.
12530  *
12531  * In general the column elements that are marked as invalid
12532  * may contain any value, that should not be given any meaning
12533  * whatsoever. In order to export the column data (using a call
12534  * to @c xxx_column_get_data_double() ) to procedures that are external
12535  * to the CPL column system, it may turn out to be appropriate
12536  * assigning to all the invalid elements a special code value.
12537  * This code value will supposedly be recognized and handled
12538  * properly by the foreign method. Note that only existing invalid
12539  * elements will be coded as indicated: new invalid column elements
12540  * would still have their actual values undefined. Also, any further
12541  * processing of the column would not take care of maintaining the
12542  * assigned code to a given invalid column element: therefore the
12543  * code should be set just before it is actually needed.
12544  *
12545  * @note
12546  *   Assigning a code to an invalid element doesn't make it valid.
12547  */
12548 
12549 
12550 
12551 
12552 
12553 
12554 
12555 
12556 
12557 
12558 
12559 
12560 
12561 
12562 
12563 
12564 
12565 
12566 
12567 
12568 
12569 
12570 
12571 
12572 
12573 
12574 
12575 cpl_error_code
12576 uves_table_sort_dfsxxxx(cpl_table *table, const uves_propertylist *reflist)
12577 {
12578     return xxx_table_sort((xxx_table *)table, reflist);
12579 }
12580 
12581 
12582 
12583 
12584 
12585 /*----------------------------------------------------------------------------*/
12591 /*----------------------------------------------------------------------------*/
12592 int
12593 uves_table_and_selected_invalid(cpl_table *t, const char *column)
12594 {
12595     if (cpl_table_get_column_type(t, column) != CPL_TYPE_STRING)
12596         {
12597             return cpl_table_and_selected_invalid(t, column);
12598         }
12599     else
12600         {
12601             int i = 0;
12602             for (i = 0; i < cpl_table_get_nrow(t); i++)
12603                 {
12604                     if (cpl_table_is_selected(t, i))
12605                         {
12606                             if (cpl_table_is_valid(t, column, i))
12607                                 {
12608                                     cpl_table_unselect_row(t, i);
12609                                 }
12610                             /* else keep it selected */
12611                         }
12612                     /* else unselected, don't change */
12613                 }
12614 
12615             return cpl_table_count_selected(t);
12616         }
12617 }
12618 
12619     
12620 /*----------------------------------------------------------------------------*/
12637 /*----------------------------------------------------------------------------*/
12638 int
12639 uves_erase_invalid_table_rows(cpl_table *t, const char *column)
12640 {
12641     int result = 0;
12642 
12643     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12644 
12645     if (column == NULL)
12646     /* Loop through all columns */
12647     {
12648         const char *name;
12649         cpl_table *argument = t;
12650         result = 0;
12651         while ( (name = cpl_table_get_column_name(argument)) != NULL)
12652         {
12653             int n_deleted_rows;
12654 
12655             argument = NULL;
12656             n_deleted_rows = uves_erase_invalid_table_rows(t, name);
12657 
12658             if (n_deleted_rows > 0) 
12659             {
12660                 uves_msg_low("%d rows with invalid '%s' removed", 
12661                      n_deleted_rows, name);
12662             }
12663             result += n_deleted_rows;
12664         }
12665     }
12666     else
12667     {
12668         assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT,
12669             "No such column: %s", column);
12670         
12671         check(( cpl_table_select_all(t),
12672             result = uves_table_and_selected_invalid(t, column), /* workaround here */
12673             uves_table_erase_selected_dfs02356(t)),              /* and here */
12674                   "Error deleting rows");
12675     }
12676     
12677   cleanup:
12678     return result;
12679 }
12680 
12681 /*----------------------------------------------------------------------------*/
12698 /*----------------------------------------------------------------------------*/
12699 cpl_table *
12700 uves_extract_table_rows(const cpl_table *t, const char *column,
12701             cpl_table_select_operator operator, double value)
12702 {
12703     cpl_table *result = NULL;
12704     
12705     assure( t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12706     assure( cpl_table_has_column(t, column), CPL_ERROR_INCOMPATIBLE_INPUT,
12707         "No such column: %s", column);
12708     
12709     /* 1. Extract (duplicate) the entire table
12710        2. remove rows *not* satisfying the criterion */
12711     check(( result = cpl_table_duplicate(t),
12712 
12713         uves_select_table_rows(result, column, operator, value),
12714         cpl_table_not_selected(result),  /* Inverses selection */
12715         
12716         uves_table_erase_selected_dfs02356(result)),
12717        
12718        "Error extracting rows");
12719 
12720     passure( cpl_table_count_selected(result) == cpl_table_get_nrow(result),
12721              "%d %d",
12722              cpl_table_count_selected(result), cpl_table_get_nrow(result) );
12723     
12724   cleanup:
12725     if (cpl_error_get_code() != CPL_ERROR_NONE)
12726     {
12727         uves_free_table(&result);
12728     }
12729     return result;
12730 }
12731 
12732 /*----------------------------------------------------------------------------*/
12744 /*----------------------------------------------------------------------------*/
12745 void
12746 uves_sort_table_1(cpl_table *t, const char *column, bool reverse)
12747 {
12748     uves_propertylist *plist = NULL;
12749     
12750     assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12751     assure(cpl_table_has_column(t, column), CPL_ERROR_ILLEGAL_INPUT, 
12752        "No column '%s'", column);
12753 
12754     check(( plist = uves_propertylist_new(),
12755         uves_propertylist_append_bool(plist, column, reverse)),
12756        "Could not create property list for sorting");
12757 
12758     check( uves_table_sort(t, plist), "Could not sort table");
12759 
12760   cleanup:
12761     uves_free_propertylist(&plist);
12762     return;
12763 }
12764 
12765 /*----------------------------------------------------------------------------*/
12781 /*----------------------------------------------------------------------------*/
12782 void
12783 uves_sort_table_2(cpl_table *t, const char *column1, const char *column2, 
12784           bool reverse1, bool reverse2)
12785 {
12786     uves_propertylist *plist = NULL;
12787     
12788     assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12789     assure(cpl_table_has_column(t, column1), CPL_ERROR_ILLEGAL_INPUT, 
12790        "No column '%s'", column1);
12791     assure(cpl_table_has_column(t, column2), CPL_ERROR_ILLEGAL_INPUT,
12792        "No column '%s'", column2);
12793 
12794     check(( plist = uves_propertylist_new(),
12795         uves_propertylist_append_bool(plist, column1, reverse1),
12796         uves_propertylist_append_bool(plist, column2, reverse2)),
12797        "Could not create property list for sorting");
12798     check( uves_table_sort(t, plist), "Could not sort table");
12799     
12800   cleanup:
12801     uves_free_propertylist(&plist);
12802     return;
12803 }
12804 /*----------------------------------------------------------------------------*/
12819 /*----------------------------------------------------------------------------*/
12820 void
12821 uves_sort_table_3(cpl_table *t, const char *column1, const char *column2, 
12822                   const char *column3,
12823           bool reverse1, bool reverse2, bool reverse3)
12824 {
12825     uves_propertylist *plist = NULL;
12826     
12827     assure(t != NULL, CPL_ERROR_NULL_INPUT, "Null table");
12828     assure(cpl_table_has_column(t, column1), CPL_ERROR_ILLEGAL_INPUT, 
12829        "No column '%s'", column1);
12830     assure(cpl_table_has_column(t, column2), CPL_ERROR_ILLEGAL_INPUT,
12831        "No column '%s'", column2);
12832     assure(cpl_table_has_column(t, column3), CPL_ERROR_ILLEGAL_INPUT,
12833        "No column '%s'", column3);
12834 
12835     check(( plist = uves_propertylist_new(),
12836         uves_propertylist_append_bool(plist, column1, reverse1),
12837         uves_propertylist_append_bool(plist, column2, reverse2),
12838             uves_propertylist_append_bool(plist, column3, reverse3)),
12839         "Could not create property list for sorting");
12840     check( uves_table_sort(t, plist), "Could not sort table");
12841     
12842   cleanup:
12843     uves_free_propertylist(&plist);
12844     return;
12845 }
12846 /*----------------------------------------------------------------------------*/
12851 /*----------------------------------------------------------------------------*/
12852 void uves_free(const void *mem)
12853 {
12854     cpl_free((void *)mem); /* No, it is not a bug. The cast is safe */
12855     return;
12856 }
12857 
12858 /*----------------------------------------------------------------------------*/
12863 /*----------------------------------------------------------------------------*/
12864 void uves_free_image(cpl_image **i) 
12865 {if(i){cpl_image_delete(*i); *i = NULL;}}
12866 /*----------------------------------------------------------------------------*/
12871 /*----------------------------------------------------------------------------*/
12872 void uves_free_mask(cpl_mask **m)
12873 {if(m){cpl_mask_delete(*m); *m = NULL;}}
12874 /*----------------------------------------------------------------------------*/
12879 /*----------------------------------------------------------------------------*/
12880 void uves_free_imagelist(cpl_imagelist **i)
12881 {if(i){cpl_imagelist_delete(*i);        *i = NULL;}}
12882 
12883 /*----------------------------------------------------------------------------*/
12888 /*----------------------------------------------------------------------------*/
12889 void uves_free_table(cpl_table **t)
12890 {if(t){cpl_table_delete(*t);            *t = NULL;}}
12891 
12892 /*----------------------------------------------------------------------------*/
12897 /*----------------------------------------------------------------------------*/
12898 void uves_free_table_const(const cpl_table **t)
12899 {if(t){cpl_table_delete(*t);            *t = NULL;}}
12900 
12901 /*----------------------------------------------------------------------------*/
12906 /*----------------------------------------------------------------------------*/
12907 void uves_free_propertylist(uves_propertylist **p)
12908 {if(p){uves_propertylist_delete(*p);     *p = NULL;}}
12909 
12910 /*----------------------------------------------------------------------------*/
12915 /*----------------------------------------------------------------------------*/
12916 void uves_free_propertylist_const(const uves_propertylist **p)
12917 {if(p){uves_propertylist_delete(*p);     *p = NULL;}}
12918 
12919 /*----------------------------------------------------------------------------*/
12924 /*----------------------------------------------------------------------------*/
12925 void uves_free_property(cpl_property **p)
12926 {if(p){cpl_property_delete(*p);     *p = NULL;}}
12927 /*----------------------------------------------------------------------------*/
12932 /*----------------------------------------------------------------------------*/
12933 void uves_free_polynomial(cpl_polynomial **p)
12934 {if(p){cpl_polynomial_delete(*p);       *p = NULL;}}
12935 /*----------------------------------------------------------------------------*/
12940 /*----------------------------------------------------------------------------*/
12941 void uves_free_matrix(cpl_matrix **m)
12942 {if(m){cpl_matrix_delete(*m);           *m = NULL;}}
12943 /*----------------------------------------------------------------------------*/
12948 /*----------------------------------------------------------------------------*/
12949 void uves_free_parameterlist(cpl_parameterlist **p)
12950 {if(p){cpl_parameterlist_delete(*p);    *p = NULL;}}
12951 /*----------------------------------------------------------------------------*/
12956 /*----------------------------------------------------------------------------*/
12957 void uves_free_frameset(cpl_frameset **f)
12958 {if(f){cpl_frameset_delete(*f);    *f = NULL;}}
12959 /*----------------------------------------------------------------------------*/
12964 /*----------------------------------------------------------------------------*/
12965 void uves_free_frame(cpl_frame **f)
12966 {if(f){cpl_frame_delete(*f);    *f = NULL;}}
12967 /*----------------------------------------------------------------------------*/
12972 /*----------------------------------------------------------------------------*/
12973 void uves_free_bivector(cpl_bivector **b)
12974 {if(b){cpl_bivector_delete(*b);           *b = NULL;}}
12975 /*----------------------------------------------------------------------------*/
12980 /*----------------------------------------------------------------------------*/
12981 void uves_free_vector(cpl_vector **v)
12982 {if(v){cpl_vector_delete(*v);           *v = NULL;}}
12983 /*----------------------------------------------------------------------------*/
12988 /*----------------------------------------------------------------------------*/
12989 void uves_free_stats(cpl_stats **s)
12990 {if(s){cpl_stats_delete(*s);            *s = NULL;}}
12991 /*----------------------------------------------------------------------------*/
12996 /*----------------------------------------------------------------------------*/
12997 void uves_unwrap_vector(cpl_vector **v)
12998 {if(v){cpl_vector_unwrap(*v);           *v = NULL;}}
12999 /*----------------------------------------------------------------------------*/
13004 /*----------------------------------------------------------------------------*/
13005 void uves_unwrap_vector_const(const cpl_vector **v)
13006 {if(v){cpl_vector_unwrap(*v);           *v = NULL;}}
13007 /*----------------------------------------------------------------------------*/
13012 /*----------------------------------------------------------------------------*/
13013 void uves_unwrap_bivector_vectors(cpl_bivector **b)
13014 {if(b){cpl_bivector_unwrap_vectors(*b); *b = NULL;}}
13015 /*----------------------------------------------------------------------------*/
13020 /*----------------------------------------------------------------------------*/
13021 void uves_free_array(cpl_array **a)
13022 {if(a){cpl_array_delete(*a);           *a = NULL;}}
13023 
13024 /*----------------------------------------------------------------------------*/
13029 /*----------------------------------------------------------------------------*/
13030 void uves_free_int(int **i)
13031 {if(i){cpl_free(*i);           *i = NULL;}}
13032 
13033 /*----------------------------------------------------------------------------*/
13038 /*----------------------------------------------------------------------------*/
13039 void uves_free_int_const(const int **i)
13040 {if(i){uves_free(*i);           *i = NULL;}}
13041 /*----------------------------------------------------------------------------*/
13046 /*----------------------------------------------------------------------------*/
13047 void uves_free_float(float **f)
13048 {if(f){cpl_free(*f);           *f = NULL;}}
13049 
13050 /*----------------------------------------------------------------------------*/
13055 /*----------------------------------------------------------------------------*/
13056 void uves_free_double(double **d)
13057 {if(d){cpl_free(*d);           *d = NULL;}}
13058 
13059 /*----------------------------------------------------------------------------*/
13064 /*----------------------------------------------------------------------------*/
13065 void uves_free_string(char **s)
13066 {if(s){cpl_free(*s);           *s = NULL;}}
13067 /*----------------------------------------------------------------------------*/
13072 /*----------------------------------------------------------------------------*/
13073 void uves_free_string_const(const char **s)
13074 {if(s){uves_free(*s);           *s = NULL;}}
13075 
13076 /*----------------------------------------------------------------------------*/
13097 /*----------------------------------------------------------------------------*/
13098 
13099 static double
13100 get_chisq(int N, int D,
13101       int (*f)(const double x[], const double a[], double *result),
13102       const double *a,
13103       const double *x,
13104       const double *y,
13105       const double *sigma)
13106 {
13107     double chi_sq;     /* Result */
13108     int i = 0;
13109 
13110     /* For efficiency, don't check input in this static function */
13111 
13112     chi_sq = 0.0;
13113     for (i = 0; i < N; i++)
13114     {
13115         double fx_i;
13116         double residual;                 /* Residual in units of uncertainty */
13117         const double *x_i = &(x[0+i*D]);
13118 
13119         /* Evaluate */
13120         cpl_ensure( f(x_i,
13121               a,
13122               &fx_i) == 0, CPL_ERROR_ILLEGAL_INPUT, -1.0);
13123 
13124         /* Accumulate */
13125         if (sigma == NULL)
13126         {
13127             residual = (fx_i - y[i]);
13128         }
13129         else
13130         {
13131             residual = (fx_i - y[i]) / sigma[i];
13132         }
13133 
13134         chi_sq += residual*residual;
13135        
13136     }
13137 
13138     return chi_sq;
13139 }
13140 /*----------------------------------------------------------------------------*/
13174 /*----------------------------------------------------------------------------*/
13175 static int
13176 get_candidate(const double *a, const int ia[],
13177           int M, int N, int D,
13178           double lambda,
13179           int    (*f)(const double x[], const double a[], double *result),
13180           int (*dfda)(const double x[], const double a[], double result[]),
13181           const double *x,
13182           const double *y,
13183           const double *sigma,
13184           double *partials,
13185           cpl_matrix *alpha,
13186           cpl_matrix *beta,
13187           double *a_da)
13188 {
13189     int Mfit = 0;         /* Number of non-constant fit parameters */
13190     cpl_matrix *da;       /* Solution of   alpha * da = beta */
13191     double *alpha_data;
13192     double *beta_data;
13193     double *da_data;
13194     int i, imfit = 0;
13195     int j, jmfit = 0;
13196     int k = 0;
13197 
13198     /* For efficiency, don't check input in this static function */
13199 
13200     Mfit = cpl_matrix_get_nrow(alpha);
13201 
13202     alpha_data    = cpl_matrix_get_data(alpha);
13203     beta_data     = cpl_matrix_get_data(beta);
13204    
13205     /* Build alpha, beta:
13206      *
13207      *  alpha[i,j] = sum_{k=1,N} (sigma_k)^-2 * df/da_i * df/da_j  *
13208      *                           (1 + delta_ij lambda) ,
13209      *
13210      *   beta[i]   = sum_{k=1,N} (sigma_k)^-2 * ( y_k - f(x_k) ) * df/da_i
13211      *
13212      * where (i,j) loop over the non-constant parameters (0 to Mfit-1),
13213      * delta is Kronecker's delta, and all df/da are evaluated in x_k
13214      */
13215 
13216     cpl_matrix_fill(alpha, 0.0);
13217     cpl_matrix_fill(beta , 0.0);
13218 
13219     for (k = 0; k < N; k++)
13220     {
13221         double sm2 = 0.0;                /* (sigma_k)^-2 */
13222         double fx_k = 0.0;               /* f(x_k)       */
13223         const double *x_k = &(x[0+k*D]); /* x_k          */
13224 
13225         if (sigma == NULL)
13226         {
13227             sm2 = 1.0;
13228         }
13229         else
13230         {
13231             sm2 = 1.0 / (sigma[k] * sigma[k]);
13232         }
13233         
13234         /* Evaluate f(x_k) */
13235         cpl_ensure( f(x_k, a, &fx_k) == 0, CPL_ERROR_ILLEGAL_INPUT, -1);
13236 
13237         /* Evaluate (all) df/da (x_k) */
13238         cpl_ensure( dfda(x_k, a, partials) == 0, 
13239             CPL_ERROR_ILLEGAL_INPUT, -1);
13240 
13241         for (i = 0, imfit = 0; i < M; i++)
13242         {
13243             if (ia[i] != 0)
13244             {
13245                 /* Beta */
13246                 beta_data[imfit] +=
13247                 sm2 * (y[k] - fx_k) * partials[i];
13248                 
13249                 /* Alpha is symmetrical, so compute
13250                    only lower-left part */
13251                 for (j = 0, jmfit = 0; j < i; j++)
13252                 {
13253                     if (ia[j] != 0)
13254                     {
13255                         alpha_data[jmfit + imfit*Mfit] +=
13256                         sm2 * partials[i] * 
13257                         partials[j];
13258                         
13259                         jmfit += 1;
13260                     }
13261                 }
13262                 
13263                 /* Alpha, diagonal terms */
13264                 j = i;
13265                 jmfit = imfit;
13266                 
13267                 alpha_data[jmfit + imfit*Mfit] += 
13268                 sm2 * partials[i] *
13269                 partials[j] * (1 + lambda);
13270                 
13271                 imfit += 1;
13272             }
13273         }
13274 
13275         assert( imfit == Mfit );
13276     }
13277 
13278     /* Create upper-right part of alpha */
13279     for (i = 0, imfit = 0; i < M; i++)
13280     {
13281         if (ia[i] != 0)
13282         {
13283             for (j = i+1, jmfit = imfit+1; j < M; j++)
13284             {
13285                 if (ia[j] != 0)
13286                 {
13287                     alpha_data[jmfit + imfit*Mfit] = 
13288                     alpha_data[imfit + jmfit*Mfit];
13289                     
13290                     jmfit += 1;
13291                 }
13292             }
13293             assert( jmfit == Mfit );
13294 
13295             imfit += 1;
13296         }
13297     }
13298     assert( imfit == Mfit );
13299     
13300     da = cpl_matrix_solve(alpha, beta);
13301 
13302     cpl_ensure(da != NULL, cpl_error_get_code(), -1);
13303 
13304     /* Create a+da vector by adding a and da */
13305     da_data   = cpl_matrix_get_data(da);
13306 
13307     for (i = 0, imfit = 0; i < M; i++)
13308     {
13309         if (ia[i] != 0)
13310         {
13311             a_da[i] = a[i] + da_data[0 + imfit*1];
13312             
13313             imfit += 1;
13314         }
13315         else
13316         {
13317             a_da[i] = a[i];
13318         }
13319     }
13320     
13321     assert( imfit == Mfit );
13322 
13323     cpl_matrix_delete(da);
13324 
13325     return 0;
13326 }
13327 

Generated on Thu Nov 15 14:32:34 2007 for UVES Pipeline Reference Manual by  doxygen 1.5.1