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