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

Generated on Mon Apr 21 10:56:57 2008 for UVES Pipeline Reference Manual by  doxygen 1.5.1