/* $Id: cpl_table.c,v 1.192 2008/01/29 10:29:26 cizzo Exp $ * * This file is part of the ESO Common Pipeline Library * Copyright (C) 2001-2004 European Southern Observatory * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * $Author: cizzo $ * $Date: 2008/01/29 10:29:26 $ * $Revision: 1.192 $ * $Name: $ */ #ifdef HAVE_CONFIG_H #include #endif #define ERASE_WCS_REGEXP "WCSAXES|WCSNAME|(PC|CD|PV|PS)[0-9]+_[0-9]+|" \ "C(RVAL|RPIX|DELT|TYPE|UNIT|RDER|SYER)[0-9]+" #include #include #include #include #include #include #include #include #include #include #include #include "cpl_errorstate.h" #include #include #include #include #include #include #include #include #include #include /** * @defgroup cpl_table Tables * * This module provides functions to create, use, and destroy * a @em cpl_table. A @em cpl_table is made of columns, and * a column consists of an array of elements of a given type. * Currently three numerical types are supported, @c CPL_TYPE_INT, * @c CPL_TYPE_FLOAT, and @c CPL_TYPE_DOUBLE, plus a type indicating * columns containing character strings, @c CPL_TYPE_STRING. * Moreover, it is possible to define columns of arrays, i.e. * columns whose elements are arrays of all the basic types * listed above. Within the same column all arrays must have * the same type. * * A table column is accessed by specifying its name. The ordering * of the columns within a table is undefined: a @em cpl_table is * not an n-tuple of columns, but just a set of columns. The N * elements of a column are counted from 0 to N-1, with element * 0 on top. The set of all the table columns elements with the * same index constitutes a table row, and table rows are counted * according to the same convention. It is possible to flag each * @em cpl_table row as "selected" or "unselected", and each column * element as "valid" or "invalid". Selecting table rows is mainly * a way to extract just those table parts fulfilling any given * condition, while invalidating column elements is a way to * exclude such elements from any computation. A @em cpl_table * is created with all rows selected, and a column is created with * all elements invalidated. * * @note * The @em cpl_table pointers specified in the argument list of all * the @em cpl_table functions must point to valid objects: these * functions do not perform any check in this sense. Only in the * particular case of a @c NULL pointer the functions will set a * @c CPL_ERROR_NULL_INPUT error code, unless differently specified. * * @par Synopsis: * @code * #include * @endcode */ /**@{*/ /* * The table type; */ struct _cpl_table_ { int nc; int nr; cpl_column **columns; cpl_column_flag *select; int selectcount; }; /* * Private methods: */ /* * @brief * Find a column. * * @param table Pointer to table where to search for the column. * @param name Column name. * * @return Pointer to found column, or @c NULL. * * This private function looks for a column with a given name in * @em table. A @c NULL is returned if no column with the specified * @em name is found. The input @em table and @em name are assumed * not to be @c NULL. */ static cpl_column *cpl_table_find_column(const cpl_table *table, const char *name) { cpl_column **column; const char *column_name; int i; column = table->columns; for (i = 0; i < table->nc; i++, column++) { column_name = cpl_column_get_name(*column); if (strcmp(name, column_name) == 0) { return *column; } } return NULL; } /* * @brief * Extract a column from a table. * * @param table Pointer to table. * @param name Column name. * * @return Pointer to extracted column, or @c NULL. * * This private function looks for a column with a given name in * @em table. If found, the column is extracted from the table, and the * table will have one column less. If no columns are left in table, * also the selection flags are lost. A @c NULL is returned if no column * with the specified @em name is found. The input @em table and @em name * are expected not to be @c NULL. */ static cpl_column *cpl_table_extract_column(cpl_table *table, const char *name) { cpl_column *column = cpl_table_find_column(table, name); int width = cpl_table_get_ncol(table); int pos; int i, j; if (column) { for (i = 0; i < width; i++) if (column == table->columns[i]) break; pos = i; j = i + 1; while(j < width) table->columns[i++] = table->columns[j++]; table->nc--; if (table->nc) { table->columns = cpl_realloc(table->columns, table->nc * sizeof(column)); } else { cpl_free(table->columns); table->columns = NULL; } if (table->nc == 0) /* Last column deleted */ cpl_table_select_all(table); } return column; } /* * @brief * Append a column to a table. * * @param table Pointer to table where to append the column. * @param column Column to append. * * @return @c CPL_ERROR_NONE on success. * * This private function appends a column to the column list of a table. * It is assumed that a column with the same name does not exist already * in the table. The input @em table and @em column are expected not to * be @c NULL, and the input column is expected not to be nameless. Also, * the input column is assumed to have the same length as all the other * columns in the table. */ static cpl_error_code cpl_table_append_column(cpl_table *table, cpl_column *column) { if (table->columns) { table->columns = cpl_realloc(table->columns, (table->nc + 1) * sizeof(column)); } else table->columns = cpl_malloc(sizeof(column)); table->columns[table->nc] = column; table->nc++; return CPL_ERROR_NONE; } /* * @brief * Check if a string matches a compiled regular expression. * * @param pattern Compiled regular expression. * @param string String to test. * * @return 1 on match, 0 on mismatch. * * This private function tests a string against an extended regular expression. * The inputs are assumed not to be @c NULL. It is assumed also that the * check on the availability of regexec() are done elsewhere. */ static int strmatch(regex_t *pattern, const char *string) { if (regexec(pattern, string, (size_t)0, NULL, 0) == REG_NOMATCH) return 0; return 1; } /* * @brief * Sort table rows according to columns values. * * @param table Pointer to table. * @param reflist Names of reference columns with corresponding sorting mode. * @param n Use only n first elements of @em reflist * @param sort_pattern Work space * @param sort_null_pattern Work space * * @return See @c cpl_table_sort() * * The table is sorted after each of the n columns, less significant columns * before more significant columns. This method depends on the sorting * algorithm being stable (i.e. it must conserve the order of equal elements). */ static cpl_error_code table_sort(cpl_table *table, const cpl_propertylist *reflist, unsigned n, int *sort_pattern, int *sort_null_pattern) { const char *fid = "table_sort"; const cpl_property *info; const char *name; int reverse; const int stable = 1; cpl_column *column; cpl_column *column_sorted_null; cpl_type type; int i, j; int nullcount; int *idata; int *work_idata; float *fdata; float *work_fdata; double *ddata; double *work_ddata; char **sdata; char **work_sdata; cpl_array **adata; cpl_array **work_adata; cpl_column_flag *ndata; cpl_column_flag *work_ndata; if (n == 0) { return CPL_ERROR_NONE; } /* * Sort after least significant column */ info = cpl_propertylist_get_const(reflist, n - 1); name = cpl_property_get_name(info); if (cpl_property_get_type(info) == CPL_TYPE_BOOL) { reverse = cpl_property_get_bool(info); } else { return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); } if (name == NULL) { return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); } if ((column = cpl_table_find_column(table, name)) == NULL) { return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); } type = cpl_column_get_type(column); if (type & CPL_TYPE_POINTER) { /* Arrays not as reference */ return cpl_error_set(fid, CPL_ERROR_UNSUPPORTED_MODE); } /* * Independent of the reverse flag, put rows with invalid values at the * beginning of the table */ nullcount = cpl_column_count_invalid(column); ndata = cpl_column_get_data_invalid(column); j = 0; for (i = 0; i < table->nr; i++) { if (nullcount == table->nr || (ndata != NULL && ndata[i])) { sort_null_pattern[j++] = i; } } assert( j == nullcount ); for (i = 0; i < table->nr; i++) { if (! (nullcount == table->nr || (ndata != NULL && ndata[i])) ) { sort_null_pattern[j++] = i; } } assert( j == table->nr ); /* * Apply NULL pattern */ column_sorted_null = cpl_column_duplicate(column); for (i = 0; i < nullcount; i++) { cpl_column_set_invalid(column_sorted_null, i); } for (i = nullcount; i < table->nr; i++) { int isnull; switch (type) { case CPL_TYPE_INT: cpl_column_set_int( column_sorted_null, i, cpl_column_get_int(column, sort_null_pattern[i], &isnull)); break; case CPL_TYPE_FLOAT: cpl_column_set_float( column_sorted_null, i, cpl_column_get_float(column, sort_null_pattern[i], &isnull)); break; case CPL_TYPE_DOUBLE: cpl_column_set_double( column_sorted_null, i, cpl_column_get_double(column, sort_null_pattern[i], &isnull)); break; case CPL_TYPE_STRING: cpl_column_set_string( column_sorted_null, i, cpl_column_get_string(column, sort_null_pattern[i])); break; default: assert( 0 ); break; } } /* * Get remaining sort pattern */ for (i = 0; i < nullcount; i++) { sort_pattern[i] = i; } switch (type) { case CPL_TYPE_INT: cpl_tools_sort_stable_pattern_int( cpl_column_get_data_int(column_sorted_null) + nullcount, table->nr - nullcount, reverse, stable, sort_pattern + nullcount); break; case CPL_TYPE_FLOAT: cpl_tools_sort_stable_pattern_float( cpl_column_get_data_float(column_sorted_null) + nullcount, table->nr - nullcount, reverse, stable, sort_pattern + nullcount); break; case CPL_TYPE_DOUBLE: cpl_tools_sort_stable_pattern_double( cpl_column_get_data_double(column_sorted_null) + nullcount, table->nr - nullcount, reverse, stable, sort_pattern + nullcount); break; case CPL_TYPE_STRING: cpl_tools_sort_stable_pattern_string( cpl_column_get_data_string(column_sorted_null) + nullcount, table->nr - nullcount, reverse, stable, sort_pattern + nullcount); break; default: assert( 0 ); break; } cpl_column_delete(column_sorted_null); /* * Transform sort pattern */ for (i = nullcount; i < table->nr; i++) { sort_pattern[i] += nullcount; } /* * Now apply the combined sort pattern to each column in the table: */ j = 0; while (j < table->nc) { cpl_column *work_column; switch (cpl_column_get_type(table->columns[j])) { case CPL_TYPE_INT: work_column = cpl_column_duplicate(table->columns[j]); nullcount = cpl_column_count_invalid(table->columns[j]); if (nullcount != table->nr) { ndata = cpl_column_get_data_invalid(table->columns[j]); if (ndata) { work_ndata = cpl_column_get_data_invalid(work_column); for (i = 0; i < table->nr; i++) ndata[i] = work_ndata[sort_null_pattern[sort_pattern[i]]]; } } work_idata = cpl_column_get_data_int(work_column); idata = cpl_column_get_data_int(table->columns[j]); for (i = 0; i < table->nr; i++) idata[i] = work_idata[sort_null_pattern[sort_pattern[i]]]; cpl_column_delete(work_column); break; case CPL_TYPE_FLOAT: work_column = cpl_column_duplicate(table->columns[j]); nullcount = cpl_column_count_invalid(table->columns[j]); if (nullcount != table->nr) { ndata = cpl_column_get_data_invalid(table->columns[j]); if (ndata) { work_ndata = cpl_column_get_data_invalid(work_column); for (i = 0; i < table->nr; i++) ndata[i] = work_ndata[sort_null_pattern[sort_pattern[i]]]; } } work_fdata = cpl_column_get_data_float(work_column); fdata = cpl_column_get_data_float(table->columns[j]); for (i = 0; i < table->nr; i++) fdata[i] = work_fdata[sort_null_pattern[sort_pattern[i]]]; cpl_column_delete(work_column); break; case CPL_TYPE_DOUBLE: work_column = cpl_column_duplicate(table->columns[j]); nullcount = cpl_column_count_invalid(table->columns[j]); if (nullcount != table->nr) { ndata = cpl_column_get_data_invalid(table->columns[j]); if (ndata) { work_ndata = cpl_column_get_data_invalid(work_column); for (i = 0; i < table->nr; i++) ndata[i] = work_ndata[sort_null_pattern[sort_pattern[i]]]; } } work_ddata = cpl_column_get_data_double(work_column); ddata = cpl_column_get_data_double(table->columns[j]); for (i = 0; i < table->nr; i++) ddata[i] = work_ddata[sort_null_pattern[sort_pattern[i]]]; cpl_column_delete(work_column); break; case CPL_TYPE_STRING: work_column = cpl_column_new_string(table->nr); work_sdata = cpl_column_get_data_string(work_column); sdata = cpl_column_get_data_string(table->columns[j]); for (i = 0; i < table->nr; i++) work_sdata[i] = sdata[i]; for (i = 0; i < table->nr; i++) sdata[i] = work_sdata[sort_null_pattern[sort_pattern[i]]]; cpl_column_delete_but_strings(work_column); break; case CPL_TYPE_INT | CPL_TYPE_POINTER: case CPL_TYPE_FLOAT | CPL_TYPE_POINTER: case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER: case CPL_TYPE_STRING | CPL_TYPE_POINTER: work_column = cpl_column_new_array(cpl_column_get_type(table->columns[j]), table->nr, cpl_column_get_depth(table->columns[j])); work_adata = cpl_column_get_data_array(work_column); adata = cpl_column_get_data_array(table->columns[j]); for (i = 0; i < table->nr; i++) work_adata[i] = adata[i]; for (i = 0; i < table->nr; i++) adata[i] = work_adata[sort_null_pattern[sort_pattern[i]]]; cpl_column_delete_but_arrays(work_column); break; default: break; /* Should never get here */ } j++; } /* * Finished sorting after least significant column. * Sort after remaining columns */ return table_sort(table, reflist, n - 1, sort_pattern, sort_null_pattern); } /* * Public methods: */ /** * @brief * Create an empty table structure. * * @param length Number of rows in table. * * @return Pointer to new table, or @c NULL in case of error. * * @error * * * * * *
CPL_ERROR_ILLEGAL_INPUT * The specified length is negative. *
* @enderror * * This function allocates and initialises memory for a table data container. * A new table is created with no columns, but the size of the columns that * will be created is defined in advance, to ensure that all columns will * be created with the same length. All table rows are marked a priori as * selected. This should be considered the normal status of a table, as * long as no row selection has been applied to it. */ cpl_table *cpl_table_new(int length) { cpl_table *table; if (length < 0) { cpl_error_set("cpl_table_new", CPL_ERROR_ILLEGAL_INPUT); return NULL; } table = cpl_calloc(1, sizeof(cpl_table)); table->nc = 0; table->nr = length; table->columns = NULL; table->select = NULL; table->selectcount = length; return table; } /** * @brief * Give to a table the same structure of another table. * * @param table Pointer to empty table. * @param mtable Pointer to model table. * * @return @c CPL_ERROR_NONE in case of success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_ILLEGAL_INPUT * table contains columns. *
* @enderror * * This function assignes to a columnless table the same column structure * (names, types, etc.) of a given model table. All columns are physically * created in the new table, and they are initialised to contain just * invalid elements. */ cpl_error_code cpl_table_copy_structure(cpl_table *table, const cpl_table *mtable) { const char *fid = "cpl_table_copy_structure"; cpl_column **column; cpl_type type; int width = cpl_table_get_ncol(mtable); int i = 0; if (table == 0x0 || mtable == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (table->nc > 0) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); column = mtable->columns; for (i = 0; i < width; i++, column++) { type = cpl_column_get_type(*column); if (type & CPL_TYPE_POINTER) { cpl_table_new_column_array(table, cpl_column_get_name(*column), type, cpl_column_get_depth(*column)); } else { cpl_table_new_column(table, cpl_column_get_name(*column), type); } } return CPL_ERROR_NONE; } /** * @brief * Create an empty column in a table. * * @param table Pointer to table. * @param name Name of the new column. * @param type Type of the new column. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_INVALID_TYPE * The specified type is not supported. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the same name already exists in table. *
* @enderror * * This function allocates memory for a new column of specified @em type, * excluding @em array types (for creating a column of arrays use the * function @c cpl_table_new_column_array(), where the column depth * must also be specified). The new column name must be different from * any other column name in the table. All the elements of the new column * are marked as invalid. */ cpl_error_code cpl_table_new_column(cpl_table *table, const char *name, cpl_type type) { const char *fid = "cpl_table_new_column"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (cpl_table_find_column(table, name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); switch(type) { case CPL_TYPE_INT: column = cpl_column_new_int(table->nr); break; case CPL_TYPE_FLOAT: column = cpl_column_new_float(table->nr); break; case CPL_TYPE_DOUBLE: column = cpl_column_new_double(table->nr); break; case CPL_TYPE_STRING: column = cpl_column_new_string(table->nr); break; default: return cpl_error_set(fid, CPL_ERROR_INVALID_TYPE); } cpl_column_set_name(column, name); cpl_table_append_column(table, column); return CPL_ERROR_NONE; } /** * @brief * Create an empty column of arrays in a table. * * @param table Pointer to table. * @param name Name of the new column. * @param type Type of the new column. * @param depth Depth of the new column. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_INVALID_TYPE * The specified type is not supported. *
CPL_ERROR_ILLEGAL_INPUT * The specified depth is negative. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the same name already exists in table. *
* @enderror * * This function allocates memory for a new column of specified array * @em type, (for creating a column of simple scalars or character strings * use the function @c cpl_table_new_column() instead). It doesn't make * any difference if a simple or an array @em type is specified, the * corresponding array type will always be created (e.g., specifying * a @em type @c CPL_TYPE_INT or a type @c CPL_TYPE_INT | @c CPL_TYPE_POINTER * would always create a column of type @c CPL_TYPE_INT | @c CPL_TYPE_POINTER). * The new column name must be different from any other column name in the * table. All the elements of the new column are marked as invalid. */ cpl_error_code cpl_table_new_column_array(cpl_table *table, const char *name, cpl_type type, int depth) { const char *fid = "cpl_table_new_column_array"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (depth < 0) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); if (cpl_table_find_column(table, name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); column = cpl_column_new_array(type, table->nr, depth); cpl_column_set_name(column, name); cpl_table_append_column(table, column); return CPL_ERROR_NONE; } /** * @brief * Create in table a new @em integer column obtained from existing data. * * @param table Pointer to table where to create the new column. * @param name Name of the new column. * @param data Existing data buffer. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the same name already exists in table. *
* @enderror * * This function creates a new column of type @c CPL_TYPE_INT that will * encapsulate the given data. The size of the input data array is not * checked in any way, and it is expected to match the number of rows * assigned to the given table. The pointed data values are all taken * as valid: invalid values should be marked using the functions * @c cpl_table_set_invalid() and @c cpl_table_set_column_invalid(). * The data buffer is not copied, so it should not be deallocated while * the table column is still in use: the functions @c cpl_table_erase_column() * or @c cpl_table_delete() would take care of deallocating it. To avoid * problems with the memory managment, the specified data buffer should * have been allocated using the functions of the @em cpl_memory module, * and statically allocated data should be avoided too. If this is not * possible, then the function @c cpl_table_unwrap() should be used on * that column before destroying the table that contains it. */ cpl_error_code cpl_table_wrap_int(cpl_table *table, int *data, const char *name) { const char *fid = "cpl_table_wrap_int"; cpl_column *column; if (table == 0x0 || data == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (cpl_table_find_column(table, name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); column = cpl_column_wrap_int(data, table->nr); cpl_column_set_name(column, name); cpl_table_append_column(table, column); return CPL_ERROR_NONE; } /** * @brief * Create in table a new @em float column obtained from existing data. * * @param table Pointer to table. * @param name Name of the new column. * @param data Existing data buffer. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the same name already exists in table. *
* @enderror * * This function creates a new column of type @c CPL_TYPE_FLOAT * that will encapsulate the given data. See the description of * @c cpl_table_wrap_int() for further details. */ cpl_error_code cpl_table_wrap_float(cpl_table *table, float *data, const char *name) { const char *fid = "cpl_table_wrap_float"; cpl_column *column; if (table == 0x0 || data == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (cpl_table_find_column(table, name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); column = cpl_column_wrap_float(data, table->nr); cpl_column_set_name(column, name); cpl_table_append_column(table, column); return CPL_ERROR_NONE; } /** * @brief * Create in table a new @em double column obtained from existing data. * * @param table Pointer to table. * @param name Name of the new column. * @param data Existing data buffer. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the same name already exists in table. *
* @enderror * * This function creates a new column of type @c CPL_TYPE_DOUBLE * that will encapsulate the given data. See the description of * @c cpl_table_wrap_int() for further details. */ cpl_error_code cpl_table_wrap_double(cpl_table *table, double *data, const char *name) { const char *fid = "cpl_table_wrap_double"; cpl_column *column; if (table == 0x0 || data == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (cpl_table_find_column(table, name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); column = cpl_column_wrap_double(data, table->nr); cpl_column_set_name(column, name); cpl_table_append_column(table, column); return CPL_ERROR_NONE; } /** * @brief * Create in table a new @em string column obtained from existing data. * * @param table Pointer to table. * @param name Name of the new column. * @param data Existing data buffer. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the same name already exists in table. *
* @enderror * * This function creates a new column of type @c CPL_TYPE_STRING that will * encapsulate the given data. See the description of @c cpl_table_wrap_int() * for further details, especially with regard to memory managment. In the * specific case of @em string columns the described restrictions applies * also to the single column elements (strings). To deallocate specific * column elements the functions @c cpl_table_set_invalid() and * @c cpl_table_set_column_invalid() should be used. */ cpl_error_code cpl_table_wrap_string(cpl_table *table, char **data, const char *name) { const char *fid = "cpl_table_wrap_string"; cpl_column *column; if (table == 0x0 || data == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (cpl_table_find_column(table, name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); column = cpl_column_wrap_string(data, table->nr); cpl_column_set_name(column, name); cpl_table_append_column(table, column); return CPL_ERROR_NONE; } /** * @brief * Unwrap a table column * * @param table Pointer to table. * @param name Name of the column. * * @return Pointer to internal data buffer, @c NULL in case of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_UNSUPPORTED_MODE * The column with the given name is a column of arrays. *
* @enderror * * This function deallocates all the memory associated to a table column, * with the exception of its data buffer. This type of destructor * should be used on columns created with the @c cpl_table_wrap_() * constructors, if the data buffer specified then was not allocated * using the functions of the @c cpl_memory module. In such a case, the * data buffer should be deallocated separately. See the documentation * of the functions @c cpl_table_wrap_(). * * @note * Columns of arrays cannot be unwrapped. Use the function * @c cpl_table_get_data_array() to directly access the column * data buffer. */ void *cpl_table_unwrap(cpl_table *table, const char *name) { const char *fid = "cpl_table_unwrap"; cpl_column *column; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return NULL; } if (cpl_table_get_column_type(table, name) & CPL_TYPE_POINTER) { cpl_error_set(fid, CPL_ERROR_UNSUPPORTED_MODE); return NULL; } column = cpl_table_extract_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return NULL; } return cpl_column_unwrap(column); } /** * @brief * Copy existing data to a table @em integer column. * * @param table Pointer to table. * @param name Name of the column. * @param data Existing data buffer. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_INT. *
* @enderror * * The input data values are copied to the specified column. The size of the * input array is not checked in any way, and it is expected to be compatible * with the number of rows in the given table. The copied data values are * all taken as valid: invalid values should be marked using the functions * @c cpl_table_set_invalid() and @c cpl_table_set_column_invalid(). */ cpl_error_code cpl_table_copy_data_int(cpl_table *table, const char *name, const int *data) { const char *fid = "cpl_table_copy_data_int"; cpl_column *column; if (table == 0x0 || data == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_copy_data_int(column, data)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Copy existing data to a table @em float column. * * @param table Pointer to table. * @param name Name of the column. * @param data Existing data buffer. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_FLOAT. *
* @enderror * * See the description of @c cpl_table_copy_data_int() for details. */ cpl_error_code cpl_table_copy_data_float(cpl_table *table, const char *name, const float *data) { const char *fid = "cpl_table_copy_data_float"; cpl_column *column; if (table == 0x0 || data == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_copy_data_float(column, data)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Copy existing data to a table @em double column. * * @param table Pointer to table. * @param name Name of the column. * @param data Existing data buffer. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_DOUBLE. *
* @enderror * * See the description of @c cpl_table_copy_data_int() for details. */ cpl_error_code cpl_table_copy_data_double(cpl_table *table, const char *name, const double *data) { const char *fid = "cpl_table_copy_data_double"; cpl_column *column; if (table == 0x0 || data == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_copy_data_double(column, data)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Copy existing data to a table @em string column. * * @param table Pointer to table. * @param name Name of the column. * @param data Existing data buffer. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_STRING. *
* @enderror * * See the description of @c cpl_table_copy_data_int() for details. * In the particular case of a string column, it should be noted that * the data are copied in-depth, i.e., also the pointed strings are * duplicated. Strings contained in the existing table column are * deallocated before being replaced by the new ones. */ cpl_error_code cpl_table_copy_data_string(cpl_table *table, const char *name, const char **data) { const char *fid = "cpl_table_copy_data_string"; cpl_column *column; if (table == 0x0 || data == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_copy_data_string(column, data)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Delete a table. * * @param table Pointer to table to be deleted. * * @return Nothing. * * This function deletes a table, releasing all the memory associated * to it, including any existing column. If @em table is @c NULL, * nothing is done, and no error is set. */ void cpl_table_delete(cpl_table *table) { int width; cpl_column **column; if (table) { width = cpl_table_get_ncol(table); column = table->columns; while (width--) cpl_column_delete(*column++); if (table->columns) cpl_free(table->columns); if (table->select) cpl_free(table->select); cpl_free(table); } } /** * @brief * Get the number of rows in a table. * * @param table Pointer to table to examine. * * @return Number of rows in the table. If a @c NULL table pointer * is passed, -1 is returned. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * table is a NULL pointer. *
* @enderror * * Get the number of rows in a table. */ int cpl_table_get_nrow(const cpl_table *table) { if (table) return table->nr; cpl_error_set("cpl_table_get_nrow", CPL_ERROR_NULL_INPUT); return -1; } /** * @brief * Get the number of columns in a table. * * @param table Pointer to table to examine. * * @return Number of columns in the table. If a @c NULL table pointer * is passed, -1 is returned. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * table is a NULL pointer. *
* @enderror * * Get the number of columns in a table. */ int cpl_table_get_ncol(const cpl_table *table) { if (table) return table->nc; cpl_error_set("cpl_table_get_ncol", CPL_ERROR_NULL_INPUT); return -1; } /** * @brief * Get the type of a table column. * * @param table Pointer to table. * @param name Column name. * * @return Column type, or @c CPL_TYPE_INVALID in case of failure. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * Get the type of a column. */ cpl_type cpl_table_get_column_type(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_type"; cpl_column *column; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return CPL_TYPE_INVALID; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return CPL_TYPE_INVALID; } return cpl_column_get_type(column); } /** * @brief * Get the depth of a table column. * * @param table Pointer to table. * @param name Column name. * * @return Column depth, or -1 in case of failure. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * Get the depth of a column. Columns of type @em array always have positive * depth, while columns listing numbers or character strings have depth 0. */ int cpl_table_get_column_depth(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_depth"; cpl_column *column; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return CPL_TYPE_INVALID; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return CPL_TYPE_INVALID; } return cpl_column_get_depth(column); } /** * @brief * Get the number of dimensions of a table column of arrays. * * @param table Pointer to table. * @param name Column name. * * @return Column number of dimensions, or 0 in case of failure. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * Get the number of dimensions of a column. If a column is not an array * column, or if it has no dimensions, 1 is returned. */ int cpl_table_get_column_dimensions(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_dimensions"; cpl_column *column; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return 0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return 0; } return cpl_column_get_dimensions(column); } /** * @brief * Set the dimensions of a table column of arrays. * * @param table Pointer to table. * @param name Column name. * @param dimensions Integer array containing the sizes of the column dimensions * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_ILLEGAL_INPUT * Either the specified column is not of type array, * or the dimensions array contains invalid elements. *
CPL_ERROR_TYPE_MISMATCH * The dimensions array is not of type CPL_TYPE_INT. *
CPL_ERROR_INCOMPATIBLE_INPUT * The specified dimensions are incompatible with the total number * of elements in the column arrays. *
* @enderror * * Set the number of dimensions of a column. If the @em dimensions array * has size less than 2, nothing is done and no error is returned. */ cpl_error_code cpl_table_set_column_dimensions(cpl_table *table, const char *name, cpl_array *dimensions) { const char *fid = "cpl_table_set_column_dimensions"; cpl_column *column; if (table == 0x0 || name == 0x0 || dimensions == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return cpl_column_set_dimensions(column, dimensions); } /** * @brief * Get size of one dimension of a table column of arrays. * * @param table Pointer to table. * @param name Column name. * @param indx Indicate dimension to query (0 = x, 1 = y, 2 = z, etc.). * * @return Size of queried dimension of the column, or zero in case of error. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_UNSUPPORTED_MODE * The specified column is not of type array. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The specified indx array is not compatible with * the column dimensions. *
CPL_ERROR_INCOMPATIBLE_INPUT * The specified dimensions are incompatible with the total number * of elements in the column arrays. *
* @enderror * * Get the size of one dimension of a column. If a column is not an array * column, or if it has no dimensions, 1 is returned. */ int cpl_table_get_column_dimension(cpl_table *table, const char *name, int indx) { const char *fid = "cpl_table_get_column_dimension"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return cpl_column_get_dimension(column, indx); } /** * @brief * Give a new unit to a table column. * * @param table Pointer to table. * @param name Column name. * @param unit New unit. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * The input unit string is duplicated before being used as the column * unit. If @em unit is a @c NULL pointer, the column will be unitless. * The unit associated to a column has no effect on any operation performed * on columns, and it must be considered just an optional description of * the content of a column. It is however saved to a FITS file when using * cpl_table_save(). */ cpl_error_code cpl_table_set_column_unit(cpl_table *table, const char *name, const char *unit) { const char *fid = "cpl_table_set_column_unit"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return cpl_column_set_unit(column, unit); } /** * @brief * Get the unit of a table column. * * @param table Pointer to table. * @param name Column name. * * @return Unit of column, or @c NULL if no unit can be returned. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * Return the unit of a column if present, otherwise a NULL pointer is * returned. Note that the returned string is a pointer to the column * unit, not its copy. Its manipulation will directly affect the column * unit, while changing the column unit using @c cpl_column_set_unit() * will turn it into garbage. Therefore it should be considered read-only, * and if a real copy of a column unit is required, this function should * be called as an argument of the function @c strdup(). */ const char *cpl_table_get_column_unit(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_unit"; cpl_column *column; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return NULL; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return NULL; } return cpl_column_get_unit(column); } /** * @brief * Give a new format to a table column. * * @param table Pointer to table. * @param name Column name. * @param format New format. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * The input format string is duplicated before being used as the column * format. If @em format is a @c NULL pointer, "%%s" will be used if * the column is of type @c CPL_TYPE_STRING, "% 1.5e" if the column is * of type @c CPL_TYPE_FLOAT or @c CPL_TYPE_DOUBLE, and "% 7d" if it is * of type @c CPL_TYPE_INT. The format associated to a column has no * effect on any operation performed on columns, and it is used just * in the @c printf() calls made while printing a table using the * function @c cpl_table_dump(). This information is lost after saving * the table in FITS format using @c cpl_table_save(). */ cpl_error_code cpl_table_set_column_format(cpl_table *table, const char *name, const char *format) { const char *fid = "cpl_table_set_column_format"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return cpl_column_set_format(column, format); } /** * @brief * Get the format of a table column. * * @param table Pointer to table. * @param name Column name. * * @return Format of column, or @c NULL in case of error. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * Return the format of a column. Note that the returned string is * a pointer to the column format, not its copy. Its manipulation * will directly affect the column format, while changing the column * format using @c cpl_column_set_format() will turn it into garbage. * Therefore it should be considered read-only, and if a real copy of * a column format is required, this function should be called as an * argument of the function @c strdup(). */ const char *cpl_table_get_column_format(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_format"; cpl_column *column; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return NULL; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return NULL; } return cpl_column_get_format(column); } /** * @brief * Get a pointer to @em integer column data. * * @param table Pointer to table. * @param name Column name. * * @return Pointer to column data, or @c NULL if the column has zero length, * or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_INT. *
* @enderror * * A @em cpl_table column of type @c CPL_TYPE_INT includes an array of * values of type @em int. This function returns a pointer to this array. * The data buffer elements corresponding to invalid column elements would * in general contain garbage. To avoid this, @c cpl_table_fill_invalid_int() * should be called just before this function, assigning to all the invalid * column elements an @em ad @em hoc numerical value. See the description * of function @c cpl_table_fill_invalid_int() for further details. * * @note * Use at your own risk: direct manipulation of column data rules out * any check performed by the table object interface, and may introduce * inconsistencies between the information maintained internally, and * the actual column data and structure. */ int *cpl_table_get_data_int(cpl_table *table, const char *name) { cpl_errorstate prestate = cpl_errorstate_get(); int *data = (int *)cpl_table_get_data_int_const(table, name); if (!cpl_errorstate_is_equal(prestate)) cpl_error_set_where(cpl_func); return data; } /** * @brief * Get a pointer to constant @em integer column data. * * @param table Pointer to constant table. * @param name Column name. * * @return Pointer to constant column data, or @c NULL if the column * has zero length, or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_INT. *
* @enderror * * A @em cpl_table column of type @c CPL_TYPE_INT includes an array of * values of type @em int. This function returns a pointer to this array. * The data buffer elements corresponding to invalid column elements would * in general contain garbage. To avoid this, @c cpl_table_fill_invalid_int() * should be called just before this function, assigning to all the invalid * column elements an @em ad @em hoc numerical value. See the description * of function @c cpl_table_fill_invalid_int() for further details. */ const int *cpl_table_get_data_int_const(const cpl_table *table, const char *name) { const cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT); return NULL; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND); return NULL; } type = cpl_column_get_type(column); if (type != CPL_TYPE_INT) { cpl_error_set(cpl_func, CPL_ERROR_TYPE_MISMATCH); return NULL; } return cpl_column_get_data_int_const(column); } /** * @brief * Get a pointer to @em float column data. * * @param table Pointer to table. * @param name Column name. * * @return Pointer to column data, or @c NULL if the column has zero length, * or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_FLOAT. *
* @enderror * * A @em cpl_table column of type @c CPL_TYPE_FLOAT includes an array * of values of type @em float. This function returns a pointer to this array. * The data buffer elements corresponding to invalid column elements would * in general contain garbage. To avoid this, @c cpl_table_fill_invalid_float() * should be called just before this function, assigning to all the invalid * column elements an @em ad @em hoc numerical value. See the description * of function @c cpl_table_fill_invalid_float() for further details. * * @note * Use at your own risk: direct manipulation of column data rules out * any check performed by the table object interface, and may introduce * inconsistencies between the information maintained internally, and * the actual column data and structure. */ float *cpl_table_get_data_float(cpl_table *table, const char *name) { cpl_errorstate prestate = cpl_errorstate_get(); float *data = (float *)cpl_table_get_data_float_const(table, name); if (!cpl_errorstate_is_equal(prestate)) cpl_error_set_where(cpl_func); return data; } /** * @brief * Get a pointer to constant @em float column data. * * @param table Pointer to constant table. * @param name Column name. * * @return Pointer to constant column data, or @c NULL if the column * has zero length, or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_FLOAT. *
* @enderror * * A @em cpl_table column of type @c CPL_TYPE_FLOAT includes an array * of values of type @em float. This function returns a pointer to this array. * The data buffer elements corresponding to invalid column elements would * in general contain garbage. To avoid this, @c cpl_table_fill_invalid_float() * should be called just before this function, assigning to all the invalid * column elements an @em ad @em hoc numerical value. See the description * of function @c cpl_table_fill_invalid_float() for further details. */ const float *cpl_table_get_data_float_const(const cpl_table *table, const char *name) { const cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT); return NULL; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND); return NULL; } type = cpl_column_get_type(column); if (type != CPL_TYPE_FLOAT) { cpl_error_set(cpl_func, CPL_ERROR_TYPE_MISMATCH); return NULL; } return cpl_column_get_data_float_const(column); } /** * @brief * Get a pointer to @em double column data. * * @param table Pointer to table. * @param name Column name. * * @return Pointer to column data, or @c NULL if the column has zero length, * or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_DOUBLE. *
* @enderror * * A @em cpl_table column of type @c CPL_TYPE_DOUBLE includes an array of * values of type @em double. This function returns a pointer to this array. * The data buffer elements corresponding to invalid column elements would in * general contain garbage. To avoid this, @c cpl_table_fill_invalid_double() * should be called just before this function, assigning to all the invalid * column elements an @em ad @em hoc numerical value. See the description * of function @c cpl_table_fill_invalid_double() for further details. * * @note * Use at your own risk: direct manipulation of column data rules out * any check performed by the table object interface, and may introduce * inconsistencies between the information maintained internally, and * the actual column data and structure. */ double *cpl_table_get_data_double(cpl_table *table, const char *name) { cpl_errorstate prestate = cpl_errorstate_get(); double *data = (double *)cpl_table_get_data_double_const(table, name); if (!cpl_errorstate_is_equal(prestate)) cpl_error_set_where(cpl_func); return data; } /** * @brief * Get a pointer to constant @em double column data. * * @param table Pointer to constant table. * @param name Column name. * * @return Pointer to constant column data, or @c NULL if the column * has zero length, or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_DOUBLE. *
* @enderror * * A @em cpl_table column of type @c CPL_TYPE_DOUBLE includes an array of * values of type @em double. This function returns a pointer to this array. * The data buffer elements corresponding to invalid column elements would in * general contain garbage. To avoid this, @c cpl_table_fill_invalid_double() * should be called just before this function, assigning to all the invalid * column elements an @em ad @em hoc numerical value. See the description * of function @c cpl_table_fill_invalid_double() for further details. */ const double *cpl_table_get_data_double_const(const cpl_table *table, const char *name) { const cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT); return NULL; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND); return NULL; } type = cpl_column_get_type(column); if (type != CPL_TYPE_DOUBLE) { cpl_error_set(cpl_func, CPL_ERROR_TYPE_MISMATCH); return NULL; } return cpl_column_get_data_double_const(column); } /** * @brief * Get a pointer to @em string column data. * * @param table Pointer to table. * @param name Column name. * * @return Pointer to column data, or @c NULL if the column has zero length, * or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_STRING. *
* @enderror * * A table column of type @c CPL_TYPE_STRING includes an array of values * of type @em char*. This function returns a pointer to this array. * * @note * Use at your own risk: direct manipulation of column data rules out * any check performed by the table object interface, and may introduce * inconsistencies between the information maintained internally, and * the actual column data and structure. */ char **cpl_table_get_data_string(cpl_table *table, const char *name) { cpl_errorstate prestate = cpl_errorstate_get(); char **data = (char **)cpl_table_get_data_string_const(table, name); if (!cpl_errorstate_is_equal(prestate)) cpl_error_set_where(cpl_func); return data; } /** * @brief * Get a pointer to constant @em string column data. * * @param table Pointer to constant table. * @param name Column name. * * @return Pointer to constant column data, or @c NULL if the column has * zero length, or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_STRING. *
* @enderror * * A table column of type @c CPL_TYPE_STRING includes an array of values * of type @em char*. This function returns a pointer to this array. */ const char **cpl_table_get_data_string_const(const cpl_table *table, const char *name) { const cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT); return NULL; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND); return NULL; } type = cpl_column_get_type(column); if (type != CPL_TYPE_STRING) { cpl_error_set(cpl_func, CPL_ERROR_TYPE_MISMATCH); return NULL; } return cpl_column_get_data_string_const(column); } /** * @brief * Get a pointer to @em array column data. * * @param table Pointer to table. * @param name Column name. * * @return Pointer to column data, or @c NULL if the column has zero length, * or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type array. *
* @enderror * * A table column of type @em array includes an array of values * of type @em cpl_array*. This function returns a pointer to this array. * * @note * Use at your own risk: direct manipulation of column data rules out * any check performed by the table object interface, and may introduce * inconsistencies between the information maintained internally, and * the actual column data and structure. */ cpl_array **cpl_table_get_data_array(cpl_table *table, const char *name) { cpl_errorstate prestate = cpl_errorstate_get(); cpl_array **data = (cpl_array **)cpl_table_get_data_array_const(table, name); if (!cpl_errorstate_is_equal(prestate)) cpl_error_set_where(cpl_func); return data; } /** * @brief * Get a pointer to @em array column data. * * @param table Pointer to table. * @param name Column name. * * @return Pointer to column data, or @c NULL if the column has zero length, * or in case of failure. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type array. *
* @enderror * * A table column of type @em array includes an array of values * of type @em cpl_array*. This function returns a pointer to this array. */ const cpl_array **cpl_table_get_data_array_const(const cpl_table *table, const char *name) { const cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(cpl_func, CPL_ERROR_NULL_INPUT); return NULL; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(cpl_func, CPL_ERROR_DATA_NOT_FOUND); return NULL; } type = cpl_column_get_type(column); if (!(type & CPL_TYPE_POINTER)) { cpl_error_set(cpl_func, CPL_ERROR_TYPE_MISMATCH); return NULL; } return cpl_column_get_data_array_const(column); } /** * @brief * Delete a column from a table. * * @param table Pointer to table. * @param name Name of table column to delete. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * Delete a column from a table. If the table is left without columns, * also the selection flags are lost. */ cpl_error_code cpl_table_erase_column(cpl_table *table, const char *name) { const char *fid = "cpl_table_erase_column"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_extract_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); cpl_column_delete(column); return CPL_ERROR_NONE; } /** * @brief * Delete a table segment. * * @param table Pointer to table. * @param start First row to delete. * @param count Number of rows to delete. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * table is a NULL pointer. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has length zero, or start is * outside the table range. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
* @enderror * * A portion of the table data is physically removed. The pointers to column * data may change, therefore pointers previously retrieved by calling * @c cpl_table_get_data_int(), @c cpl_table_get_data_string(), etc., * should be discarded. The table selection flags are set back to * "all selected". The specified segment can extend beyond the end of * the table, and in that case rows will be removed up to the end of * the table. */ cpl_error_code cpl_table_erase_window(cpl_table *table, int start, int count) { const char *fid = "cpl_table_erase_window"; int width = cpl_table_get_ncol(table); cpl_column **column; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (count > table->nr - start) count = table->nr - start; column = table->columns; /* * If it will fail, it will be at the first column: the table * will never be returned half-done. */ while (width--) { if (cpl_column_erase_segment(*column++, start, count)) { cpl_error_set_where(fid); return cpl_error_get_code(); } } table->nr -= count; return cpl_table_select_all(table); } /** * @brief * Delete the selected rows of a table. * * @param table Pointer to table * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * table is a NULL pointer. *
* @enderror * * A portion of the table data is physically removed. The pointer to * column data may change, therefore pointers previously retrieved by * calling @c cpl_table_get_data_int(), @c cpl_table_get_data_string(), * etc., should be discarded. The table selection flags are set back to * "all selected". */ cpl_error_code cpl_table_erase_selected(cpl_table *table) { const char *fid = "cpl_table_erase_selected"; int length = cpl_table_get_nrow(table); int i, width; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (table->selectcount == 0) return cpl_table_select_all(table); if (table->selectcount == length) return cpl_table_set_size(table, 0); width = cpl_table_get_ncol(table); for (i = 0; i < width; i++) if (cpl_column_erase_pattern(table->columns[i], table->select)) { cpl_error_set_where(fid); return cpl_error_get_code(); } table->nr -= table->selectcount; return cpl_table_select_all(table); } /** * @brief * Insert a segment of rows into table data. * * @param table Pointer to table * @param start Row where to insert the segment. * @param count Length of the segment. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * table is a NULL pointer. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * start is negative. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
* @enderror * * Insert a segment of empty rows, just containing invalid elements. * Setting @em start to a number greater than the column length is legal, * and has the effect of appending extra rows at the end of the table: * this is equivalent to expanding the table using @c cpl_table_set_size(). * The input @em column may also have zero length. The pointers to column * data values may change, therefore pointers previously retrieved by * calling @c cpl_table_get_data_int(), @c cpl_table_get_data_string(), * etc., should be discarded. The table selection flags are set back to * "all selected". */ cpl_error_code cpl_table_insert_window(cpl_table *table, int start, int count) { const char *fid = "cpl_table_insert_window"; int width = cpl_table_get_ncol(table); cpl_column **column; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = table->columns; /* * If it will fail, it will be at the first column: the table * will never be returned half-done. */ while (width--) { if (cpl_column_insert_segment(*column++, start, count)) { cpl_error_set_where(fid); return cpl_error_get_code(); } } table->nr += count; return cpl_table_select_all(table); } /** * @brief * Compare the structure of two tables. * * @param table1 Pointer to a table. * @param table2 Pointer to another table. * * @return 0 if the tables have the same structure, 1 otherwise. * In case of error, -1 is returned. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
* @enderror * * Two tables have the same structure if they have the same number * of columns, with the same names and the same types. The order of the * columns is not relevant. */ int cpl_table_compare_structure(const cpl_table *table1, const cpl_table *table2) { const char *fid = "cpl_table_compare_structure"; int width1 = cpl_table_get_ncol(table1); int width2 = cpl_table_get_ncol(table2); const char *name = NULL; if (table1 == 0x0 || table2 == 0x0) { cpl_error_set_where(fid); return -1; } if (width1 == width2) { name = cpl_table_get_column_name(table1); while (name) { if (!cpl_table_has_column(table2, name)) return 1; if (cpl_table_get_column_type(table1, name) != cpl_table_get_column_type(table2, name)) return 1; if (cpl_table_get_column_depth(table1, name) != cpl_table_get_column_depth(table2, name)) return 1; name = cpl_table_get_column_name(NULL); } return 0; /* Same structure */ } return 1; } /** * @brief * Merge two tables. * * @param target_table Target table. * @param insert_table Table to be inserted in the target table. * @param row Row where to insert the insert table. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any input table is a NULL pointer. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * row is negative. *
CPL_ERROR_INCOMPATIBLE_INPUT * The input tables do not have the same structure. *
* @enderror * * The input tables must have the same structure, as defined by the function * @c cpl_table_compare_structure() . Data from the @em insert_table are * duplicated and inserted at the specified position of the @em target_table. * If the specified @em row is not less than the target table length, the * second table will be appended to the target table. The selection flags * of the target table are always set back to "all selected". The pointers * to column data in the target table may change, therefore pointers * previously retrieved by calling @c cpl_table_get_data_int(), * @c cpl_table_get_data_string(), etc., should be discarded. */ cpl_error_code cpl_table_insert(cpl_table *target_table, const cpl_table *insert_table, int row) { const char *fid = "cpl_table_insert"; int width = cpl_table_get_ncol(target_table); cpl_column **column; if (cpl_table_compare_structure(target_table, insert_table)) return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT); column = target_table->columns; while (width--) { if (cpl_column_merge(*column, cpl_table_find_column(insert_table, cpl_column_get_name(*column)), row)) { cpl_error_set_where(fid); return cpl_error_get_code(); } column++; } target_table->nr += insert_table->nr; return cpl_table_select_all(target_table); } /** * @brief * Read a value from a numerical column. * * @param table Pointer to table. * @param name Name of table column to be accessed. * @param row Position of element to be read. * @param null Flag indicating @em null values, or error condition. * * @return Value read. In case of invalid table element, or in case of * error, 0.0 is returned. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical, or is a column of arrays. *
* @enderror * * Rows are counted starting from 0. The @em null flag is used to * indicate whether the accessed table element is valid (0) or * invalid (1). The @em null flag also signals an error condition (-1). * The @em null argument can be left to @c NULL. */ double cpl_table_get(const cpl_table *table, const char *name, int row, int *null) { const char *fid = "cpl_table_get"; cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (null) *null = -1; return 0.0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (null) *null = -1; return 0.0; } type = cpl_column_get_type(column); if ((type == CPL_TYPE_STRING) || (type & CPL_TYPE_POINTER)) { cpl_error_set(fid, CPL_ERROR_INVALID_TYPE); if (null) *null = -1; return 0.0; } return cpl_column_get(column, row, null); } /** * @brief * Read a value from an @em integer column. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position of element to be read. * @param null Flag indicating @em null values, or error condition. * * @return Integer value read. In case of an invalid table element, or in * case of error, 0 is always returned. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_INT. *
* @enderror * * Read a value from a column of type @c CPL_TYPE_INT. If the @em null * flag is a valid pointer, it is used to indicate whether the accessed * column element is valid (0) or invalid (1). The @em null flag also signals * an error condition (-1). The @em null flag pointer can also be @c NULL, * and in that case this option will be disabled. Rows are counted starting * from 0. * * @note * For automatic conversion (always to type @em double), use the function * @c cpl_table_get(). */ int cpl_table_get_int(const cpl_table *table, const char *name, int row, int *null) { const char *fid = "cpl_table_get_int"; cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (null) *null = -1; return 0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (null) *null = -1; return 0; } type = cpl_column_get_type(column); if (type != CPL_TYPE_INT) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); if (null) *null = -1; return 0.0; } return cpl_column_get_int(column, row, null); } /** * @brief * Read a value from a @em float column. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position of element to be read. * @param null Flag indicating @em null values, or error condition. * * @return Float value read. In case of an invalid table element, or in * case of error, 0.0 is always returned. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_FLOAT. *
* @enderror * * Read a value from a column of type @c CPL_TYPE_FLOAT. See the documentation * of function cpl_table_get_int(). */ float cpl_table_get_float(const cpl_table *table, const char *name, int row, int *null) { const char *fid = "cpl_table_get_float"; cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (null) *null = -1; return 0.0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (null) *null = -1; return 0.0; } type = cpl_column_get_type(column); if (type != CPL_TYPE_FLOAT) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); if (null) *null = -1; return 0.0; } return cpl_column_get_float(column, row, null); } /** * @brief * Read a value from a @em double column. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position of element to be read. * @param null Flag indicating @em null values, or error condition. * * @return Double value read. In case of an invalid table element, or in * case of error, 0.0 is always returned. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_DOUBLE. *
* @enderror * * Read a value from a column of type @c CPL_TYPE_DOUBLE. See the * documentation of function cpl_table_get_int(). */ double cpl_table_get_double(const cpl_table *table, const char *name, int row, int *null) { const char *fid = "cpl_table_get_double"; cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (null) *null = -1; return 0.0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (null) *null = -1; return 0.0; } type = cpl_column_get_type(column); if (type != CPL_TYPE_DOUBLE) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); if (null) *null = -1; return 0.0; } return cpl_column_get_double(column, row, null); } /** * @brief * Read a value from a @em string column. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position of element to be read. * * @return Pointer to string. In case of an invalid column element, or in * case of error, a @c NULL pointer is always returned. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_STRING. *
* @enderror * * Read a value from a column of type @c CPL_TYPE_STRING. * Rows are counted starting from 0. * * @note * The returned string is a pointer to a table element, not its copy. * Its manipulation will directly affect that element, while changing * that element using @c cpl_table_set_string() will turn it into garbage. * Therefore, if a real copy of a string column element is required, this * function should be called as an argument of the function @c strdup(). */ const char *cpl_table_get_string(const cpl_table *table, const char *name, int row) { const char *fid = "cpl_table_get_string"; cpl_type type; cpl_column *column; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return NULL; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return NULL; } type = cpl_column_get_type(column); if (type != CPL_TYPE_STRING) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return NULL; } return cpl_column_get_string(column, row); } /** * @brief * Read an array from an @em array column. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position of element to be read. * * @return Pointer to array. In case of an invalid column element, or in * case of error, a @c NULL pointer is always returned. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type array. *
* @enderror * * Read a value from a column of any array type. * Rows are counted starting from 0. * * @note * The returned array is a pointer to a table element, not its copy. * Its manipulation will directly affect that element, while changing * that element using @c cpl_table_set_array() will turn it into garbage. * Therefore, if a real copy of an array column element is required, * this function should be called as an argument of the function * @c cpl_array_duplicate(). */ const cpl_array *cpl_table_get_array(const cpl_table *table, const char *name, int row) { const char *fid = "cpl_table_get_array"; cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return NULL; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return NULL; } type = cpl_column_get_type(column); if (!(type & CPL_TYPE_POINTER)) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return NULL; } return cpl_column_get_array(column, row); } /** * @brief * Write a value to a numerical table column element. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position where to write value. * @param value Value to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical, or it is of type * array. *
* @enderror * * Write a value to a numerical column element. The value is cast to the * accessed column type according to the C casting rules. The written value * is automatically marked as valid. To invalidate a column value use * @c cpl_table_set_invalid(). Table rows are counted starting from 0. */ cpl_error_code cpl_table_set(cpl_table *table, const char *name, int row, double value) { const char *fid = "cpl_table_set"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_set(column, row, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write a value to an @em integer table column element. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position where to write value. * @param value Value to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_INT. *
* @enderror * * Write a value to a table column of type @c CPL_TYPE_INT. The written * value is automatically marked as valid. To invalidate a column value use * @c cpl_table_set_invalid(). Table rows are counted starting from 0. * * @note * For automatic conversion to the column type, use the function * @c cpl_table_set(). */ cpl_error_code cpl_table_set_int(cpl_table *table, const char *name, int row, int value) { const char *fid = "cpl_table_set_int"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_set_int(column, row, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write a value to a @em float table column element. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position where to write value. * @param value Value to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_FLOAT. *
* @enderror * * Write a value to a table column of type @c CPL_TYPE_FLOAT. The written * value is automatically marked as valid. To invalidate a column value use * @c cpl_table_set_invalid(). Table rows are counted starting from 0. * * @note * For automatic conversion to the column type, use the function * @c cpl_table_set(). */ cpl_error_code cpl_table_set_float(cpl_table *table, const char *name, int row, float value) { const char *fid = "cpl_table_set_float"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_set_float(column, row, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write a value to a @em double table column element. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position where to write value. * @param value Value to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_DOUBLE. *
* @enderror * * Write a value to a table column of type @c CPL_TYPE_DOUBLE. The written * value is automatically marked as valid. To invalidate a column value use * @c cpl_table_set_invalid(). Table rows are counted starting from 0. * * @note * For automatic conversion to the column type, use the function * @c cpl_table_set(). */ cpl_error_code cpl_table_set_double(cpl_table *table, const char *name, int row, double value) { const char *fid = "cpl_table_set_double"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_set_double(column, row, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write a character string to a @em string table column element. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position where to write the character string. * @param value Character string to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_STRING. *
* @enderror * * Write a string to a table column of type @c CPL_TYPE_STRING. The written * value can also be a @c NULL pointer, that is equivalent to a call to * @c cpl_table_set_invalid(). Note that the character string is copied, * therefore the original can be modified without affecting the table * element. To "plug" a character string directly into a table element, * use the function @c cpl_table_get_data_string(). */ cpl_error_code cpl_table_set_string(cpl_table *table, const char *name, int row, const char *value) { const char *fid = "cpl_table_set_string"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_set_string(column, row, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write an array to an @em array table column element. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Position where to write the array. * @param array Array to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type array. *
* @enderror * * Write an array to a table column of type @em array. The written * value can also be a @c NULL pointer, that is equivalent to a call * to @c cpl_table_set_invalid(). Note that the array is copied, * therefore the original can be modified without affecting the * table element. To "plug" an array directly into a table element, * use the function @c cpl_table_get_data_array(). Beware that the * "plugged" array must be the same type declared for the column. */ cpl_error_code cpl_table_set_array(cpl_table *table, const char *name, int row, const cpl_array *array) { const char *fid = "cpl_table_set_array"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_set_array(column, row, array)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Flag a column element as invalid. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Row where to write a @em null. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * In the case of either a @em string or an @em array column, the * corresponding string or array is set free and its pointer is set * to @c NULL. For other data types, the corresponding table element * is flagged internally as invalid. */ cpl_error_code cpl_table_set_invalid(cpl_table *table, const char *name, int row) { const char *fid = "cpl_table_set_invalid"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_set_invalid(column, row)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write a value to a numerical column segment. * * @param table Pointer to table. * @param name Name of table column to access. * @param start Position where to begin to write the value. * @param count Number of values to write. * @param value Value to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical, or is of type array. *
* @enderror * * Write the same value to a numerical column segment. The value is cast * to the type of the accessed column according to the C casting rules. * The written values are automatically marked as valid. To invalidate * a column interval use @c cpl_table_set_column_invalid() instead. * If the sum of @em start and @em count exceeds the number of table * rows, the column is filled up to its end. */ cpl_error_code cpl_table_fill_column_window(cpl_table *table, const char *name, int start, int count, double value) { const char *fid = "cpl_table_fill_column_window"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_fill(column, start, count, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write a value to an @em integer column segment. * * @param table Pointer to table. * @param name Name of table column to access. * @param start Position where to begin to write the value. * @param count Number of values to write. * @param value Value to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_INT. *
* @enderror * * Write the same value to an @em integer column segment. The written * values are automatically marked as valid. To invalidate a column * interval use @c cpl_table_set_column_invalid() instead. If the sum * of @em start and @em count exceeds the number of table rows, the * column is filled up to its end. * * @note * For automatic conversion to the accessed column type use the function * @c cpl_table_fill_column_window(). */ cpl_error_code cpl_table_fill_column_window_int(cpl_table *table, const char *name, int start, int count, int value) { const char *fid = "cpl_table_fill_column_window_int"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_fill_int(column, start, count, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write a value to a @em float column segment. * * @param table Pointer to table. * @param name Name of table column to access. * @param start Position where to begin to write the value. * @param count Number of values to write. * @param value Value to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_FLOAT. *
* @enderror * * Write the same value to a @em float column segment. The written * values are automatically marked as valid. To invalidate a column * interval use @c cpl_table_set_column_invalid() instead. If the sum * of @em start and @em count exceeds the number of table rows, the * column is filled up to its end. */ cpl_error_code cpl_table_fill_column_window_float(cpl_table *table, const char *name, int start, int count, float value) { const char *fid = "cpl_table_fill_column_window_float"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_fill_float(column, start, count, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write a value to a @em double column segment. * * @param table Pointer to table. * @param name Name of table column to access. * @param start Position where to begin to write the value. * @param count Number of values to write. * @param value Value to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_DOUBLE. *
* @enderror * * Write the same value to a @em double column segment. The written * values are automatically marked as valid. To invalidate a column * interval use @c cpl_table_set_column_invalid() instead. If the sum * of @em start and @em count exceeds the number of table rows, the * column is filled up to its end. */ cpl_error_code cpl_table_fill_column_window_double(cpl_table *table, const char *name, int start, int count, double value) { const char *fid = "cpl_table_fill_column_window_double"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_fill_double(column, start, count, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write a character string to a @em string column segment. * * @param table Pointer to table. * @param name Name of table column to access. * @param start Position where to begin to write the character string. * @param count Number of strings to write. * @param value Character string to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_STRING. *
* @enderror * * Write the same value to a @em string column segment. If the input string * is not a @c NULL pointer, it is duplicated for each accessed column * element. If the input string is a @c NULL pointer, this call is equivalent * to a call to @c cpl_table_set_column_invalid(). If the sum of @em start * and @em count exceeds the number of rows in the table, the column is * filled up to its end. */ cpl_error_code cpl_table_fill_column_window_string(cpl_table *table, const char *name, int start, int count, char *value) { const char *fid = "cpl_table_fill_column_window_string"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_fill_string(column, start, count, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Write an array to an @em array column segment. * * @param table Pointer to table. * @param name Name of table column to access. * @param start Position where to begin to write the array. * @param count Number of arrays to write. * @param array Array to write. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column does not match the type of the input * array, or it is not made of arrays. *
CPL_ERROR_INCOMPATIBLE_INPUT * The size of the input array is different from the * depth of the specified column. *
* @enderror * * Write the same array to a segment of an array column. If the input array * is not a @c NULL pointer, it is duplicated for each accessed column * element. If the input array is a @c NULL pointer, this call is equivalent * to a call to @c cpl_table_set_column_invalid(). If the sum of @em start * and @em count exceeds the number of rows in the table, the column is * filled up to its end. */ cpl_error_code cpl_table_fill_column_window_array(cpl_table *table, const char *name, int start, int count, cpl_array *array) { const char *fid = "cpl_table_fill_column_window_array"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_fill_array(column, start, count, array)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Invalidate a column segment. * * @param table Pointer to table. * @param name Name of table column to access. * @param start Position where to begin invalidation. * @param count Number of column elements to invalidate. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * All the column elements in the specified interval are invalidated. * In the case of either a @em string or an @em array column, the * corresponding strings or arrays are set free. If the sum of @em start * and @em count exceeds the number of rows in the table, the column is * invalidated up to its end. */ cpl_error_code cpl_table_set_column_invalid(cpl_table *table, const char *name, int start, int count) { const char *fid = "cpl_table_set_column_invalid"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_fill_invalid(column, start, count)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Check if a column element is valid. * * @param table Pointer to table. * @param name Name of table column to access. * @param row Column element to examine. * * @return 1 if the column element is valid, 0 if invalid, -1 in case of * error. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
* @enderror * * Check if a column element is valid. */ int cpl_table_is_valid(const cpl_table *table, const char *name, int row) { const char *fid = "cpl_table_is_valid"; cpl_column *column; int validity; cpl_errorstate prevstate; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } prevstate = cpl_errorstate_get(); validity = cpl_column_is_invalid(column, row) ? 0 : 1; if (!cpl_errorstate_is_equal(prevstate)) { cpl_error_set_where(fid); return -1; } return validity; } /** * @brief * Check if a column contains at least one invalid value. * * @param table Pointer to table. * @param name Name of table column to access. * * @return 1 if the column contains at least one invalid element, 0 if not, * -1 in case of error. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * Check if there are invalid elements in a column. In case of columns * of arrays, invalid values within an array are not considered: an * invalid element here means that an array element is not allocated, * i.e., it is a @c NULL pointer. In order to detect invalid elements * within an array element, this element must be extracted using * the function @c cpl_table_get_array(), and then use the function * @c cpl_array_has_invalid(). */ int cpl_table_has_invalid(const cpl_table *table, const char *name) { const char *fid = "cpl_table_has_invalid"; cpl_column *column; int answer; cpl_errorstate prevstate; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } prevstate = cpl_errorstate_get(); answer = cpl_column_has_invalid(column); if (!cpl_errorstate_is_equal(prevstate)) cpl_error_set_where(fid); return answer; } /** * @brief * Check if a column contains at least one valid value. * * @param table Pointer to table. * @param name Name of table column to access. * * @return 1 if the column contains at least one valid value, 0 if not, * -1 in case of error. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * Check if there are valid elements in a column. In case of columns * of arrays, invalid values within an array are not considered: an * invalid element here means that an array element is not allocated, * i.e., it is a @c NULL pointer. In order to detect valid elements * within an array element, this element must be extracted using * the function @c cpl_table_get_array(), and then use the function * @c cpl_array_has_valid(). */ int cpl_table_has_valid(const cpl_table *table, const char *name) { const char *fid = "cpl_table_has_valid"; cpl_column *column; int answer; cpl_errorstate prevstate; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } prevstate = cpl_errorstate_get(); answer = cpl_column_has_valid(column); if (!cpl_errorstate_is_equal(prevstate)) cpl_error_set_where(fid); return answer; } /** * @brief * Count number of invalid values in a table column. * * @param table Pointer to table. * @param name Name of table column to examine. * * @return Number of invalid elements in a table column, or -1 in case of * error. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in table. *
* @enderror * * Count number of invalid elements in a table column. */ int cpl_table_count_invalid(const cpl_table *table, const char *name) { const char *fid = "cpl_table_count_invalid"; cpl_column *column; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } return cpl_column_count_invalid(column); } /** * @brief * Move a column from a table to another. * * @param to_table Target table. * @param name Name of column to move. * @param from_table Source table. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_INCOMPATIBLE_INPUT * The input tables do not have the same number of rows. *
CPL_ERROR_ILLEGAL_INPUT * Source and target tables are the same table. *
CPL_ERROR_DATA_NOT_FOUND * A column with the given name is not found in the * source table. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the same name already exists in the * target table. *
* @enderror * * Move a column from a table to another. */ cpl_error_code cpl_table_move_column(cpl_table *to_table, const char *name, cpl_table *from_table) { const char *fid = "cpl_table_move_column"; cpl_column *column; if (to_table == 0x0 || from_table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (to_table == from_table) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); if (to_table->nr != from_table->nr) return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT); if (cpl_table_find_column(to_table, name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); column = cpl_table_extract_column(from_table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); cpl_table_append_column(to_table, column); return CPL_ERROR_NONE; } /** * @brief * Copy a column from a table to another. * * @param to_table Target table. * @param to_name New name of copied column. * @param from_table Source table. * @param from_name Name of column to copy. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_INCOMPATIBLE_INPUT * The input tables do not have the same number of rows. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified from_name is not found in the * source table. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the specified to_name already exists in the * target table. *
* @enderror * * Copy a column from a table to another. The column is duplicated. A column * may be duplicated also within the same table. */ cpl_error_code cpl_table_duplicate_column(cpl_table *to_table, const char *to_name, const cpl_table *from_table, const char *from_name) { const char *fid = "cpl_table_duplicate_column"; cpl_column *column; if (to_table == 0x0 || from_table == 0x0 || to_name == 0x0 || from_name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (to_table->nr != from_table->nr) return cpl_error_set(fid, CPL_ERROR_INCOMPATIBLE_INPUT); if (cpl_table_find_column(to_table, to_name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); column = cpl_table_find_column(from_table, from_name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); column = cpl_column_duplicate(column); cpl_column_set_name(column, to_name); cpl_table_append_column(to_table, column); return CPL_ERROR_NONE; } /** * @brief * Rename a table column. * * @param table Pointer to table. * @param from_name Name of table column to rename. * @param to_name New name of column. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified from_name is not found * in table. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the specified to_name already exists in * table. *
* @enderror * * This function is used to change the name of a column. */ cpl_error_code cpl_table_name_column(cpl_table *table, const char *from_name, const char *to_name) { const char *fid = "cpl_table_name_column"; cpl_column *column; if (from_name == 0x0 || to_name == 0x0 || table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (cpl_table_find_column(table, to_name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); column = cpl_table_find_column(table, from_name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return cpl_column_set_name(column, to_name); } /** * @brief * Check if a column with a given name exists. * * @param table Pointer to table. * @param name Name of table column. * * @return 1 if column exists, 0 if column doesn't exist, -1 in case of error. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * Any argument is a NULL pointer. *
* @enderror * * Check if a column with a given name exists in the specified table. */ int cpl_table_has_column(const cpl_table *table, const char *name) { if (table == 0x0 || name == 0x0) { cpl_error_set("cpl_table_has_column", CPL_ERROR_NULL_INPUT); return -1; } return (cpl_table_find_column(table, name) != NULL ? 1 : 0); } /** * @brief * Get table columns names. * * @param table Pointer to table. * * @return Name of a table column. * * If this function is not called with a @c NULL pointer the name of * the first table column will be returned. Further calls made with * a @c NULL pointer would return the next columns names, till the * end of the list of columns when a @c NULL would be returned. This * function only guarantees that all the table column names would be * returned by subsequent calls to this function, but the order in which * the column names are returned is undefined. The table structure must * not be modified (e.g. by deleting, creating, moving, or renaming * columns) between a sequence of calls to @c cpl_table_get_column_name() * related to the same table, or this function behaviour will be * undetermined. This function returns a pointer to the table column * name, and not to its copy, therefore the pointed string shouldn't * be deallocated or manipulated in any way. Its manipulation would * directly affect the column name, while changing the column name * using @c cpl_table_name_column() would turn it into garbage. * Therefore, if a real copy of a column name is required, this * function should be called as an argument of the function @c strdup(). * * @note * This function is deprecated, because its usage could create * serious problems in case it is attempted to get names from * different tables simultaneously. For instance, a programmer * may call cpl_table_get_column_name() in a loop, and in the * same loop call a CPL function that calls as well the same * function. The behaviour in this case would be unpredictable. * The function cpl_table_get_column_names() should be used * instead. */ const char *cpl_table_get_column_name(const cpl_table *table) { static cpl_table *looking = NULL; static int width = 0; static int i = 0; if (table) { looking = (cpl_table *)table; width = cpl_table_get_ncol(table); i = 0; } else { if (looking) i++; else return NULL; } if (i < width) return cpl_column_get_name(looking->columns[i]); return NULL; } /** * @brief * Get table columns names. * * @param table Pointer to table. * * @return Array of table columns names. * * The returned CPL array of strings should be finally destroyed * using cpl_array_delete(). */ cpl_array *cpl_table_get_column_names(const cpl_table *table) { const char *fid = "cpl_table_get_column_names"; cpl_array *names; int i; if (table == NULL) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return NULL; } names = cpl_array_new(table->nc, CPL_TYPE_STRING); for (i = 0; i < table->nc; i++) cpl_array_set_string(names, i, cpl_column_get_name(table->columns[i])); return names; } /** * @brief * Resize a table to a new number of rows. * * @param table Pointer to table. * @param new_length New number of rows in table. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
CPL_ERROR_ILLEGAL_INPUT * The specified new length is negative. *
* @enderror * * The contents of the columns will be unchanged up to the lesser of the * new and old sizes. If the table is expanded, the extra table rows would * just contain invalid elements. The table selection flags are set back * to "all selected". The pointer to column data may change, therefore * pointers previously retrieved by calling @c cpl_table_get_data_int(), * @c cpl_table_get_data_string(), etc. should be discarded. */ cpl_error_code cpl_table_set_size(cpl_table *table, int new_length) { const char *fid = "cpl_table_set_size"; int width = cpl_table_get_ncol(table); cpl_column **column; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (new_length < 0) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); column = table->columns; /* * If it will fail, it will be at the first column: the table * will never be returned half-done. */ while (width--) { if (cpl_column_set_size(*column++, new_length)) { cpl_error_set_where(fid); return cpl_error_get_code(); } } table->nr = new_length; return cpl_table_select_all(table); } /** * @brief * Modify depth of a column of arrays * * @param table Pointer to table. * @param name Column name. * @param depth New column depth. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Any input argument is a NULL pointer. *
CPL_ERROR_ILLEGAL_INPUT * The specified new depth is negative. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found * in table. *
CPL_ERROR_INVALID_TYPE * The column with the specified name is not an * array type. *
* @enderror * * This function is applicable just to columns of arrays. The contents * of the arrays in the specified column will be unchanged up to the * lesser of the new and old depths. If the depth is increased, the * extra array elements would be flagged as invalid. The pointers to * array data may change, therefore pointers previously retrieved by * calling @c cpl_array_get_data_int(), @c cpl_array_get_data_string(), * etc. should be discarded. */ cpl_error_code cpl_table_set_column_depth(cpl_table *table, const char *name, int depth) { const char *fid = "cpl_table_set_column_depth"; int length; int old_depth; cpl_column *column; cpl_type type; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (depth < 0) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); type = cpl_column_get_type(column); if (!(type & CPL_TYPE_POINTER)) return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); length = table->nr; old_depth = cpl_table_get_column_depth(table, name); /* * If it will fail, it will be at the first array: the column * will never be returned half-done. */ while (length--) { if (cpl_column_set_depth(column, depth)) { cpl_error_set_where(fid); return cpl_error_get_code(); } } return CPL_ERROR_NONE; } /** * @brief * Make a copy of a table. * * @param table Pointer to table. * * @return Pointer to the new table, or @c NULL in case of @c NULL input, * or in case of error. * * The copy operation is done "in depth": columns data are duplicated * too, not just their pointers. Also the selection flags of the original * table are transferred to the new table. */ cpl_table *cpl_table_duplicate(const cpl_table *table) { int length = cpl_table_get_nrow(table); int width = cpl_table_get_ncol(table); int i; cpl_table *new_table = NULL; cpl_column *column; if (table) new_table = cpl_table_new(length); else return NULL; if (table->select) { new_table->select = cpl_malloc(length * sizeof(cpl_column_flag)); memcpy(new_table->select, table->select, length * sizeof(cpl_column_flag)); } new_table->selectcount = table->selectcount; for (i = 0; i < width; i++) { column = cpl_column_duplicate(table->columns[i]); cpl_table_append_column(new_table, column); } return new_table; } /** * @brief * Create a table from a section of another table. * * @param table Pointer to table. * @param start First row to be copied to new table. * @param count Number of rows to be copied. * * @return Pointer to the new table, or @c NULL in case or error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
* @enderror * * A number of consecutive rows are copied from an input table to a * newly created table. The new table will have the same structure of * the original table (see function @c cpl_table_compare_structure() ). * If the sum of @em start and @em count goes beyond the end of the * input table, rows are copied up to the end. All the rows of the * new table are selected, i.e., existing selection flags are not * transferred from the old table to the new one. */ cpl_table *cpl_table_extract(const cpl_table *table, int start, int count) { const char *fid = "cpl_table_extract"; int width = cpl_table_get_ncol(table); int length = cpl_table_get_nrow(table); int i; cpl_table *new_table = NULL; cpl_column *column = NULL; if (table == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return NULL; } if (count > length - start) count = length - start; new_table = cpl_table_new(count); for (i = 0; i < width; i++) { column = cpl_column_extract(table->columns[i], start, count); if (column) { cpl_column_set_name(column, cpl_column_get_name(table->columns[i])); cpl_table_append_column(new_table, column); } else { cpl_error_set_where(fid); cpl_table_delete(new_table); return NULL; } } return new_table; } /** * @brief * Cast a numeric column to a new numeric type column. * * @param table Pointer to table. * @param from_name Name of table column to cast. * @param to_name Name of new table column. * @param type Type of new table column. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or any column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified from_name is not found * in table. *
CPL_ERROR_ILLEGAL_OUTPUT * A column with the specified to_name already exists in * table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical. *
CPL_ERROR_ILLEGAL_INPUT * The specified type is not numerical. *
* @enderror * * A new column of the specified type is created, and the content of the * given numeric column is cast to the new type. If the input column type * is identical to the specified type the column is duplicated as is done * by the function @c cpl_table_duplicate_column(). Note that a column of * arrays is always cast to another column of arrays of the specified type. * It is not allowed to cast a column of arrays into a column of numbers, and * viceversa (e.g., a column of type @c CPL_TYPE_INT | @c CPL_TYPE_POINTER * cannot be cast into a column of type @c CPL_TYPE_INT, and neither can * be the opposite). A request in this sense would anyway be interpreted * consistently (e.g., a request to cast a column of arrays from * @c CPL_TYPE_INT | @c CPL_TYPE_POINTER to @c CPL_TYPE_FLOAT would * be interpreted as a cast to @c CPL_TYPE_FLOAT | @c CPL_TYPE_POINTER, * while a request to cast a column of type @c CPL_TYPE_FLOAT to a type * @c CPL_TYPE_INT | @c CPL_TYPE_POINTER would be interpreted as a cast * to @c CPL_TYPE_INT). */ cpl_error_code cpl_table_cast_column(cpl_table *table, const char *from_name, const char *to_name, cpl_type type) { const char *fid = "cpl_table_cast_column"; cpl_column *column; if (table == 0x0 || to_name == 0x0 || from_name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (cpl_table_find_column(table, to_name)) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); column = cpl_table_find_column(table, from_name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); type &= ~CPL_TYPE_POINTER; switch (type) { case CPL_TYPE_INT: column = cpl_column_cast_to_int(column); break; case CPL_TYPE_FLOAT: column = cpl_column_cast_to_float(column); break; case CPL_TYPE_DOUBLE: column = cpl_column_cast_to_double(column); break; default: return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); } if (column) { cpl_column_set_name(column, to_name); cpl_table_append_column(table, column); } else { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Add the values of two numeric table columns. * * @param table Pointer to table. * @param to_name Name of target column. * @param from_name Name of source column. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or any column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with any specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * Any specified column is not numerical, or is an array column. *
* @enderror * * The columns are summed element by element, and the result of the sum is * stored in the target column. The columns' types may differ, and in that * case the operation would be performed using the standard C upcasting * rules, with a final cast of the result to the target column type. * Invalid elements are propagated consistently: if either or both members * of the sum are invalid, the result will be invalid too. Underflows and * overflows are ignored. */ cpl_error_code cpl_table_add_columns(cpl_table *table, const char *to_name, const char *from_name) { const char *fid = "cpl_table_add_columns"; cpl_column *to_column; cpl_column *from_column; if (table == 0x0 || to_name == 0x0 || from_name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); to_column = cpl_table_find_column(table, to_name); from_column = cpl_table_find_column(table, from_name); if (!(to_column && from_column)) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_add(to_column, from_column)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Subtract two numeric table columns. * * @param table Pointer to table. * @param to_name Name of target column. * @param from_name Name of column to be subtracted from target column. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or any column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with any specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * Any specified column is not numerical, or is an array column. *
* @enderror * * The columns are subtracted element by element, and the result of the * subtraction is stored in the target column. See the documentation of * the function @c cpl_table_add_columns() for further details. */ cpl_error_code cpl_table_subtract_columns(cpl_table *table, const char *to_name, const char *from_name) { const char *fid = "cpl_table_subtract_columns"; cpl_column *to_column; cpl_column *from_column; if (table == 0x0 || to_name == 0x0 || from_name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); to_column = cpl_table_find_column(table, to_name); from_column = cpl_table_find_column(table, from_name); if (!(to_column && from_column)) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_subtract(to_column, from_column)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Multiply two numeric table columns. * * @param table Pointer to table. * @param to_name Name of target column. * @param from_name Name of column to be multiplied with target column. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or any column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with any specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * Any specified column is not numerical, or is an array column. *
* @enderror * * The columns are multiplied element by element, and the result of the * multiplication is stored in the target column. See the documentation of * the function @c cpl_table_add_columns() for further details. */ cpl_error_code cpl_table_multiply_columns(cpl_table *table, const char *to_name, const char *from_name) { const char *fid = "cpl_table_multiply_columns"; cpl_column *to_column; cpl_column *from_column; if (table == 0x0 || to_name == 0x0 || from_name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); to_column = cpl_table_find_column(table, to_name); from_column = cpl_table_find_column(table, from_name); if (!(to_column && from_column)) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_multiply(to_column, from_column)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Divide two numeric table columns. * * @param table Pointer to table. * @param to_name Name of target column. * @param from_name Name of column dividing the target column. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or any column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with any specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * Any specified column is not numerical, or is an array column. *
* @enderror * * The columns are divided element by element, and the result of the * division is stored in the target column. The columns' types may * differ, and in that case the operation would be performed using * the standard C upcasting rules, with a final cast of the result * to the target column type. Invalid elements are propagated consistently: * if either or both members of the division are invalid, the result * will be invalid too. Underflows and overflows are ignored, but a * division by exactly zero will set an invalid column element. */ cpl_error_code cpl_table_divide_columns(cpl_table *table, const char *to_name, const char *from_name) { const char *fid = "cpl_table_divide_columns"; cpl_column *to_column; cpl_column *from_column; if (table == 0x0 || to_name == 0x0 || from_name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); to_column = cpl_table_find_column(table, to_name); from_column = cpl_table_find_column(table, from_name); if (!(to_column && from_column)) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_divide(to_column, from_column)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Add a constant value to a numerical column. * * @param table Pointer to table. * @param name Column name. * @param value Value to add. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical, or is an array column. *
* @enderror * * The operation is always performed in double precision, with a final * cast of the result to the target column type. Invalid elements are * are not modified by this operation. */ cpl_error_code cpl_table_add_scalar(cpl_table *table, const char *name, double value) { const char *fid = "cpl_table_add_scalar"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_add_scalar(column, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Subtract a constant value from a numerical column. * * @param table Pointer to table. * @param name Column name. * @param value Value to subtract. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical, or is an array column. *
* @enderror * * See the description of the function @c cpl_table_add_scalar(). */ cpl_error_code cpl_table_subtract_scalar(cpl_table *table, const char *name, double value) { const char *fid = "cpl_table_subtract_scalar"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_subtract_scalar(column, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Multiply a numerical column by a constant. * * @param table Pointer to table. * @param name Column name. * @param value Multiplication factor. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical, or is an array column. *
* @enderror * * See the description of the function @c cpl_table_add_scalar(). */ cpl_error_code cpl_table_multiply_scalar(cpl_table *table, const char *name, double value) { const char *fid = "cpl_table_multiply_scalar"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_multiply_scalar(column, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Divide a numerical column by a constant. * * @param table Pointer to table. * @param name Column name. * @param value Divisor value. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical, or is an array column. *
CPL_ERROR_DIVISION_BY_ZERO * The input value is 0.0. *
* @enderror * * The operation is always performed in double precision, with a final * cast of the result to the target column type. Invalid elements are * not modified by this operation. */ cpl_error_code cpl_table_divide_scalar(cpl_table *table, const char *name, double value) { const char *fid = "cpl_table_divide_scalar"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_divide_scalar(column, value)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Compute the absolute value of column values. * * @param table Pointer to table. * @param name Table column name. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical, or has type array. *
* @enderror * * Each column element is replaced by its absolute value. * Invalid elements are not modified by this operation. */ cpl_error_code cpl_table_abs_column(cpl_table *table, const char *name) { const char *fid = "cpl_table_abs_column"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_absolute(column)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Compute the logarithm of column values. * * @param table Pointer to table. * @param name Table column name. * @param base Logarithm base. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical, or is an array column. *
CPL_ERROR_ILLEGAL_INPUT * The input base is not positive. *
* @enderror * * Each column element is replaced by its logarithm in the specified base. * The operation is always performed in double precision, with a final * cast of the result to the target column type. Invalid elements are * not modified by this operation, but zero or negative elements are * invalidated by this operation. */ cpl_error_code cpl_table_logarithm_column(cpl_table *table, const char *name, double base) { const char *fid = "cpl_table_logarithm_column"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_logarithm(column, base)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Compute the exponential of column values. * * @param table Pointer to table. * @param name Column name. * @param base Exponential base. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical. *
CPL_ERROR_ILLEGAL_INPUT * The input base is not positive. *
* @enderror * * Each column element is replaced by its exponential in the specified base. * The operation is always performed in double precision, with a final * cast of the result to the target column type. Invalid elements are * not modified by this operation. */ cpl_error_code cpl_table_exponential_column(cpl_table *table, const char *name, double base) { const char *fid = "cpl_table_exponential_column"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_exponential(column, base)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Compute the power of column values. * * @param table Pointer to table. * @param name Column name. * @param exponent Constant exponent. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical. *
* @enderror * * Each column element is replaced by its power to the specified exponent. * The operation is always performed in double precision, with a final * cast of the result to the target column type. Invalid elements are * not modified by this operation, but elements are invalidated at any * illegal operation: if the specified @em exponent is not negative, all * column elements must be not negative, and if the specified @em exponent * is negative, all column elements must be positive; column values not * fulfilling this condition will be invalidated. If the exponent is 0.0, * then any (valid) column element would be assigned the value 1.0. */ cpl_error_code cpl_table_power_column(cpl_table *table, const char *name, double exponent) { const char *fid = "cpl_table_power_column"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_power(column, exponent)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Compute the mean value of a numerical column. * * @param table Pointer to table. * @param name Column name. * * @return Mean value. In case of error 0.0 is returned. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in * table, or it just contains invalid elements, or * the table has length zero. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical. *
* @enderror * * Invalid column values are excluded from the computation. The table * selection flags have no influence on the result. */ double cpl_table_get_column_mean(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_mean"; cpl_column *column; double mean; cpl_errorstate prevstate; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return 0.0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return 0.0; } prevstate = cpl_errorstate_get(); mean = cpl_column_get_mean(column); if (!cpl_errorstate_is_equal(prevstate)) cpl_error_set_where(fid); return mean; } /** * @brief * Compute the median value of a numerical column. * * @param table Pointer to table. * @param name Column name. * * @return Median value. See documentation of @c cpl_table_get_column_mean(). * * See the description of the function @c cpl_table_get_column_mean(). */ double cpl_table_get_column_median(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_median"; cpl_column *column; double median; cpl_errorstate prevstate; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return 0.0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return 0.0; } prevstate = cpl_errorstate_get(); median = cpl_column_get_median(column); if (!cpl_errorstate_is_equal(prevstate)) cpl_error_set_where(fid); return median; } /** * @brief * Find the standard deviation of a table column. * * @param table Pointer to table. * @param name Column name. * * @return Standard deviation. See documentation of * @c cpl_table_get_column_mean(). * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in * table, or it just contains invalid elements, or * the table has length zero. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical. *
* @enderror * * Invalid column values are excluded from the computation of the * standard deviation. If just one valid element is found, 0.0 is * returned but no error is set. The table selection flags have no * influence on the result. */ double cpl_table_get_column_stdev(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_stdev"; cpl_column *column; double stdev; cpl_errorstate prevstate; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return 0.0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return 0.0; } prevstate = cpl_errorstate_get(); stdev = cpl_column_get_stdev(column); if (!cpl_errorstate_is_equal(prevstate)) cpl_error_set_where(fid); return stdev; } /** * @brief * Get maximum value in a numerical column. * * @param table Pointer to table. * @param name Column name. * * @return Maximum value. See documentation of @c cpl_table_get_column_mean(). * * See the description of the function @c cpl_table_get_column_mean(). */ double cpl_table_get_column_max(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_max"; cpl_column *column; double max; cpl_errorstate prevstate; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return 0.0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return 0.0; } prevstate = cpl_errorstate_get(); max = cpl_column_get_max(column); if (!cpl_errorstate_is_equal(prevstate)) cpl_error_set_where(fid); return max; } /** * @brief * Get minimum value in a numerical column. * * @param table Pointer to table. * @param name Column name. * * @return Minimum value. See documentation of @c cpl_table_get_column_mean(). * * See the description of the function @c cpl_table_get_column_mean(). */ double cpl_table_get_column_min(const cpl_table *table, const char *name) { const char *fid = "cpl_table_get_column_min"; cpl_column *column; double min; cpl_errorstate prevstate; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return 0.0; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return 0.0; } prevstate = cpl_errorstate_get(); min = cpl_column_get_min(column); if (!cpl_errorstate_is_equal(prevstate)) cpl_error_set_where(fid); return min; } /** * @brief * Get position of maximum in a numerical column. * * @param table Pointer to table. * @param name Column name. * @param row Returned position of maximum value. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in * table, or it just contains invalid elements, or * the table has length zero. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical. *
* @enderror * * Invalid column values are excluded from the search. The @em row argument * will be assigned the position of the maximum value, where rows are counted * starting from 0. If more than one column element correspond to the max * value, the position with the lowest row number is returned. In case of * error, @em row is left untouched. The table selection flags have no * influence on the result. */ cpl_error_code cpl_table_get_column_maxpos(const cpl_table *table, const char *name, int *row) { const char *fid = "cpl_table_get_column_maxpos"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_get_maxpos(column, row)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Get position of minimum in a numerical column. * * @param table Pointer to table. * @param name Column name. * @param row Returned position of minimum value. * * @return See function @c cpl_table_get_column_maxpos(). * * See the description of the function @c cpl_table_get_column_maxpos(). */ cpl_error_code cpl_table_get_column_minpos(const cpl_table *table, const char *name, int *row) { const char *fid = "cpl_table_get_column_minpos"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_get_minpos(column, row)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return CPL_ERROR_NONE; } /** * @brief * Remove from a table columns and rows just containing invalid elements. * * @param table Pointer to table. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
* @enderror * * Table columns and table rows just containing invalid elements are deleted * from the table. The selection flags are set back to "all selected" even * if no rows or columns are removed. The pointers to data may change, * therefore pointers previously retrieved by @c cpl_table_get_data_int(), * @c cpl_table_get_data_string(), etc., should be discarded. * * @note * If the input table just contains invalid elements, all columns are * deleted. */ cpl_error_code cpl_table_erase_invalid_rows(cpl_table *table) { const char *fid = "cpl_table_erase_invalid_rows"; int length = cpl_table_get_nrow(table); int width = cpl_table_get_ncol(table); int new_width; int any_valid; int all_valid = 0; int count = 0; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); while (width--) { if (!cpl_column_has_valid(table->columns[width])) cpl_table_erase_column(table, cpl_column_get_name(table->columns[width])); else if (!cpl_column_has_invalid(table->columns[width])) all_valid = 1; } if (all_valid) return cpl_table_select_all(table); new_width = cpl_table_get_ncol(table); if (new_width == 0) return CPL_ERROR_NONE; while (length--) { width = new_width; any_valid = 0; while (width--) { if (!cpl_column_is_invalid(table->columns[width], length)) { any_valid = 1; break; } } if (any_valid) { /* Current row does not contain just invalids */ if (count) { /* End of segment of just invalids */ cpl_table_erase_window(table, length + 1, count); count = 0; } } else /* Current row just contains invalids */ count++; } if (count) /* The first table row is invalid */ cpl_table_erase_window(table, 0, count); return cpl_table_select_all(table); } /** * @brief * Remove from a table all columns just containing invalid elements, * and then all rows containing at least one invalid element. * * @param table Pointer to table. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
* @enderror * * Firstly, all columns consisting just of invalid elements are deleted * from the table. Next, the remaining table rows containing at least * one invalid element are also deleted from the table. The selection * flags are set back to "all selected" even if no rows or columns are * erased. The pointers to data may change, therefore pointers previously * retrieved by calling @c cpl_table_get_data_int(), etc., should be * discarded. * * @note * If the input table just contains invalid elements, all columns are * deleted. */ cpl_error_code cpl_table_erase_invalid(cpl_table *table) { const char *fid = "cpl_table_erase_invalid"; int length = cpl_table_get_nrow(table); int width = cpl_table_get_ncol(table); int new_width; int count = 0; int any_null; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); while (width--) if (!cpl_column_has_valid(table->columns[width])) cpl_table_erase_column(table, cpl_column_get_name(table->columns[width])); new_width = cpl_table_get_ncol(table); if (new_width == 0) return CPL_ERROR_NONE; while (length--) { width = new_width; any_null = 0; while (width--) { if (cpl_column_is_invalid(table->columns[width], length)) { any_null = 1; break; } } if (any_null) { /* Current row contains at least an invalid */ count++; } else { /* Current row contains no invalids */ if (count) { /* End of segment of rows with some invalids */ cpl_table_erase_window(table, length + 1, count); count = 0; } } } if (count) /* The first table row has at least a NULL */ cpl_table_erase_window(table, 0, count); return cpl_table_select_all(table); } /** * @brief * Flag a table row as selected. * * @param table Pointer to table. * @param row Row to select. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
* @enderror * * Flag a table row as selected. Any previous selection is kept. */ cpl_error_code cpl_table_select_row(cpl_table *table, int row) { const char *fid = "cpl_table_select_row"; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (row < 0 || row >= table->nr) return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE); if (table->selectcount == table->nr) return CPL_ERROR_NONE; if (table->selectcount == 0) table->select = cpl_calloc(table->nr, sizeof(cpl_column_flag)); if (table->select[row] == 0) { table->select[row] = 1; table->selectcount++; if (table->selectcount == table->nr) { cpl_free(table->select); table->select = NULL; } } return CPL_ERROR_NONE; } /** * @brief * Select all table rows. * * @param table Pointer to table. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
* @enderror * * The table selection flags are reset, meaning that they are * all marked as selected. This is the initial state of any * table. */ cpl_error_code cpl_table_select_all(cpl_table *table) { const char *fid = "cpl_table_select_all"; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (table->select) cpl_free(table->select); table->select = NULL; table->selectcount = table->nr; return CPL_ERROR_NONE; } /** * @brief * Flag a table row as unselected. * * @param table Pointer to table. * @param row Row to unselect. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
* @enderror * * Flag a table row as unselected. Any previous selection is kept. */ cpl_error_code cpl_table_unselect_row(cpl_table *table, int row) { const char *fid = "cpl_table_unselect_row"; int length; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (row < 0 || row >= table->nr) return cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE); if (table->selectcount == 0) return CPL_ERROR_NONE; length = table->nr; if (table->selectcount == length) table->select = cpl_malloc(table->nr * sizeof(cpl_column_flag)); if (table->selectcount == length) while (length--) table->select[length] = 1; if (table->select[row] == 1) { table->select[row] = 0; table->selectcount--; if (table->selectcount == 0) { if (table->select) cpl_free(table->select); table->select = NULL; } } return CPL_ERROR_NONE; } /** * @brief * Unselect all table rows. * * @param table Pointer to table. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
* @enderror * * The table selection flags are all unset, meaning that no table * rows are selected. */ cpl_error_code cpl_table_unselect_all(cpl_table *table) { const char *fid = "cpl_table_unselect_row"; if (table == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (table->select) cpl_free(table->select); table->select = NULL; table->selectcount = 0; return CPL_ERROR_NONE; } /** * @brief * Describe the structure and the contents of a table. * * @param table Pointer to table. * @param stream The output stream * * @return Nothing. * * This function is mainly intended for debug purposes. Some information * about the structure of a table and its contents is printed to terminal: * * - Number of columns, with their names and types * - Number of invalid elements for each column * - Number of rows and of selected rows * * If the specified stream is @c NULL, it is set to @em stdout. The function * used for printing is the standard C @c fprintf(). */ void cpl_table_dump_structure(const cpl_table *table, FILE *stream) { int width = cpl_table_get_ncol(table); int i = 0; if (stream == 0x0) stream = stdout; if (table == 0x0) { fprintf(stream, "NULL table\n\n"); return; } if (width > 0) fprintf(stream, "Table with %d/%d selected rows and %d columns:\n\n", table->selectcount, table->nr, table->nc); while (i < width) { fprintf(stream, " %s:\n %d ", cpl_column_get_name(table->columns[i]), cpl_column_get_size(table->columns[i])); switch (cpl_column_get_type(table->columns[i])) { case CPL_TYPE_INT: fprintf(stream, "integer "); break; case CPL_TYPE_FLOAT: fprintf(stream, "float "); break; case CPL_TYPE_DOUBLE: fprintf(stream, "double "); break; case CPL_TYPE_STRING: fprintf(stream, "string "); break; case CPL_TYPE_INT | CPL_TYPE_POINTER: fprintf(stream, "arrays of integer "); break; case CPL_TYPE_FLOAT | CPL_TYPE_POINTER: fprintf(stream, "arrays of float "); break; case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER: fprintf(stream, "arrays of double "); break; case CPL_TYPE_STRING | CPL_TYPE_POINTER: fprintf(stream, "arrays of string "); break; default: fprintf(stream, "UNDEFINED "); } fprintf(stream, "elements, of which %d are flagged invalid.\n", cpl_column_count_invalid(table->columns[i])); i++; } } /** * @brief * Print a table. * * @param table Pointer to table * @param start First row to print * @param count Number of rows to print * @param stream The output stream * * @return Nothing. * * This function is mainly intended for debug purposes. * All column elements are printed according to the column formats, * that may be specified for each table column with the function * @c cpl_table_set_column_format(). The default column formats * have been chosen to provide a reasonable printout in most cases. * Table rows are counted from 0, and their sequence number is printed * at the left of each row. Invalid table elements are represented * as a sequence of "-" as wide as the field occupied by the column * to which they belong. Array elements are not resolved, and are * represented by a sequence of "+" as wide as the field occupied by the * column to which they belong. It is not shown whether a table row is * selected or not. Specifying a @em start beyond the table boundaries, * or a non-positive @em count, would generate a warning message, but no * error would be set. The specified number of rows to print may exceed * the table end, and in that case the table would be printed up to its * last row. If the specified stream is @c NULL, it is set to @em stdout. * The function used for printing is the standard C @c fprintf(). */ void cpl_table_dump(const cpl_table *table, int start, int count, FILE *stream) { int size; int inum; float fnum; double dnum; char **fields; char *string; cpl_array *array; char *row_field; int *field_size; int *label_len; int null; int nc = cpl_table_get_ncol(table); int found; int offset; int i, j, k; int row, end; if (stream == 0x0) stream = stdout; if (table == 0x0) { fprintf(stream, "NULL table\n\n"); return; } if (table->nr == 0) { fprintf(stream, "Zero length table\n\n"); return; } if (start < 0 || start >= table->nr || count < 1) { fprintf(stream, "Illegal cpl_table_dump() arguments!\n"); return; } if (count > table->nr - start) count = table->nr - start; end = start + count; row = cx_snprintf(NULL, 0, "% -d", end); row_field = cpl_malloc((row + 1) * sizeof(char)); memset(row_field, ' ', row + 1); row_field[row] = '\0'; label_len = cpl_calloc(nc, sizeof(int)); field_size = cpl_calloc(nc, sizeof(int)); fields = cpl_calloc(nc, sizeof(char *)); for (j = 0; j < nc; j++) { label_len[j] = field_size[j] = strlen(cpl_column_get_name(table->columns[j])); switch (cpl_column_get_type(table->columns[j])) { case CPL_TYPE_INT: for (i = start; i < end; i++) { inum = cpl_column_get_int(table->columns[j], i, &null); if (null) size = 4; else size = cx_snprintf(NULL, 0, cpl_column_get_format(table->columns[j]), inum); if (size > field_size[j]) field_size[j] = size; } break; case CPL_TYPE_FLOAT: for (i = start; i < end; i++) { fnum = cpl_column_get_float(table->columns[j], i, &null); if (null) size = 4; else size = cx_snprintf(NULL, 0, cpl_column_get_format(table->columns[j]), fnum); if (size > field_size[j]) field_size[j] = size; } break; case CPL_TYPE_DOUBLE: for (i = start; i < end; i++) { dnum = cpl_column_get_double(table->columns[j], i, &null); if (null) size = 4; else size = cx_snprintf(NULL, 0, cpl_column_get_format(table->columns[j]), dnum); if (size > field_size[j]) field_size[j] = size; } break; case CPL_TYPE_STRING: for (i = start; i < end; i++) { string = (char *)cpl_column_get_string(table->columns[j], i); if (string == 0x0) size = 4; else size = cx_snprintf(NULL, 0, cpl_column_get_format(table->columns[j]), string); if (size > field_size[j]) field_size[j] = size; } break; case CPL_TYPE_INT | CPL_TYPE_POINTER: case CPL_TYPE_FLOAT | CPL_TYPE_POINTER: case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER: case CPL_TYPE_STRING | CPL_TYPE_POINTER: break; default: field_size[j] = 4; break; } field_size[j]++; label_len[j]++; fields[j] = cpl_malloc(field_size[j] * sizeof(char)); } fprintf(stream, "%s ", row_field); for (j = 0; j < nc; j++) { offset = (field_size[j] - label_len[j]) / 2; for (i = 0; i < offset; i++) fields[j][i] = ' '; cx_snprintf(fields[j] + offset, label_len[j], "%s", cpl_column_get_name(table->columns[j])); for (i = label_len[j] + offset - 1; i < field_size[j]; i++) fields[j][i] = ' '; fields[j][field_size[j] - 1] = '\0'; fprintf(stream, "%-*s ", label_len[j], fields[j]); } fprintf(stream, "\n\n"); for (i = start; i < end; i++) { fprintf(stream, "%*d ", row, i); for (j = 0; j < nc; j++) { switch (cpl_column_get_type(table->columns[j])) { case CPL_TYPE_INT: inum = cpl_column_get_int(table->columns[j], i, &null); if (null) { memset(fields[j], '-', field_size[j]); fields[j][field_size[j] - 1] = '\0'; } else cx_snprintf(fields[j], field_size[j], cpl_column_get_format(table->columns[j]), inum); break; case CPL_TYPE_FLOAT: fnum = cpl_column_get_float(table->columns[j], i, &null); if (null) { memset(fields[j], '-', field_size[j]); fields[j][field_size[j] - 1] = '\0'; } else cx_snprintf(fields[j], field_size[j], cpl_column_get_format(table->columns[j]), fnum); break; case CPL_TYPE_DOUBLE: dnum = cpl_column_get_double(table->columns[j], i, &null); if (null) { memset(fields[j], '-', field_size[j]); fields[j][field_size[j] - 1] = '\0'; } else cx_snprintf(fields[j], field_size[j], cpl_column_get_format(table->columns[j]), dnum); break; case CPL_TYPE_STRING: string = (char *)cpl_column_get_string(table->columns[j], i); if (!string) { memset(fields[j], '-', field_size[j]); fields[j][field_size[j] - 1] = '\0'; } else cx_snprintf(fields[j], field_size[j], cpl_column_get_format(table->columns[j]), string); break; case CPL_TYPE_INT | CPL_TYPE_POINTER: case CPL_TYPE_FLOAT | CPL_TYPE_POINTER: case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER: case CPL_TYPE_STRING | CPL_TYPE_POINTER: default: array = (cpl_array *)cpl_column_get_array(table->columns[j], i); if (!array) { memset(fields[j], '-', field_size[j]); } else memset(fields[j], '+', field_size[j]); fields[j][field_size[j] - 1] = '\0'; break; } found = 0; for (k = 0; k < field_size[j]; k++) { if (fields[j][k] == '\0') found = 1; if (found) fields[j][k] = ' '; } fields[j][field_size[j] - 1] = '\0'; fprintf(stream, "%-*s ", field_size[j], fields[j]); } fprintf(stream, "\n"); } for (j = 0; j < nc; j++) cpl_free(fields[j]); cpl_free(fields); cpl_free(row_field); cpl_free(label_len); cpl_free(field_size); } /** * @brief * Shift the position of numeric column values. * * @param table Pointer to table. * @param name Name of table column to shift. * @param shift Shift column values by so many rows. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_INVALID_TYPE * The specified column is not numerical. *
CPL_ERROR_ILLEGAL_INPUT * The absolute value of shift is greater than the column * length. *
* @enderror * * The position of all column values is shifted by the specified amount. * If @em shift is positive, all values will be moved toward the bottom * of the column, otherwise toward its top. In either case as many column * elements as the amount of the @em shift will be left undefined, either * at the top or at the bottom of the column according to the direction * of the shift. These column elements will be marked as invalid. This * function is applicable just to numeric columns, and not to strings * and or array types. The selection flags are always set back to * "all selected" after this operation. */ cpl_error_code cpl_table_shift_column(cpl_table *table, const char *name, int shift) { const char *fid = "cpl_table_shift_column"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); if (cpl_column_shift(column, shift)) { cpl_error_set_where(fid); return cpl_error_get_code(); } return cpl_table_select_all(table); } /** * @brief * Write to invalid @em integer column elements a numeric code. * * @param table Pointer to table containing the column. * @param name Column name. * @param code Code to write to invalid column elements. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_INT, * or of type CPL_TYPE_INT | CPL_TYPE_POINTER. *
* @enderror * * This function can be applied also to columns of arrays of integers. * In general, numeric column elements that are flagged as invalid may contain * any value, that should not be given any meaning whatsoever. In order to * export the column data (using a call to @c cpl_table_get_data_int() ) to * procedures that are external to the CPL column system, it may turn out * to be appropriate assigning to all the invalid elements a conventional * code value. This code value will supposedly be recognized and handled * properly by a given foreign method applied directly to the column data * buffer. Note that only existing invalid elements will be coded as * indicated: new invalid column elements would still have their actual * values left undefined. Also, any further processing of the column would * not take care of maintaining the assigned code to a given invalid column * element: therefore the code should be applied just before it is actually * needed. * * @note * Assigning a code to an invalid element doesn't make it valid. */ cpl_error_code cpl_table_fill_invalid_int(cpl_table *table, const char *name, int code) { const char *fid = "cpl_table_fill_invalid_int"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return cpl_column_fill_invalid_int(column, code); } /** * @brief * Write to invalid @em float column elements a numeric code. * * @param table Pointer to table containing the column. * @param name Column name. * @param code Code to write to invalid column elements. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_FLOAT, * or of type CPL_TYPE_INT | CPL_TYPE_POINTER. *
* @enderror * * This function can be applied also to columns of arrays of floats. * In general, numeric column elements that are flagged as invalid may contain * any value, that should not be given any meaning whatsoever. In order to * export the column data (using a call to @c cpl_table_get_data_float() ) * to procedures that are external to the CPL column system, it may turn out * to be appropriate assigning to all the invalid elements a conventional * code value. This code value will supposedly be recognized and handled * properly by a given foreign method applied directly to the column data * buffer. Note that only existing invalid elements will be coded as * indicated: new invalid column elements would still have their actual * values left undefined. Also, any further processing of the column would * not take care of maintaining the assigned code to a given invalid column * element: therefore the code should be applied just before it is actually * needed. * * @note * Assigning a code to an invalid element doesn't make it valid. */ cpl_error_code cpl_table_fill_invalid_float(cpl_table *table, const char *name, float code) { const char *fid = "cpl_table_fill_invalid_float"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return cpl_column_fill_invalid_float(column, code); } /** * @brief * Write to invalid @em double column elements a numeric code. * * @param table Pointer to table containing the column. * @param name Column name. * @param code Code to write to invalid column elements. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_DOUBLE, * or of type CPL_TYPE_INT | CPL_TYPE_POINTER. *
* @enderror * * This function can be applied also to columns of arrays of doubles. * In general, numeric column elements that are flagged as invalid may contain * any value, that should not be given any meaning whatsoever. In order to * export the column data (using a call to @c cpl_table_get_data_double() ) * to procedures that are external to the CPL column system, it may turn out * to be appropriate assigning to all the invalid elements a conventional * code value. This code value will supposedly be recognized and handled * properly by a given foreign method applied directly to the column data * buffer. Note that only existing invalid elements will be coded as * indicated: new invalid column elements would still have their actual * values left undefined. Also, any further processing of the column would * not take care of maintaining the assigned code to a given invalid column * element: therefore the code should be applied just before it is actually * needed. * * @note * Assigning a code to an invalid element doesn't make it valid. */ cpl_error_code cpl_table_fill_invalid_double(cpl_table *table, const char *name, double code) { const char *fid = "cpl_table_fill_invalid_double"; cpl_column *column; if (table == 0x0 || name == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); column = cpl_table_find_column(table, name); if (!column) return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return cpl_column_fill_invalid_double(column, code); } /** * @brief * Select from selected table rows, by comparing @em integer column * values with a constant. * * @param table Pointer to table. * @param name Column name. * @param operator Relational operator. * @param value Reference value. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_INT. *
* @enderror * * For all the already selected table rows, the values of the specified * column are compared with the reference value. All table rows not * fulfilling the comparison are unselected. An invalid element never * fulfills any comparison by definition. Allowed relational operators * are @c CPL_EQUAL_TO, @c CPL_NOT_EQUAL_TO, @c CPL_GREATER_THAN, * @c CPL_NOT_GREATER_THAN, @c CPL_LESS_THAN, and @c CPL_NOT_LESS_THAN. * If the table has no rows, no error is set, and 0 is returned. See * also the function @c cpl_table_or_selected_int(). */ int cpl_table_and_selected_int(cpl_table *table, const char *name, cpl_table_select_operator operator, int value) { const char *fid = "cpl_table_and_selected_int"; cpl_column *column; cpl_type type; cpl_column_flag *nulldata; int *data; int length; int nullcount; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type != CPL_TYPE_INT) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return -1; } nulldata = cpl_column_get_data_invalid(column); data = cpl_column_get_data_int(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); /* * All invalid elements by definition do not fulfill any comparison */ if (nullcount == length) cpl_table_unselect_all(table); if (table->selectcount == 0) return 0; if (nulldata) /* Some (not all!) invalid elements */ while (length--) if (nulldata[length]) cpl_table_unselect_row(table, length); if (table->selectcount == 0) return 0; /* * Moreover unselect anything that does not fulfill the comparison: */ length = cpl_table_get_nrow(table); /* Restore */ switch (operator) { case CPL_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] != value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] != value) cpl_table_unselect_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] == value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] == value) cpl_table_unselect_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] <= value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] <= value) cpl_table_unselect_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] > value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] > value) cpl_table_unselect_row(table, length); } break; case CPL_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] >= value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] >= value) cpl_table_unselect_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] < value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] < value) cpl_table_unselect_row(table, length); } break; } return table->selectcount; } /** * @brief * Select from unselected table rows, by comparing @em integer column * values with a constant. * * @param table Pointer to table. * @param name Column name. * @param operator Relational operator. * @param value Reference value. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_INT. *
* @enderror * * For all the unselected table rows, the values of the specified * column are compared with the reference value. The table rows * fulfilling the comparison are selected. An invalid element never * fulfills any comparison by definition. Allowed relational operators * are @c CPL_EQUAL_TO, @c CPL_NOT_EQUAL_TO, @c CPL_GREATER_THAN, * @c CPL_NOT_GREATER_THAN, @c CPL_LESS_THAN, and @c CPL_NOT_LESS_THAN. * If the table has no rows, no error is set, and 0 is returned. See * also the description of the function @c cpl_table_and_selected_int(). */ int cpl_table_or_selected_int(cpl_table *table, const char *name, cpl_table_select_operator operator, int value) { const char *fid = "cpl_table_or_selected_int"; cpl_column *column; cpl_type type; cpl_column_flag *nulldata; int *data; int length; int nullcount; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type != CPL_TYPE_INT) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return -1; } nulldata = cpl_column_get_data_invalid(column); data = cpl_column_get_data_int(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); if (table->selectcount == length) /* It's already all selected */ return length; if (nullcount == length) /* Just invalids, no need to check values */ return table->selectcount; /* * Select anything that fulfills the comparison, avoiding the invalids: */ switch (operator) { case CPL_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] == value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] == value) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] != value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] != value) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] > value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] > value) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] <= value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] <= value) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] < value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] < value) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] >= value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] >= value) cpl_table_select_row(table, length); } break; } return table->selectcount; } /** * @brief * Select from selected table rows, by comparing @em float column values * with a constant. * * @param table Pointer to table. * @param name Column name. * @param operator Relational operator. * @param value Reference value. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_FLOAT. *
* @enderror * * For all the already selected table rows, the values of the specified * column are compared with the reference value. All table rows not * fulfilling the comparison are unselected. An invalid element never * fulfills any comparison by definition. Allowed relational operators * are @c CPL_EQUAL_TO, @c CPL_NOT_EQUAL_TO, @c CPL_GREATER_THAN, * @c CPL_NOT_GREATER_THAN, @c CPL_LESS_THAN, and @c CPL_NOT_LESS_THAN. * If the table has no rows, no error is set, and 0 is returned. See * also the function @c cpl_table_or_selected_float(). */ int cpl_table_and_selected_float(cpl_table *table, const char *name, cpl_table_select_operator operator, float value) { const char *fid = "cpl_table_and_selected_float"; cpl_column *column; cpl_type type; cpl_column_flag *nulldata; float *data; int length; int nullcount; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type != CPL_TYPE_FLOAT) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return -1; } nulldata = cpl_column_get_data_invalid(column); data = cpl_column_get_data_float(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); /* * All invalid elements by definition do not fulfill any comparison */ if (nullcount == length) cpl_table_unselect_all(table); if (table->selectcount == 0) return 0; if (nulldata) /* Some (not all!) invalids */ while (length--) if (nulldata[length]) cpl_table_unselect_row(table, length); if (table->selectcount == 0) return 0; /* * Moreover unselect anything that does not fulfill the comparison: */ length = cpl_table_get_nrow(table); /* Restore */ switch (operator) { case CPL_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] != value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] != value) cpl_table_unselect_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] == value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] == value) cpl_table_unselect_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] <= value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] <= value) cpl_table_unselect_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] > value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] > value) cpl_table_unselect_row(table, length); } break; case CPL_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] >= value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] >= value) cpl_table_unselect_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] < value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] < value) cpl_table_unselect_row(table, length); } break; } return table->selectcount; } /** * @brief * Select from unselected table rows, by comparing @em float column * values with a constant. * * @param table Pointer to table. * @param name Column name. * @param operator Relational operator. * @param value Reference value. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_FLOAT. *
* @enderror * * For all the unselected table rows, the values of the specified * column are compared with the reference value. The table rows * fulfilling the comparison are selected. An invalid element never * fulfills any comparison by definition. Allowed relational operators * are @c CPL_EQUAL_TO, @c CPL_NOT_EQUAL_TO, @c CPL_GREATER_THAN, * @c CPL_NOT_GREATER_THAN, @c CPL_LESS_THAN, and @c CPL_NOT_LESS_THAN. * If the table has no rows, no error is set, and 0 is returned. See * also the description of the function @c cpl_table_and_selected_float(). */ int cpl_table_or_selected_float(cpl_table *table, const char *name, cpl_table_select_operator operator, float value) { const char *fid = "cpl_table_or_selected_float"; cpl_column *column; cpl_type type; cpl_column_flag *nulldata; float *data; int length; int nullcount; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type != CPL_TYPE_FLOAT) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return -1; } nulldata = cpl_column_get_data_invalid(column); data = cpl_column_get_data_float(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); if (table->selectcount == length) return length; if (nullcount == length) return table->selectcount; /* * Select anything that fulfills the comparison, avoiding the invalids: */ switch (operator) { case CPL_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] == value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] == value) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] != value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] != value) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] > value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] > value) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] <= value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] <= value) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] < value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] < value) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] >= value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] >= value) cpl_table_select_row(table, length); } break; } return table->selectcount; } /** * @brief * Select from selected table rows, by comparing @em double column values * with a constant. * * @param table Pointer to table. * @param name Column name. * @param operator Relational operator. * @param value Reference value. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_DOUBLE. *
* @enderror * * For all the already selected table rows, the values of the specified * column are compared with the reference value. All table rows not * fulfilling the comparison are unselected. An invalid element never * fulfills any comparison by definition. Allowed relational operators * are @c CPL_EQUAL_TO, @c CPL_NOT_EQUAL_TO, @c CPL_GREATER_THAN, * @c CPL_NOT_GREATER_THAN, @c CPL_LESS_THAN, and @c CPL_NOT_LESS_THAN. * If the table has no rows, no error is set, and 0 is returned. See * also the function @c cpl_table_or_selected_double(). */ int cpl_table_and_selected_double(cpl_table *table, const char *name, cpl_table_select_operator operator, double value) { const char *fid = "cpl_table_and_selected_double"; cpl_column *column; cpl_type type; cpl_column_flag *nulldata; double *data; int length; int nullcount; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type != CPL_TYPE_DOUBLE) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return -1; } nulldata = cpl_column_get_data_invalid(column); data = cpl_column_get_data_double(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); /* * All invalid by definition do not fulfill any comparison */ if (nullcount == length) cpl_table_unselect_all(table); if (table->selectcount == 0) return 0; if (nulldata) /* Some (not all!) invalids */ while (length--) if (nulldata[length]) cpl_table_unselect_row(table, length); if (table->selectcount == 0) return 0; /* * Moreover unselect anything that does not fulfill the comparison: */ length = cpl_table_get_nrow(table); /* Restore */ switch (operator) { case CPL_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] != value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] != value) cpl_table_unselect_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] == value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] == value) cpl_table_unselect_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] <= value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] <= value) cpl_table_unselect_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] > value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] > value) cpl_table_unselect_row(table, length); } break; case CPL_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] >= value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] >= value) cpl_table_unselect_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] < value) cpl_table_unselect_row(table, length); } else { while (length--) if (data[length] < value) cpl_table_unselect_row(table, length); } break; } return table->selectcount; } /** * @brief * Select from unselected table rows, by comparing @em double column * values with a constant. * * @param table Pointer to table. * @param name Column name. * @param operator Relational operator. * @param value Reference value. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_DOUBLE. *
* @enderror * * For all the unselected table rows, the values of the specified * column are compared with the reference value. The table rows * fulfilling the comparison are selected. An invalid element never * fulfills any comparison by definition. Allowed relational operators * are @c CPL_EQUAL_TO, @c CPL_NOT_EQUAL_TO, @c CPL_GREATER_THAN, * @c CPL_NOT_GREATER_THAN, @c CPL_LESS_THAN, and @c CPL_NOT_LESS_THAN. * If the table has no rows, no error is set, and 0 is returned. See * also the description of the function @c cpl_table_and_selected_double(). */ int cpl_table_or_selected_double(cpl_table *table, const char *name, cpl_table_select_operator operator, double value) { const char *fid = "cpl_table_or_selected_double"; cpl_column *column; cpl_type type; cpl_column_flag *nulldata; double *data; int length; int nullcount; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type != CPL_TYPE_DOUBLE) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return -1; } nulldata = cpl_column_get_data_invalid(column); data = cpl_column_get_data_double(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); if (table->selectcount == length) return length; if (nullcount == length) return table->selectcount; /* * Select anything that fulfills the comparison, avoiding the invalids: */ switch (operator) { case CPL_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] == value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] == value) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] != value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] != value) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] > value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] > value) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] <= value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] <= value) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] < value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] < value) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata) { while (length--) if (nulldata[length] == 0) if (data[length] >= value) cpl_table_select_row(table, length); } else { while (length--) if (data[length] >= value) cpl_table_select_row(table, length); } break; } return table->selectcount; } /** * @brief * Select from selected table rows, by comparing @em string column values * with a character string. * * @param table Pointer to table. * @param name Column name. * @param operator Relational operator. * @param string Reference character string. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_STRING. *
CPL_ERROR_ILLEGAL_INPUT * Invalid regular expression. *
* @enderror * * For all the already selected table rows, the values of the specified * column are compared with the reference string. The comparison function * used is the C standard @c strcmp(), but in case the relational operators * @c CPL_EQUAL_TO or @c CPL_NOT_EQUAL_TO are specified, the comparison * string is treated as a regular expression. All table rows not fulfilling * the comparison are unselected. An invalid element never fulfills * any comparison by definition. Allowed relational operators are * @c CPL_EQUAL_TO, @c CPL_NOT_EQUAL_TO, @c CPL_GREATER_THAN, * @c CPL_NOT_GREATER_THAN, @c CPL_LESS_THAN, and @c CPL_NOT_LESS_THAN. * If the table has no rows, no error is set, and 0 is returned. See also * the function @c cpl_table_or_selected_string(). */ int cpl_table_and_selected_string(cpl_table *table, const char *name, cpl_table_select_operator operator, const char *string) { const char *fid = "cpl_table_and_selected_string"; cpl_column *column; cpl_type type; char **data; int length; int nullcount; int status; regex_t re; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type != CPL_TYPE_STRING) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return -1; } data = cpl_column_get_data_string(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); if (length == 0) return 0; /* * Compile the regular expression only if a match operator is used. */ if (operator == CPL_EQUAL_TO || operator == CPL_NOT_EQUAL_TO) { status = regcomp(&re, string, REG_EXTENDED|REG_NOSUB); if (status) { cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); return -1; } } /* * All invalids by definition do not fulfill any comparison */ if (nullcount == length) cpl_table_unselect_all(table); if (table->selectcount == 0) return 0; if (nullcount) /* Some (not all!) invalids */ while (length--) if (data[length] == NULL) cpl_table_unselect_row(table, length); if (table->selectcount == 0) return 0; /* * Moreover unselect anything that does not fulfill the comparison: */ length = cpl_table_get_nrow(table); /* Restore */ switch (operator) { case CPL_EQUAL_TO: while (length--) if (data[length]) if (!strmatch(&re, data[length])) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if (data[length]) if (strmatch(&re, data[length])) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if (data[length]) if (strcmp(data[length], string) <= 0) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if (data[length]) if (strcmp(data[length], string) > 0) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if (data[length]) if (strcmp(data[length], string) >= 0) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if (data[length]) if (strcmp(data[length], string) < 0) cpl_table_unselect_row(table, length); break; } if (operator == CPL_EQUAL_TO || operator == CPL_NOT_EQUAL_TO) regfree(&re); return table->selectcount; } /** * @brief * Select from unselected table rows, by comparing column values with * a constant. * * @param table Pointer to table. * @param name Column name. * @param operator Relational operator. * @param string Reference value. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
CPL_ERROR_TYPE_MISMATCH * The specified column is not of type CPL_TYPE_STRING. *
CPL_ERROR_ILLEGAL_INPUT * Invalid regular expression. *
* @enderror * * For all the unselected table rows, the values of the specified column * are compared with the reference value. The comparison function used * is the C standard @c strcmp(), but in case the relational operators * @c CPL_EQUAL_TO or @c CPL_NOT_EQUAL_TO are specified, the comparison * string is treated as a regular expression. The table rows fulfilling * the comparison are selected. An invalid element never fulfills any * comparison by definition. Allowed relational operators are @c CPL_EQUAL_TO, * @c CPL_NOT_EQUAL_TO, @c CPL_GREATER_THAN, @c CPL_NOT_GREATER_THAN, * @c CPL_LESS_THAN, and @c CPL_NOT_LESS_THAN. If the table has no rows, * no error is set, and 0 is returned. See also the description of the * function @c cpl_table_and_selected_string(). */ int cpl_table_or_selected_string(cpl_table *table, const char *name, cpl_table_select_operator operator, const char *string) { const char *fid = "cpl_table_or_selected_string"; cpl_column *column; cpl_type type; char **data; int length; int nullcount; int status; regex_t re; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type != CPL_TYPE_STRING) { cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); return -1; } data = cpl_column_get_data_string(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); if (length == 0) return 0; /* * Compile the regular expression only if a match operator is used. */ if (operator == CPL_EQUAL_TO || operator == CPL_NOT_EQUAL_TO) { status = regcomp(&re, string, REG_EXTENDED|REG_NOSUB); if (status) { cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); return -1; } } if (table->selectcount == length) return length; if (nullcount == length) return table->selectcount; /* * Select anything that fulfills the comparison, avoiding the NULLs: */ switch (operator) { case CPL_EQUAL_TO: while (length--) if (data[length]) if (strmatch(&re, data[length])) cpl_table_select_row(table, length); regfree(&re); break; case CPL_NOT_EQUAL_TO: while (length--) if (data[length]) if (!strmatch(&re, data[length])) cpl_table_select_row(table, length); regfree(&re); break; case CPL_GREATER_THAN: while (length--) if (data[length]) if (strcmp(data[length], string) > 0) cpl_table_select_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if (data[length]) if (strcmp(data[length], string) <= 0) cpl_table_select_row(table, length); break; case CPL_LESS_THAN: while (length--) if (data[length]) if (strcmp(data[length], string) < 0) cpl_table_select_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if (data[length]) if (strcmp(data[length], string) >= 0) cpl_table_select_row(table, length); break; } return table->selectcount; } /** * @brief * Select from selected table rows all rows with an invalid value in * a specified column. * * @param table Pointer to table. * @param name Column name. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
* @enderror * * For all the already selected table rows, all the rows containing valid * values at the specified column are unselected. See also the function * @c cpl_table_or_selected_invalid(). */ int cpl_table_and_selected_invalid(cpl_table *table, const char *name) { const char *fid = "cpl_table_and_selected_invalid"; cpl_column *column; cpl_type type; cpl_column_flag *nulldata = NULL; cpl_array **adata = NULL; char **cdata = NULL; int length; int nullcount; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type == CPL_TYPE_STRING) cdata = cpl_column_get_data_string(column); else if (type & CPL_TYPE_POINTER) adata = cpl_column_get_data_array(column); else nulldata = cpl_column_get_data_invalid(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); if (nullcount == length) return table->selectcount; if (nullcount == 0) cpl_table_unselect_all(table); if (table->selectcount == 0) return 0; /* * If this point is reached, there are some (not all!) invalid elements. */ if (cdata) { /* String column */ while (length--) if (cdata[length]) cpl_table_unselect_row(table, length); } else if (adata) { /* Array column */ while (length--) if (adata[length]) cpl_table_unselect_row(table, length); } else { while (length--) if (!nulldata[length]) cpl_table_unselect_row(table, length); } return table->selectcount; } /** * @brief * Select from unselected table rows all rows with an invalid value in * a specified column. * * @param table Pointer to table. * @param name Column name. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column name are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with the specified name is not found in table. *
* @enderror * * For all the unselected table rows, all the rows containing invalid * values at the specified column are selected. See also the function * @c cpl_table_and_selected_invalid(). */ int cpl_table_or_selected_invalid(cpl_table *table, const char *name) { const char *fid = "cpl_table_or_selected_invalid"; cpl_column *column; cpl_type type; cpl_column_flag *nulldata = NULL; cpl_array **adata = NULL; char **cdata = NULL; int length; int nullcount; if (table == 0x0 || name == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column = cpl_table_find_column(table, name); if (!column) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type = cpl_column_get_type(column); if (type == CPL_TYPE_STRING) cdata = cpl_column_get_data_string(column); else if (type & CPL_TYPE_POINTER) adata = cpl_column_get_data_array(column); else nulldata = cpl_column_get_data_invalid(column); length = cpl_column_get_size(column); nullcount = cpl_column_count_invalid(column); if (nullcount == 0) return table->selectcount; if (nullcount == length) cpl_table_select_all(table); if (table->selectcount == length) return length; /* * If this point is reached, there are some (not all!) invalid elements. */ if (cdata) { /* String column */ while (length--) if (!cdata[length]) cpl_table_select_row(table, length); } else if (adata) { /* Array column */ while (length--) if (!adata[length]) cpl_table_select_row(table, length); } else { while (length--) if (nulldata[length]) cpl_table_select_row(table, length); } return table->selectcount; } /** * @brief * Select from selected rows only those within a table segment. * * @param table Pointer to table. * @param start First row of table segment. * @param count Length of segment. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
* @enderror * * All the selected table rows that are outside the specified interval are * unselected. If the sum of @em start and @em count goes beyond the end * of the input table, rows are checked up to the end of the table. See * also the function @c cpl_table_or_selected_window(). */ int cpl_table_and_selected_window(cpl_table *table, int start, int count) { const char *fid = "cpl_table_and_selected_window"; int i; if (table == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } if (start < 0 || start >= table->nr) { cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE); return -1; } if (count < 0) { cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); return -1; } if (table->selectcount == 0) /* Nothing was selected, nothing to "and" */ return 0; if (count > table->nr - start) count = table->nr - start; if (count == table->nr) /* "Anding" the whole table, no change */ return table->selectcount; if (table->selectcount == table->nr) { table->select = cpl_calloc(table->nr, sizeof(cpl_column_flag)); i = start; table->selectcount = count; while (count--) { table->select[i] = 1; i++; } } else { i = 0; while (i < start) { if (table->select[i] == 1) { table->select[i] = 0; table->selectcount--; } i++; } i += count; while (i < table->nr) { if (table->select[i] == 1) { table->select[i] = 0; table->selectcount--; } i++; } if (table->selectcount == 0) { if (table->select) cpl_free(table->select); table->select = NULL; } } return table->selectcount; } /** * @brief * Select from unselected rows only those within a table segment. * * @param table Table to handle. * @param start First row of table segment. * @param count Length of segment. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or start is * outside the table boundaries. *
CPL_ERROR_ILLEGAL_INPUT * count is negative. *
* @enderror * * All the unselected table rows that are within the specified interval are * selected. If the sum of @em start and @em count goes beyond the end of * the input table, rows are checked up to the end of the table. See also * the function @c cpl_table_and_selected_window(). */ int cpl_table_or_selected_window(cpl_table *table, int start, int count) { const char *fid = "cpl_table_or_selected_window"; int i = start; if (table == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } if (start < 0 || start >= table->nr) { cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE); return -1; } if (count < 0) { cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); return -1; } if (count > table->nr - start) count = table->nr - start; if (count == table->nr) /* "Oring" the whole table */ cpl_table_select_all(table); if (table->selectcount == table->nr) /* All was selected, no "or" is due */ return table->selectcount; if (table->selectcount == 0) { table->select = cpl_calloc(table->nr, sizeof(cpl_column_flag)); table->selectcount = count; while (count--) { table->select[i] = 1; i++; } } else { while (count--) { if (table->select[i] == 0) { table->select[i] = 1; table->selectcount++; } i++; } if (table->selectcount == table->nr) { if (table->select) cpl_free(table->select); table->select = NULL; } } return table->selectcount; } /** * @brief * Select unselected table rows, and unselect selected ones. * * @param table Pointer to table. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
* @enderror * * Select unselected table rows, and unselect selected ones. */ int cpl_table_not_selected(cpl_table *table) { const char *fid = "cpl_table_not_selected"; int length; if (table == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } if (table->selectcount == 0) return table->selectcount = table->nr; if (table->selectcount == table->nr) return table->selectcount = 0; length = table->nr; while (length--) { if (table->select[length]) table->select[length] = 0; else table->select[length] = 1; } return table->selectcount = table->nr - table->selectcount; } /** * @brief * Select from selected table rows, by comparing the values of two * numerical columns. * * @param table Pointer to table. * @param name1 Name of first table column. * @param operator Relational operator. * @param name2 Name of second table column. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column names are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with any of the specified names is not found in * table. *
CPL_ERROR_INVALID_TYPE * Any of the specified columns is not numerical. *
* @enderror * * Both columns must be numerical. For all the already selected table * rows, the values of the specified columns are compared. The table * rows not fulfilling the comparison are unselected. Invalid elements * from either columns never fulfill any comparison by definition. * Allowed relational operators are @c CPL_EQUAL_TO, @c CPL_NOT_EQUAL_TO, * @c CPL_GREATER_THAN, @c CPL_NOT_GREATER_THAN, @c CPL_LESS_THAN, * @c CPL_NOT_LESS_THAN. See also the function @c cpl_table_or_selected(). */ int cpl_table_and_selected(cpl_table *table, const char *name1, cpl_table_select_operator operator, const char *name2) { const char *fid = "cpl_table_and_selected"; cpl_column *column1; cpl_column *column2; cpl_type type1; cpl_type type2; cpl_column_flag *nulldata1; cpl_column_flag *nulldata2; int *idata1; float *fdata1; double *ddata1; int *idata2; float *fdata2; double *ddata2; int nullcount1; int nullcount2; int length; if (table == 0x0 || name1 == 0x0 || name2 == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column1 = cpl_table_find_column(table, name1); column2 = cpl_table_find_column(table, name2); if (!(column1 && column2)) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type1 = cpl_column_get_type(column1); type2 = cpl_column_get_type(column2); if ((type1 == CPL_TYPE_STRING) || (type2 == CPL_TYPE_STRING) || (type1 & CPL_TYPE_POINTER) || (type2 & CPL_TYPE_POINTER)) { cpl_error_set(fid, CPL_ERROR_INVALID_TYPE); return -1; } nulldata1 = cpl_column_get_data_invalid(column1); nulldata2 = cpl_column_get_data_invalid(column2); nullcount1 = cpl_column_count_invalid(column1); nullcount2 = cpl_column_count_invalid(column2); length = cpl_column_get_size(column1); if (length == 0) return 0; /* * All invalid elements by definition do not fulfill any comparison */ if (nullcount1 == length || nullcount2 == length) cpl_table_unselect_all(table); if (table->selectcount == 0) return 0; if (nulldata1) /* Some (not all!) NULLs */ while (length--) if (nulldata1[length]) cpl_table_unselect_row(table, length); if (table->selectcount == 0) return 0; length = cpl_table_get_nrow(table); /* Restore */ if (nulldata2) /* Some (not all!) NULLs */ while (length--) if (nulldata2[length]) cpl_table_unselect_row(table, length); if (table->selectcount == 0) return 0; /* * Moreover unselect anything that does not fulfill the comparison: */ length = cpl_table_get_nrow(table); /* Restore */ switch (type1) { case CPL_TYPE_INT: idata1 = cpl_column_get_data_int(column1); switch (type2) { case CPL_TYPE_INT: idata2 = cpl_column_get_data_int(column2); switch (operator) { case CPL_EQUAL_TO: while (length--) if (idata1[length] != idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if (idata1[length] == idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if (idata1[length] <= idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if (idata1[length] > idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if (idata1[length] >= idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if (idata1[length] < idata2[length]) cpl_table_unselect_row(table, length); break; } break; case CPL_TYPE_FLOAT: fdata2 = cpl_column_get_data_float(column2); switch (operator) { case CPL_EQUAL_TO: while (length--) if ((float)idata1[length] != fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if ((float)idata1[length] == fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if ((float)idata1[length] <= fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if ((float)idata1[length] > fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if ((float)idata1[length] >= fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if ((float)idata1[length] < fdata2[length]) cpl_table_unselect_row(table, length); break; } break; case CPL_TYPE_DOUBLE: ddata2 = cpl_column_get_data_double(column2); switch (operator) { case CPL_EQUAL_TO: while (length--) if ((double)idata1[length] != ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if ((double)idata1[length] == ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if ((double)idata1[length] <= ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if ((double)idata1[length] > ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if ((double)idata1[length] >= ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if ((double)idata1[length] < ddata2[length]) cpl_table_unselect_row(table, length); break; } default: break; } break; case CPL_TYPE_FLOAT: fdata1 = cpl_column_get_data_float(column1); switch (type2) { case CPL_TYPE_INT: idata2 = cpl_column_get_data_int(column2); switch (operator) { case CPL_EQUAL_TO: while (length--) if (fdata1[length] != (float)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if (fdata1[length] == (float)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if (fdata1[length] <= (float)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if (fdata1[length] > (float)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if (fdata1[length] >= (float)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if (fdata1[length] < (float)idata2[length]) cpl_table_unselect_row(table, length); break; } break; case CPL_TYPE_FLOAT: fdata2 = cpl_column_get_data_float(column2); switch (operator) { case CPL_EQUAL_TO: while (length--) if (fdata1[length] != fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if (fdata1[length] == fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if (fdata1[length] <= fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if (fdata1[length] > fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if (fdata1[length] >= fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if (fdata1[length] < fdata2[length]) cpl_table_unselect_row(table, length); break; } break; case CPL_TYPE_DOUBLE: ddata2 = cpl_column_get_data_double(column2); switch (operator) { case CPL_EQUAL_TO: while (length--) if ((double)fdata1[length] != ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if ((double)fdata1[length] == ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if ((double)fdata1[length] <= ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if ((double)fdata1[length] > ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if ((double)fdata1[length] >= ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if ((double)fdata1[length] < ddata2[length]) cpl_table_unselect_row(table, length); break; } default: break; } break; case CPL_TYPE_DOUBLE: ddata1 = cpl_column_get_data_double(column1); switch (type2) { case CPL_TYPE_INT: idata2 = cpl_column_get_data_int(column2); switch (operator) { case CPL_EQUAL_TO: while (length--) if (ddata1[length] != (double)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if (ddata1[length] == (double)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if (ddata1[length] <= (double)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if (ddata1[length] > (double)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if (ddata1[length] >= (double)idata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if (ddata1[length] < (double)idata2[length]) cpl_table_unselect_row(table, length); break; } break; case CPL_TYPE_FLOAT: fdata2 = cpl_column_get_data_float(column2); switch (operator) { case CPL_EQUAL_TO: while (length--) if (ddata1[length] != (double)fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if (ddata1[length] == (double)fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if (ddata1[length] <= (double)fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if (ddata1[length] > (double)fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if (ddata1[length] >= (double)fdata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if (ddata1[length] < (double)fdata2[length]) cpl_table_unselect_row(table, length); break; } break; case CPL_TYPE_DOUBLE: ddata2 = cpl_column_get_data_double(column2); switch (operator) { case CPL_EQUAL_TO: while (length--) if (ddata1[length] != ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_EQUAL_TO: while (length--) if (ddata1[length] == ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_GREATER_THAN: while (length--) if (ddata1[length] <= ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_GREATER_THAN: while (length--) if (ddata1[length] > ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_LESS_THAN: while (length--) if (ddata1[length] >= ddata2[length]) cpl_table_unselect_row(table, length); break; case CPL_NOT_LESS_THAN: while (length--) if (ddata1[length] < ddata2[length]) cpl_table_unselect_row(table, length); break; } default: break; } default: break; } return table->selectcount; } /** * @brief * Select from unselected table rows, by comparing the values of two * numerical columns. * * @param table Pointer to table. * @param name1 Name of first table column. * @param operator Relational operator. * @param name2 Name of second table column. * * @return Current number of selected rows, or a negative number in case * of error. * * @error * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or column names are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * A column with any of the specified names is not found in * table. *
CPL_ERROR_INVALID_TYPE * Any of the specified columns is not numerical. *
* @enderror * * Both columns must be numerical. For all the unselected table rows, the * values of the specified columns are compared. The table rows fulfilling * the comparison are selected. Invalid elements from either columns never * fulfill any comparison by definition. Allowed relational operators * are @c CPL_EQUAL_TO, @c CPL_NOT_EQUAL_TO, @c CPL_GREATER_THAN, * @c CPL_NOT_GREATER_THAN, @c CPL_LESS_THAN, @c CPL_NOT_LESS_THAN. * See also the function @c cpl_table_and_selected(). */ int cpl_table_or_selected(cpl_table *table, const char *name1, cpl_table_select_operator operator, const char *name2) { const char *fid = "cpl_table_or_selected"; cpl_column *column1; cpl_column *column2; cpl_type type1; cpl_type type2; cpl_column_flag *nulldata1; cpl_column_flag *nulldata2; int *idata1; float *fdata1; double *ddata1; int *idata2; float *fdata2; double *ddata2; int nullcount1; int nullcount2; int length; if (table == 0x0 || name1 == 0x0 || name2 == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } column1 = cpl_table_find_column(table, name1); column2 = cpl_table_find_column(table, name2); if (!(column1 && column2)) { cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return -1; } type1 = cpl_column_get_type(column1); type2 = cpl_column_get_type(column2); if ((type1 == CPL_TYPE_STRING) || (type2 == CPL_TYPE_STRING) || (type1 & CPL_TYPE_POINTER) || (type2 & CPL_TYPE_POINTER)) { cpl_error_set(fid, CPL_ERROR_INVALID_TYPE); return -1; } nulldata1 = cpl_column_get_data_invalid(column1); nulldata2 = cpl_column_get_data_invalid(column2); nullcount1 = cpl_column_count_invalid(column1); nullcount2 = cpl_column_count_invalid(column2); length = cpl_column_get_size(column1); if (length == 0) return 0; if (table->selectcount == length) /* It's already all selected */ return length; if (nullcount1 == length || nullcount2 == length) return table->selectcount; /* * Select anything that fulfills the comparison, avoiding the NULLs: */ switch (type1) { case CPL_TYPE_INT: idata1 = cpl_column_get_data_int(column1); switch (type2) { case CPL_TYPE_INT: idata2 = cpl_column_get_data_int(column2); switch (operator) { case CPL_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (idata1[length] == idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (idata1[length] == idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (idata1[length] == idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (idata1[length] == idata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (idata1[length] != idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (idata1[length] != idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (idata1[length] != idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (idata1[length] != idata2[length]) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (idata1[length] > idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (idata1[length] > idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (idata1[length] > idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (idata1[length] > idata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (idata1[length] <= idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (idata1[length] <= idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (idata1[length] <= idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (idata1[length] <= idata2[length]) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (idata1[length] < idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (idata1[length] < idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (idata1[length] < idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (idata1[length] < idata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (idata1[length] >= idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (idata1[length] >= idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (idata1[length] >= idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (idata1[length] >= idata2[length]) cpl_table_select_row(table, length); } break; } break; case CPL_TYPE_FLOAT: fdata2 = cpl_column_get_data_float(column2); switch (operator) { case CPL_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((float)idata1[length] == fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((float)idata1[length] == fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((float)idata1[length] == fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((float)idata1[length] == fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((float)idata1[length] != fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((float)idata1[length] != fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((float)idata1[length] != fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((float)idata1[length] != fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((float)idata1[length] > fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((float)idata1[length] > fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((float)idata1[length] > fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((float)idata1[length] > fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((float)idata1[length] <= fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((float)idata1[length] <= fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((float)idata1[length] <= fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((float)idata1[length] <= fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((float)idata1[length] < fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((float)idata1[length] < fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((float)idata1[length] < fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((float)idata1[length] < fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((float)idata1[length] >= fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((float)idata1[length] >= fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((float)idata1[length] >= fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((float)idata1[length] >= fdata2[length]) cpl_table_select_row(table, length); } break; } break; case CPL_TYPE_DOUBLE: ddata2 = cpl_column_get_data_double(column2); switch (operator) { case CPL_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)idata1[length] == ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)idata1[length] == ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)idata1[length] == ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)idata1[length] == ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)idata1[length] != ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)idata1[length] != ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)idata1[length] != ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)idata1[length] != ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)idata1[length] > ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)idata1[length] > ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)idata1[length] > ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)idata1[length] > ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)idata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)idata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)idata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)idata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)idata1[length] < ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)idata1[length] < ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)idata1[length] < ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)idata1[length] < ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)idata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)idata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)idata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)idata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } break; } default: break; } break; case CPL_TYPE_FLOAT: fdata1 = cpl_column_get_data_float(column1); switch (type2) { case CPL_TYPE_INT: idata2 = cpl_column_get_data_int(column2); switch (operator) { case CPL_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] == (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] == (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] == (float)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] == (float)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] != (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] != (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] != (float)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] != (float)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] > (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] > (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] > (float)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] > (float)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] <= (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] <= (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] <= (float)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] <= (float)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] < (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] < (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] < (float)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] < (float)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] >= (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] >= (float)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] >= (float)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] >= (float)idata2[length]) cpl_table_select_row(table, length); } break; } break; case CPL_TYPE_FLOAT: fdata2 = cpl_column_get_data_float(column2); switch (operator) { case CPL_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] == fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] == fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] == fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] == fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] != fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] != fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] != fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] != fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] > fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] > fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] > fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] > fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] <= fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] <= fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] <= fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] <= fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] < fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] < fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] < fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] < fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (fdata1[length] >= fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (fdata1[length] >= fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (fdata1[length] >= fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (fdata1[length] >= fdata2[length]) cpl_table_select_row(table, length); } break; } break; case CPL_TYPE_DOUBLE: ddata2 = cpl_column_get_data_double(column2); switch (operator) { case CPL_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)fdata1[length] == ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)fdata1[length] == ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)fdata1[length] == ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)fdata1[length] == ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)fdata1[length] != ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)fdata1[length] != ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)fdata1[length] != ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)fdata1[length] != ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)fdata1[length] > ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)fdata1[length] > ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)fdata1[length] > ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)fdata1[length] > ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)fdata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)fdata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)fdata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)fdata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)fdata1[length] < ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)fdata1[length] < ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)fdata1[length] < ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)fdata1[length] < ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if ((double)fdata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if ((double)fdata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if ((double)fdata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if ((double)fdata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } break; } default: break; } break; case CPL_TYPE_DOUBLE: ddata1 = cpl_column_get_data_double(column1); switch (type2) { case CPL_TYPE_INT: idata2 = cpl_column_get_data_int(column2); switch (operator) { case CPL_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] == (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] == (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] == (double)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] == (double)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] != (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] != (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] != (double)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] != (double)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] > (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] > (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] > (double)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] > (double)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] <= (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] <= (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] <= (double)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] <= (double)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] < (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] < (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] < (double)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] < (double)idata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] >= (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] >= (double)idata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] >= (double)idata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] >= (double)idata2[length]) cpl_table_select_row(table, length); } break; } break; case CPL_TYPE_FLOAT: fdata2 = cpl_column_get_data_float(column2); switch (operator) { case CPL_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] == (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] == (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] == (double)fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] == (double)fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] != (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] != (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] != (double)fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] != (double)fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] > (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] > (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] > (double)fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] > (double)fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] <= (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] <= (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] <= (double)fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] <= (double)fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] < (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] < (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] < (double)fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] < (double)fdata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] >= (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] >= (double)fdata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] >= (double)fdata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] >= (double)fdata2[length]) cpl_table_select_row(table, length); } break; } break; case CPL_TYPE_DOUBLE: ddata2 = cpl_column_get_data_double(column2); switch (operator) { case CPL_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] == ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] == ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] == ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] == ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_EQUAL_TO: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] != ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] != ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] != ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] != ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] > ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] > ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] > ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] > ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_GREATER_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] <= ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] < ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] < ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] < ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] < ddata2[length]) cpl_table_select_row(table, length); } break; case CPL_NOT_LESS_THAN: if (nulldata1 && nulldata2) { while (length--) if (nulldata1[length] == 0 && nulldata2[length] == 0) if (ddata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata1) { while (length--) if (nulldata1[length] == 0) if (ddata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } else if (nulldata2) { while (length--) if (nulldata2[length] == 0) if (ddata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } else { while (length--) if (ddata1[length] >= ddata2[length]) cpl_table_select_row(table, length); } break; } default: break; } default: break; } return table->selectcount; } /** * @brief * Determine whether a table row is selected or not. * * @param table Pointer to table. * @param row Table row to check. * * @return 1 if row is selected, 0 if it is not selected, -1 in case of error. * * @error * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * The input table has zero length, or row is * outside the table boundaries. *
* @enderror * * Check if a table row is selected. */ int cpl_table_is_selected(const cpl_table *table, int row) { const char *fid = "cpl_table_is_selected"; if (table == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } if (row < 0 || row >= table->nr) { cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE); return -1; } if (table->selectcount == 0) return 0; if (table->selectcount == table->nr) return 1; return table->select[row]; } /** * @brief * Get number of selected rows in given table. * * @param table Pointer to table. * * @return Number of selected rows, or a negative number in case of error. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
* @enderror * * Get number of selected rows in given table. */ int cpl_table_count_selected(const cpl_table *table) { const char *fid = "cpl_table_count_selected"; if (table == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return -1; } return table->selectcount; } /** * @brief * Create a new table from the selected rows of another table. * * @param table Pointer to table. * * @return Pointer to new table, or @c NULL in case of error. * * @error * * * * * *
CPL_ERROR_NULL_INPUT * Input table is a NULL pointer. *
* @enderror * * A new table is created, containing a copy of all the selected * rows of the input table. In the output table all rows are selected. */ cpl_table *cpl_table_extract_selected(const cpl_table *table) { const char *fid = "cpl_table_extract_selected"; cpl_table *new_table; int ivalue; float fvalue; double dvalue; char *svalue; cpl_array *avalue; int from_row; int to_row; int count; int i, j, l, m, n; int isnull; if (table == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return NULL; } if (table->selectcount == table->nr) return cpl_table_duplicate(table); new_table = cpl_table_new(table->selectcount); cpl_table_copy_structure(new_table, table); if (table->selectcount == 0) return new_table; from_row = 0; to_row = 0; count = 0; i = 0; while (i < table->nr) { if (table->select[i]) { if (count == 0) from_row = i; count++; i++; if (i != table->nr) continue; i--; } if (count) { j = 0; while (j < table->nc) { l = 0; m = from_row; n = to_row; switch (cpl_column_get_type(table->columns[j])) { case CPL_TYPE_INT: /* * This is slow, but acceptable for the moment. * It should be replaced by a call to a function * that copies efficiently column segments into * other column segments (including the NULL * flags). */ while (l < count) { ivalue = cpl_column_get_int(table->columns[j], m, &isnull); if (isnull) cpl_column_set_invalid(new_table->columns[j], n); else cpl_column_set_int(new_table->columns[j], n, ivalue); l++; m++; n++; } break; case CPL_TYPE_FLOAT: while (l < count) { fvalue = cpl_column_get_float(table->columns[j], m, &isnull); if (isnull) cpl_column_set_invalid(new_table->columns[j], n); else cpl_column_set_float( new_table->columns[j], n, fvalue); l++; m++; n++; } break; case CPL_TYPE_DOUBLE: while (l < count) { dvalue = cpl_column_get_double(table->columns[j], m, &isnull); if (isnull) cpl_column_set_invalid(new_table->columns[j], n); else cpl_column_set_double( new_table->columns[j], n, dvalue); l++; m++; n++; } break; case CPL_TYPE_STRING: while (l < count) { svalue = (char *)cpl_column_get_string(table->columns[j], m); cpl_column_set_string(new_table->columns[j], n, svalue); l++; m++; n++; } break; case CPL_TYPE_INT | CPL_TYPE_POINTER: case CPL_TYPE_FLOAT | CPL_TYPE_POINTER: case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER: case CPL_TYPE_STRING | CPL_TYPE_POINTER: while (l < count) { avalue = (cpl_array *)cpl_column_get_array(table->columns[j], m); cpl_column_set_array(new_table->columns[j], n, avalue); l++; m++; n++; } break; default: break; } j++; } to_row += count; count = 0; if (to_row == new_table->nr) break; } i++; } return new_table; } /** * @brief * Sort table rows according to columns values. * * @param table Pointer to table. * @param reflist Names of reference columns with corresponding sorting mode. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or reflist are NULL pointers. *
CPL_ERROR_DATA_NOT_FOUND * Any reference column specified in reflist is not found in * table. *
CPL_ERROR_ILLEGAL_INPUT * The size of reflist exceeds the total number of columns * in table, or reflist is empty. *
CPL_ERROR_TYPE_MISMATCH * The input reflist includes properties of type * different from CPL_TYPE_BOOL. *
CPL_ERROR_UNSUPPORTED_MODE * Any reference column specified in reflist is of type * array. *
* @enderror * * The table rows are sorted according to the values of the specified * reference columns. The reference column names are listed in the input * @em reflist, that associates to each reference column a boolean value. * If the associated value is @c FALSE, the table is sorted according * to the ascending values of the specified column, otherwise if the * associated value is @c TRUE, the table is sorted according to the * descending values of that column. The sorting will be performed by * comparing the values of the first reference column; if the compared * values are equal, the values from the next column in the list are * compared, and so on till the end of the reference columns list. * An invalid table element is always treated as if it doesn't fulfill * any comparison, i.e., sorting either by increasing or decreasing * column values would accumulate invalid elements toward the top of * the table. The sorting is made in-place, therefore pointers to * data retrieved with calls to @c cpl_table_get_data_() * remain valid. */ cpl_error_code cpl_table_sort(cpl_table *table, const cpl_propertylist *reflist) { const char *fid = "cpl_table_sort"; int *sort_pattern, *sort_null_pattern; cpl_error_code ec; if (table == NULL || reflist == NULL) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (cpl_propertylist_get_size(reflist) == 0) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); if (table->nr < 2) return CPL_ERROR_NONE; sort_pattern = cpl_malloc(table->nr * sizeof(int)); sort_null_pattern = cpl_malloc(table->nr * sizeof(int)); ec = table_sort(table, reflist, cpl_propertylist_get_size(reflist), sort_pattern, sort_null_pattern); cpl_free(sort_pattern); cpl_free(sort_null_pattern); return ec; } #ifdef OLDTABLE cpl_error_code cpl_table_sort(cpl_table *table, const cpl_propertylist *reflist) { const char *fid = "cpl_table_sort"; cpl_column **columns; cpl_column *sorted_column; cpl_type *types; char **names; int *reverse; long i, j; long ncol; int *sort_pattern; int *p; int reach; int keep; int nullcount; cpl_property *info; int *idata; int *sorted_idata; float *fdata; float *sorted_fdata; double *ddata; double *sorted_ddata; char **sdata; char **sorted_sdata; cpl_array **adata; cpl_array **sorted_adata; cpl_column_flag *ndata; cpl_column_flag *sorted_ndata; if (table == 0x0 || reflist == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); ncol = cpl_propertylist_get_size(reflist); if (ncol <= 0 || ncol > table->nc) return cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); if (table->nr < 2) return CPL_ERROR_NONE; names = cpl_malloc(ncol * sizeof(char *)); reverse = cpl_malloc(ncol * sizeof(int)); for (i = 0; i < ncol; i++) { info = cpl_propertylist_get((cpl_propertylist *)reflist, i); names[i] = (char *)cpl_property_get_name(info); if (cpl_property_get_type(info) == CPL_TYPE_BOOL) reverse[i] = cpl_property_get_bool(info); else return cpl_error_set(fid, CPL_ERROR_TYPE_MISMATCH); } /* * Get pointers to reference columns. */ columns = cpl_malloc(ncol * sizeof(*columns)); for (i = 0; i < ncol; i++) { if (names[i] == 0x0) { cpl_free(columns); cpl_free(names); cpl_free(reverse); return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); } if (!(columns[i] = cpl_table_find_column(table, names[i]))) { cpl_free(columns); cpl_free(names); cpl_free(reverse); return cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); } } /* * Get type of each column. */ types = cpl_malloc(ncol * sizeof(cpl_type)); for (i = 0; i < ncol; i++) { types[i] = cpl_column_get_type(columns[i]); if (types[i] & CPL_TYPE_POINTER) { /* Arrays not yet as reference */ cpl_free(types); cpl_free(columns); cpl_free(names); cpl_free(reverse); return cpl_error_set(fid, CPL_ERROR_UNSUPPORTED_MODE); } } /* * Allocate the arrays for computing the sort pattern (i.e., the * list of arrival positions of array values after sorting). */ sort_pattern = cpl_malloc(table->nr * sizeof(int)); p = cpl_malloc(table->nr * sizeof(int)); for (i = 0; i < table->nr; i++) sort_pattern[i] = p[i] = i; /* * Find sorting pattern examining selected columns. */ j = 0; i = 1; reach = 1; while (i < table->nr) { ndata = cpl_column_get_data_invalid(columns[j]); switch (types[j]) { case CPL_TYPE_INT: idata = cpl_column_get_data_int(columns[j]); if (!reverse || reverse[j] == 0) { while (i < table->nr) { if (ndata) { if (ndata[p[i]]) { if (ndata[p[i-1]]) { /* Two NULLs */ if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } else { /* Not-NULL followed by NULL */ keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } if (j) { j = 0; break; } continue; } else if (ndata[p[i-1]]) { /* NULL flwd by not-NULL */ i++; if (i > reach) reach = i; if (j) { j = 0; break; } continue; } } if (idata[p[i]] > idata[p[i-1]]) { i++; if (i > reach) reach = i; } else if (idata[p[i]] < idata[p[i-1]]) { keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } else { if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } if (j) { j = 0; break; } } } else { while (i < table->nr) { if (ndata) { if (ndata[p[i]]) { if (ndata[p[i-1]]) { /* Two NULLs */ if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } else { /* Not-NULL followed by NULL */ keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } if (j) { j = 0; break; } continue; } else if (ndata[p[i-1]]) { /* NULL flwd by not-NULL */ i++; if (i > reach) reach = i; if (j) { j = 0; break; } continue; } } if (idata[p[i]] < idata[p[i-1]]) { i++; if (i > reach) reach = i; } else if (idata[p[i]] > idata[p[i-1]]) { keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } else { if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } if (j) { j = 0; break; } } } break; case CPL_TYPE_FLOAT: fdata = cpl_column_get_data_float(columns[j]); if (!reverse || reverse[j] == 0) { while (i < table->nr) { if (ndata) { if (ndata[p[i]]) { if (ndata[p[i-1]]) { /* Two NULLs */ if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } else { /* Not-NULL followed by NULL */ keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } if (j) { j = 0; break; } continue; } else if (ndata[p[i-1]]) { /* NULL flwd by not-NULL */ i++; if (i > reach) reach = i; if (j) { j = 0; break; } continue; } } if (fdata[p[i]] > fdata[p[i-1]]) { i++; if (i > reach) reach = i; } else if (fdata[p[i]] < fdata[p[i-1]]) { keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } else { if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } if (j) { j = 0; break; } } } else { while (i < table->nr) { if (ndata) { if (ndata[p[i]]) { if (ndata[p[i-1]]) { /* Two NULLs */ if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } else { /* Not-NULL followed by NULL */ keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } if (j) { j = 0; break; } continue; } else if (ndata[p[i-1]]) { /* NULL flwd by not-NULL */ i++; if (i > reach) reach = i; if (j) { j = 0; break; } continue; } } if (fdata[p[i]] < fdata[p[i-1]]) { i++; if (i > reach) reach = i; } else if (fdata[p[i]] > fdata[p[i-1]]) { keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } else { if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } if (j) { j = 0; break; } } } break; case CPL_TYPE_DOUBLE: ddata = cpl_column_get_data_double(columns[j]); if (!reverse || reverse[j] == 0) { while (i < table->nr) { if (ndata) { if (ndata[p[i]]) { if (ndata[p[i-1]]) { /* Two NULLs */ if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } else { /* Not-NULL followed by NULL */ keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } if (j) { j = 0; break; } continue; } else if (ndata[p[i-1]]) { /* NULL flwd by not-NULL */ i++; if (i > reach) reach = i; if (j) { j = 0; break; } continue; } } if (ddata[p[i]] > ddata[p[i-1]]) { i++; if (i > reach) reach = i; } else if (ddata[p[i]] < ddata[p[i-1]]) { keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } else { if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } if (j) { j = 0; break; } } } else { while (i < table->nr) { if (ndata) { if (ndata[p[i]]) { if (ndata[p[i-1]]) { /* Two NULLs */ if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } else { /* Not-NULL followed by NULL */ keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } if (j) { j = 0; break; } continue; } else if (ndata[p[i-1]]) { /* NULL flwd by not-NULL */ i++; if (i > reach) reach = i; if (j) { j = 0; break; } continue; } } if (ddata[p[i]] < ddata[p[i-1]]) { i++; if (i > reach) reach = i; } else if (ddata[p[i]] > ddata[p[i-1]]) { keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } else { if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } if (j) { j = 0; break; } } } break; case CPL_TYPE_STRING: sdata = cpl_column_get_data_string(columns[j]); if (!reverse || reverse[j] == 0) { while (i < table->nr) { if (!sdata[p[i]]) { if (!sdata[p[i-1]]) { /* Two NULLs */ if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } else { /* Not-NULL followed by NULL */ keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } if (j) { j = 0; break; } continue; } else if (!sdata[p[i-1]]) { /* NULL flwd by not-NULL */ i++; if (i > reach) reach = i; if (j) { j = 0; break; } continue; } if (strcmp(sdata[p[i]], sdata[p[i-1]]) > 0) { i++; if (i > reach) reach = i; } else if (strcmp(sdata[p[i]], sdata[p[i-1]]) < 0) { keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } else { if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } if (j) { j = 0; break; } } } else { while (i < table->nr) { if (!sdata[p[i]]) { if (!sdata[p[i-1]]) { /* Two NULLs */ if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } else { /* Not-NULL followed by NULL */ keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } if (j) { j = 0; break; } continue; } else if (!sdata[p[i-1]]) { /* NULL flwd by not-NULL */ i++; if (i > reach) reach = i; if (j) { j = 0; break; } continue; } if (strcmp(sdata[p[i]], sdata[p[i-1]]) < 0) { i++; if (i > reach) reach = i; } else if (strcmp(sdata[p[i]], sdata[p[i-1]]) > 0) { keep = p[i-1]; p[i-1] = p[i]; p[i] = keep; if (i > 1) i--; else i = reach + 1; } else { if (ncol == 1) { i++; continue; } j++; if (j == ncol) { j = 0; i++; if (i > reach) reach = i; } break; } if (j) { j = 0; break; } } } break; default: break; /* Should never come to this point */ } } /* * To obtain the sort pattern this is the trick: */ reach = 1; i = 1; while (i < table->nr) { if (p[sort_pattern[i]] > p[sort_pattern[i-1]]) { i++; if (i > reach) reach = i; } else { keep = sort_pattern[i-1]; sort_pattern[i-1] = sort_pattern[i]; sort_pattern[i] = keep; if (i > 1) i--; else i = reach + 1; } } /* * Now apply the sorting pattern to each column in the table: */ j = 0; while (j < table->nc) { switch (cpl_column_get_type(table->columns[j])) { case CPL_TYPE_INT: sorted_column = cpl_column_new_int(table->nr); cpl_column_set_name(sorted_column, cpl_column_get_name(table->columns[j])); nullcount = cpl_column_count_invalid(table->columns[j]); if (nullcount != table->nr) { /* * This is just a trick to make the null column exist, * with the right number of nulls: */ cpl_column_fill_int(sorted_column, 0, table->nr - nullcount, 0); ndata = cpl_column_get_data_invalid(table->columns[j]); if (ndata) { sorted_ndata = cpl_column_get_data_invalid(sorted_column); for (i = 0; i < table->nr; i++) sorted_ndata[sort_pattern[i]] = ndata[i]; } } sorted_idata = cpl_column_get_data_int(sorted_column); idata = cpl_column_get_data_int(table->columns[j]); for (i = 0; i < table->nr; i++) sorted_idata[sort_pattern[i]] = idata[i]; cpl_column_delete(table->columns[j]); table->columns[j] = sorted_column; break; case CPL_TYPE_FLOAT: sorted_column = cpl_column_new_float(table->nr); cpl_column_set_name(sorted_column, cpl_column_get_name(table->columns[j])); nullcount = cpl_column_count_invalid(table->columns[j]); if (nullcount != table->nr) { /* * This is just a trick to make the null column exist, * with the right number of nulls: */ cpl_column_fill_float(sorted_column, 0, table->nr - nullcount, 0.0); ndata = cpl_column_get_data_invalid(table->columns[j]); if (ndata) { sorted_ndata = cpl_column_get_data_invalid(sorted_column); for (i = 0; i < table->nr; i++) sorted_ndata[sort_pattern[i]] = ndata[i]; } } sorted_fdata = cpl_column_get_data_float(sorted_column); fdata = cpl_column_get_data_float(table->columns[j]); for (i = 0; i < table->nr; i++) sorted_fdata[sort_pattern[i]] = fdata[i]; cpl_column_delete(table->columns[j]); table->columns[j] = sorted_column; break; case CPL_TYPE_DOUBLE: sorted_column = cpl_column_new_double(table->nr); cpl_column_set_name(sorted_column, cpl_column_get_name(table->columns[j])); nullcount = cpl_column_count_invalid(table->columns[j]); if (nullcount != table->nr) { /* * This is just a trick to make the null column exist, * with the right number of nulls: */ cpl_column_fill_double(sorted_column, 0, table->nr - nullcount, 0.0); ndata = cpl_column_get_data_invalid(table->columns[j]); if (ndata) { sorted_ndata = cpl_column_get_data_invalid(sorted_column); for (i = 0; i < table->nr; i++) sorted_ndata[sort_pattern[i]] = ndata[i]; } } sorted_ddata = cpl_column_get_data_double(sorted_column); ddata = cpl_column_get_data_double(table->columns[j]); for (i = 0; i < table->nr; i++) sorted_ddata[sort_pattern[i]] = ddata[i]; cpl_column_delete(table->columns[j]); table->columns[j] = sorted_column; break; case CPL_TYPE_STRING: sorted_column = cpl_column_new_string(table->nr); cpl_column_set_name(sorted_column, cpl_column_get_name(table->columns[j])); sorted_sdata = cpl_column_get_data_string(sorted_column); sdata = cpl_column_get_data_string(table->columns[j]); for (i = 0; i < table->nr; i++) sorted_sdata[sort_pattern[i]] = sdata[i]; cpl_column_delete_but_strings(table->columns[j]); table->columns[j] = sorted_column; break; case CPL_TYPE_INT | CPL_TYPE_POINTER: case CPL_TYPE_FLOAT | CPL_TYPE_POINTER: case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER: case CPL_TYPE_STRING | CPL_TYPE_POINTER: sorted_column = cpl_column_new_array(cpl_column_get_type(table->columns[j]), table->nr, cpl_column_get_depth(table->columns[j])); cpl_column_set_name(sorted_column, cpl_column_get_name(table->columns[j])); sorted_adata = cpl_column_get_data_array(sorted_column); adata = cpl_column_get_data_array(table->columns[j]); for (i = 0; i < table->nr; i++) sorted_adata[sort_pattern[i]] = adata[i]; cpl_column_delete_but_arrays(table->columns[j]); table->columns[j] = sorted_column; break; default: break; /* Should never get here */ } j++; } cpl_free(names); cpl_free(reverse); cpl_free(columns); cpl_free(types); cpl_free(p); cpl_free(sort_pattern); return CPL_ERROR_NONE; } #endif static cpl_table *cpl_table_overload_window(const char *filename, int xtnum, int check_nulls, cpl_array *selcol, int firstrow, int nrow) { const char *fid = "cpl_table_load_window"; fitsfile *fptr; cpl_table *table; char **scolumn; int *icolumn; float *fcolumn; double *dcolumn; char colname[FLEN_VALUE]; char colunit[FLEN_VALUE]; char comment[FLEN_COMMENT]; char keyname[FLEN_KEYWORD]; char scolnum[5]; /* Keeping column numbers up to 9999 */ int nullcount; int extension_count; int field_size; int ncol, nrows; int naxis; long *naxes; long lnrow; int i, j, k; int depth; int z; cpl_array *adim; cpl_array **array; cpl_column *acolumn; cpl_column_flag *nulldata; char err_text[FLEN_STATUS]; char **extcol = NULL; int xcol = 0; int extract; int colnum; int status = 0; int hdutype; int typecode; if (filename == 0x0) { cpl_error_set(fid, CPL_ERROR_NULL_INPUT); return NULL; } if (access(filename, F_OK)) { cpl_error_set(fid, CPL_ERROR_FILE_NOT_FOUND); return NULL; } fits_open_diskfile(&fptr, filename, READONLY, &status); fits_get_num_hdus(fptr, &extension_count, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (L1): %s\n", err_text); cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); status = 0; fits_close_file(fptr, &status); return NULL; } if (extension_count < 0) { cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); fits_close_file(fptr, &status); return NULL; } if (extension_count == 0) { cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); fits_close_file(fptr, &status); return NULL; } /* * HDUs in the CFITSIO convention are counted starting from 1 * (the primary array). Therefore we need to adapt the input to * this convention: */ xtnum++; if (xtnum < 2 || xtnum > extension_count) { cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE); fits_close_file(fptr, &status); return NULL; } fits_movabs_hdu(fptr, xtnum, NULL, &status); fits_get_hdu_type(fptr, &hdutype, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (L2): %s\n", err_text); cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); status = 0; fits_close_file(fptr, &status); return NULL; } if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) { cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); fits_close_file(fptr, &status); return NULL; } /* * CPL table initialisation */ fits_get_num_cols(fptr, &ncol, &status); fits_get_num_rows(fptr, &lnrow, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (L3): %s\n", err_text); cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); status = 0; fits_close_file(fptr, &status); return NULL; } if (ncol > 9999) { cx_print("cpl_table_load(): max number of columns: 9999\n"); fits_close_file(fptr, &status); return NULL; } /* FIXME: * Here there is an important issue: in CPL the number of rows is * of type int, but CFITSIO supports long (i.e., in principle larger * tables). It is unlikely that such large table would be loaded * into memory as a whole, so this problem may be just solved by * always loading the tables in chunks... */ nrows = (int) lnrow; if (ncol < 1 || nrows < 0) { fits_close_file(fptr, &status); cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); return NULL; } if (firstrow > nrows) { fits_close_file(fptr, &status); cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE); return NULL; } /* * nrows is the actual number of rows in table, while nrow is the * requested number of rows to extract. */ if (nrows == 0) check_nulls = 0; if (firstrow < 0) { if (nrow < 0) { firstrow = 0; nrow = nrows; } } if (nrow > nrows - firstrow) nrow = nrows - firstrow; table = cpl_table_new(nrow); /* * In case they were given, get the names of the columns to extract. */ if (selcol) { extcol = cpl_array_get_data_string(selcol); if (extcol == NULL) { cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); fits_close_file(fptr, &status); cpl_table_delete(table); return NULL; } xcol = cpl_array_get_size(selcol); /* * Check if all specified columns exist in table */ for (i = 0; i < xcol; i++) { if (extcol[i] == NULL) { cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); fits_close_file(fptr, &status); cpl_table_delete(table); return NULL; } fits_get_colnum(fptr, CASEINSEN, extcol[i], &colnum, &status); if (status) { cpl_table_delete(table); cpl_error_set(fid, CPL_ERROR_DATA_NOT_FOUND); status = 0; fits_close_file(fptr, &status); return NULL; } } } /* * Columns initialisation - k counts the really created columns. */ for (i = 0, k = 0; i < ncol; i++) { long repeat; long width; int anynul; char *nullarray; sprintf(scolnum, "%d", i + 1); fits_get_colname(fptr, CASEINSEN, scolnum, colname, &colnum, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (L4): %s\n", err_text); cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); status = 0; fits_close_file(fptr, &status); return NULL; } if (colnum != i + 1) { /* * This has the sense of an assertion */ fits_close_file(fptr, &status); cx_print("cpl_table_load(): unexpected column number " "(%d instead of %d)\n", colnum, i + 1); return NULL; } if (extcol) { /* * Check if this column should be extracted */ extract = 0; for (j = 0; j < xcol; j++) { if (strcmp(extcol[j], colname) == 0) { extract = 1; break; } } if (extract == 0) continue; } fits_get_eqcoltype(fptr, i + 1, &typecode, &repeat, &width, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (L5): %s\n", err_text); cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); status = 0; fits_close_file(fptr, &status); return NULL; } depth = (int) repeat; if (depth < 1) { cx_print("cpl_table_load(): found dummy column (%d)\n", i); continue; } switch (typecode) { case TSTRING: if (hdutype == ASCII_TBL) { /* * No arrays of strings in ASCII tables (i.e., repeat = 1 * always, it's the width that rules). */ repeat = width; } field_size = width + 1; depth = repeat / width; if (depth > 1) { cpl_table_new_column_array(table, colname, CPL_TYPE_STRING, depth); array = cpl_table_get_data_array(table, colname); nullarray = cpl_malloc(depth * sizeof(char)); for (j = 0; j < nrow; j++) { scolumn = cpl_array_get_data_string(array[j]); for (z = 0; z < depth; z++) scolumn[z] = cpl_malloc(field_size * sizeof(char)); if (check_nulls) { fits_read_colnull(fptr, TSTRING, i + 1, firstrow + j + 1, 1, depth, scolumn, nullarray, &anynul, &status); nullcount = 0; if (anynul) { for (z = 0; z < depth; z++) { if (nullarray[z]) { nullcount++; cpl_free(scolumn[z]); scolumn[z] = NULL; } } } if (nullcount == depth) { cpl_free(array[j]); array[j] = NULL; } } else { fits_read_col(fptr, TSTRING, i + 1, firstrow + j + 1, 1, depth, 0, scolumn, &anynul, &status); } } cpl_free(nullarray); } else { cpl_table_new_column(table, colname, CPL_TYPE_STRING); scolumn = cpl_table_get_data_string(table, colname); for (j = 0; j < nrow; j++) scolumn[j] = cpl_malloc(field_size * sizeof(char)); if (check_nulls) { nullarray = cpl_malloc(nrow * sizeof(char)); fits_read_colnull(fptr, TSTRING, i + 1, firstrow + 1, 1, nrow, scolumn, nullarray, &anynul, &status); if (anynul) { for (j = 0; j < nrow; j++) { if (nullarray[j]) { cpl_free(scolumn[j]); scolumn[j] = NULL; } } } cpl_free(nullarray); } else { fits_read_col(fptr, TSTRING, i + 1, firstrow + 1, 1, nrow, 0, scolumn, &anynul, &status); } } break; case TLOGICAL: case TBYTE: case TSBYTE: case TSHORT: case TUSHORT: case TINT: case TLONG: if (depth > 1) { cpl_table_new_column_array(table, colname, CPL_TYPE_INT, depth); array = cpl_table_get_data_array(table, colname); nullarray = cpl_malloc(depth * sizeof(char)); for (j = 0; j < nrow; j++) { array[j] = cpl_array_new(depth, CPL_TYPE_INT); acolumn = cpl_array_get_column(array[j]); icolumn = cpl_column_get_data_int(acolumn); if (check_nulls) { fits_read_colnull(fptr, TINT, i + 1, firstrow + j + 1, 1, depth, icolumn, nullarray, &anynul, &status); nullcount = 0; if (anynul) { for (z = 0; z < depth; z++) if (nullarray[z]) nullcount++; if (nullcount == depth) { cpl_array_delete(array[j]); array[j] = NULL; } else { nulldata = cpl_malloc(depth * sizeof(cpl_column_flag)); for (z = 0; z < depth; z++) nulldata[z] = nullarray[z]; cpl_column_set_data_invalid(acolumn, nulldata, nullcount); } } else { cpl_column_set_data_invalid(acolumn, NULL, 0); } } else { fits_read_col(fptr, TINT, i + 1, firstrow + j + 1, 1, depth, 0, icolumn, &anynul, &status); cpl_column_set_data_invalid(acolumn, NULL, 0); } } cpl_free(nullarray); } else { cpl_table_new_column(table, colname, CPL_TYPE_INT); icolumn = cpl_table_get_data_int(table, colname); if (check_nulls) { nullarray = cpl_malloc(nrow * sizeof(char)); fits_read_colnull(fptr, TINT, i + 1, firstrow + 1, 1, nrow, icolumn, nullarray, &anynul, &status); nullcount = 0; nulldata = NULL; if (anynul) { for (j = 0; j < nrow; j++) if (nullarray[j]) nullcount++; if (nullcount < nrow) { nulldata = cpl_malloc(nrow * sizeof(cpl_column_flag)); for (j = 0; j < nrow; j++) nulldata[j] = nullarray[j]; } } cpl_free(nullarray); cpl_column_set_data_invalid(table->columns[k], nulldata, nullcount); } else { fits_read_col(fptr, TINT, i + 1, firstrow + 1, 1, nrow, 0, icolumn, &anynul, &status); cpl_column_set_data_invalid(table->columns[k], NULL, 0); } } break; case TFLOAT: if (depth > 1) { cpl_table_new_column_array(table, colname, CPL_TYPE_FLOAT, depth); array = cpl_table_get_data_array(table, colname); nullarray = cpl_malloc(depth * sizeof(char)); for (j = 0; j < nrow; j++) { array[j] = cpl_array_new(depth, CPL_TYPE_FLOAT); acolumn = cpl_array_get_column(array[j]); fcolumn = cpl_column_get_data_float(acolumn); if (check_nulls) { fits_read_colnull(fptr, TFLOAT, i + 1, firstrow + j + 1, 1, depth, fcolumn, nullarray, &anynul, &status); nullcount = 0; if (anynul) { for (z = 0; z < depth; z++) if (nullarray[z]) nullcount++; if (nullcount == depth) { cpl_array_delete(array[j]); array[j] = NULL; } else { nulldata = cpl_malloc(depth * sizeof(cpl_column_flag)); for (z = 0; z < depth; z++) nulldata[z] = nullarray[z]; cpl_column_set_data_invalid(acolumn, nulldata, nullcount); } } else { cpl_column_set_data_invalid(acolumn, NULL, 0); } } else { fits_read_col(fptr, TFLOAT, i + 1, firstrow + j + 1, 1, depth, 0, fcolumn, &anynul, &status); cpl_column_set_data_invalid(acolumn, NULL, 0); } } cpl_free(nullarray); } else { cpl_table_new_column(table, colname, CPL_TYPE_FLOAT); fcolumn = cpl_table_get_data_float(table, colname); if (check_nulls) { nullarray = cpl_malloc(nrow * sizeof(char)); fits_read_colnull(fptr, TFLOAT, i + 1, firstrow + 1, 1, nrow, fcolumn, nullarray, &anynul, &status); nullcount = 0; nulldata = NULL; if (anynul) { for (j = 0; j < nrow; j++) if (nullarray[j]) nullcount++; if (nullcount < nrow) { nulldata = cpl_malloc(nrow * sizeof(cpl_column_flag)); for (j = 0; j < nrow; j++) nulldata[j] = nullarray[j]; } } cpl_free(nullarray); cpl_column_set_data_invalid(table->columns[k], nulldata, nullcount); } else { fits_read_col(fptr, TFLOAT, i + 1, firstrow + 1, 1, nrow, 0, fcolumn, &anynul, &status); cpl_column_set_data_invalid(table->columns[k], NULL, 0); } } break; case TDOUBLE: if (depth > 1) { cpl_table_new_column_array(table, colname, CPL_TYPE_DOUBLE, depth); array = cpl_table_get_data_array(table, colname); nullarray = cpl_malloc(depth * sizeof(char)); for (j = 0; j < nrow; j++) { array[j] = cpl_array_new(depth, CPL_TYPE_DOUBLE); acolumn = cpl_array_get_column(array[j]); dcolumn = cpl_column_get_data_double(acolumn); if (check_nulls) { fits_read_colnull(fptr, TDOUBLE, i + 1, firstrow + j + 1, 1, depth, dcolumn, nullarray, &anynul, &status); nullcount = 0; if (anynul) { for (z = 0; z < depth; z++) if (nullarray[z]) nullcount++; if (nullcount == depth) { cpl_array_delete(array[j]); array[j] = NULL; } else { nulldata = cpl_malloc(depth * sizeof(cpl_column_flag)); for (z = 0; z < depth; z++) nulldata[z] = nullarray[z]; cpl_column_set_data_invalid(acolumn, nulldata, nullcount); } } else { cpl_column_set_data_invalid(acolumn, NULL, 0); } } else { fits_read_col(fptr, TDOUBLE, i + 1, firstrow + j + 1, 1, depth, 0, dcolumn, &anynul, &status); cpl_column_set_data_invalid(acolumn, NULL, 0); } } cpl_free(nullarray); } else { cpl_table_new_column(table, colname, CPL_TYPE_DOUBLE); dcolumn = cpl_table_get_data_double(table, colname); if (check_nulls) { nullarray = cpl_malloc(nrow * sizeof(char)); fits_read_colnull(fptr, TDOUBLE, i + 1, firstrow + 1, 1, nrow, dcolumn, nullarray, &anynul, &status); nullcount = 0; nulldata = NULL; if (anynul) { for (j = 0; j < nrow; j++) if (nullarray[j]) nullcount++; if (nullcount < nrow) { nulldata = cpl_malloc(nrow * sizeof(cpl_column_flag)); for (j = 0; j < nrow; j++) nulldata[j] = nullarray[j]; } } cpl_free(nullarray); cpl_column_set_data_invalid(table->columns[k], nulldata, nullcount); } else { fits_read_col(fptr, TDOUBLE, i + 1, firstrow + 1, 1, nrow, 0, dcolumn, &anynul, &status); cpl_column_set_data_invalid(table->columns[k], NULL, 0); } } break; default: cx_print("cpl_table_load(): found unsupported type (%s)\n", colname); continue; } if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (L6): %s\n", err_text); cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); status = 0; fits_close_file(fptr, &status); return NULL; } /* * Get the column unit (if present). */ colunit[0] = '\0'; cx_snprintf(keyname, FLEN_KEYWORD, "%s%d", "TUNIT", colnum); if (fits_read_key(fptr, TSTRING, keyname, colunit, comment, &status)) { status = 0; } else { cpl_column_set_unit(table->columns[k], colunit); } if (depth > 1) { /* * Read TDIM keyword. The first call is just to get the * number of dimensions. */ fits_read_tdim(fptr, i + 1, 0, &naxis, NULL, &status); naxes = cpl_malloc(naxis * sizeof(long)); fits_read_tdim(fptr, i + 1, naxis, &naxis, naxes, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (L7): %s\n", err_text); cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); status = 0; fits_close_file(fptr, &status); return NULL; } adim = cpl_array_new(naxis, CPL_TYPE_INT); for (j = 0; j < naxis; j++) cpl_array_set_int(adim, j, (int) naxes[j]); cpl_free(naxes); cpl_column_set_dimensions(table->columns[k], adim); cpl_array_delete(adim); } k++; /* A valid column was successfully processed */ } fits_close_file(fptr, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (L8): %s\n", err_text); cpl_error_set(fid, CPL_ERROR_BAD_FILE_FORMAT); return NULL; } return table; } /** * @brief * Load a FITS table extension into a new @em cpl_table. * * @param filename Name of FITS file with at least one table extension. * @param xtnum Number of extension to read, starting from 1. * @param check_nulls If set to 0, identified invalid values are not marked. * * @return New table, or @c NULL in case of failure. * * @error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input filename is a NULL pointer. *
CPL_ERROR_FILE_NOT_FOUND * A file named as specified in filename is not found. *
CPL_ERROR_BAD_FILE_FORMAT * The input file is not in FITS format. *
CPL_ERROR_ILLEGAL_INPUT * The specified FITS file extension is not a table. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * xtnum is greater than the number of FITS extensions * in the FITS file, or is less than 1. *
CPL_ERROR_DATA_NOT_FOUND * The FITS table has no rows or no columns. *
CPL_ERROR_UNSPECIFIED * Generic error condition, that should be reported to the * CPL Team. *
* @enderror * * The selected FITS file table extension is just read and converted into * the @em cpl_table conventions. */ cpl_table *cpl_table_load(const char *filename, int xtnum, int check_nulls) { cpl_table *table = cpl_table_overload_window(filename, xtnum, check_nulls, NULL, -1, -1); /* cpl_ensure(table, cpl_error_get_code(), NULL); */ return table; } /** * @brief * Load part of a FITS table extension into a new @em cpl_table. * * @param filename Name of FITS file with at least one table extension. * @param xtnum Number of extension to read, starting from 1. * @param check_nulls If set to 0, identified invalid values are not marked. * @param selcol Array with the names of the columns to extract. * @param firstrow First table row to extract. * @param nrow Number of rows to extract. * * @return New table, or @c NULL in case of failure. * * @error * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input filename is a NULL pointer. *
CPL_ERROR_FILE_NOT_FOUND * A file named as specified in filename is not found. *
CPL_ERROR_BAD_FILE_FORMAT * The input file is not in FITS format. *
CPL_ERROR_ILLEGAL_INPUT * The specified FITS file extension is not a table. * Or the specified number of rows to extract is less than zero. * Or the array of column names to extract contains empty fields. *
CPL_ERROR_ACCESS_OUT_OF_RANGE * xtnum is greater than the number of FITS extensions * in the FITS file, or is less than 1. * Or firstrow is either less than zero, or greater * than the number of rows in the table. *
CPL_ERROR_DATA_NOT_FOUND * The FITS table has no columns. * Or selcol includes columns that are not found in table. *
CPL_ERROR_UNSPECIFIED * Generic error condition, that should be reported to the * CPL Team. *
* @enderror * * The selected FITS file table extension is just read in the specified * columns and rows intervals, and converted into the @em cpl_table * conventions. If @em selcol is NULL, all columns are selected. */ cpl_table *cpl_table_load_window(const char *filename, int xtnum, int check_nulls, cpl_array *selcol, int firstrow, int nrow) { const char *fid = "cpl_table_load_window"; cpl_table *table; if (firstrow < 0) { cpl_error_set(fid, CPL_ERROR_ACCESS_OUT_OF_RANGE); return NULL; } if (nrow < 0) { cpl_error_set(fid, CPL_ERROR_ILLEGAL_INPUT); return NULL; } table = cpl_table_overload_window(filename, xtnum, check_nulls, selcol, firstrow, nrow); /* cpl_ensure(table, cpl_error_get_code(), NULL); */ return table; } /** * @brief * Save a @em cpl_table to a FITS file. * * @param table Input table. * @param pheader Primary header entries. * @param header Table header entries. * @param filename Name of output FITS file. * @param mode Output mode. * * @return @c CPL_ERROR_NONE on success. * * @error * * * * * * * * * * * * * * * * * * * * * * * * * *
CPL_ERROR_NULL_INPUT * Input table or filename are NULL pointers. *
CPL_ERROR_FILE_NOT_FOUND * While mode is set to CPL_IO_EXTEND, * a file named as specified in filename is not found, *
CPL_ERROR_BAD_FILE_FORMAT * While mode is set to CPL_IO_EXTEND, the * specified file is not in FITS format. *
CPL_ERROR_FILE_NOT_CREATED * The FITS file could not be created. *
CPL_ERROR_FILE_IO * The FITS file could only partially be created. *
CPL_ERROR_UNSPECIFIED * Generic error condition, that should be reported to the * CPL Team. *
* @enderror * * This function can be used to convert a CPL table into a binary FITS * table extension. If the @em mode is set to @c CPL_IO_DEFAULT, a new * FITS file will be created containing an empty primary array, with * just one FITS table extension. An existing (and writable) FITS file * with the same name would be overwritten. If the @em mode flag is set * to @c CPL_IO_EXTEND, a new table extension would be appended to an * existing FITS file. Note that also in this case the file must be * writable (and do not take for granted that a file is writable just * because it was created by the same application, as this depends * from the system @em umask). * Two property lists may be passed to this function, both * optionally. The first property list, @em pheader, is just used if * the @em mode is set to @c CPL_IO_DEFAULT, and it is assumed to * contain entries for the FITS file primary header. In @em pheader any * property name related to the FITS convention, as SIMPLE, BITPIX, * NAXIS, EXTEND, BLOCKED, and END, are ignored: such entries would * be written anyway to the primary header and set to some standard * values. * If a @c NULL @em pheader is passed, the primary array would be created * with just such entries, that are mandatory in any regular FITS file. * The second property list, @em header, is assumed to contain entries * for the FITS table extension header. In this property list any * property name related to the FITS convention, as XTENSION, BITPIX, * NAXIS, PCOUNT, GCOUNT, and END, and to the table structure, as * TFIELDS, TTYPEi, TUNITi, TDISPi, TNULLi, TFORMi, would be ignored: * such entries are always computed internally, to guarantee their * consistency with the actual table structure. A DATE keyword * containing the date of table creation in ISO8601 format is also * added automatically. * * @note * Invalid strings in columns of type @c CPL_TYPE_STRING are * written to FITS as blanks. Invalid values in columns of type * @c CPL_TYPE_FLOAT or @c CPL_TYPE_DOUBLE will be written to * the FITS file as a @c NaN. Invalid values in columns of type * @c CPL_TYPE_INT are the only ones that need a specific code * to be explicitly assigned to them. This can be realised * by calling the function @c cpl_table_fill_invalid_int() * for each table column of type @c CPL_TYPE_INT containing * invalid values, just before saving the table to FITS. The * numerical values identifying invalid integer column elements * are written to the FITS keywords TNULLn (where n is the column * sequence number). Beware that if valid column elements have * the value identical to the chosen null-code, they will also * be considered invalid in the FITS convention. */ cpl_error_code cpl_table_save(const cpl_table *table, const cpl_propertylist *pheader, const cpl_propertylist *header, const char *filename, unsigned mode) { const char *fid = "cpl_table_save"; int depth; int dimensions; cpl_array **arrays; cpl_column *acolumn; cpl_column **column; fitsfile *outfile; int nc = cpl_table_get_ncol(table); int nr = cpl_table_get_nrow(table); int bwidth, field_size; int i, j, z; int *found; int *nb; int count; int fcount = 0; int rsize; int *nval; int *idata; float *fdata; double *ddata; char **sdata; cpl_column_flag *ndata; char *nstring; char *sval; char **tunit; char **ttype; char **tform; char tnull[FLEN_KEYWORD]; char err_text[FLEN_STATUS]; int status = 0; if (table == 0x0 || filename == 0x0) return cpl_error_set(fid, CPL_ERROR_NULL_INPUT); if (mode & CPL_IO_EXTEND) { /* * The file must exist, and must be writable. */ if (access(filename, F_OK)) return cpl_error_set(fid, CPL_ERROR_FILE_NOT_FOUND); if (access(filename, W_OK)) return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); if (fits_open_diskfile(&outfile, filename, READWRITE, &status)) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S1): %s\n", err_text); return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } else { /* * If the file exists, it must be (over)writable. */ if (!access(filename, F_OK)) { if (access(filename, W_OK)) { return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } /* DFS04866 else { fits_open_diskfile(&outfile, filename, READWRITE, &status); if (status == 0) { fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S2): %s\n", err_text); return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } status = 0; } */ } sval = cpl_sprintf("!%s", filename); fits_create_file(&outfile, sval, &status); cpl_free(sval); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S3): %s\n", err_text); return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } if (pheader) { /* * Write property list to primary FITS header */ if (fits_create_img(outfile, SHORT_IMG, 0, NULL, &status)) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S71): %s\n", err_text); return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } if (cpl_fits_add_properties(outfile, pheader, "^(" ERASE_WCS_REGEXP ")$|" CPL_FITS_BADKEYS_PRIM "|" CPL_FITS_COMPRKEYS) != CPL_ERROR_NONE) { fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S4): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } /* * Defining the FITS table and its columns. */ /* * The table width is the sum of all column widths (in bytes). */ nb = cpl_calloc(nc, sizeof(int)); bwidth = 0; column = table->columns; ttype = cpl_calloc(nc, sizeof(char *)); tform = cpl_calloc(nc, sizeof(char *)); tunit = cpl_calloc(nc, sizeof(char *)); for (i = 0; i < nc; i++, column++) { depth = cpl_table_get_column_depth(table, cpl_column_get_name(*column)); /* * Note that strings ttype[i] and tunit[i] do not need to be * deallocated (this is done by cpl_table_delete()), while * tform[i] do. This is because of the string format (see below), * and this is why cpl_strdup() is also used below. */ ttype[i] = (char *) cpl_column_get_name(*column); tunit[i] = (char *) cpl_column_get_unit(*column); if (tunit[i] == NULL) tunit[i] = ""; switch (cpl_column_get_type(*column)) { case CPL_TYPE_INT: tform[i] = cpl_strdup("1J"); nb[i] = 1; break; case CPL_TYPE_FLOAT: tform[i] = cpl_strdup("1E"); nb[i] = 1; break; case CPL_TYPE_DOUBLE: tform[i] = cpl_strdup("1D"); nb[i] = 1; break; case CPL_TYPE_STRING: /* * Determine the longest string in column. */ sdata = cpl_column_get_data_string(*column); field_size = 0; for (j = 0; j < nr; j++) if (sdata[j]) if ((int)strlen(sdata[j]) > field_size) field_size = strlen(sdata[j]); if (field_size == 0) field_size = 1; nb[i] = field_size; /* * "rsize" is the number of digits (log10() + 1), plus letter A, * plus string terminating null (\0). */ rsize = floor(log10(field_size)) + 3; tform[i] = cpl_calloc(rsize, sizeof(char)); sprintf(tform[i], "%dA", field_size); break; case CPL_TYPE_STRING | CPL_TYPE_POINTER: cx_print("cpl_table_save(): unsupported type found (%s)\n", cpl_column_get_name(*column)); break; case CPL_TYPE_INT | CPL_TYPE_POINTER: if (depth > 0) { /* * "rsize" is the number of digits (log10() + 1), * plus letter J, plus string terminating null (\0). */ rsize = floor(log10(depth)) + 3; tform[i] = cpl_calloc(rsize, sizeof(char)); sprintf(tform[i], "%dJ", depth); nb[i] = depth; } else { cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); } break; case CPL_TYPE_FLOAT | CPL_TYPE_POINTER: if (depth > 0) { /* * "rsize" is the number of digits (log10() + 1), * plus letter E, plus string terminating null (\0). */ rsize = floor(log10(depth)) + 3; tform[i] = cpl_calloc(rsize, sizeof(char)); sprintf(tform[i], "%dE", depth); nb[i] = depth; } else { cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); } break; case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER: if (depth > 0) { /* * "rsize" is the number of digits (log10() + 1), * plus letter D, plus string terminating null (\0). */ rsize = floor(log10(depth)) + 3; tform[i] = cpl_calloc(rsize, sizeof(char)); sprintf(tform[i], "%dD", depth); nb[i] = depth; } else { cpl_error_set(fid, CPL_ERROR_ILLEGAL_OUTPUT); } break; default: fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S6): %s\n", err_text); } cpl_free(nb); for (i = 0; i < nc; i++) cpl_free(tform[i]); cpl_free(tform); return cpl_error_set(fid, CPL_ERROR_UNSPECIFIED); } bwidth += nb[i]; } fits_create_tbl(outfile, BINARY_TBL, nr, nc, ttype, tform, tunit, NULL, &status); for (i = 0; i < nc; i++) cpl_free(tform[i]); cpl_free(tform); cpl_free(ttype); cpl_free(tunit); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S7): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S8): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } /* * Special treatment for integer columns (null value). */ nval = cpl_calloc(nc, sizeof(int)); found = cpl_calloc(nc, sizeof(int)); column = table->columns; for (i = 0; i < nc; i++, column++) { depth = cpl_table_get_column_depth(table, cpl_column_get_name(*column)); switch (cpl_column_get_type(*column)) { case CPL_TYPE_INT: /* * Determine the NULL value (if any). The TNULLi keyword * can be used just for integer column types. The following * code is just a check that the caller sets the NULL column * elements to a special value. If this was not done, then * no TNULLi keyword will be generated, and the NULL column * elements may contain garbage. */ if (cpl_column_has_invalid(*column)) { idata = cpl_column_get_data_int(*column); ndata = cpl_column_get_data_invalid(*column); if (ndata == NULL) { for (j = 0; j < nr; j++) { if (found[i]) { if (nval[i] != idata[j]) { found[i] = 0; break; } } else { found[i] = 1; nval[i] = idata[j]; } } } else { for (j = 0; j < nr; j++) { if (ndata[j]) { if (found[i]) { if (nval[i] != idata[j]) { found[i] = 0; break; } } else { found[i] = 1; nval[i] = idata[j]; } } } } } /* * Write the appropriate TNULLi keyword to header if necessary */ if (found[i]) { sprintf(tnull, "TNULL%d", i + 1); fits_write_key(outfile, TINT, tnull, nval + i, NULL, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S9): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S10): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } break; case CPL_TYPE_INT | CPL_TYPE_POINTER: arrays = cpl_column_get_data_array(*column); for (j = 0; j < nr; j++) { if (arrays[j] == NULL) { break; } acolumn = cpl_array_get_column(arrays[j]); if (cpl_column_has_invalid(acolumn) == 1) { idata = cpl_column_get_data_int(acolumn); ndata = cpl_column_get_data_invalid(acolumn); if (ndata == NULL) { for (z = 0; z < depth; z++) { if (found[i]) { if (nval[i] != idata[z]) { found[i] = 0; break; } } else { found[i] = 1; nval[i] = idata[z]; } } } else { for (z = 0; z < depth; z++) { if (ndata[z]) { if (found[i]) { if (nval[i] != idata[z]) { found[i] = 0; break; } } else { found[i] = 1; nval[i] = idata[z]; } } } } } } /* * Write the appropriate TNULLi keyword to header if necessary */ if (found[i]) { sprintf(tnull, "TNULL%d", i + 1); fits_write_key(outfile, TINT, tnull, nval + i, NULL, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S11): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S12): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } /* * The "break" statement is intentionally missing here: * fall through the next cases, where the TDIM keyword * must be handled. */ case CPL_TYPE_FLOAT | CPL_TYPE_POINTER: case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER: dimensions = cpl_column_get_dimensions(*column); if (dimensions > 1) { long *naxes = cpl_malloc(dimensions * sizeof(long)); for (z = 0; z < dimensions; z++) naxes[z] = cpl_column_get_dimension(*column, z); fits_write_tdim(outfile, i + 1, dimensions, naxes, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S13): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S14): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } cpl_free(naxes); } break; default: break; /* Nothing to do for other types... */ } } if (header) { /* * Complete secondary header with property list information */ if (cpl_fits_add_properties(outfile, header, "^(" ERASE_WCS_REGEXP ")$|" CPL_FITS_BADKEYS_EXT "|" CPL_FITS_COMPRKEYS) != CPL_ERROR_NONE) { fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S5): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } /* * Finally prepare the data section. */ column = table->columns; for (i = 0; i < nc; i++, column++) { depth = cpl_table_get_column_depth(table, cpl_column_get_name(*column)); switch (cpl_column_get_type(*column)) { case CPL_TYPE_STRING: sdata = cpl_column_get_data_string(*column); /* * If there are NULL strings, assign a zero-length string * or a call to strcmp() in fits_write_colnull() would segfault. */ nstring = ""; for (j = 0; j < nr; j++) if (sdata[j] == NULL) sdata[j] = nstring; fits_write_colnull(outfile, TSTRING, i + 1, 1, 1, nr, sdata, nstring, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S15): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S16): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } /* * Restore the fake zero-length strings to a NULL pointer. * Note that this is done only if the zero-length string * is the one pointed by nstring: in this way the zero-length * strings that were already present in the table are not * leaked. */ for (j = 0; j < nr; j++) if (sdata[j] == nstring) sdata[j] = NULL; break; case CPL_TYPE_INT: /* * Get the data buffer of the current column. */ idata = cpl_column_get_data_int(*column); if (found[i]) { fits_write_colnull(outfile, TINT, i + 1, 1, 1, nr, idata, nval + i, &status); } else { fits_write_col(outfile, TINT, i + 1, 1, 1, nr, idata, &status); } if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S17): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S18): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } break; case CPL_TYPE_FLOAT: /* * Get the data buffer of the current column. */ fdata = cpl_column_get_data_float(*column); if (cpl_column_has_invalid(*column)) { /* * If some invalid values are present, * get also the array with invalid flags. */ ndata = cpl_column_get_data_invalid(*column); if (ndata) { /* * Preliminarily fill this data section * including also the garbage (i.e., the * invalid values). */ fits_write_col(outfile, TFLOAT, i + 1, 1, 1, nr, fdata, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S19): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S20): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } /* * Finally overwrite the garbage with NaN. * The function fits_write_colnull(), that * would allow to do this operation in a single * step, is not used here because * * 1) it is based on == comparison between * floats, and * 2) it would introduce an API change, * forcing the user to specify a float * value before saving a table column. */ count = 0; for (j = 0; j < nr; j++) { if (ndata[j]) { /* * Invalid flag found. If the first of * a sequence mark its position, and * keep counting. */ if (count == 0) { fcount = j + 1; } count++; } else { /* * Valid element found. If it's closing * a sequence of invalid elements, dump * it to this data section and reset * counter. */ if (count) { fits_write_col_null(outfile, i + 1, fcount, 1, count, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S21): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S22): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } count = 0; } } } if (count) { fits_write_col_null(outfile, i + 1, fcount, 1, count, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S23): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S24): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * All elements are invalid: just pad with NaN * the current data section. */ fits_write_col_null(outfile, i + 1, 1, 1, nr, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S25): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S26): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * No invalid values are present, simply copy * the whole array buffer to this data section. */ fits_write_col(outfile, TFLOAT, i + 1, 1, 1, nr, fdata, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S27): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S28): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } break; case CPL_TYPE_DOUBLE: /* * Get the data buffer of the current column. */ ddata = cpl_column_get_data_double(*column); if (cpl_column_has_invalid(*column)) { /* * If some invalid values are present, * get also the array with invalid flags. */ ndata = cpl_column_get_data_invalid(*column); if (ndata) { /* * Preliminarily fill this data section * including also the garbage (i.e., the * invalid values). */ fits_write_col(outfile, TDOUBLE, i + 1, 1, 1, nr, ddata, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S29): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S30): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } /* * Finally overwrite the garbage with NaN. * The function fits_write_colnull(), that * would allow to do this operation in a single * step, is not used here because * * 1) it is based on == comparison between * floats, and * 2) it would introduce an API change, * forcing the user to specify a float * value before saving a table column. */ count = 0; for (j = 0; j < nr; j++) { if (ndata[j]) { /* * Invalid flag found. If the first of * a sequence mark its position, and * keep counting. */ if (count == 0) { fcount = j + 1; } count++; } else { /* * Valid element found. If it's closing * a sequence of invalid elements, dump * it to this data section and reset * counter. */ if (count) { fits_write_col_null(outfile, i + 1, fcount, 1, count, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S31): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S32): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } count = 0; } } } if (count) { fits_write_col_null(outfile, i + 1, fcount, 1, count, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S33): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S34): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * All elements are invalid: just pad with NaN * the current data section. */ fits_write_col_null(outfile, i + 1, 1, 1, nr, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S35): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S36): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * No invalid values are present, simply copy * the whole array buffer to this data section. */ fits_write_col(outfile, TDOUBLE, i + 1, 1, 1, nr, ddata, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S37): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S38): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } break; case CPL_TYPE_STRING | CPL_TYPE_POINTER: break; case CPL_TYPE_INT | CPL_TYPE_POINTER: if(depth == 0) break; arrays = cpl_column_get_data_array(*column); if (found[i]) { for (j = 0; j < nr; j++) { acolumn = cpl_array_get_column(arrays[j]); fits_write_colnull(outfile, TINT, i + 1, j + 1, 1, depth, cpl_column_get_data_int(acolumn), nval + i, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S39): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S40): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { for (j = 0; j < nr; j++) { acolumn = cpl_array_get_column(arrays[j]); fits_write_col(outfile, TINT, i + 1, j + 1, 1, depth, cpl_column_get_data_int(acolumn), &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S41): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S42): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } break; case CPL_TYPE_FLOAT | CPL_TYPE_POINTER: if (depth == 0) break; arrays = cpl_column_get_data_array(*column); for (j = 0; j < nr; j++) { if (arrays[j]) { /* * Get the data buffer of the current array. */ acolumn = cpl_array_get_column(arrays[j]); fdata = cpl_column_get_data_float(acolumn); if (cpl_column_has_invalid(acolumn)) { /* * If some invalid values are present, * get also the array with invalid flags. */ ndata = cpl_column_get_data_invalid(acolumn); if (ndata) { /* * Preliminarily fill this data section * including also the garbage (i.e., the * invalid values). */ fits_write_col(outfile, TFLOAT, i + 1, j + 1, 1, depth, fdata, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S43): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S44): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } /* * Finally overwrite the garbage with NaN. * The function fits_write_colnull(), that * would allow to do this operation in a single * step, is not used here because * * 1) it is based on == comparison between * floats, and * 2) it would introduce an API change, * forcing the user to specify a float * value before saving a table column. */ count = 0; for (z = 0; z < depth; z++) { if (ndata[j]) { /* * Invalid flag found. If the first of * a sequence mark its position, and * keep counting. */ if (count == 0) { fcount = z + 1; } count++; } else { /* * Valid element found. If it's closing * a sequence of invalid elements, dump * it to this data section and reset * counter. */ if (count) { fits_write_col_null(outfile, i + 1, j + 1, fcount, count, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S45): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S46): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } count = 0; } } } if (count) { fits_write_col_null(outfile, i + 1, j + 1, fcount, count, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S47): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S48): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * All elements are invalid: just pad with NaN * the current data section. */ fits_write_col_null(outfile, i + 1, j + 1, 1, depth, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S49): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S50): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * No invalid values are present, simply copy * the whole array buffer to this data section. */ fits_write_col(outfile, TFLOAT, i + 1, j + 1, 1, depth, fdata, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S51): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S52): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * All elements are invalid: just pad with NaN * the current data section. */ fits_write_col_null(outfile, i + 1, j + 1, 1, depth, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S53): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S54): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } break; case CPL_TYPE_DOUBLE | CPL_TYPE_POINTER: if (depth == 0) break; arrays = cpl_column_get_data_array(*column); for (j = 0; j < nr; j++) { if (arrays[j]) { /* * Get the data buffer of the current array. */ acolumn = cpl_array_get_column(arrays[j]); ddata = cpl_column_get_data_double(acolumn); if (cpl_column_has_invalid(acolumn)) { /* * If some invalid values are present, * get also the array with invalid flags. */ ndata = cpl_column_get_data_invalid(acolumn); if (ndata) { /* * Preliminarily fill this data section * including also the garbage (i.e., the * invalid values). */ fits_write_col(outfile, TDOUBLE, i + 1, j + 1, 1, depth, ddata, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S55): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S56): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } /* * Finally overwrite the garbage with NaN. * The function fits_write_colnull(), that * would allow to do this operation in a single * step, is not used here because * * 1) it is based on == comparison between * floats, and * 2) it would introduce an API change, * forcing the user to specify a float * value before saving a table column. */ count = 0; for (z = 0; z < depth; z++) { if (ndata[j]) { /* * Invalid flag found. If the first of * a sequence mark its position, and * keep counting. */ if (count == 0) { fcount = z + 1; } count++; } else { /* * Valid element found. If it's closing * a sequence of invalid elements, dump * it to this data section and reset * counter. */ if (count) { fits_write_col_null(outfile, i + 1, j + 1, fcount, count, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S57): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S58): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } count = 0; } } } if (count) { fits_write_col_null(outfile, i + 1, j + 1, fcount, count, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S59): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S60): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * All elements are invalid: just pad with NaN * the current data section. */ fits_write_col_null(outfile, i + 1, j + 1, 1, depth, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S61): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S62): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * No invalid values are present, simply copy * the whole array buffer to this data section. */ fits_write_col(outfile, TDOUBLE, i + 1, j + 1, 1, depth, ddata, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S63): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S64): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } else { /* * All elements are invalid: just pad with NaN * the current data section. */ fits_write_col_null(outfile, i + 1, j + 1, 1, depth, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S65): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S66): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } } } break; default: break; /* Should never get here... */ } } cpl_free(nval); cpl_free(found); cpl_free(nb); /* * Write the date of creation to the primary array. * Perhaps it would be better to add the DATE card * to the header before the table HDU is created, even * if that wouldn't be exactly the creation date. * I guess that would generally result in higher * efficiency in creating big files. */ fits_movabs_hdu(outfile, 1, NULL, &status); fits_write_date(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S67): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S68): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } fits_close_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S69): %s\n", err_text); status = 0; fits_delete_file(outfile, &status); if (status) { fits_get_errstatus(status, err_text); cx_print("CFITSIO (S70): %s\n", err_text); } return cpl_error_set(fid, CPL_ERROR_FILE_NOT_CREATED); } return CPL_ERROR_NONE; } /**@}*/