From aae7c2a085ee7f681595efde47fd0d98b8393ba7 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Tue, 23 Feb 2021 16:49:43 -1000 Subject: [PATCH 01/12] Allow GMT_Put_Vector to convert other text items than datetime While we already support a type of GMT_DATETIME, this PR adds support for incoming text strings via GMT_TEXTLON, GMT_TEXTLAT, and GMT_TEXT (Cartesian values). --- doc/rst/source/api.rst | 8 +-- src/gmt_api.c | 119 ++++++++++++++++++++++++++++------------- src/gmt_io.c | 20 +++++-- src/gmt_resources.h | 6 ++- 4 files changed, 108 insertions(+), 45 deletions(-) diff --git a/doc/rst/source/api.rst b/doc/rst/source/api.rst index 3a38a930762..f405870bf2c 100644 --- a/doc/rst/source/api.rst +++ b/doc/rst/source/api.rst @@ -1363,9 +1363,11 @@ For vectors the same principles apply: where ``V`` is the :ref:`GMT_VECTOR ` created by GMT_Create_Data_, ``col`` is the vector column in question, ``type`` is one of the recognized data :ref:`types ` used for this vector, and ``vector`` is -a pointer to this custom vector. In addition, ``type`` may be also **GMT_DATETIME**, in which case -we expect an array of strings with ISO datetime strings and we do the conversion to internal -GMT time and allocate a vector to hold the result in the given ``col``. +a pointer to this custom vector. In addition, ``type`` may be also **GMT_TEXTLON**, **GMT_TEXTLAT**, +or **GMT_DATETIME**, in which case +we expect an array of strings with longitues, latitudes, or ISO datetime strings and we do the conversion to internal +numerical values and allocate a vector to hold the result in the given ``col``. By deault tht vector will be +**GMT_DOUBLE** but you can add in another data type for the conversion if you prefer (e.g., **GMT_LONG**\|\ **GMT_DATETIME**) To extract a custom vector from an output :ref:`GMT_VECTOR ` you can use .. _GMT_Get_Vector: diff --git a/src/gmt_api.c b/src/gmt_api.c index 1afd2571fb5..43ccb6568e3 100644 --- a/src/gmt_api.c +++ b/src/gmt_api.c @@ -252,6 +252,8 @@ static const char *GMT_geometry[] = {"Not Set", "Point", "Line", "Polygon", "Poi static const char *GMT_class[] = {"QUIET", "NOTICE", "ERROR", "WARNING", "TIMING", "INFORMATION", "COMPATIBILITY", "DEBUG"}; static unsigned int GMT_no_pad[4] = {0, 0, 0, 0}; static const char *GMT_family_abbrev[] = {"D", "G", "I", "C", "X", "M", "V", "U", "-"}; +static const char *GMT_type[GMT_N_TYPES] = {"byte", "byte", "integer", "integer", "integer", "integer", + "integer", "integer", "double", "double", "string", "datetime"}; /*! Two different i/o mode: GMT_Put|Get_Data vs GMT_Put|Get_Record */ enum GMT_enum_iomode { @@ -14469,53 +14471,98 @@ int GMT_Change_Layout_ (unsigned int *family, char *code, unsigned int *mode, vo int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigned int type, void *vector) { /* Hooks a users custom vector onto V's column array and sets the type. * It is the user's responsibility to pass correct type for the given vector. - * We also check that the number of rows have been set earlier. */ + * We also check that the number of rows have been set earlier. + * We also allow special text-based arrays for longitude, latitdue, and datetime to be passed + * which may be logically OR'ed with desired array type (e.g., GMT_LONG|GMT_DATETIME. + * Note: We do not check for data loss in the conversion (e..g, GMT_UCHAR|GMT_TEXTLON) */ + unsigned int special_type; + enum GMT_enum_alloc alloc_mode = GMT_ALLOC_EXTERNALLY; struct GMTAPI_CTRL *API = NULL; struct GMT_VECTOR_HIDDEN *VH = NULL; - char **dt = NULL; - double *t_vector = NULL; - uint64_t row, n_bad = 0; API = gmtapi_get_api_ptr (V_API); if (API == NULL) return_error (API, GMT_NOT_A_SESSION); if (V == NULL) return_error (API, GMT_PTR_IS_NULL); if (V->n_rows == 0) return_error (API, GMT_DIM_TOO_SMALL); if (col >= V->n_columns) return_error (API, GMT_DIM_TOO_LARGE); - switch (type) { - case GMT_DOUBLE: V->type[col] = GMT_DOUBLE; V->data[col].f8 = vector; break; - case GMT_FLOAT: V->type[col] = GMT_FLOAT; V->data[col].f4 = vector; break; - case GMT_ULONG: V->type[col] = GMT_ULONG; V->data[col].ui8 = vector; break; - case GMT_LONG: V->type[col] = GMT_LONG; V->data[col].si8 = vector; break; - case GMT_UINT: V->type[col] = GMT_UINT; V->data[col].ui4 = vector; break; - case GMT_INT: V->type[col] = GMT_INT; V->data[col].si4 = vector; break; - case GMT_USHORT: V->type[col] = GMT_USHORT; V->data[col].ui2 = vector; break; - case GMT_SHORT: V->type[col] = GMT_SHORT; V->data[col].si2 = vector; break; - case GMT_UCHAR: V->type[col] = GMT_UCHAR; V->data[col].uc1 = vector; break; - case GMT_CHAR: V->type[col] = GMT_CHAR; V->data[col].sc1 = vector; break; - case GMT_DATETIME: /* Must convert from string-time to double */ - if ((dt = gmtapi_get_char_char_ptr (vector)) == NULL) { - GMT_Report (API, GMT_MSG_ERROR, "Datetime string array is NULL\n"); - return GMT_MEMORY_ERROR; - } - if ((t_vector = malloc (V->n_rows * sizeof(double))) == NULL) { - GMT_Report (API, GMT_MSG_ERROR, "Unable to allocate array of %" PRIu64 " doubles for converted datetime strings\n", V->n_rows); - return GMT_MEMORY_ERROR; - } - for (row = 0; row < V->n_rows; row++) { - if (gmt_scanf (API->GMT, dt[row], GMT_IS_ABSTIME, &(t_vector[row])) == GMT_IS_NAN) { - n_bad++; - t_vector[row] = API->GMT->session.d_NaN; - } + special_type = type & (GMT_TEXT | GMT_TEXTLAT | GMT_TEXTLON | GMT_DATETIME); + if (special_type == 0) { /* Just passing in a numerical array directly via read-only pointer */ + switch (type) { + case GMT_DOUBLE: V->type[col] = GMT_DOUBLE; V->data[col].f8 = vector; break; + case GMT_FLOAT: V->type[col] = GMT_FLOAT; V->data[col].f4 = vector; break; + case GMT_ULONG: V->type[col] = GMT_ULONG; V->data[col].ui8 = vector; break; + case GMT_LONG: V->type[col] = GMT_LONG; V->data[col].si8 = vector; break; + case GMT_UINT: V->type[col] = GMT_UINT; V->data[col].ui4 = vector; break; + case GMT_INT: V->type[col] = GMT_INT; V->data[col].si4 = vector; break; + case GMT_USHORT: V->type[col] = GMT_USHORT; V->data[col].ui2 = vector; break; + case GMT_SHORT: V->type[col] = GMT_SHORT; V->data[col].si2 = vector; break; + case GMT_UCHAR: V->type[col] = GMT_UCHAR; V->data[col].uc1 = vector; break; + case GMT_CHAR: V->type[col] = GMT_CHAR; V->data[col].sc1 = vector; break; + default: + return_error (API, GMT_NOT_A_VALID_TYPE); + break; + } + } + else { /* Convert text to something else */ + unsigned L_type; + double value; + uint64_t row, n_bad = 0; + char **dt = NULL; + GMT_putfunction api_put_val = NULL; + + if (GMT_Get_Vector (API, V, col)) { /* Refuse to overwrite existing pointer unless NULL */ + GMT_Report (API, GMT_MSG_ERROR, "Array already exist for column %d\n", col); + return_error (API, GMT_PTR_NOT_NULL); + } + type -= special_type; /* Remove the higher bitflag(s) */ + if (type == 0) type = GMT_DOUBLE; /* Default is double precision if type was not specified */ + if (special_type & GMT_TEXT) special_type -= GMT_TEXT; /* If user used GMT_TEXT */ + if (special_type == GMT_TEXTLAT) L_type = GMT_IS_LAT; /* L_type are internal codes for or known column types */ + else if (special_type == GMT_TEXTLON) L_type = GMT_IS_LON; + else if (special_type == GMT_DATETIME) L_type = GMT_IS_ABSTIME; + else L_type = GMT_IS_FLOAT; + if ((dt = gmtapi_get_char_char_ptr (vector)) == NULL) { + GMT_Report (API, GMT_MSG_ERROR, "Given string array is NULL\n"); + return_error (API, GMT_MEMORY_ERROR); + } + switch (type) { /* Get put function but check for bad type */ + case GMT_DOUBLE: case GMT_FLOAT: case GMT_ULONG: case GMT_LONG: case GMT_UINT: + case GMT_INT: case GMT_USHORT: case GMT_SHORT: case GMT_UCHAR: case GMT_CHAR: + if ((api_put_val = gmtapi_select_put_function (API, type)) == NULL) + return_error (API, GMT_NOT_A_VALID_TYPE); + break; + + default: + return_error (API, GMT_NOT_A_VALID_TYPE); + break; + } + /* Here we know the type is valid */ + if (gmtlib_alloc_univector (API->GMT, &V->data[col], type, V->n_rows) != GMT_NOERROR) { + GMT_Report (API, GMT_MSG_ERROR, "Unable to allocate array of %" PRIu64 " %s-values for converted strings\n", V->n_rows, GMT_type[type]); + return_error (API, GMT_MEMORY_ERROR); + } + /* Do the conversion to double precision */ + for (row = 0; row < V->n_rows; row++) { + if (gmt_scanf (API->GMT, dt[row], L_type, &value) == GMT_IS_NAN) { + n_bad++; /* Check for bad conversions */ + value = API->GMT->session.d_NaN; } - V->type[col] = GMT_DOUBLE; V->data[col].f8 = t_vector; - if (n_bad) GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " datetime strings (ISO datetime format required)\n", n_bad); - break; - default: - return_error (API, GMT_NOT_A_VALID_TYPE); - break; + api_put_val (&(V->data[col]), row, value); /* Place value in vector of selected type */ + } + V->type[col] = type; /* Flag as the new type after conversion */ + if (n_bad) { + if (special_type == GMT_TEXTLON) + GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " longitude strings\n", n_bad); + else if (special_type == GMT_TEXTLAT) + GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " latitude strings\n", n_bad); + else if (special_type == GMT_DATETIME) + GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " datetime strings (ISO datetime format required)\n", n_bad); + } + alloc_mode = GMT_ALLOC_INTERNALLY; } VH = gmt_get_V_hidden (V); - VH->alloc_mode[col] = (type == GMT_DATETIME) ? GMT_ALLOC_INTERNALLY : GMT_ALLOC_EXTERNALLY; + VH->alloc_mode[col] = alloc_mode; + return GMT_NOERROR; } diff --git a/src/gmt_io.c b/src/gmt_io.c index 7fe4ffa508b..7e9d166de48 100644 --- a/src/gmt_io.c +++ b/src/gmt_io.c @@ -925,12 +925,20 @@ GMT_LOCAL unsigned int gmtio_assign_aspatial_cols (struct GMT_CTRL *GMT) { return (n); /* Only numerical columns add to the count */ } +GMT_LOCAL unsigned int gmtio_type_index (unsigned int type) { + if (type == GMT_TEXT) return GMT_N_TYPES-2; + if (type == GMT_DATETIME) return GMT_N_TYPES-1; + return type; +} + /*! Fill a string with the aspatial columns */ void gmt_list_aspatials (struct GMT_CTRL *GMT, char buffer[]) { char item[GMT_LEN64] = {""}; + unsigned int type; sprintf (buffer, "Aspatial columns:"); for (unsigned int k = 0; k < GMT->common.a.n_aspatial; k++) { - sprintf (item, " %s[%s]", GMT->common.a.name[k], GMT_type[GMT->common.a.type[k]]); + type = gmtio_type_index (GMT->common.a.type[k]); + sprintf (item, " %s[%s]", GMT->common.a.name[k], GMT_type[type]); strcat (buffer, item); } } @@ -4320,7 +4328,7 @@ int gmtlib_append_ogr_item (struct GMT_CTRL *GMT, char *name, enum GMT_enum_type //*! . */ void gmtlib_write_ogr_header (FILE *fp, struct GMT_OGR *G) { /* Write out table-level OGR/GMT header metadata */ - unsigned int k, col; + unsigned int k, col, type; char *flavor = "egpw"; fprintf (fp, "# @VGMT1.0 @G"); @@ -4335,8 +4343,12 @@ void gmtlib_write_ogr_header (FILE *fp, struct GMT_OGR *G) { if (G->n_aspatial) { fprintf (fp, "# @N%s", G->name[0]); for (col = 1; col < G->n_aspatial; col++) fprintf (fp, "|%s", G->name[col]); - fprintf (fp, "\n# @T%s", GMT_type[G->type[0]]); - for (col = 1; col < G->n_aspatial; col++) fprintf (fp, "|%s", GMT_type[G->type[col]]); + type = gmtio_type_index (G->type[0]); + fprintf (fp, "\n# @T%s", GMT_type[type]); + for (col = 1; col < G->n_aspatial; col++) { + type = gmtio_type_index (G->type[col]); + fprintf (fp, "|%s", GMT_type[type]); + } fprintf (fp, "\n"); } fprintf (fp, "# FEATURE_DATA\n"); diff --git a/src/gmt_resources.h b/src/gmt_resources.h index 7cc544ffb7d..1eb32be752e 100644 --- a/src/gmt_resources.h +++ b/src/gmt_resources.h @@ -90,9 +90,11 @@ enum GMT_enum_type { GMT_ULONG = 7, /* uint64_t, 8-byte unsigned integer type */ GMT_FLOAT = 8, /* 4-byte data float type */ GMT_DOUBLE = 9, /* 8-byte data float type */ - GMT_TEXT = 10, /* Arbitrarily long text string [OGR/GMT use only] */ - GMT_DATETIME = 11, /* string with date/time info [OGR/GMT use only] */ + GMT_TEXT = 16, /* Arbitrarily long text string [OGR/GMT use only and GMT_Put_Vector only] */ + GMT_DATETIME = 32, /* string with date/time info [OGR/GMT use and GMT_Put_Vector only] */ GMT_N_TYPES = 12, /* The number of supported data types above */ + GMT_TEXTLAT = 64, /* string with latitude info [GMT_Put_Vector use only] */ + GMT_TEXTLON = 128, /* string with longitude info [GMT_Put_VectorT use only] */ GMT_VIA_CHAR = 100, /* int8_t, 1-byte signed integer type */ GMT_VIA_UCHAR = 200, /* uint8_t, 1-byte unsigned integer type */ GMT_VIA_SHORT = 300, /* int16_t, 2-byte signed integer type */ From 2b004b984ab32f863d1486444c3facb614a0a156 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Tue, 23 Feb 2021 16:50:38 -1000 Subject: [PATCH 02/12] Update gmt_enum_dict.h --- src/gmt_enum_dict.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/gmt_enum_dict.h b/src/gmt_enum_dict.h index 26a448ed697..3af30ca7c30 100644 --- a/src/gmt_enum_dict.h +++ b/src/gmt_enum_dict.h @@ -28,7 +28,7 @@ struct GMT_API_DICT { int value; }; -#define GMT_N_API_ENUMS 253 +#define GMT_N_API_ENUMS 255 static struct GMT_API_DICT gmt_api_enums[GMT_N_API_ENUMS] = { {"GMT_ADD_DEFAULT", 6}, @@ -76,7 +76,7 @@ static struct GMT_API_DICT gmt_api_enums[GMT_N_API_ENUMS] = { {"GMT_CPT_TIME", 16}, {"GMT_CUBE_IS_STACK", 64}, {"GMT_DATA_ONLY", 2}, - {"GMT_DATETIME", 11}, + {"GMT_DATETIME", 32}, {"GMT_DOUBLE", 9}, {"GMT_DUPLICATE_ALLOC", 1}, {"GMT_DUPLICATE_DATA", 2}, @@ -234,7 +234,9 @@ static struct GMT_API_DICT gmt_api_enums[GMT_N_API_ENUMS] = { {"GMT_STRICT_CONVERSION", 1024}, {"GMT_SYNOPSIS", 1}, {"GMT_TBL", 0}, - {"GMT_TEXT", 10}, + {"GMT_TEXT", 16}, + {"GMT_TEXTLAT", 64}, + {"GMT_TEXTLON", 128}, {"GMT_TIME_CLOCK", 1}, {"GMT_TIME_ELAPSED", 2}, {"GMT_TIME_NONE", 0}, From f2829cdf90822719315b5257179d7f29cb19ad93 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Tue, 23 Feb 2021 18:19:34 -1000 Subject: [PATCH 03/12] Update api.rst --- doc/rst/source/api.rst | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/doc/rst/source/api.rst b/doc/rst/source/api.rst index f405870bf2c..5f952b2d398 100644 --- a/doc/rst/source/api.rst +++ b/doc/rst/source/api.rst @@ -1360,14 +1360,20 @@ For vectors the same principles apply: int GMT_Put_Vector (void *API, struct GMT_VECTOR *V, unsigned int col, unsigned int type, void *vector); -where ``V`` is the :ref:`GMT_VECTOR ` created by GMT_Create_Data_, ``col`` is the vector -column in question, ``type`` is one of the +where ``V`` is the :ref:`GMT_VECTOR ` created by GMT_Create_Data_, +``col`` is the vector column in question, ``type`` is one of the recognized data :ref:`types ` used for this vector, and ``vector`` is -a pointer to this custom vector. In addition, ``type`` may be also **GMT_TEXTLON**, **GMT_TEXTLAT**, -or **GMT_DATETIME**, in which case -we expect an array of strings with longitues, latitudes, or ISO datetime strings and we do the conversion to internal -numerical values and allocate a vector to hold the result in the given ``col``. By deault tht vector will be -**GMT_DOUBLE** but you can add in another data type for the conversion if you prefer (e.g., **GMT_LONG**\|\ **GMT_DATETIME**) +a pointer to this read-only custom vector. In addition, ``type`` may be also **GMT_TEXT**, +**GMT_TEXTLON**, **GMT_TEXTLAT**, or **GMT_DATETIME**, in which case we expect an +array of strings with numbers, longitudes, latitudes, or ISO datetime strings,\ +respectively, and we do the conversion to internal numerical values and allocate +a vector to hold the result in the given ``col``. By default that vector will be +assigned to type **GMT_DOUBLE** but you can add another primary data type for the +conversion if you prefer (e.g., **GMT_LONG**\|\ **GMT_DATETIME** to get final +internal absolute time in integer seconds). For these four special data types GMT +allocates internal memory to hold the concerted data and ``vector'' is not used +any further. + To extract a custom vector from an output :ref:`GMT_VECTOR ` you can use .. _GMT_Get_Vector: From e449d9427dbd197b4f0ca9f9a9e673784bc63b4a Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Tue, 23 Feb 2021 18:20:56 -1000 Subject: [PATCH 04/12] Update api.rst --- doc/rst/source/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/rst/source/api.rst b/doc/rst/source/api.rst index 5f952b2d398..ab5d063e9f9 100644 --- a/doc/rst/source/api.rst +++ b/doc/rst/source/api.rst @@ -1371,7 +1371,7 @@ a vector to hold the result in the given ``col``. By default that vector will b assigned to type **GMT_DOUBLE** but you can add another primary data type for the conversion if you prefer (e.g., **GMT_LONG**\|\ **GMT_DATETIME** to get final internal absolute time in integer seconds). For these four special data types GMT -allocates internal memory to hold the concerted data and ``vector'' is not used +allocates internal memory to hold the concerted data and ``vector`` is not used any further. To extract a custom vector from an output :ref:`GMT_VECTOR ` you can use From 5c8bd9c1d10fa49d967ff6336340a0d0481e7908 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Tue, 23 Feb 2021 19:50:17 -1000 Subject: [PATCH 05/12] Update api.rst --- doc/rst/source/api.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/rst/source/api.rst b/doc/rst/source/api.rst index ab5d063e9f9..0486b608077 100644 --- a/doc/rst/source/api.rst +++ b/doc/rst/source/api.rst @@ -1361,11 +1361,11 @@ For vectors the same principles apply: unsigned int type, void *vector); where ``V`` is the :ref:`GMT_VECTOR ` created by GMT_Create_Data_, -``col`` is the vector column in question, ``type`` is one of the -recognized data :ref:`types ` used for this vector, and ``vector`` is -a pointer to this read-only custom vector. In addition, ``type`` may be also **GMT_TEXT**, +``col`` is the vector column in question, ``type`` is one of the recognized data +:ref:`types ` used for this vector, and ``vector`` is a pointer to the +user's read-only custom vector. In addition, ``type`` may also be one of **GMT_TEXT**, **GMT_TEXTLON**, **GMT_TEXTLAT**, or **GMT_DATETIME**, in which case we expect an -array of strings with numbers, longitudes, latitudes, or ISO datetime strings,\ +array of strings with numbers, longitudes, latitudes, or ISO datetime strings, respectively, and we do the conversion to internal numerical values and allocate a vector to hold the result in the given ``col``. By default that vector will be assigned to type **GMT_DOUBLE** but you can add another primary data type for the From c285173b23411e33540d9703d3c3febc0463c5b2 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Wed, 24 Feb 2021 05:37:10 -1000 Subject: [PATCH 06/12] Simplify assignments and add comments --- src/gmt_api.c | 139 ++++++++++++++++++++++---------------------------- 1 file changed, 61 insertions(+), 78 deletions(-) diff --git a/src/gmt_api.c b/src/gmt_api.c index 43ccb6568e3..8298d1d6176 100644 --- a/src/gmt_api.c +++ b/src/gmt_api.c @@ -14468,6 +14468,46 @@ int GMT_Change_Layout_ (unsigned int *family, char *code, unsigned int *mode, vo /* Deal with assignments of custom vectors and matrices to GMT containers */ +GMT_LOCAL int gmtapi_insert_vector (struct GMTAPI_CTRL *API, union GMT_UNIVECTOR *V, unsigned int type, void *vector) { + /* Hook a vector to the correct union member given data type */ + switch (type) { + case GMT_DOUBLE: V->f8 = vector; break; + case GMT_FLOAT: V->f4 = vector; break; + case GMT_ULONG: V->ui8 = vector; break; + case GMT_LONG: V->si8 = vector; break; + case GMT_UINT: V->ui4 = vector; break; + case GMT_INT: V->si4 = vector; break; + case GMT_USHORT: V->ui2 = vector; break; + case GMT_SHORT: V->si2 = vector; break; + case GMT_UCHAR: V->uc1 = vector; break; + case GMT_CHAR: V->sc1 = vector; break; + default: + return (GMT_NOT_A_VALID_TYPE); + break; + } + return (GMT_NOERROR); +} + +GMT_LOCAL void * gmtapi_retrieve_vector (void *API, union GMT_UNIVECTOR *V, unsigned int type) { + void *vector = NULL; + switch (type) { + case GMT_DOUBLE: vector = V->f8; break; + case GMT_FLOAT: vector = V->f4; break; + case GMT_ULONG: vector = V->ui8; break; + case GMT_LONG: vector = V->si8; break; + case GMT_UINT: vector = V->ui4; break; + case GMT_INT: vector = V->si4; break; + case GMT_USHORT: vector = V->ui2; break; + case GMT_SHORT: vector = V->si2; break; + case GMT_UCHAR: vector = V->uc1; break; + case GMT_CHAR: vector = V->sc1; break; + default: + return_null (API, GMT_NOT_A_VALID_TYPE); + break; + } + return vector; +} + int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigned int type, void *vector) { /* Hooks a users custom vector onto V's column array and sets the type. * It is the user's responsibility to pass correct type for the given vector. @@ -14476,7 +14516,7 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne * which may be logically OR'ed with desired array type (e.g., GMT_LONG|GMT_DATETIME. * Note: We do not check for data loss in the conversion (e..g, GMT_UCHAR|GMT_TEXTLON) */ unsigned int special_type; - enum GMT_enum_alloc alloc_mode = GMT_ALLOC_EXTERNALLY; + enum GMT_enum_alloc alloc_mode = GMT_ALLOC_EXTERNALLY; /* Default is to pass vectors in read-only */ struct GMTAPI_CTRL *API = NULL; struct GMT_VECTOR_HIDDEN *VH = NULL; @@ -14485,23 +14525,12 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne if (V == NULL) return_error (API, GMT_PTR_IS_NULL); if (V->n_rows == 0) return_error (API, GMT_DIM_TOO_SMALL); if (col >= V->n_columns) return_error (API, GMT_DIM_TOO_LARGE); + special_type = type & (GMT_TEXT | GMT_TEXTLAT | GMT_TEXTLON | GMT_DATETIME); - if (special_type == 0) { /* Just passing in a numerical array directly via read-only pointer */ - switch (type) { - case GMT_DOUBLE: V->type[col] = GMT_DOUBLE; V->data[col].f8 = vector; break; - case GMT_FLOAT: V->type[col] = GMT_FLOAT; V->data[col].f4 = vector; break; - case GMT_ULONG: V->type[col] = GMT_ULONG; V->data[col].ui8 = vector; break; - case GMT_LONG: V->type[col] = GMT_LONG; V->data[col].si8 = vector; break; - case GMT_UINT: V->type[col] = GMT_UINT; V->data[col].ui4 = vector; break; - case GMT_INT: V->type[col] = GMT_INT; V->data[col].si4 = vector; break; - case GMT_USHORT: V->type[col] = GMT_USHORT; V->data[col].ui2 = vector; break; - case GMT_SHORT: V->type[col] = GMT_SHORT; V->data[col].si2 = vector; break; - case GMT_UCHAR: V->type[col] = GMT_UCHAR; V->data[col].uc1 = vector; break; - case GMT_CHAR: V->type[col] = GMT_CHAR; V->data[col].sc1 = vector; break; - default: - return_error (API, GMT_NOT_A_VALID_TYPE); - break; - } + if (special_type == 0) { /* Just passing in a numerical array directly via read-only pointer; hook it up */ + if (gmtapi_insert_vector (API, &(V->data[col]), type, vector)) + return_error (API, GMT_NOT_A_VALID_TYPE); + V->type[col] = type; /* Set column type */ } else { /* Convert text to something else */ unsigned L_type; @@ -14514,10 +14543,10 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne GMT_Report (API, GMT_MSG_ERROR, "Array already exist for column %d\n", col); return_error (API, GMT_PTR_NOT_NULL); } - type -= special_type; /* Remove the higher bitflag(s) */ - if (type == 0) type = GMT_DOUBLE; /* Default is double precision if type was not specified */ - if (special_type & GMT_TEXT) special_type -= GMT_TEXT; /* If user used GMT_TEXT */ - if (special_type == GMT_TEXTLAT) L_type = GMT_IS_LAT; /* L_type are internal codes for or known column types */ + type -= special_type; /* Remove the higher bit flag(s) */ + if (type == 0) type = GMT_DOUBLE; /* Default is double precision if a type was not specified */ + if (special_type & GMT_TEXT) special_type -= GMT_TEXT; /* Just in case user used GMT_TEXT as well */ + if (special_type == GMT_TEXTLAT) L_type = GMT_IS_LAT; /* L_type are internal codes for our known column types */ else if (special_type == GMT_TEXTLON) L_type = GMT_IS_LON; else if (special_type == GMT_DATETIME) L_type = GMT_IS_ABSTIME; else L_type = GMT_IS_FLOAT; @@ -14525,17 +14554,8 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne GMT_Report (API, GMT_MSG_ERROR, "Given string array is NULL\n"); return_error (API, GMT_MEMORY_ERROR); } - switch (type) { /* Get put function but check for bad type */ - case GMT_DOUBLE: case GMT_FLOAT: case GMT_ULONG: case GMT_LONG: case GMT_UINT: - case GMT_INT: case GMT_USHORT: case GMT_SHORT: case GMT_UCHAR: case GMT_CHAR: - if ((api_put_val = gmtapi_select_put_function (API, type)) == NULL) - return_error (API, GMT_NOT_A_VALID_TYPE); - break; - - default: - return_error (API, GMT_NOT_A_VALID_TYPE); - break; - } + if ((api_put_val = gmtapi_select_put_function (API, type)) == NULL) + return_error (API, GMT_NOT_A_VALID_TYPE); /* Here we know the type is valid */ if (gmtlib_alloc_univector (API->GMT, &V->data[col], type, V->n_rows) != GMT_NOERROR) { GMT_Report (API, GMT_MSG_ERROR, "Unable to allocate array of %" PRIu64 " %s-values for converted strings\n", V->n_rows, GMT_type[type]); @@ -14550,7 +14570,7 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne api_put_val (&(V->data[col]), row, value); /* Place value in vector of selected type */ } V->type[col] = type; /* Flag as the new type after conversion */ - if (n_bad) { + if (n_bad) { /* Report on values that could not be converted */ if (special_type == GMT_TEXTLON) GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " longitude strings\n", n_bad); else if (special_type == GMT_TEXTLAT) @@ -14560,6 +14580,7 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne } alloc_mode = GMT_ALLOC_INTERNALLY; } + VH = gmt_get_V_hidden (V); VH->alloc_mode[col] = alloc_mode; @@ -14580,21 +14601,8 @@ void * GMT_Get_Vector (void *API, struct GMT_VECTOR *V, unsigned int col) { if (API == NULL) return_null (API, GMT_NOT_A_SESSION); if (V == NULL) return_null (API, GMT_PTR_IS_NULL); if (col >= V->n_columns) return_null (API, GMT_DIM_TOO_LARGE); - switch (V->type[col]) { - case GMT_DOUBLE: vector = V->data[col].f8; break; - case GMT_FLOAT: vector = V->data[col].f4; break; - case GMT_ULONG: vector = V->data[col].ui8; break; - case GMT_LONG: vector = V->data[col].si8; break; - case GMT_UINT: vector = V->data[col].ui4; break; - case GMT_INT: vector = V->data[col].si4; break; - case GMT_USHORT: vector = V->data[col].ui2; break; - case GMT_SHORT: vector = V->data[col].si2; break; - case GMT_UCHAR: vector = V->data[col].uc1; break; - case GMT_CHAR: vector = V->data[col].sc1; break; - default: - return_null (API, GMT_NOT_A_VALID_TYPE); - break; - } + if ((vector = gmtapi_retrieve_vector (API, &(V->data[col]), V->type[col])) == NULL) + return_null (API, GMT_NOT_A_VALID_TYPE); return vector; } @@ -14613,21 +14621,9 @@ int GMT_Put_Matrix (void *API, struct GMT_MATRIX *M, unsigned int type, int pad, if (API == NULL) return_error (API, GMT_NOT_A_SESSION); if (M == NULL) return_error (API, GMT_PTR_IS_NULL); if (M->n_columns == 0 || M->n_rows == 0) return_error (API, GMT_DIM_TOO_SMALL); - switch (type) { - case GMT_DOUBLE: M->type = GMT_DOUBLE; M->data.f8 = matrix; break; - case GMT_FLOAT: M->type = GMT_FLOAT; M->data.f4 = matrix; break; - case GMT_ULONG: M->type = GMT_ULONG; M->data.ui8 = matrix; break; - case GMT_LONG: M->type = GMT_LONG; M->data.si8 = matrix; break; - case GMT_UINT: M->type = GMT_UINT; M->data.ui4 = matrix; break; - case GMT_INT: M->type = GMT_INT; M->data.si4 = matrix; break; - case GMT_USHORT: M->type = GMT_USHORT; M->data.ui2 = matrix; break; - case GMT_SHORT: M->type = GMT_SHORT; M->data.si2 = matrix; break; - case GMT_UCHAR: M->type = GMT_UCHAR; M->data.uc1 = matrix; break; - case GMT_CHAR: M->type = GMT_CHAR; M->data.sc1 = matrix; break; - default: - return_error (API, GMT_NOT_A_VALID_TYPE); - break; - } + if (gmtapi_insert_vector (API, &(M->data), type, matrix)) + return_error (API, GMT_NOT_A_VALID_TYPE); + M->type = type; MH = gmt_get_M_hidden (M); MH->alloc_mode = GMT_ALLOC_EXTERNALLY; /* Since it clearly is a user array */ MH->pad = pad; /* Placing the pad argument here */ @@ -14647,21 +14643,8 @@ void * GMT_Get_Matrix (void *API, struct GMT_MATRIX *M) { void *matrix = NULL; if (API == NULL) return_null (API, GMT_NOT_A_SESSION); if (M == NULL) return_null (API, GMT_PTR_IS_NULL); - switch (M->type) { - case GMT_DOUBLE: matrix = M->data.f8; break; - case GMT_FLOAT: matrix = M->data.f4; break; - case GMT_ULONG: matrix = M->data.ui8; break; - case GMT_LONG: matrix = M->data.si8; break; - case GMT_UINT: matrix = M->data.ui4; break; - case GMT_INT: matrix = M->data.si4; break; - case GMT_USHORT: matrix = M->data.ui2; break; - case GMT_SHORT: matrix = M->data.si2; break; - case GMT_UCHAR: matrix = M->data.uc1; break; - case GMT_CHAR: matrix = M->data.sc1; break; - default: - return_null (API, GMT_NOT_A_VALID_TYPE); - break; - } + if ((matrix = gmtapi_retrieve_vector (API, &(M->data), M->type)) == NULL) + return_null (API, GMT_NOT_A_VALID_TYPE); return matrix; } From ea20f4fbe5d7c81fdd5c4b25cc10b3296db52d2e Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Wed, 24 Feb 2021 05:53:06 -1000 Subject: [PATCH 07/12] Update gmt_api.c --- src/gmt_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmt_api.c b/src/gmt_api.c index 8298d1d6176..a39ebc61732 100644 --- a/src/gmt_api.c +++ b/src/gmt_api.c @@ -14512,7 +14512,7 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne /* Hooks a users custom vector onto V's column array and sets the type. * It is the user's responsibility to pass correct type for the given vector. * We also check that the number of rows have been set earlier. - * We also allow special text-based arrays for longitude, latitdue, and datetime to be passed + * We also allow special text-based arrays for longitude, latitude, datetime or Cartesian data to be passed * which may be logically OR'ed with desired array type (e.g., GMT_LONG|GMT_DATETIME. * Note: We do not check for data loss in the conversion (e..g, GMT_UCHAR|GMT_TEXTLON) */ unsigned int special_type; From bc4f157e9ff92413abf3c55c14f674b48893e973 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Wed, 24 Feb 2021 10:20:35 -1000 Subject: [PATCH 08/12] Add test --- doc/rst/source/api.rst | 13 +++++----- src/gmt_api.c | 52 ++++++++++++++++++++++++++-------------- src/gmt_enum_dict.h | 4 +--- src/gmt_resources.h | 2 -- src/testapi_putvector.c | 34 ++++++++++++++++++++++++++ test/api/apiputvector.sh | 12 ++++++++++ 6 files changed, 87 insertions(+), 30 deletions(-) create mode 100644 src/testapi_putvector.c create mode 100755 test/api/apiputvector.sh diff --git a/doc/rst/source/api.rst b/doc/rst/source/api.rst index 0486b608077..c83519fe14c 100644 --- a/doc/rst/source/api.rst +++ b/doc/rst/source/api.rst @@ -1363,13 +1363,12 @@ For vectors the same principles apply: where ``V`` is the :ref:`GMT_VECTOR ` created by GMT_Create_Data_, ``col`` is the vector column in question, ``type`` is one of the recognized data :ref:`types ` used for this vector, and ``vector`` is a pointer to the -user's read-only custom vector. In addition, ``type`` may also be one of **GMT_TEXT**, -**GMT_TEXTLON**, **GMT_TEXTLAT**, or **GMT_DATETIME**, in which case we expect an -array of strings with numbers, longitudes, latitudes, or ISO datetime strings, -respectively, and we do the conversion to internal numerical values and allocate -a vector to hold the result in the given ``col``. By default that vector will be -assigned to type **GMT_DOUBLE** but you can add another primary data type for the -conversion if you prefer (e.g., **GMT_LONG**\|\ **GMT_DATETIME** to get final +user's read-only custom vector. In addition, ``type`` may also be **GMT_TEXT**, +in which case we expect an array of strings with numbers, longitudes, latitudes, +or ISO datetime strings and we do the conversion to internal numerical values and +allocate a vector to hold the result in the given ``col``. By default that vector +will be assigned to type **GMT_DOUBLE** but you can add another primary data type +for the conversion if you prefer (e.g., **GMT_TEXT**\|\ **GMT_LONG** to get final internal absolute time in integer seconds). For these four special data types GMT allocates internal memory to hold the concerted data and ``vector`` is not used any further. diff --git a/src/gmt_api.c b/src/gmt_api.c index a39ebc61732..c5d59e755be 100644 --- a/src/gmt_api.c +++ b/src/gmt_api.c @@ -6685,10 +6685,10 @@ GMT_LOCAL int gmtapi_write_vector (struct GMT_CTRL *GMT, void *dest, unsigned in if (gmtapi_bin_input_memory (GMT, V->n_columns, V->n_columns) < 0) /* Segment header found, finish the segment we worked on and goto next */ gmt_write_segmentheader (GMT, fp, V->n_columns); else { /* Format an ASCII record for output */ - fprintf (fp, GMT->current.setting.format_float_out, GMT->current.io.curr_rec[0]); + gmt_ascii_output_col (GMT, fp, GMT->current.io.curr_rec[0], 0); for (col = 1; col < V->n_columns; col++) { fprintf (fp, "%s", GMT->current.setting.io_col_separator); - fprintf (fp, GMT->current.setting.format_float_out, GMT->current.io.curr_rec[col]); + gmt_ascii_output_col (GMT, fp, GMT->current.io.curr_rec[col], col); } if (V->text && V->text[row]) fprintf (fp, "%s%s", GMT->current.setting.io_col_separator, V->text[row]); @@ -14470,6 +14470,7 @@ int GMT_Change_Layout_ (unsigned int *family, char *code, unsigned int *mode, vo GMT_LOCAL int gmtapi_insert_vector (struct GMTAPI_CTRL *API, union GMT_UNIVECTOR *V, unsigned int type, void *vector) { /* Hook a vector to the correct union member given data type */ + gmt_M_unused (API); switch (type) { case GMT_DOUBLE: V->f8 = vector; break; case GMT_FLOAT: V->f4 = vector; break; @@ -14490,6 +14491,7 @@ GMT_LOCAL int gmtapi_insert_vector (struct GMTAPI_CTRL *API, union GMT_UNIVECTOR GMT_LOCAL void * gmtapi_retrieve_vector (void *API, union GMT_UNIVECTOR *V, unsigned int type) { void *vector = NULL; + gmt_M_unused (API); switch (type) { case GMT_DOUBLE: vector = V->f8; break; case GMT_FLOAT: vector = V->f4; break; @@ -14502,7 +14504,7 @@ GMT_LOCAL void * gmtapi_retrieve_vector (void *API, union GMT_UNIVECTOR *V, unsi case GMT_UCHAR: vector = V->uc1; break; case GMT_CHAR: vector = V->sc1; break; default: - return_null (API, GMT_NOT_A_VALID_TYPE); + return NULL; break; } return vector; @@ -14513,8 +14515,8 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne * It is the user's responsibility to pass correct type for the given vector. * We also check that the number of rows have been set earlier. * We also allow special text-based arrays for longitude, latitude, datetime or Cartesian data to be passed - * which may be logically OR'ed with desired array type (e.g., GMT_LONG|GMT_DATETIME. - * Note: We do not check for data loss in the conversion (e..g, GMT_UCHAR|GMT_TEXTLON) */ + * which may be logically OR'ed with desired array type (e.g., GMT_LONG|GMT_TEXT. + * Note: We do not check for data loss in the conversion (e..g, GMT_UCHAR|GMT_TEXT) */ unsigned int special_type; enum GMT_enum_alloc alloc_mode = GMT_ALLOC_EXTERNALLY; /* Default is to pass vectors in read-only */ struct GMTAPI_CTRL *API = NULL; @@ -14526,34 +14528,44 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne if (V->n_rows == 0) return_error (API, GMT_DIM_TOO_SMALL); if (col >= V->n_columns) return_error (API, GMT_DIM_TOO_LARGE); - special_type = type & (GMT_TEXT | GMT_TEXTLAT | GMT_TEXTLON | GMT_DATETIME); + special_type = type & (GMT_TEXT | GMT_DATETIME); /* Backwards compatible with just GMT_DATETIME */ if (special_type == 0) { /* Just passing in a numerical array directly via read-only pointer; hook it up */ if (gmtapi_insert_vector (API, &(V->data[col]), type, vector)) return_error (API, GMT_NOT_A_VALID_TYPE); V->type[col] = type; /* Set column type */ } else { /* Convert text to something else */ - unsigned L_type; + bool no_T = false; + unsigned L_type = GMT_IS_UNKNOWN, got; double value; - uint64_t row, n_bad = 0; + uint64_t row, n_bad = 0, L; char **dt = NULL; + char text[GMT_LEN64] = {""}; GMT_putfunction api_put_val = NULL; - if (GMT_Get_Vector (API, V, col)) { /* Refuse to overwrite existing pointer unless NULL */ + if (gmtapi_retrieve_vector (API, &(V->data[col]), type)) { /* Refuse to overwrite existing pointer unless NULL */ GMT_Report (API, GMT_MSG_ERROR, "Array already exist for column %d\n", col); return_error (API, GMT_PTR_NOT_NULL); } type -= special_type; /* Remove the higher bit flag(s) */ if (type == 0) type = GMT_DOUBLE; /* Default is double precision if a type was not specified */ - if (special_type & GMT_TEXT) special_type -= GMT_TEXT; /* Just in case user used GMT_TEXT as well */ - if (special_type == GMT_TEXTLAT) L_type = GMT_IS_LAT; /* L_type are internal codes for our known column types */ - else if (special_type == GMT_TEXTLON) L_type = GMT_IS_LON; - else if (special_type == GMT_DATETIME) L_type = GMT_IS_ABSTIME; - else L_type = GMT_IS_FLOAT; if ((dt = gmtapi_get_char_char_ptr (vector)) == NULL) { GMT_Report (API, GMT_MSG_ERROR, "Given string array is NULL\n"); return_error (API, GMT_MEMORY_ERROR); } + strncpy (text, dt[0], GMT_LEN64); /* Since gmt_scanf may try to temporarily change the string... */ + if ((L = strlen (text)) == 0) { + GMT_Report (API, GMT_MSG_ERROR, "Given blank string in array\n"); + return_error (API, GMT_MEMORY_ERROR); + } + if (special_type == GMT_DATETIME || gmtlib_maybe_abstime (API->GMT, text, &no_T)) /* Honor backwards compatibility for GMT_DATETIME */ + L_type = GMT_IS_ABSTIME; + else if (strchr ("WE", text[L])) + L_type = GMT_IS_LON; + else if (strchr ("SN", text[L])) + L_type = GMT_IS_LAT; + else if (strchr (text, ':')) + L_type = GMT_IS_GEO; if ((api_put_val = gmtapi_select_put_function (API, type)) == NULL) return_error (API, GMT_NOT_A_VALID_TYPE); /* Here we know the type is valid */ @@ -14563,19 +14575,23 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne } /* Do the conversion to double precision */ for (row = 0; row < V->n_rows; row++) { - if (gmt_scanf (API->GMT, dt[row], L_type, &value) == GMT_IS_NAN) { + strncpy (text, dt[row], GMT_LEN64); + if ((got = gmt_scanf (API->GMT, text, L_type, &value)) == GMT_IS_NAN) { n_bad++; /* Check for bad conversions */ value = API->GMT->session.d_NaN; } + else if (got != GMT_IS_FLOAT && L_type == GMT_IS_UNKNOWN) /* Got something other than plain float, use that from now on */ + L_type = got; api_put_val (&(V->data[col]), row, value); /* Place value in vector of selected type */ } V->type[col] = type; /* Flag as the new type after conversion */ + gmt_set_column_type (API->GMT, GMT_IO, col, L_type); if (n_bad) { /* Report on values that could not be converted */ - if (special_type == GMT_TEXTLON) + if (L_type == GMT_IS_LON) GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " longitude strings\n", n_bad); - else if (special_type == GMT_TEXTLAT) + else if (L_type == GMT_IS_LAT) GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " latitude strings\n", n_bad); - else if (special_type == GMT_DATETIME) + else if (L_type == GMT_IS_ABSTIME) GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " datetime strings (ISO datetime format required)\n", n_bad); } alloc_mode = GMT_ALLOC_INTERNALLY; diff --git a/src/gmt_enum_dict.h b/src/gmt_enum_dict.h index 3af30ca7c30..577572c65c2 100644 --- a/src/gmt_enum_dict.h +++ b/src/gmt_enum_dict.h @@ -28,7 +28,7 @@ struct GMT_API_DICT { int value; }; -#define GMT_N_API_ENUMS 255 +#define GMT_N_API_ENUMS 253 static struct GMT_API_DICT gmt_api_enums[GMT_N_API_ENUMS] = { {"GMT_ADD_DEFAULT", 6}, @@ -235,8 +235,6 @@ static struct GMT_API_DICT gmt_api_enums[GMT_N_API_ENUMS] = { {"GMT_SYNOPSIS", 1}, {"GMT_TBL", 0}, {"GMT_TEXT", 16}, - {"GMT_TEXTLAT", 64}, - {"GMT_TEXTLON", 128}, {"GMT_TIME_CLOCK", 1}, {"GMT_TIME_ELAPSED", 2}, {"GMT_TIME_NONE", 0}, diff --git a/src/gmt_resources.h b/src/gmt_resources.h index 1eb32be752e..ef7cf6e0be0 100644 --- a/src/gmt_resources.h +++ b/src/gmt_resources.h @@ -93,8 +93,6 @@ enum GMT_enum_type { GMT_TEXT = 16, /* Arbitrarily long text string [OGR/GMT use only and GMT_Put_Vector only] */ GMT_DATETIME = 32, /* string with date/time info [OGR/GMT use and GMT_Put_Vector only] */ GMT_N_TYPES = 12, /* The number of supported data types above */ - GMT_TEXTLAT = 64, /* string with latitude info [GMT_Put_Vector use only] */ - GMT_TEXTLON = 128, /* string with longitude info [GMT_Put_VectorT use only] */ GMT_VIA_CHAR = 100, /* int8_t, 1-byte signed integer type */ GMT_VIA_UCHAR = 200, /* uint8_t, 1-byte unsigned integer type */ GMT_VIA_SHORT = 300, /* int16_t, 2-byte signed integer type */ diff --git a/src/testapi_putvector.c b/src/testapi_putvector.c new file mode 100644 index 00000000000..f8c81582b2b --- /dev/null +++ b/src/testapi_putvector.c @@ -0,0 +1,34 @@ +#include "gmt.h" +/* + * Testing the use GMT_Put_Vector and its ability to convert ascii stuff. + */ + +/* Dimensions of the test dataset */ +#define NCOLS 4 +#define NROWS 2 + +int main () { + void *API = NULL; /* The API control structure */ + struct GMT_VECTOR *V = NULL; /* Structure to hold input dataset as vectors */ + + uint64_t dim[4] = {NCOLS, NROWS, 1, 0}; /* ncols, nrows, nlayers, type */ + /* two records with cartesian, time, lon, lat data */ + char *S0[NROWS] = {"134.9", "202"}; + char *S1[NROWS] = {"2020-06-01T14:55:33", "2020-06005T16:00:50.75"}; + char *S2[NROWS] = {"12:45:36W", "19:48E"}; + char *S3[NROWS] = {"16:15:00S", "29:30N"}; + + /* Initialize the GMT session */ + API = GMT_Create_Session ("testapi_putvector", 2U, GMT_SESSION_EXTERNAL, NULL); + /* Create a dataset */ + V = GMT_Create_Data (API, GMT_IS_VECTOR, GMT_IS_POINT, GMT_CONTAINER_ONLY, dim, NULL, NULL, 0, 0, NULL); + /* Hook the five converted text vectors up to this container */ + GMT_Put_Vector(API, V, 0, GMT_TEXT|GMT_DOUBLE, S0); + GMT_Put_Vector(API, V, 1, GMT_TEXT|GMT_LONG, S1); + GMT_Put_Vector(API, V, 2, GMT_TEXT|GMT_DOUBLE, S2); + GMT_Put_Vector(API, V, 3, GMT_TEXT|GMT_DOUBLE, S3); + /* Write table to stdout */ + GMT_Write_Data (API, GMT_IS_VECTOR, GMT_IS_FILE, GMT_IS_POINT, GMT_WRITE_SET, NULL, NULL, V); + /* Destroy the GMT session */ + GMT_Destroy_Session (API); +}; diff --git a/test/api/apiputvector.sh b/test/api/apiputvector.sh new file mode 100755 index 00000000000..73e30a6c60e --- /dev/null +++ b/test/api/apiputvector.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# +# Test the GMT_Put_Vector function for mixed textcolumns of +# Cartesian values, datetime, longitude, and latitude strings + +# This file holds what is expected to be produced on output +cat << EOF > answer.txt +134.9 2020-06-01T14:55:33 -12.76 -16.25 +-158 2020-06-01T16:00:51 19.8 29.5 +EOF +testapi_putvector > results.txt +diff -q --strip-trailing-cr results.txt answer.txt > fail From 861e9d05b35712ed4a0e73c33483b71082026ea8 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Wed, 24 Feb 2021 10:39:41 -1000 Subject: [PATCH 09/12] Update gmt_api.c --- src/gmt_api.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gmt_api.c b/src/gmt_api.c index c5d59e755be..a151c12deaf 100644 --- a/src/gmt_api.c +++ b/src/gmt_api.c @@ -14585,6 +14585,7 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne api_put_val (&(V->data[col]), row, value); /* Place value in vector of selected type */ } V->type[col] = type; /* Flag as the new type after conversion */ + if (L_type == GMT_IS_UNKNOWN) L_type = GMT_IS_FLOAT; /* We held out this long but now must default to it */ gmt_set_column_type (API->GMT, GMT_IO, col, L_type); if (n_bad) { /* Report on values that could not be converted */ if (L_type == GMT_IS_LON) From ab85b6f25c86e58a5f68a5ef7612589975e48fb2 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Sat, 27 Feb 2021 22:00:45 -1000 Subject: [PATCH 10/12] Update doc/rst/source/api.rst Co-authored-by: Dongdong Tian --- doc/rst/source/api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/rst/source/api.rst b/doc/rst/source/api.rst index c83519fe14c..a37a9d3fa5d 100644 --- a/doc/rst/source/api.rst +++ b/doc/rst/source/api.rst @@ -1369,8 +1369,8 @@ or ISO datetime strings and we do the conversion to internal numerical values an allocate a vector to hold the result in the given ``col``. By default that vector will be assigned to type **GMT_DOUBLE** but you can add another primary data type for the conversion if you prefer (e.g., **GMT_TEXT**\|\ **GMT_LONG** to get final -internal absolute time in integer seconds). For these four special data types GMT -allocates internal memory to hold the concerted data and ``vector`` is not used +internal absolute time in integer seconds). For the special data type **GMT_TEXT** GMT +allocates internal memory to hold the converted data and ``vector`` is not used any further. To extract a custom vector from an output :ref:`GMT_VECTOR ` you can use From d80ff6cba484c347edfc6bc11a24a4c924b93c82 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Sat, 27 Feb 2021 22:01:04 -1000 Subject: [PATCH 11/12] Update src/gmt_api.c Co-authored-by: Dongdong Tian --- src/gmt_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmt_api.c b/src/gmt_api.c index a151c12deaf..e7194af89ff 100644 --- a/src/gmt_api.c +++ b/src/gmt_api.c @@ -14515,7 +14515,7 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne * It is the user's responsibility to pass correct type for the given vector. * We also check that the number of rows have been set earlier. * We also allow special text-based arrays for longitude, latitude, datetime or Cartesian data to be passed - * which may be logically OR'ed with desired array type (e.g., GMT_LONG|GMT_TEXT. + * which may be logically OR'ed with desired array type (e.g., GMT_LONG|GMT_TEXT). * Note: We do not check for data loss in the conversion (e..g, GMT_UCHAR|GMT_TEXT) */ unsigned int special_type; enum GMT_enum_alloc alloc_mode = GMT_ALLOC_EXTERNALLY; /* Default is to pass vectors in read-only */ From 726ba483deb30e5317f9d0822978772b8cee7630 Mon Sep 17 00:00:00 2001 From: Paul Wessel Date: Sat, 27 Feb 2021 22:01:12 -1000 Subject: [PATCH 12/12] Update src/gmt_api.c Co-authored-by: Dongdong Tian --- src/gmt_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmt_api.c b/src/gmt_api.c index e7194af89ff..93ca3302c10 100644 --- a/src/gmt_api.c +++ b/src/gmt_api.c @@ -14516,7 +14516,7 @@ int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigne * We also check that the number of rows have been set earlier. * We also allow special text-based arrays for longitude, latitude, datetime or Cartesian data to be passed * which may be logically OR'ed with desired array type (e.g., GMT_LONG|GMT_TEXT). - * Note: We do not check for data loss in the conversion (e..g, GMT_UCHAR|GMT_TEXT) */ + * Note: We do not check for data loss in the conversion (e.g., GMT_UCHAR|GMT_TEXT) */ unsigned int special_type; enum GMT_enum_alloc alloc_mode = GMT_ALLOC_EXTERNALLY; /* Default is to pass vectors in read-only */ struct GMTAPI_CTRL *API = NULL;