@@ -252,6 +252,8 @@ static const char *GMT_geometry[] = {"Not Set", "Point", "Line", "Polygon", "Poi
252
252
static const char *GMT_class[] = {"QUIET", "NOTICE", "ERROR", "WARNING", "TIMING", "INFORMATION", "COMPATIBILITY", "DEBUG"};
253
253
static unsigned int GMT_no_pad[4] = {0, 0, 0, 0};
254
254
static 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"};
255
257
256
258
/*! Two different i/o mode: GMT_Put|Get_Data vs GMT_Put|Get_Record */
257
259
enum GMT_enum_iomode {
@@ -6683,10 +6685,10 @@ GMT_LOCAL int gmtapi_write_vector (struct GMT_CTRL *GMT, void *dest, unsigned in
6683
6685
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 */
6684
6686
gmt_write_segmentheader (GMT, fp, V->n_columns);
6685
6687
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 );
6687
6689
for (col = 1; col < V->n_columns; col++) {
6688
6690
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 );
6690
6692
}
6691
6693
if (V->text && V->text[row])
6692
6694
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
14466
14468
14467
14469
/* Deal with assignments of custom vectors and matrices to GMT containers */
14468
14470
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
+
14469
14513
int GMT_Put_Vector (void *V_API, struct GMT_VECTOR *V, unsigned int col, unsigned int type, void *vector) {
14470
14514
/* Hooks a users custom vector onto V's column array and sets the type.
14471
14515
* 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 */
14473
14522
struct GMTAPI_CTRL *API = NULL;
14474
14523
struct GMT_VECTOR_HIDDEN *VH = NULL;
14475
- char **dt = NULL;
14476
- double *t_vector = NULL;
14477
- uint64_t row, n_bad = 0;
14478
14524
14479
14525
API = gmtapi_get_api_ptr (V_API);
14480
14526
if (API == NULL) return_error (API, GMT_NOT_A_SESSION);
14481
14527
if (V == NULL) return_error (API, GMT_PTR_IS_NULL);
14482
14528
if (V->n_rows == 0) return_error (API, GMT_DIM_TOO_SMALL);
14483
14529
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))
14514
14534
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;
14516
14599
}
14600
+
14517
14601
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
+
14519
14604
return GMT_NOERROR;
14520
14605
}
14521
14606
@@ -14533,21 +14618,8 @@ void * GMT_Get_Vector (void *API, struct GMT_VECTOR *V, unsigned int col) {
14533
14618
if (API == NULL) return_null (API, GMT_NOT_A_SESSION);
14534
14619
if (V == NULL) return_null (API, GMT_PTR_IS_NULL);
14535
14620
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);
14551
14623
return vector;
14552
14624
}
14553
14625
@@ -14566,21 +14638,9 @@ int GMT_Put_Matrix (void *API, struct GMT_MATRIX *M, unsigned int type, int pad,
14566
14638
if (API == NULL) return_error (API, GMT_NOT_A_SESSION);
14567
14639
if (M == NULL) return_error (API, GMT_PTR_IS_NULL);
14568
14640
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;
14584
14644
MH = gmt_get_M_hidden (M);
14585
14645
MH->alloc_mode = GMT_ALLOC_EXTERNALLY; /* Since it clearly is a user array */
14586
14646
MH->pad = pad; /* Placing the pad argument here */
@@ -14600,21 +14660,8 @@ void * GMT_Get_Matrix (void *API, struct GMT_MATRIX *M) {
14600
14660
void *matrix = NULL;
14601
14661
if (API == NULL) return_null (API, GMT_NOT_A_SESSION);
14602
14662
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);
14618
14665
return matrix;
14619
14666
}
14620
14667
0 commit comments