diff --git a/doc/rst/source/api.rst b/doc/rst/source/api.rst index f18f7ed801b..10cc57ecca6 100644 --- a/doc/rst/source/api.rst +++ b/doc/rst/source/api.rst @@ -1352,9 +1352,11 @@ array of text strings, one per row. This is done via where ``family`` is either GMT_IS_VECTOR or GMT_IS_MATRIX, ``X`` is either a :ref:`GMT_VECTOR ` or :ref:`GMT_MATRIX `, and -``array`` is the a pointer to your string array. +``array`` is the a pointer to your string array. You may add ``GMT_IS_DUPLICATE`` to +``family`` to indicate you want the array of strings to be duplicated; the default +is to just set a pointer to ``array``. -To extract the string array from an output vector or matrix container you will use +To access the string array from an output vector or matrix container you will use .. _GMT_Get_Strings: diff --git a/src/gmt_api.c b/src/gmt_api.c index 105f17d159b..55861c95a01 100644 --- a/src/gmt_api.c +++ b/src/gmt_api.c @@ -274,6 +274,13 @@ enum GMTAPI_enum_status { * gmtlib_* functions are exported and may be used in other gmt_*.c files */ +GMT_LOCAL const char *gmtapi_method (unsigned int M) { + if (M < GMT_IS_DUPLICATE) return (GMT_method[M]); + if (M == GMT_IS_DUPLICATE) return (GMT_method[3]); + if (M == GMT_IS_REFERENCE) return (GMT_method[4]); + return NULL; +} + GMT_LOCAL void gmtapi_get_record_init (struct GMTAPI_CTRL *API); GMT_LOCAL int gmtapi_sort_on_classic (const void *vA, const void *vB) { @@ -2942,7 +2949,7 @@ GMT_LOCAL struct GMT_PALETTE * gmtapi_import_palette (struct GMTAPI_CTRL *API, i switch (S_obj->method) { /* From where are we getting the palette ? */ case GMT_IS_FILE: /* gmtlib_read_cpt will report where it is reading from if level is GMT_MSG_INFORMATION */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading CPT from %s %s\n", GMT_method[S_obj->method], S_obj->filename); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading CPT from %s %s\n", gmtapi_method (S_obj->method), S_obj->filename); snprintf (tmp_cptfile, GMT_LEN64, "gmtapi_colors2cpt_%d.cpt", (int)getpid()); if (!strcmp (tmp_cptfile, S_obj->filename)) /* This file was created when we gave "name" as red,blue,... instead */ flag = GMT_CPT_TEMPORARY; /* So we can take action later when we learn if user wanted a discrete or continuous CPT */ @@ -2957,7 +2964,7 @@ GMT_LOCAL struct GMT_PALETTE * gmtapi_import_palette (struct GMTAPI_CTRL *API, i case GMT_IS_STREAM: /* gmtlib_read_cpt will report where it is reading from if level is GMT_MSG_INFORMATION */ kind = (S_obj->fp == GMT->session.std[GMT_IN]) ? 0 : 1; /* 0 if stdin, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading CPT from %s %s stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading CPT from %s %s stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((P_obj = gmtlib_read_cpt (GMT, S_obj->fp, S_obj->method, mode)) == NULL) return_null (API, GMT_CPT_READ_ERROR); S_obj->resource = P_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -2965,7 +2972,7 @@ GMT_LOCAL struct GMT_PALETTE * gmtapi_import_palette (struct GMTAPI_CTRL *API, i case GMT_IS_FDESC: /* gmtlib_read_cpt will report where it is reading from if level is GMT_MSG_INFORMATION */ kind = (*((int *)S_obj->fp) == GMT_IN) ? 0 : 1; /* 0 if stdin, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading CPT from %s %s stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading CPT from %s %s stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((P_obj = gmtlib_read_cpt (GMT, S_obj->fp, S_obj->method, mode)) == NULL) return_null (API, GMT_CPT_READ_ERROR); S_obj->resource = P_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3027,19 +3034,19 @@ GMT_LOCAL int gmtapi_export_palette (struct GMTAPI_CTRL *API, int object_ID, uns switch (S_obj->method) { /* File, array, stream etc ? */ case GMT_IS_FILE: /* gmtlib_write_cpt will report where it is writing from if level is GMT_MSG_INFORMATION */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write CPT to %s %s\n", GMT_method[S_obj->method], S_obj->filename); + GMT_Report (API, GMT_MSG_INFORMATION, "Write CPT to %s %s\n", gmtapi_method (S_obj->method), S_obj->filename); if ((error = gmtlib_write_cpt (GMT, S_obj->filename, S_obj->method, mode, P_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_STREAM: /* gmtlib_write_cpt will report where it is writing from if level is GMT_MSG_INFORMATION */ kind = (S_obj->fp == GMT->session.std[GMT_OUT]) ? 0 : 1; /* 0 if stdout, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write CPT to %s %s output stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Write CPT to %s %s output stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((error = gmtlib_write_cpt (GMT, S_obj->fp, S_obj->method, mode, P_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_FDESC: /* gmtlib_write_cpt will report where it is writing from if level is GMT_MSG_INFORMATION */ kind = (*((int *)S_obj->fp) == GMT_OUT) ? 0 : 1; /* 0 if stdout, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write CPT to %s %s output stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Write CPT to %s %s output stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((error = gmtlib_write_cpt (GMT, S_obj->fp, S_obj->method, mode, P_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_DUPLICATE: /* Duplicate the input cpt */ @@ -3097,7 +3104,7 @@ GMT_LOCAL struct GMT_POSTSCRIPT * gmtapi_import_postscript (struct GMTAPI_CTRL * switch (S_obj->method) { /* File, array, stream etc ? */ case GMT_IS_FILE: /* gmtlib_read_ps will report where it is reading from if level is GMT_MSG_INFORMATION */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading PS from %s %s\n", GMT_method[S_obj->method], S_obj->filename); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading PS from %s %s\n", gmtapi_method (S_obj->method), S_obj->filename); if ((P_obj = gmtlib_read_ps (GMT, S_obj->filename, S_obj->method, mode)) == NULL) return_null (API, GMT_CPT_READ_ERROR); S_obj->resource = P_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3105,7 +3112,7 @@ GMT_LOCAL struct GMT_POSTSCRIPT * gmtapi_import_postscript (struct GMTAPI_CTRL * case GMT_IS_STREAM: /* gmtlib_read_ps will report where it is reading from if level is GMT_MSG_INFORMATION */ kind = (S_obj->fp == GMT->session.std[GMT_IN]) ? 0 : 1; /* 0 if stdin, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading PS from %s %s stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading PS from %s %s stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((P_obj = gmtlib_read_ps (GMT, S_obj->fp, S_obj->method, mode)) == NULL) return_null (API, GMT_CPT_READ_ERROR); S_obj->resource = P_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3113,7 +3120,7 @@ GMT_LOCAL struct GMT_POSTSCRIPT * gmtapi_import_postscript (struct GMTAPI_CTRL * case GMT_IS_FDESC: /* gmtlib_read_ps will report where it is reading from if level is GMT_MSG_INFORMATION */ kind = (*((int *)S_obj->fp) == GMT_IN) ? 0 : 1; /* 0 if stdin, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading PS from %s %s stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading PS from %s %s stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((P_obj = gmtlib_read_ps (GMT, S_obj->fp, S_obj->method, mode)) == NULL) return_null (API, GMT_CPT_READ_ERROR); S_obj->resource = P_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3168,19 +3175,19 @@ GMT_LOCAL int gmtapi_export_postscript (struct GMTAPI_CTRL *API, int object_ID, switch (S_obj->method) { /* File, array, stream etc ? */ case GMT_IS_FILE: /* gmtlib_write_ps will report where it is writing from if level is GMT_MSG_INFORMATION */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write PS to %s %s\n", GMT_method[S_obj->method], S_obj->filename); + GMT_Report (API, GMT_MSG_INFORMATION, "Write PS to %s %s\n", gmtapi_method (S_obj->method), S_obj->filename); if ((error = gmtlib_write_ps (GMT, S_obj->filename, S_obj->method, mode, P_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_STREAM: /* gmtlib_write_ps will report where it is writing from if level is GMT_MSG_INFORMATION */ kind = (S_obj->fp == GMT->session.std[GMT_OUT]) ? 0 : 1; /* 0 if stdout, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write PS to %s %s output stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Write PS to %s %s output stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((error = gmtlib_write_ps (GMT, S_obj->fp, S_obj->method, mode, P_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_FDESC: /* gmtlib_write_ps will report where it is writing from if level is GMT_MSG_INFORMATION */ kind = (*((int *)S_obj->fp) == GMT_OUT) ? 0 : 1; /* 0 if stdout, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write PS to %s %s output stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Write PS to %s %s output stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((error = gmtlib_write_ps (GMT, S_obj->fp, S_obj->method, mode, P_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_DUPLICATE: /* Duplicate the input cpt */ @@ -3334,7 +3341,7 @@ GMT_LOCAL struct GMT_MATRIX * gmtapi_import_matrix (struct GMTAPI_CTRL *API, int switch (S_obj->method) { /* File, array, stream etc ? */ case GMT_IS_FILE: /* gmtapi_read_vector will report where it is reading from if level is GMT_MSG_INFORMATION */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading MATRIX from %s %s\n", GMT_method[S_obj->method], S_obj->filename); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading MATRIX from %s %s\n", gmtapi_method (S_obj->method), S_obj->filename); if ((M_obj = gmtapi_read_matrix (GMT, S_obj->filename, S_obj->method, mode)) == NULL) return_null (API, GMT_DATA_READ_ERROR); S_obj->resource = M_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3342,7 +3349,7 @@ GMT_LOCAL struct GMT_MATRIX * gmtapi_import_matrix (struct GMTAPI_CTRL *API, int case GMT_IS_STREAM: /* gmtapi_read_vector will report where it is reading from if level is GMT_MSG_INFORMATION */ kind = (S_obj->fp == GMT->session.std[GMT_IN]) ? 0 : 1; /* Used for message: 0 if stdin, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading MATRIX from %s %s stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading MATRIX from %s %s stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((M_obj = gmtapi_read_matrix (GMT, S_obj->fp, S_obj->method, mode)) == NULL) return_null (API, GMT_DATA_READ_ERROR); S_obj->resource = M_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3350,7 +3357,7 @@ GMT_LOCAL struct GMT_MATRIX * gmtapi_import_matrix (struct GMTAPI_CTRL *API, int case GMT_IS_FDESC: /* gmtapi_read_vector will report where it is reading from if level is GMT_MSG_INFORMATION */ kind = (*((int *)S_obj->fp) == GMT_IN) ? 0 : 1; /* Used for message: 0 if stdin, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading MATRIX from %s %s stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading MATRIX from %s %s stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((M_obj = gmtapi_read_matrix (GMT, S_obj->fp, S_obj->method, mode)) == NULL) return_null (API, GMT_CPT_READ_ERROR); S_obj->resource = M_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3487,19 +3494,19 @@ GMT_LOCAL int gmtapi_export_matrix (struct GMTAPI_CTRL *API, int object_ID, unsi switch (S_obj->method) { /* File, array, stream etc ? */ case GMT_IS_FILE: /* gmtapi_write_matrix will report where it is writing from if level is GMT_MSG_INFORMATION */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write MATRIX to %s %s\n", GMT_method[S_obj->method], S_obj->filename); + GMT_Report (API, GMT_MSG_INFORMATION, "Write MATRIX to %s %s\n", gmtapi_method (S_obj->method), S_obj->filename); if ((error = gmtapi_write_matrix (GMT, S_obj->filename, S_obj->method, mode, M_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_STREAM: /* gmtapi_write_matrix will report where it is writing from if level is GMT_MSG_INFORMATION */ kind = (S_obj->fp == GMT->session.std[GMT_OUT]) ? 0 : 1; /* For message only: 0 if stdout, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write MATRIX to %s %s output stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Write MATRIX to %s %s output stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((error = gmtapi_write_matrix (GMT, S_obj->fp, S_obj->method, mode, M_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_FDESC: /* gmtapi_write_matrix will report where it is writing from if level is GMT_MSG_INFORMATION */ kind = (*((int *)S_obj->fp) == GMT_OUT) ? 0 : 1; /* For message only: 0 if stdout, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write MATRIX to %s %s output stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Write MATRIX to %s %s output stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((error = gmtapi_write_matrix (GMT, S_obj->fp, S_obj->method, mode, M_obj))) return (gmtlib_report_error (API, error)); break; default: @@ -3628,19 +3635,19 @@ GMT_LOCAL int gmtapi_export_vector (struct GMTAPI_CTRL *API, int object_ID, unsi switch (S_obj->method) { /* File, array, stream etc ? */ case GMT_IS_FILE: /* gmtapi_write_vector will report where it is writing from if level is GMT_MSG_INFORMATION */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write VECTOR to %s %s\n", GMT_method[S_obj->method], S_obj->filename); + GMT_Report (API, GMT_MSG_INFORMATION, "Write VECTOR to %s %s\n", gmtapi_method (S_obj->method), S_obj->filename); if ((error = gmtapi_write_vector (GMT, S_obj->filename, S_obj->method, mode, V_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_STREAM: /* gmtapi_write_vector will report where it is writing from if level is GMT_MSG_INFORMATION */ kind = (S_obj->fp == GMT->session.std[GMT_OUT]) ? 0 : 1; /* For message only: 0 if stdout, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write VECTOR to %s %s output stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Write VECTOR to %s %s output stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((error = gmtapi_write_vector (GMT, S_obj->fp, S_obj->method, mode, V_obj))) return (gmtlib_report_error (API, error)); break; case GMT_IS_FDESC: /* gmtapi_write_vector will report where it is writing from if level is GMT_MSG_INFORMATION */ kind = (*((int *)S_obj->fp) == GMT_OUT) ? 0 : 1; /* For message only: 0 if stdout, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Write VECTOR to %s %s output stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Write VECTOR to %s %s output stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((error = gmtapi_write_vector (GMT, S_obj->fp, S_obj->method, mode, V_obj))) return (gmtlib_report_error (API, error)); break; default: @@ -3769,7 +3776,7 @@ GMT_LOCAL struct GMT_VECTOR * gmtapi_import_vector (struct GMTAPI_CTRL *API, int switch (S_obj->method) { /* File, array, stream etc ? */ case GMT_IS_FILE: /* gmtapi_read_vector will report where it is reading from if level is GMT_MSG_INFORMATION */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading VECTOR from %s %s\n", GMT_method[S_obj->method], S_obj->filename); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading VECTOR from %s %s\n", gmtapi_method (S_obj->method), S_obj->filename); if ((V_obj = gmtapi_read_vector (GMT, S_obj->filename, S_obj->method, mode)) == NULL) return_null (API, GMT_DATA_READ_ERROR); S_obj->resource = V_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3777,7 +3784,7 @@ GMT_LOCAL struct GMT_VECTOR * gmtapi_import_vector (struct GMTAPI_CTRL *API, int case GMT_IS_STREAM: /* gmtapi_read_vector will report where it is reading from if level is GMT_MSG_INFORMATION */ kind = (S_obj->fp == GMT->session.std[GMT_IN]) ? 0 : 1; /* For message only: 0 if stdin, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading VECTOR from %s %s stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading VECTOR from %s %s stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((V_obj = gmtapi_read_vector (GMT, S_obj->fp, S_obj->method, mode)) == NULL) return_null (API, GMT_DATA_READ_ERROR); S_obj->resource = V_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3785,7 +3792,7 @@ GMT_LOCAL struct GMT_VECTOR * gmtapi_import_vector (struct GMTAPI_CTRL *API, int case GMT_IS_FDESC: /* gmtapi_read_vector will report where it is reading from if level is GMT_MSG_INFORMATION */ kind = (*((int *)S_obj->fp) == GMT_IN) ? 0 : 1; /* For message only: 0 if stdin, 1 otherwise for user pointer */ - GMT_Report (API, GMT_MSG_INFORMATION, "Reading VECTOR from %s %s stream\n", GMT_method[S_obj->method], GMT_stream[kind]); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading VECTOR from %s %s stream\n", gmtapi_method (S_obj->method), GMT_stream[kind]); if ((V_obj = gmtapi_read_vector (GMT, S_obj->fp, S_obj->method, mode)) == NULL) return_null (API, GMT_CPT_READ_ERROR); S_obj->resource = V_obj; /* Retain pointer to the allocated data so we use garbage collection later */ @@ -3936,7 +3943,7 @@ GMT_LOCAL struct GMT_DATASET * gmtapi_import_dataset (struct GMTAPI_CTRL *API, i return_null (API, GMT_OGR_ONE_TABLE_ONLY); } GMT_Report (API, GMT_MSG_INFORMATION, - "Reading %s from %s %s\n", GMT_family[S_obj->family], GMT_method[S_obj->method], S_obj->filename); + "Reading %s from %s %s\n", GMT_family[S_obj->family], gmtapi_method (S_obj->method), S_obj->filename); if ((D_obj->table[D_obj->n_tables] = gmtlib_read_table (GMT, S_obj->filename, S_obj->method, greenwich, &geometry, &type, use_GMT_io)) == NULL) continue; /* Ran into an empty file (e.g., /dev/null or equivalent). Skip to next item, */ TH = gmt_get_DT_hidden (D_obj->table[D_obj->n_tables]); @@ -3955,7 +3962,7 @@ GMT_LOCAL struct GMT_DATASET * gmtapi_import_dataset (struct GMTAPI_CTRL *API, i if (GMT->current.io.ogr == GMT_OGR_TRUE && D_obj->n_tables > 0) { /* Only single tables if GMT/OGR */ gmt_M_free (GMT, D_obj); return_null (API, GMT_OGR_ONE_TABLE_ONLY); } - GMT_Report (API, GMT_MSG_INFORMATION, "Reading %s from %s %" PRIxS "\n", GMT_family[S_obj->family], GMT_method[S_obj->method], (size_t)S_obj->fp); + GMT_Report (API, GMT_MSG_INFORMATION, "Reading %s from %s %" PRIxS "\n", GMT_family[S_obj->family], gmtapi_method (S_obj->method), (size_t)S_obj->fp); if ((D_obj->table[D_obj->n_tables] = gmtlib_read_table (GMT, S_obj->fp, S_obj->method, greenwich, &geometry, &type, use_GMT_io)) == NULL) continue; /* Ran into an empty file (e.g., /dev/null or equivalent). Skip to next item, */ TH = gmt_get_DT_hidden (D_obj->table[D_obj->n_tables]); TH->id = D_obj->n_tables; /* Give sequential internal object_ID numbers to tables */ @@ -6344,7 +6351,7 @@ void gmtlib_garbage_collection (struct GMTAPI_CTRL *API, int level) { /* Here we will try to free the memory pointed to by S_obj->resource|data */ GMT_Report (API, GMT_MSG_DEBUG, "gmtlib_garbage_collection: Destroying object: C=%d A=%d ID=%d W=%s F=%s M=%s S=%s P=%" PRIxS " N=%s\n", S_obj->close_file, S_obj->alloc_mode, S_obj->ID, GMT_direction[S_obj->direction], - GMT_family[S_obj->family], GMT_method[S_obj->method], GMT_status[S_obj->status&2], + GMT_family[S_obj->family], gmtapi_method (S_obj->method), GMT_status[S_obj->status&2], (size_t)S_obj->resource, S_obj->filename); if (S_obj->resource) { address = S_obj->resource; /* Keep a record of what the address was (since S_obj->resource will be set to NULL when freed) */ @@ -6964,7 +6971,7 @@ int GMT_Register_IO (void *V_API, unsigned int family, unsigned int method, unsi if (strlen (resource)) /* Strip off any beginning of the name */ S_obj->filename = strdup (&file[first]); gmt_M_str_free (file); - snprintf (message, GMT_LEN256, "Object ID %%d : Registered %s %s %s as an %s resource with geometry %s [n_objects = %%d]\n", GMT_family[family], GMT_method[method], S_obj->filename, GMT_direction[direction], GMT_geometry[gmtapi_gmtry(geometry)]); + snprintf (message, GMT_LEN256, "Object ID %%d : Registered %s %s %s as an %s resource with geometry %s [n_objects = %%d]\n", GMT_family[family], gmtapi_method (method), S_obj->filename, GMT_direction[direction], GMT_geometry[gmtapi_gmtry(geometry)]); break; case GMT_IS_STREAM: /* Methods that indirectly involve a file */ @@ -6976,7 +6983,7 @@ int GMT_Register_IO (void *V_API, unsigned int family, unsigned int method, unsi return_value (API, GMT_MEMORY_ERROR, GMT_NOTSET); /* No more memory */ } S_obj->fp = resource; /* Pass the stream of fdesc onward */ - snprintf (message, GMT_LEN256, "Object ID %%d : Registered %s %s %" PRIxS " as an %s resource with geometry %s [n_objects = %%d]\n", GMT_family[family], GMT_method[method], (size_t)resource, GMT_direction[direction], GMT_geometry[gmtapi_gmtry(geometry)]); + snprintf (message, GMT_LEN256, "Object ID %%d : Registered %s %s %" PRIxS " as an %s resource with geometry %s [n_objects = %%d]\n", GMT_family[family], gmtapi_method (method), (size_t)resource, GMT_direction[direction], GMT_geometry[gmtapi_gmtry(geometry)]); break; case GMT_IS_DUPLICATE: @@ -6987,7 +6994,7 @@ int GMT_Register_IO (void *V_API, unsigned int family, unsigned int method, unsi if ((S_obj = gmtapi_make_dataobject (API, family, method, geometry, resource, direction)) == NULL) { return_value (API, GMT_MEMORY_ERROR, GMT_NOTSET); /* No more memory */ } - snprintf (message, GMT_LEN256, "Object ID %%d : Registered %s %s %" PRIxS " as an %s resource with geometry %s [n_objects = %%d]\n", GMT_family[family], GMT_method[method], (size_t)resource, GMT_direction[direction], GMT_geometry[gmtapi_gmtry(geometry)]); + snprintf (message, GMT_LEN256, "Object ID %%d : Registered %s %s %" PRIxS " as an %s resource with geometry %s [n_objects = %%d]\n", GMT_family[family], gmtapi_method (method), (size_t)resource, GMT_direction[direction], GMT_geometry[gmtapi_gmtry(geometry)]); break; case GMT_IS_COORD: /* Internal registration of coordinate arrays so that GMT_Destroy_Data can free them */ @@ -8064,7 +8071,7 @@ int GMT_Write_Data (void *V_API, unsigned int family, unsigned int method, unsig if (in_item != GMT_NOTSET) { int out_item = gmtlib_validate_id (API, GMT_NOTSET, out_ID, GMT_OUT, GMT_NOTSET); /* Get the item in the API array; pass family = GMT_NOTSET to bypass status check */ GMT_Report (API, GMT_MSG_DEBUG, "GMT_Write_Data: Writing %s to memory object %d from object %d which transfers ownership\n", GMT_family[family], out_ID, in_ID); - if (API->object[out_item]->method < GMT_IS_VECTOR) API->object[in_item]->no_longer_owner = true; /* Since we have passed the content onto an output object */ + if (API->object[out_item]->method == GMT_IS_REFERENCE) API->object[in_item]->no_longer_owner = true; /* Since we have passed the content onto an output object */ if (!API->object[out_item]->filename) API->object[out_item]->filename = strdup (output); } } /* else it is a regular file and we just register it and get the new out_ID needed below */ @@ -13182,20 +13189,55 @@ void * GMT_Get_Matrix_ (struct GMT_MATRIX *M) { int GMT_Put_Strings (void *V_API, unsigned int family, void *object, char **array) { /* Hook pointer to the text array in a matrix or vector */ + bool dup = false; if (V_API == NULL) return_error (V_API, GMT_NOT_A_SESSION); if (object == NULL) return_error (V_API, GMT_PTR_IS_NULL); + if (array == NULL) return_error (V_API, GMT_PTR_IS_NULL); + if (family & GMT_IS_DUPLICATE) { /* Need to duplicate the strings */ + dup = true; + family -= GMT_IS_DUPLICATE; + } + else if (family & GMT_IS_REFERENCE) /* This is the default action, just remove the mode */ + family -= GMT_IS_REFERENCE; + if (!(family == GMT_IS_VECTOR || family == GMT_IS_MATRIX)) return_error (V_API, GMT_NOT_A_VALID_FAMILY); if (family == GMT_IS_VECTOR) { struct GMT_VECTOR *V = gmtapi_get_vector_data (object); struct GMT_VECTOR_HIDDEN *VH = gmt_get_V_hidden (V); - V->text = array; - VH->alloc_mode_text = GMT_ALLOC_EXTERNALLY; + if (dup) { /* Must duplicate the input array of strings */ + uint64_t k; + struct GMTAPI_CTRL *API = gmtapi_get_api_ptr (V_API); + if ((V->text = gmt_M_memory (API->GMT, NULL, V->n_rows, char **)) == NULL) { + GMT_Report (API, GMT_MSG_ERROR, "GMT_Put_Strings: Unable to allocate text string array for vector\n"); + return (GMT_MEMORY_ERROR); + } + for (k = 0; k < V->n_rows; k++) + if (array[k]) V->text[k] = strdup (array[k]); + VH->alloc_mode_text = GMT_ALLOC_INTERNALLY; + } + else { /* By reference */ + V->text = array; + VH->alloc_mode_text = GMT_ALLOC_EXTERNALLY; + } } else if (family == GMT_IS_MATRIX) { struct GMT_MATRIX *M = gmtapi_get_matrix_data (object); struct GMT_MATRIX_HIDDEN *MH = gmt_get_M_hidden (M); - M->text = array; - MH->alloc_mode_text = GMT_ALLOC_EXTERNALLY; + if (dup) { /* Must duplicate the input array of strings */ + uint64_t k; + struct GMTAPI_CTRL *API = gmtapi_get_api_ptr (V_API); + if ((M->text = gmt_M_memory (API->GMT, NULL, M->n_rows, char **)) == NULL) { + GMT_Report (API, GMT_MSG_ERROR, "GMT_Put_Strings: Unable to allocate text string array for matrix\n"); + return (GMT_MEMORY_ERROR); + } + for (k = 0; k < M->n_rows; k++) + if (array[k]) M->text[k] = strdup (array[k]); + MH->alloc_mode_text = GMT_ALLOC_INTERNALLY; + } + else { /* By reference */ + M->text = array; + MH->alloc_mode_text = GMT_ALLOC_EXTERNALLY; + } } return (GMT_NOERROR); } diff --git a/src/gmt_enum_dict.h b/src/gmt_enum_dict.h index bb9d6280cdd..fa3db98e459 100644 --- a/src/gmt_enum_dict.h +++ b/src/gmt_enum_dict.h @@ -138,7 +138,7 @@ static struct GMT_API_DICT gmt_api_enums[GMT_N_API_ENUMS] = { {"GMT_IS_COL_FORMAT", 2}, {"GMT_IS_COORD", 7}, {"GMT_IS_DATASET", 0}, - {"GMT_IS_DUPLICATE", 3}, + {"GMT_IS_DUPLICATE", 16}, {"GMT_IS_FDESC", 2}, {"GMT_IS_FILE", 0}, {"GMT_IS_GRID", 1}, @@ -155,7 +155,7 @@ static struct GMT_API_DICT gmt_api_enums[GMT_N_API_ENUMS] = { {"GMT_IS_POINT", 1}, {"GMT_IS_POLY", 4}, {"GMT_IS_POSTSCRIPT", 4}, - {"GMT_IS_REFERENCE", 4}, + {"GMT_IS_REFERENCE", 32}, {"GMT_IS_ROW_FORMAT", 1}, {"GMT_IS_STREAM", 1}, {"GMT_IS_SURFACE", 8}, diff --git a/src/gmt_resources.h b/src/gmt_resources.h index c17837516d6..80519a7ab61 100644 --- a/src/gmt_resources.h +++ b/src/gmt_resources.h @@ -120,8 +120,8 @@ enum GMT_enum_method { GMT_IS_FILE = 0, /* Entity is a filename */ GMT_IS_STREAM = 1, /* Entity is an open stream */ GMT_IS_FDESC = 2, /* Entity is an open file descriptor */ - GMT_IS_DUPLICATE = 3, /* Entity is a memory location that should be duplicated */ - GMT_IS_REFERENCE = 4, /* Entity is a memory location that should be referenced */ + GMT_IS_DUPLICATE = 16, /* Entity is a memory location that should be duplicated */ + GMT_IS_REFERENCE = 32, /* Entity is a memory location that should be referenced */ GMT_IS_OUTPUT = 1024 /* When creating a resource as a container for output */ }; diff --git a/src/gmt_support.c b/src/gmt_support.c index e61724e947a..d629ac0b570 100644 --- a/src/gmt_support.c +++ b/src/gmt_support.c @@ -8088,6 +8088,7 @@ struct GMT_PALETTE *gmt_get_palette (struct GMT_CTRL *GMT, char *file, enum GMT_ double noise; struct GMT_PALETTE_HIDDEN *PH = NULL; + GMT_Report (GMT->parent, GMT_MSG_DEBUG, "CPT argument %s understood to be a master table\n", file); if (gmt_M_is_dnan (zmin) || gmt_M_is_dnan (zmax)) { /* Safety valve 1 */ GMT_Report (GMT->parent, GMT_MSG_ERROR, "Passing zmax or zmin == NaN prevents automatic CPT generation!\n"); return (NULL); @@ -8124,6 +8125,7 @@ struct GMT_PALETTE *gmt_get_palette (struct GMT_CTRL *GMT, char *file, enum GMT_ gmt_save_current_cpt (GMT, P, 0); /* Save for use by session, if modern */ } else if (file) { /* Gave a CPT file */ + GMT_Report (GMT->parent, GMT_MSG_DEBUG, "CPT argument %s understood to be a regular CPT table\n", file); P = GMT_Read_Data (GMT->parent, GMT_IS_PALETTE, GMT_IS_FILE, GMT_IS_NONE, GMT_READ_NORMAL, NULL, &file[first], NULL); } else diff --git a/src/testapi_vector_strings2.c b/src/testapi_vector_strings2.c new file mode 100644 index 00000000000..600319a5a86 --- /dev/null +++ b/src/testapi_vector_strings2.c @@ -0,0 +1,58 @@ +#include "gmt.h" +#include +#include +/* + * Testing the use of user data provided via a GMT_VECTOR to pstext, + * passing both numerical vectors and a string array. + */ + +/* Dimensions of the test dataset */ +#define NCOLS 3 +#define NROWS 2 + +int main () { + void *API = NULL; /* The API control structure */ + struct GMT_VECTOR *V = NULL; /* Structure to hold input dataset as vectors */ + char input[GMT_VF_LEN] = {""}; /* String to hold virtual input filename */ + char args[128] = {""}; /* String to hold module command arguments */ + + uint64_t dim[4] = {NCOLS, NROWS, 1, 0}; /* ncols, nrows, nlayers, type */ + /* two data points */ + double x[2] = {5.0, 5.0}; + double y[2] = {3.0, 8.0}; + double angle[2] = {30.0, 60.0}; + char *strings[NROWS]; + + int i; + for (i=0; i