@@ -252,6 +252,8 @@ static const char *GMT_geometry[] = {"Not Set", "Point", "Line", "Polygon", "Poi
252252static const char *GMT_class[] = {"QUIET", "NOTICE", "ERROR", "WARNING", "TIMING", "INFORMATION", "COMPATIBILITY", "DEBUG"};
253253static unsigned int GMT_no_pad[4] = {0, 0, 0, 0};
254254static const char *GMT_family_abbrev[] = {"D", "G", "I", "C", "X", "M", "V", "U", "-"};
255+ static const char *GMT_type[GMT_N_TYPES] = {"byte", "byte", "integer", "integer", "integer", "integer",
256+ "integer", "integer", "double", "double", "string", "datetime"};
255257
256258/*! Two different i/o mode: GMT_Put|Get_Data vs GMT_Put|Get_Record */
257259enum GMT_enum_iomode {
@@ -6683,10 +6685,10 @@ GMT_LOCAL int gmtapi_write_vector (struct GMT_CTRL *GMT, void *dest, unsigned in
66836685 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 */
66846686 gmt_write_segmentheader (GMT, fp, V->n_columns);
66856687 else { /* Format an ASCII record for output */
6686- fprintf (fp, GMT->current.setting.format_float_out , GMT->current.io.curr_rec[0]);
6688+ gmt_ascii_output_col (GMT, fp , GMT->current.io.curr_rec[0], 0 );
66876689 for (col = 1; col < V->n_columns; col++) {
66886690 fprintf (fp, "%s", GMT->current.setting.io_col_separator);
6689- fprintf (fp, GMT->current.setting.format_float_out , GMT->current.io.curr_rec[col]);
6691+ gmt_ascii_output_col (GMT, fp , GMT->current.io.curr_rec[col], col );
66906692 }
66916693 if (V->text && V->text[row])
66926694 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
1446614468
1446714469/* Deal with assignments of custom vectors and matrices to GMT containers */
1446814470
14471+ GMT_LOCAL int gmtapi_insert_vector (struct GMTAPI_CTRL *API, union GMT_UNIVECTOR *V, unsigned int type, void *vector) {
14472+ /* Hook a vector to the correct union member given data type */
14473+ gmt_M_unused (API);
14474+ switch (type) {
14475+ case GMT_DOUBLE: V->f8 = vector; break;
14476+ case GMT_FLOAT: V->f4 = vector; break;
14477+ case GMT_ULONG: V->ui8 = vector; break;
14478+ case GMT_LONG: V->si8 = vector; break;
14479+ case GMT_UINT: V->ui4 = vector; break;
14480+ case GMT_INT: V->si4 = vector; break;
14481+ case GMT_USHORT: V->ui2 = vector; break;
14482+ case GMT_SHORT: V->si2 = vector; break;
14483+ case GMT_UCHAR: V->uc1 = vector; break;
14484+ case GMT_CHAR: V->sc1 = vector; break;
14485+ default:
14486+ return (GMT_NOT_A_VALID_TYPE);
14487+ break;
14488+ }
14489+ return (GMT_NOERROR);
14490+ }
14491+
14492+ GMT_LOCAL void * gmtapi_retrieve_vector (void *API, union GMT_UNIVECTOR *V, unsigned int type) {
14493+ void *vector = NULL;
14494+ gmt_M_unused (API);
14495+ switch (type) {
14496+ case GMT_DOUBLE: vector = V->f8; break;
14497+ case GMT_FLOAT: vector = V->f4; break;
14498+ case GMT_ULONG: vector = V->ui8; break;
14499+ case GMT_LONG: vector = V->si8; break;
14500+ case GMT_UINT: vector = V->ui4; break;
14501+ case GMT_INT: vector = V->si4; break;
14502+ case GMT_USHORT: vector = V->ui2; break;
14503+ case GMT_SHORT: vector = V->si2; break;
14504+ case GMT_UCHAR: vector = V->uc1; break;
14505+ case GMT_CHAR: vector = V->sc1; break;
14506+ default:
14507+ return NULL;
14508+ break;
14509+ }
14510+ return vector;
14511+ }
14512+
1446914513int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigned int type, void *vector) {
1447014514 /* Hooks a users custom vector onto V's column array and sets the type.
1447114515 * It is the user's responsibility to pass correct type for the given vector.
14472- * We also check that the number of rows have been set earlier. */
14516+ * We also check that the number of rows have been set earlier.
14517+ * We also allow special text-based arrays for longitude, latitude, datetime or Cartesian data to be passed
14518+ * which may be logically OR'ed with desired array type (e.g., GMT_LONG|GMT_TEXT).
14519+ * Note: We do not check for data loss in the conversion (e.g., GMT_UCHAR|GMT_TEXT) */
14520+ unsigned int special_type;
14521+ enum GMT_enum_alloc alloc_mode = GMT_ALLOC_EXTERNALLY; /* Default is to pass vectors in read-only */
1447314522 struct GMTAPI_CTRL *API = NULL;
1447414523 struct GMT_VECTOR_HIDDEN *VH = NULL;
14475- char **dt = NULL;
14476- double *t_vector = NULL;
14477- uint64_t row, n_bad = 0;
1447814524
1447914525 API = gmtapi_get_api_ptr (V_API);
1448014526 if (API == NULL) return_error (API, GMT_NOT_A_SESSION);
1448114527 if (V == NULL) return_error (API, GMT_PTR_IS_NULL);
1448214528 if (V->n_rows == 0) return_error (API, GMT_DIM_TOO_SMALL);
1448314529 if (col >= V->n_columns) return_error (API, GMT_DIM_TOO_LARGE);
14484- switch (type) {
14485- case GMT_DOUBLE: V->type[col] = GMT_DOUBLE; V->data[col].f8 = vector; break;
14486- case GMT_FLOAT: V->type[col] = GMT_FLOAT; V->data[col].f4 = vector; break;
14487- case GMT_ULONG: V->type[col] = GMT_ULONG; V->data[col].ui8 = vector; break;
14488- case GMT_LONG: V->type[col] = GMT_LONG; V->data[col].si8 = vector; break;
14489- case GMT_UINT: V->type[col] = GMT_UINT; V->data[col].ui4 = vector; break;
14490- case GMT_INT: V->type[col] = GMT_INT; V->data[col].si4 = vector; break;
14491- case GMT_USHORT: V->type[col] = GMT_USHORT; V->data[col].ui2 = vector; break;
14492- case GMT_SHORT: V->type[col] = GMT_SHORT; V->data[col].si2 = vector; break;
14493- case GMT_UCHAR: V->type[col] = GMT_UCHAR; V->data[col].uc1 = vector; break;
14494- case GMT_CHAR: V->type[col] = GMT_CHAR; V->data[col].sc1 = vector; break;
14495- case GMT_DATETIME: /* Must convert from string-time to double */
14496- if ((dt = gmtapi_get_char_char_ptr (vector)) == NULL) {
14497- GMT_Report (API, GMT_MSG_ERROR, "Datetime string array is NULL\n");
14498- return GMT_MEMORY_ERROR;
14499- }
14500- if ((t_vector = malloc (V->n_rows * sizeof(double))) == NULL) {
14501- GMT_Report (API, GMT_MSG_ERROR, "Unable to allocate array of %" PRIu64 " doubles for converted datetime strings\n", V->n_rows);
14502- return GMT_MEMORY_ERROR;
14503- }
14504- for (row = 0; row < V->n_rows; row++) {
14505- if (gmt_scanf (API->GMT, dt[row], GMT_IS_ABSTIME, &(t_vector[row])) == GMT_IS_NAN) {
14506- n_bad++;
14507- t_vector[row] = API->GMT->session.d_NaN;
14508- }
14509- }
14510- V->type[col] = GMT_DOUBLE; V->data[col].f8 = t_vector;
14511- if (n_bad) GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " datetime strings (ISO datetime format required)\n", n_bad);
14512- break;
14513- default:
14530+
14531+ special_type = type & (GMT_TEXT | GMT_DATETIME); /* Backwards compatible with just GMT_DATETIME */
14532+ if (special_type == 0) { /* Just passing in a numerical array directly via read-only pointer; hook it up */
14533+ if (gmtapi_insert_vector (API, &(V->data[col]), type, vector))
1451414534 return_error (API, GMT_NOT_A_VALID_TYPE);
14515- break;
14535+ V->type[col] = type; /* Set column type */
14536+ }
14537+ else { /* Convert text to something else */
14538+ bool no_T = false;
14539+ unsigned L_type = GMT_IS_UNKNOWN, got;
14540+ double value;
14541+ uint64_t row, n_bad = 0, L;
14542+ char **dt = NULL;
14543+ char text[GMT_LEN64] = {""};
14544+ GMT_putfunction api_put_val = NULL;
14545+
14546+ if (gmtapi_retrieve_vector (API, &(V->data[col]), type)) { /* Refuse to overwrite existing pointer unless NULL */
14547+ GMT_Report (API, GMT_MSG_ERROR, "Array already exist for column %d\n", col);
14548+ return_error (API, GMT_PTR_NOT_NULL);
14549+ }
14550+ type -= special_type; /* Remove the higher bit flag(s) */
14551+ if (type == 0) type = GMT_DOUBLE; /* Default is double precision if a type was not specified */
14552+ if ((dt = gmtapi_get_char_char_ptr (vector)) == NULL) {
14553+ GMT_Report (API, GMT_MSG_ERROR, "Given string array is NULL\n");
14554+ return_error (API, GMT_MEMORY_ERROR);
14555+ }
14556+ strncpy (text, dt[0], GMT_LEN64); /* Since gmt_scanf may try to temporarily change the string... */
14557+ if ((L = strlen (text)) == 0) {
14558+ GMT_Report (API, GMT_MSG_ERROR, "Given blank string in array\n");
14559+ return_error (API, GMT_MEMORY_ERROR);
14560+ }
14561+ if (special_type == GMT_DATETIME || gmtlib_maybe_abstime (API->GMT, text, &no_T)) /* Honor backwards compatibility for GMT_DATETIME */
14562+ L_type = GMT_IS_ABSTIME;
14563+ else if (strchr ("WE", text[L]))
14564+ L_type = GMT_IS_LON;
14565+ else if (strchr ("SN", text[L]))
14566+ L_type = GMT_IS_LAT;
14567+ else if (strchr (text, ':'))
14568+ L_type = GMT_IS_GEO;
14569+ if ((api_put_val = gmtapi_select_put_function (API, type)) == NULL)
14570+ return_error (API, GMT_NOT_A_VALID_TYPE);
14571+ /* Here we know the type is valid */
14572+ if (gmtlib_alloc_univector (API->GMT, &V->data[col], type, V->n_rows) != GMT_NOERROR) {
14573+ GMT_Report (API, GMT_MSG_ERROR, "Unable to allocate array of %" PRIu64 " %s-values for converted strings\n", V->n_rows, GMT_type[type]);
14574+ return_error (API, GMT_MEMORY_ERROR);
14575+ }
14576+ /* Do the conversion to double precision */
14577+ for (row = 0; row < V->n_rows; row++) {
14578+ strncpy (text, dt[row], GMT_LEN64);
14579+ if ((got = gmt_scanf (API->GMT, text, L_type, &value)) == GMT_IS_NAN) {
14580+ n_bad++; /* Check for bad conversions */
14581+ value = API->GMT->session.d_NaN;
14582+ }
14583+ else if (got != GMT_IS_FLOAT && L_type == GMT_IS_UNKNOWN) /* Got something other than plain float, use that from now on */
14584+ L_type = got;
14585+ api_put_val (&(V->data[col]), row, value); /* Place value in vector of selected type */
14586+ }
14587+ V->type[col] = type; /* Flag as the new type after conversion */
14588+ if (L_type == GMT_IS_UNKNOWN) L_type = GMT_IS_FLOAT; /* We held out this long but now must default to it */
14589+ gmt_set_column_type (API->GMT, GMT_IO, col, L_type);
14590+ if (n_bad) { /* Report on values that could not be converted */
14591+ if (L_type == GMT_IS_LON)
14592+ GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " longitude strings\n", n_bad);
14593+ else if (L_type == GMT_IS_LAT)
14594+ GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " latitude strings\n", n_bad);
14595+ else if (L_type == GMT_IS_ABSTIME)
14596+ GMT_Report (API, GMT_MSG_WARNING, "Unable to parse %" PRIu64 " datetime strings (ISO datetime format required)\n", n_bad);
14597+ }
14598+ alloc_mode = GMT_ALLOC_INTERNALLY;
1451614599 }
14600+
1451714601 VH = gmt_get_V_hidden (V);
14518- VH->alloc_mode[col] = (type == GMT_DATETIME) ? GMT_ALLOC_INTERNALLY : GMT_ALLOC_EXTERNALLY;
14602+ VH->alloc_mode[col] = alloc_mode;
14603+
1451914604 return GMT_NOERROR;
1452014605}
1452114606
@@ -14533,21 +14618,8 @@ void * GMT_Get_Vector (void *API, struct GMT_VECTOR *V, unsigned int col) {
1453314618 if (API == NULL) return_null (API, GMT_NOT_A_SESSION);
1453414619 if (V == NULL) return_null (API, GMT_PTR_IS_NULL);
1453514620 if (col >= V->n_columns) return_null (API, GMT_DIM_TOO_LARGE);
14536- switch (V->type[col]) {
14537- case GMT_DOUBLE: vector = V->data[col].f8; break;
14538- case GMT_FLOAT: vector = V->data[col].f4; break;
14539- case GMT_ULONG: vector = V->data[col].ui8; break;
14540- case GMT_LONG: vector = V->data[col].si8; break;
14541- case GMT_UINT: vector = V->data[col].ui4; break;
14542- case GMT_INT: vector = V->data[col].si4; break;
14543- case GMT_USHORT: vector = V->data[col].ui2; break;
14544- case GMT_SHORT: vector = V->data[col].si2; break;
14545- case GMT_UCHAR: vector = V->data[col].uc1; break;
14546- case GMT_CHAR: vector = V->data[col].sc1; break;
14547- default:
14548- return_null (API, GMT_NOT_A_VALID_TYPE);
14549- break;
14550- }
14621+ if ((vector = gmtapi_retrieve_vector (API, &(V->data[col]), V->type[col])) == NULL)
14622+ return_null (API, GMT_NOT_A_VALID_TYPE);
1455114623 return vector;
1455214624}
1455314625
@@ -14566,21 +14638,9 @@ int GMT_Put_Matrix (void *API, struct GMT_MATRIX *M, unsigned int type, int pad,
1456614638 if (API == NULL) return_error (API, GMT_NOT_A_SESSION);
1456714639 if (M == NULL) return_error (API, GMT_PTR_IS_NULL);
1456814640 if (M->n_columns == 0 || M->n_rows == 0) return_error (API, GMT_DIM_TOO_SMALL);
14569- switch (type) {
14570- case GMT_DOUBLE: M->type = GMT_DOUBLE; M->data.f8 = matrix; break;
14571- case GMT_FLOAT: M->type = GMT_FLOAT; M->data.f4 = matrix; break;
14572- case GMT_ULONG: M->type = GMT_ULONG; M->data.ui8 = matrix; break;
14573- case GMT_LONG: M->type = GMT_LONG; M->data.si8 = matrix; break;
14574- case GMT_UINT: M->type = GMT_UINT; M->data.ui4 = matrix; break;
14575- case GMT_INT: M->type = GMT_INT; M->data.si4 = matrix; break;
14576- case GMT_USHORT: M->type = GMT_USHORT; M->data.ui2 = matrix; break;
14577- case GMT_SHORT: M->type = GMT_SHORT; M->data.si2 = matrix; break;
14578- case GMT_UCHAR: M->type = GMT_UCHAR; M->data.uc1 = matrix; break;
14579- case GMT_CHAR: M->type = GMT_CHAR; M->data.sc1 = matrix; break;
14580- default:
14581- return_error (API, GMT_NOT_A_VALID_TYPE);
14582- break;
14583- }
14641+ if (gmtapi_insert_vector (API, &(M->data), type, matrix))
14642+ return_error (API, GMT_NOT_A_VALID_TYPE);
14643+ M->type = type;
1458414644 MH = gmt_get_M_hidden (M);
1458514645 MH->alloc_mode = GMT_ALLOC_EXTERNALLY; /* Since it clearly is a user array */
1458614646 MH->pad = pad; /* Placing the pad argument here */
@@ -14600,21 +14660,8 @@ void * GMT_Get_Matrix (void *API, struct GMT_MATRIX *M) {
1460014660 void *matrix = NULL;
1460114661 if (API == NULL) return_null (API, GMT_NOT_A_SESSION);
1460214662 if (M == NULL) return_null (API, GMT_PTR_IS_NULL);
14603- switch (M->type) {
14604- case GMT_DOUBLE: matrix = M->data.f8; break;
14605- case GMT_FLOAT: matrix = M->data.f4; break;
14606- case GMT_ULONG: matrix = M->data.ui8; break;
14607- case GMT_LONG: matrix = M->data.si8; break;
14608- case GMT_UINT: matrix = M->data.ui4; break;
14609- case GMT_INT: matrix = M->data.si4; break;
14610- case GMT_USHORT: matrix = M->data.ui2; break;
14611- case GMT_SHORT: matrix = M->data.si2; break;
14612- case GMT_UCHAR: matrix = M->data.uc1; break;
14613- case GMT_CHAR: matrix = M->data.sc1; break;
14614- default:
14615- return_null (API, GMT_NOT_A_VALID_TYPE);
14616- break;
14617- }
14663+ if ((matrix = gmtapi_retrieve_vector (API, &(M->data), M->type)) == NULL)
14664+ return_null (API, GMT_NOT_A_VALID_TYPE);
1461814665 return matrix;
1461914666}
1462014667
0 commit comments