diff --git a/doc/rst/source/api.rst b/doc/rst/source/api.rst index 3a38a930762..a37a9d3fa5d 100644 --- a/doc/rst/source/api.rst +++ b/doc/rst/source/api.rst @@ -1360,12 +1360,19 @@ 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 -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``. +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 **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 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 .. _GMT_Get_Vector: diff --git a/src/gmt_api.c b/src/gmt_api.c index 1afd2571fb5..93ca3302c10 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 { @@ -6683,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]); @@ -14466,56 +14468,139 @@ 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 */ + gmt_M_unused (API); + 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; + gmt_M_unused (API); + 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; + 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. - * 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, 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) */ + 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; 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; - } - } - 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: + + 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); - break; + V->type[col] = type; /* Set column type */ + } + else { /* Convert text to something else */ + bool no_T = false; + unsigned L_type = GMT_IS_UNKNOWN, got; + double value; + uint64_t row, n_bad = 0, L; + char **dt = NULL; + char text[GMT_LEN64] = {""}; + GMT_putfunction api_put_val = 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 ((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 */ + 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++) { + 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 */ + 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) + GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " longitude strings\n", n_bad); + else if (L_type == GMT_IS_LAT) + GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " latitude strings\n", n_bad); + 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; } + 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; } @@ -14533,21 +14618,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; } @@ -14566,21 +14638,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 */ @@ -14600,21 +14660,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; } diff --git a/src/gmt_enum_dict.h b/src/gmt_enum_dict.h index 26a448ed697..577572c65c2 100644 --- a/src/gmt_enum_dict.h +++ b/src/gmt_enum_dict.h @@ -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,7 @@ 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_TIME_CLOCK", 1}, {"GMT_TIME_ELAPSED", 2}, {"GMT_TIME_NONE", 0}, 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..ef7cf6e0be0 100644 --- a/src/gmt_resources.h +++ b/src/gmt_resources.h @@ -90,8 +90,8 @@ 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_VIA_CHAR = 100, /* int8_t, 1-byte signed integer type */ GMT_VIA_UCHAR = 200, /* uint8_t, 1-byte unsigned 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