GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-eb16a2cfc9
raster_metadata.c
Go to the documentation of this file.
1 /*!
2  \file lib/raster/raster_metadata.c
3 
4  \brief Raster library - Functions to read and write raster "units",
5  "semantic label" and "vertical datum" meta-data info
6 
7  (C) 2007-2009, 2021 by Hamish Bowman, Maris Nartiss,
8  and the GRASS Development Team
9 
10  This program is free software under the GNU General Public License
11  (>=v2). Read the file COPYING that comes with GRASS for details.
12 
13  \author Hamish Bowman
14  */
15 
16 #include <stdbool.h>
17 #include <stdio.h>
18 #include <string.h>
19 
20 #include <grass/gis.h>
21 #include <grass/raster.h>
22 #include <grass/glocale.h>
23 
24 static char *misc_read_line(const char *, const char *, const char *);
25 static void misc_write_line(const char *, const char *, const char *);
26 
27 /*!
28  * \brief Get a raster map's units metadata string
29  *
30  * Read the raster's units metadata file and put string in str
31  *
32  * \param name raster map name
33  * \param mapset mapset name
34  *
35  * \return string representing units on success
36  * \return NULL on error
37  */
38 char *Rast_read_units(const char *name, const char *mapset)
39 {
40  return misc_read_line("units", name, mapset);
41 }
42 
43 /*!
44  * \brief Write a string to a raster map's units metadata file
45  *
46  * Raster map must exist in the current mapset.
47  *
48  * \param name raster map name
49  * \param str string containing data to be written
50  */
51 void Rast_write_units(const char *name, const char *str)
52 {
53  misc_write_line("units", name, str);
54 }
55 
56 /*!
57  * \brief Get a raster map's vertical datum metadata string
58  *
59  * Read the raster's vertical datum metadata file and put string in str
60  *
61  * \param name raster map name
62  * \param mapset mapset name
63  *
64  * \return string representing vertical datum on success
65  * \return NULL on error
66  */
67 char *Rast_read_vdatum(const char *name, const char *mapset)
68 {
69  return misc_read_line("vertical_datum", name, mapset);
70 }
71 
72 /*!
73  * \brief Write a string into a raster's vertical datum metadata file
74  *
75  * Raster map must exist in the current mapset.
76  *
77  * \param name raster map name
78  * \param str string containing data to be written
79  */
80 void Rast_write_vdatum(const char *name, const char *str)
81 {
82  misc_write_line("vertical_datum", name, str);
83 }
84 
85 /*!
86  * \brief Get a raster map semantic label metadata string
87  *
88  * Read raster semantic label metadata file and put string in to str
89  *
90  * \param name raster map name
91  * \param mapset mapset name
92  *
93  * \return string representing semantic label on success
94  * \return NULL on error
95  */
96 char *Rast_read_semantic_label(const char *name, const char *mapset)
97 {
98  return misc_read_line("semantic_label", name, mapset);
99 }
100 
101 /*!
102  * \brief Get a raster map semantic label or fall back to its name
103  *
104  * Use this function if a semantic label is needed but not mandated.
105  *
106  * \param name raster map name
107  * \param mapset mapset name
108  *
109  * \return string representing semantic label or map name
110  */
111 char *Rast_get_semantic_label_or_name(const char *name, const char *mapset)
112 {
113  char *buff;
114 
115  buff = Rast_read_semantic_label(name, mapset);
116  return buff ? buff : G_store(name);
117 }
118 
119 /*!
120  * \brief Write a string into a rasters semantic label metadata file
121  *
122  * Raster map must exist in the current mapset.
123  *
124  * It is up to the caller to validate semantic label string in advance
125  * with Rast_legal_semantic_label().
126  *
127  * \param name raster map name
128  * \param str string containing data to be written
129  */
130 void Rast_write_semantic_label(const char *name, const char *str)
131 {
132  misc_write_line("semantic_label", name, str);
133 }
134 
135 /*!
136  * \brief Check for legal semantic label
137  *
138  * Legal semantic label must be a legal GRASS file name.
139  * Semantic labels are capped in length to GNAME_MAX.
140  *
141  * This function will return false if provided semantic label is not
142  * considered to be valid.
143  * This function does not check if semantic label maps to any entry in
144  * metadata files of semantic labels as not all semantic labels have
145  * files with extra metadata.
146  *
147  * The function prints a warning on error.
148  *
149  * \param semantic label reference to check
150  *
151  * \return true success
152  * \return false failure
153  */
154 bool Rast_legal_semantic_label(const char *semantic_label)
155 {
156  const char *s;
157 
158  if (strlen(semantic_label) >= GNAME_MAX) {
159  G_warning(_("Semantic label is too long"));
160  return false;
161  }
162 
163  if (G_legal_filename(semantic_label) != 1)
164  return false;
165 
166  s = semantic_label;
167  while (*s) {
168  if (!((*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') ||
169  (*s >= '0' && *s <= '9') || *s == '_' || *s == '-')) {
170  G_warning(_("Character '%c' not allowed in a semantic label."), *s);
171  return false;
172  }
173  s++;
174  }
175 
176  return true;
177 }
178 
179 /*!
180  * \brief Read the first line of a file in cell_misc/
181  *
182  * Read the first line of data from a cell_misc/ meta-data file.
183  *
184  * \param element metadata component filename
185  * \param name
186  * \param mapset
187  * \return dynamically-allocated string on success
188  * \return NULL on error
189  */
190 static char *misc_read_line(const char *elem, const char *name,
191  const char *mapset)
192 {
193  char buff[GNAME_MAX];
194  FILE *fp;
195 
196  buff[0] = '\0';
197 
198  if (G_find_file2_misc("cell_misc", elem, name, mapset) == NULL)
199  return NULL;
200 
201  fp = G_fopen_old_misc("cell_misc", elem, name, mapset);
202  if (!fp) {
203  G_warning(_("Unable to read <%s> for raster map <%s@%s>"), elem, name,
204  mapset);
205  return NULL;
206  }
207  if (G_getl2(buff, sizeof(buff) - 1, fp) == 0) {
208  /* file is empty */
209  *buff = '\0';
210  }
211 
212  if (fclose(fp) != 0)
214  _("Error closing <%s> metadata file for raster map <%s@%s>"), elem,
215  name, mapset);
216 
217  return *buff ? G_store(buff) : NULL;
218 }
219 
220 /*!
221  * \brief Write a line to a raster map metadata file
222  *
223  * Write (including overwrite) a string into a raster map's metadata file
224  * found in in cell_misc/ in the current mapset.
225  *
226  * \param element metadata component filename
227  * \param name
228  * \param *str string containing data to be written
229  */
230 static void misc_write_line(const char *elem, const char *name, const char *str)
231 {
232  FILE *fp;
233 
234  fp = G_fopen_new_misc("cell_misc", elem, name);
235  if (!fp) {
237  _("Unable to create <%s> metadata file for raster map <%s@%s>"),
238  elem, name, G_mapset());
239  } /* This else block is unnecessary but helps to silence static code
240  analysis tools */
241  else {
242  fprintf(fp, "%s\n", str);
243 
244  if (fclose(fp) != 0)
246  _("Error closing <%s> metadata file for raster map <%s@%s>"),
247  elem, name, G_mapset());
248  }
249 }
#define NULL
Definition: ccmath.h:32
int G_getl2(char *, int, FILE *)
Gets a line of text from a file of any pedigree.
Definition: getl.c:60
FILE * G_fopen_old_misc(const char *, const char *, const char *, const char *)
open a database misc file for reading
Definition: open_misc.c:205
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
int G_legal_filename(const char *)
Check for legal database file name.
Definition: legal_name.c:34
FILE * G_fopen_new_misc(const char *, const char *, const char *)
open a new database misc file
Definition: open_misc.c:178
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
const char * G_find_file2_misc(const char *, const char *, const char *, const char *)
Searches for a misc file from the mapset search list or in a specified mapset. (look but don't touch)
Definition: find_file.c:257
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
#define GNAME_MAX
Definition: gis.h:196
#define _(str)
Definition: glocale.h:10
const char * name
Definition: named_colr.c:6
bool Rast_legal_semantic_label(const char *semantic_label)
Check for legal semantic label.
char * Rast_read_vdatum(const char *name, const char *mapset)
Get a raster map's vertical datum metadata string.
void Rast_write_semantic_label(const char *name, const char *str)
Write a string into a rasters semantic label metadata file.
char * Rast_read_units(const char *name, const char *mapset)
Get a raster map's units metadata string.
char * Rast_read_semantic_label(const char *name, const char *mapset)
Get a raster map semantic label metadata string.
void Rast_write_units(const char *name, const char *str)
Write a string to a raster map's units metadata file.
char * Rast_get_semantic_label_or_name(const char *name, const char *mapset)
Get a raster map semantic label or fall back to its name.
void Rast_write_vdatum(const char *name, const char *str)
Write a string into a raster's vertical datum metadata file.