GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-835afb4352
raster/history.c
Go to the documentation of this file.
1 /*!
2  * \file lib/raster/history.c
3  *
4  * \brief Raster Library - History management
5  *
6  * (C) 2001-2009 GRASS Development Team
7  *
8  * This program is free software under the GNU General Public License
9  * (>=v2). Read the file COPYING that comes with GRASS for details.
10  *
11  * \author Original author CERL
12  */
13 
14 #include <stdarg.h>
15 #include <string.h>
16 #include <grass/gis.h>
17 #include <grass/raster.h>
18 #include <grass/glocale.h>
19 
20 /*!
21  * \brief Append a string to a History structure
22  *
23  *
24  * \param hist pointer to History structure which holds history info
25  * \param str string to append
26  *
27  * \return void
28  */
29 void Rast_append_history(struct History *hist, const char *str)
30 {
31  hist->lines = G_realloc(hist->lines, (hist->nlines + 1) * sizeof(char *));
32  hist->lines[hist->nlines++] = G_store(str);
33 }
34 
35 /*!
36  * \brief Append a formatted string to a History structure
37  *
38  *
39  * \param hist pointer to History structure which holds history info
40  * \param fmt a string of format characters
41  * \param ... the arguments associated with the format characters
42  *
43  * \return void
44  */
45 void Rast_append_format_history(struct History *hist, const char *fmt, ...)
46 {
47  va_list ap;
48  char *str;
49 
50  hist->lines = G_realloc(hist->lines, (hist->nlines + 1) * sizeof(char *));
51 
52  va_start(ap, fmt);
53  G_vasprintf(&str, fmt, ap);
54  va_end(ap);
55 
56  hist->lines[hist->nlines++] = str;
57 }
58 
59 int Rast__read_history(struct History *hist, FILE *fp)
60 {
61  int i;
62 
63  for (i = 0; i < HIST_NUM_FIELDS; i++) {
64  char buf[4096];
65 
66  if (!G_getl(buf, sizeof(buf), fp)) {
67  fclose(fp);
68  return -1;
69  }
70 
71  G_ascii_check(buf);
72 
73  hist->fields[i] = G_store(buf);
74  }
75 
76  hist->nlines = 0;
77 
78  for (;;) {
79  char buf[4096];
80 
81  if (!G_getl(buf, sizeof(buf), fp))
82  break;
83  Rast_append_history(hist, buf);
84  }
85 
86  fclose(fp);
87 
88  return 0;
89 }
90 
91 /*!
92  * \brief Read raster history file
93  *
94  * This routine reads the history file for the raster map <i>name</i>
95  * in <i>mapset</i> into the <i>hist</i> structure.
96  *
97  * A diagnostic message is printed and -1 is returned if there is an
98  * error reading the history file. Otherwise, 0 is returned.
99  *
100  * \param name map name
101  * \param mapset mapset name
102  * \param hist pointer to History structure which holds history info
103  *
104  * \return -1 on error
105  * \return 0 on success
106  */
107 int Rast_read_history(const char *name, const char *mapset,
108  struct History *hist)
109 {
110  FILE *fp;
111 
112  G_zero(hist, sizeof(struct History));
113 
114  fp = G_fopen_old("hist", name, mapset);
115  if (!fp) {
116  G_warning(_("Unable to get history information for <%s@%s>"), name,
117  mapset);
118  return -1;
119  }
120 
121  if (Rast__read_history(hist, fp) == 0)
122  return 0;
123 
124  G_warning(_("Unable to get history information for <%s@%s>"), name, mapset);
125  return -1;
126 }
127 
128 void Rast__write_history(struct History *hist, FILE *fp)
129 {
130  int i;
131 
132  for (i = 0; i < HIST_NUM_FIELDS; i++)
133  fprintf(fp, "%s\n", hist->fields[i] ? hist->fields[i] : "");
134 
135  for (i = 0; i < hist->nlines; i++)
136  fprintf(fp, "%s\n", hist->lines[i]);
137 
138  fclose(fp);
139 }
140 
141 /*!
142  * \brief Write raster history file
143  *
144  * This routine writes the history file for the raster map
145  * <i>name</i> in the current mapset from the <i>hist</i> structure.
146  *
147  * A diagnostic message is printed and -1 is returned if there is an
148  * error writing the history file. Otherwise, 0 is returned.
149  *
150  * <b>Note:</b> The <i>hist</i> structure should first be initialized
151  * using Rast_short_history().
152  *
153  * \param name map name
154  * \param[out] hist pointer to History structure which holds history info
155  *
156  * \return void
157  */
158 void Rast_write_history(const char *name, struct History *hist)
159 {
160  FILE *fp = G_fopen_new("hist", name);
161 
162  if (!fp)
163  G_fatal_error(_("Unable to write history information for <%s>"), name);
164 
165  Rast__write_history(hist, fp);
166 }
167 
168 /*!
169  * \brief Set the string of a specific history field
170  *
171  *
172  * \param hist pointer to History structure which holds history info
173  * \param field number of a specific history field, should be accessed with
174  * macros (HIST_MAPID, ...)
175  *
176  * \return string of the history field
177  */
178 const char *Rast_get_history(struct History *hist, int field)
179 {
180  return hist->fields[field];
181 }
182 
183 /*!
184  * \brief Set the string of a specific history field
185  *
186  *
187  * \param hist pointer to History structure which holds history info
188  * \param field number of a specific history field, should be accessed with
189  * macros (HIST_MAPID, ...) \param str string of the history field
190  *
191  * \return void
192  */
193 void Rast_set_history(struct History *hist, int field, const char *str)
194 {
195  if (hist->fields[field])
196  G_free(hist->fields[field]);
197  hist->fields[field] = str ? G_store(str) : NULL;
198 }
199 
200 void Rast_format_history(struct History *hist, int field, const char *fmt, ...)
201 {
202  va_list ap;
203 
204  if (hist->fields[field])
205  G_free(hist->fields[field]);
206 
207  va_start(ap, fmt);
208  G_vasprintf(&hist->fields[field], fmt, ap);
209  va_end(ap);
210 }
211 
212 /*!
213  * \brief Initialize history structure
214  *
215  * This routine initializes the <i>hist</i> structure, recording the
216  * date, user, module name and the raster map <i>name</i>
217  * structure. The <i>type</i> can be "raster", "reclass", "GDAL-link",
218  * or "virtual".
219  *
220  * <b>Note:</b> This routine only initializes the data structure. It
221  * does not write the history file.
222  *
223  * \param name map name
224  * \param type map type
225  * \param hist pointer to History structure which holds history info
226  */
227 void Rast_short_history(const char *name, const char *type,
228  struct History *hist)
229 {
230  G_zero(hist, sizeof(struct History));
235  Rast_set_history(hist, HIST_MAPTYPE, type);
236  Rast_format_history(hist, HIST_KEYWRD, _("generated by %s"),
237  G_program_name());
238  Rast_set_history(hist, HIST_DATSRC_1, "");
239  Rast_set_history(hist, HIST_DATSRC_2, "");
240  hist->nlines = 0;
241 }
242 
243 /*!
244  * \brief Save command line to raster history structure
245  *
246  * This routine takes an existing (run Rast_short_history first() history
247  * structure and adds the command line to the end of the comments
248  * array, as cleaned & expanded by the parser.
249  *
250  * - First version had for loops of [i][j] character assignments and ending
251  * nulls, but using the string libraries is cleaner and less bug prone.
252  * - Second version had white space detection, intelligent wrapping, and
253  * indentation of continued lines, but this proved a pain in the neck for
254  * things like r.patch which can have long strings without any
255  * parser-acceptable breaks.
256  * - This is MK-III, simplified, but that's good: it's cut & paste-able.
257  *
258  * Note: use Rast_write_history() to write the structure.
259  *
260  * Sample Usage:
261  * \code
262  * struct History history;
263  * Rast_short_history(rasterfile, "raster", &history);
264  * Rast_command_history(&history);
265  * Rast_write_history(rasterfile, &history);
266  * \endcode
267  *
268  * \param hist pointer to History structure which holds history info
269  *
270  * \return 0 on success
271  * \return 1 on failure (history file full, no change)
272  * \return 2 on failure (history file full, added as much as we could)
273  */
274 int Rast_command_history(struct History *hist)
275 {
276  char *cmdlin;
277  int cmdlen;
278 
279  cmdlin = G_recreate_command();
280  cmdlen = strlen(cmdlin);
281 
282  if (hist->nlines > 0) /* add a blank line if preceding history exists */
283  Rast_append_history(hist, "");
284 
285  if (cmdlen < 70) /* ie if it will fit on a single line */
286  Rast_append_history(hist, cmdlin);
287  else { /* multi-line required */
288  int j; /* j is the current position in the command line string */
289 
290  for (j = 0; cmdlen - j > 70; j += 68) {
291  char buf[80];
292 
293  memcpy(buf, &cmdlin[j], 68);
294  buf[68] = '\\';
295  buf[69] = '\0';
296  Rast_append_history(hist, buf);
297  }
298  if (cmdlen - j > 0) /* ie anything left */
299  Rast_append_history(hist, &cmdlin[j]);
300  }
301 
302  G_free(cmdlin);
303 
304  return 0;
305 }
306 
307 void Rast_clear_history(struct History *hist)
308 {
309  int i;
310 
311  for (i = 0; i < hist->nlines; i++)
312  G_free(hist->lines[i]);
313 
314  if (hist->lines)
315  G_free(hist->lines);
316 
317  hist->lines = NULL;
318  hist->nlines = 0;
319 }
320 
321 void Rast_free_history(struct History *hist)
322 {
323  int i;
324 
325  for (i = 0; i < HIST_NUM_FIELDS; i++)
326  if (hist->fields[i]) {
327  G_free(hist->fields[i]);
328  hist->fields[i] = NULL;
329  }
330 
331  Rast_clear_history(hist);
332 }
333 
334 int Rast_history_length(struct History *hist)
335 {
336  return hist->nlines;
337 }
338 
339 const char *Rast_history_line(struct History *hist, int line)
340 {
341  if (line < 0 || line >= hist->nlines)
342  return "";
343  return hist->lines[line];
344 }
#define NULL
Definition: ccmath.h:32
void G_ascii_check(char *)
Removes non-ascii characters from buffer.
Definition: ascii_chk.c:31
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition: gis/open.c:251
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
const char * G_date(void)
Current date and time.
Definition: date.c:26
void G_warning(const char *,...) __attribute__((format(printf
const char * G_whoami(void)
Gets user's name.
Definition: gis/whoami.c:35
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
char * G_recreate_command(void)
Creates command to run non-interactive.
Definition: parser.c:838
int G_getl(char *, int, FILE *)
Gets a line of text from a file.
Definition: getl.c:31
const char * G_program_name(void)
Return module name.
Definition: progrm_nme.c:28
int G_vasprintf(char **, const char *, va_list)
Safe replacement for asprintf().
Definition: asprintf.c:41
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
FILE * G_fopen_new(const char *, const char *)
Open a new database file.
Definition: gis/open.c:219
#define _(str)
Definition: glocale.h:10
const char * name
Definition: named_colr.c:6
const char * Rast_history_line(struct History *hist, int line)
void Rast_free_history(struct History *hist)
void Rast_append_history(struct History *hist, const char *str)
Append a string to a History structure.
void Rast_clear_history(struct History *hist)
int Rast__read_history(struct History *hist, FILE *fp)
int Rast_history_length(struct History *hist)
int Rast_read_history(const char *name, const char *mapset, struct History *hist)
Read raster history file.
void Rast_write_history(const char *name, struct History *hist)
Write raster history file.
void Rast_append_format_history(struct History *hist, const char *fmt,...)
Append a formatted string to a History structure.
void Rast_format_history(struct History *hist, int field, const char *fmt,...)
int Rast_command_history(struct History *hist)
Save command line to raster history structure.
void Rast_set_history(struct History *hist, int field, const char *str)
Set the string of a specific history field.
void Rast__write_history(struct History *hist, FILE *fp)
void Rast_short_history(const char *name, const char *type, struct History *hist)
Initialize history structure.
const char * Rast_get_history(struct History *hist, int field)
Set the string of a specific history field.
@ HIST_NUM_FIELDS
Number of fields to be defined in History structure.
Definition: raster.h:168
@ HIST_KEYWRD
One-line data description.
Definition: raster.h:165
@ HIST_MAPID
Raster name.
Definition: raster.h:152
@ HIST_MAPTYPE
Map type ("raster", "reclass", "GDAL-link", or "virtual")
Definition: raster.h:160
@ HIST_TITLE
Raster title.
Definition: raster.h:154
@ HIST_MAPSET
Raster mapset.
Definition: raster.h:156
@ HIST_CREATOR
User who creates raster map.
Definition: raster.h:158
@ HIST_DATSRC_1
Description of original data source (two lines)
Definition: raster.h:162
@ HIST_DATSRC_2
Definition: raster.h:163
Raster history info (metadata)
Definition: raster.h:172
int nlines
Number of lines in lines array.
Definition: raster.h:176
char ** lines
Lines array.
Definition: raster.h:178
char * fields[HIST_NUM_FIELDS]
Array of fields (see History_field for details)
Definition: raster.h:174