GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
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  if (!G_getl(buf, sizeof(buf), fp))
81  break;
82  Rast_append_history(hist, buf);
83  }
84 
85  fclose(fp);
86 
87  return 0;
88 }
89 
90 /*!
91  * \brief Read raster history file
92  *
93  * This routine reads the history file for the raster map <i>name</i>
94  * in <i>mapset</i> into the <i>hist</i> structure.
95  *
96  * A diagnostic message is printed and -1 is returned if there is an
97  * error reading the history file. Otherwise, 0 is returned.
98  *
99  * \param name map name
100  * \param mapset mapset name
101  * \param hist pointer to History structure which holds history info
102  *
103  * \return -1 on error
104  * \return 0 on success
105  */
106 int Rast_read_history(const char *name, const char *mapset,
107  struct History *hist)
108 {
109  FILE *fp;
110 
111  G_zero(hist, sizeof(struct History));
112 
113  fp = G_fopen_old("hist", name, mapset);
114  if (!fp) {
115  G_warning(_("Unable to get history information for <%s@%s>"),
116  name, mapset);
117  return -1;
118  }
119 
120  if (Rast__read_history(hist, fp) == 0)
121  return 0;
122 
123  G_warning(_("Unable to get history information for <%s@%s>"),
124  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  if (!fp)
162  G_fatal_error(_("Unable to write history information for <%s>"), name);
163 
164  Rast__write_history(hist, fp);
165 }
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 macros (HIST_MAPID, ...)
174  *
175  * \return string of the history field
176  */
177 const char *Rast_get_history(struct History *hist, int field)
178 {
179  return hist->fields[field];
180 }
181 
182 /*!
183  * \brief Set the string of a specific history field
184  *
185  *
186  * \param hist pointer to History structure which holds history info
187  * \param field number of a specific history field, should be accessed with macros (HIST_MAPID, ...)
188  * \param str string of the history field
189  *
190  * \return void
191  */
192 void Rast_set_history(struct History *hist, int field, const char *str)
193 {
194  if (hist->fields[field])
195  G_free(hist->fields[field]);
196  hist->fields[field] = str ? G_store(str) : NULL;
197 }
198 
199 void Rast_format_history(struct History *hist, int field, const char *fmt, ...)
200 {
201  va_list ap;
202 
203  if (hist->fields[field])
204  G_free(hist->fields[field]);
205 
206  va_start(ap, fmt);
207  G_vasprintf(&hist->fields[field], fmt, ap);
208  va_end(ap);
209 }
210 
211 /*!
212  * \brief Initialize history structure
213  *
214  * This routine initializes the <i>hist</i> structure, recording the
215  * date, user, module name and the raster map <i>name</i>
216  * structure. The <i>type</i> can be "raster", "reclass", "GDAL-link",
217  * or "virtual".
218  *
219  * <b>Note:</b> This routine only initializes the data structure. It
220  * does not write the history file.
221  *
222  * \param name map name
223  * \param type map type
224  * \param hist pointer to History structure which holds history info
225  */
226 void Rast_short_history(const char *name, const char *type,
227  struct History *hist)
228 {
229  G_zero(hist, sizeof(struct History));
231  Rast_set_history(hist, HIST_TITLE, name);
234  Rast_set_history(hist, HIST_MAPTYPE, type);
235  Rast_format_history(hist, HIST_KEYWRD, _("generated by %s"), G_program_name());
236  Rast_set_history(hist, HIST_DATSRC_1, "");
237  Rast_set_history(hist, HIST_DATSRC_2, "");
238  hist->nlines = 0;
239 }
240 
241 /*!
242  * \brief Save command line to raster history structure
243  *
244  * This routine takes an existing (run Rast_short_history first() history
245  * structure and adds the command line to the end of the comments
246  * array, as cleaned & expanded by the parser.
247  *
248  * - First version had for loops of [i][j] character assignments and ending
249  * nulls, but using the string libraries is cleaner and less bug prone.
250  * - Second version had white space detection, intelligent wrapping, and
251  * indentation of continued lines, but this proved a pain in the neck for
252  * things like r.patch which can have long strings without any
253  * parser-acceptable breaks.
254  * - This is MK-III, simplified, but that's good: it's cut & paste-able.
255  *
256  * Note: use Rast_write_history() to write the structure.
257  *
258  * Sample Usage:
259  * \code
260  * struct History history;
261  * Rast_short_history(rasterfile, "raster", &history);
262  * Rast_command_history(&history);
263  * Rast_write_history(rasterfile, &history);
264  * \endcode
265  *
266  * \param hist pointer to History structure which holds history info
267  *
268  * \return 0 on success
269  * \return 1 on failure (history file full, no change)
270  * \return 2 on failure (history file full, added as much as we could)
271  */
272 int Rast_command_history(struct History *hist)
273 {
274  char *cmdlin;
275  int cmdlen;
276 
277  cmdlin = G_recreate_command();
278  cmdlen = strlen(cmdlin);
279 
280  if (hist->nlines > 0) /* add a blank line if preceding history exists */
281  Rast_append_history(hist, "");
282 
283  if (cmdlen < 70) /* ie if it will fit on a single line */
284  Rast_append_history(hist, cmdlin);
285  else { /* multi-line required */
286  int j; /* j is the current position in the command line string */
287  for (j = 0; cmdlen - j > 70; j += 68) {
288  char buf[80];
289  memcpy(buf, &cmdlin[j], 68);
290  buf[68] = '\\';
291  buf[69] = '\0';
292  Rast_append_history(hist, buf);
293  }
294  if (cmdlen - j > 0) /* ie anything left */
295  Rast_append_history(hist, &cmdlin[j]);
296  }
297 
298  G_free(cmdlin);
299 
300  return 0;
301 }
302 
303 void Rast_clear_history(struct History *hist)
304 {
305  int i;
306 
307  for (i = 0; i < hist->nlines; i++)
308  G_free(hist->lines[i]);
309 
310  if (hist->lines)
311  G_free(hist->lines);
312 
313  hist->lines = NULL;
314  hist->nlines = 0;
315 }
316 
317 void Rast_free_history(struct History *hist)
318 {
319  int i;
320 
321  for (i = 0; i < HIST_NUM_FIELDS; i++)
322  if (hist->fields[i]) {
323  G_free(hist->fields[i]);
324  hist->fields[i] = NULL;
325  }
326 
327  Rast_clear_history(hist);
328 }
329 
330 int Rast_history_length(struct History *hist)
331 {
332  return hist->nlines;
333 }
334 
335 const char *Rast_history_line(struct History *hist, int line)
336 {
337  if (line < 0 || line >= hist->nlines)
338  return "";
339  return hist->lines[line];
340 }
341 
int G_getl(char *, int, FILE *)
Gets a line of text from a file.
Definition: getl.c:31
void Rast_format_history(struct History *hist, int field, const char *fmt,...)
Definition: history.c:199
const char * G_program_name(void)
Return module name.
Definition: progrm_nme.c:28
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
const char * G_whoami(void)
Gets user&#39;s name.
Definition: gis/whoami.c:35
User who creater raster map.
Definition: raster.h:166
Map type ("raster", "reclass", "GDAL-link", or "virtual")
Definition: raster.h:168
void Rast_append_format_history(struct History *hist, const char *fmt,...)
Append a formatted string to a History structure.
Definition: history.c:45
void G_ascii_check(char *)
Removes non-ascii characters from buffer.
Definition: ascii_chk.c:34
const char * Rast_get_history(struct History *hist, int field)
Set the string of a specific history field.
Definition: history.c:177
int Rast__read_history(struct History *hist, FILE *fp)
Definition: history.c:59
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
#define NULL
Definition: ccmath.h:32
Raster name.
Definition: raster.h:160
int G_vasprintf(char **, const char *, va_list)
Safe replacement for asprintf().
Definition: asprintf.c:42
One-line data description.
Definition: raster.h:173
char * G_recreate_command(void)
Creates command to run non-interactive.
Definition: parser.c:822
FILE * G_fopen_new(const char *, const char *)
Open a new database file.
Definition: gis/open.c:220
void Rast_append_history(struct History *hist, const char *str)
Append a string to a History structure.
Definition: history.c:29
void Rast_free_history(struct History *hist)
Definition: history.c:317
int Rast_history_length(struct History *hist)
Definition: history.c:330
Raster history info (metadata)
Definition: raster.h:180
Description of original data source (two lines)
Definition: raster.h:170
const char * Rast_history_line(struct History *hist, int line)
Definition: history.c:335
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition: gis/open.c:253
Raster mapset.
Definition: raster.h:164
int Rast_read_history(const char *name, const char *mapset, struct History *hist)
Read raster history file.
Definition: history.c:106
void Rast_write_history(const char *name, struct History *hist)
Write raster history file.
Definition: history.c:158
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
void G_warning(const char *,...) __attribute__((format(printf
#define G_realloc(p, n)
Definition: defs/gis.h:114
#define _(str)
Definition: glocale.h:10
int nlines
Number of lines in lines array.
Definition: raster.h:185
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
char ** lines
Lines array.
Definition: raster.h:187
void Rast_clear_history(struct History *hist)
Definition: history.c:303
void Rast_short_history(const char *name, const char *type, struct History *hist)
Initialize history structure.
Definition: history.c:226
char * fields[HIST_NUM_FIELDS]
Array of fields (see History_field for details)
Definition: raster.h:183
const char * name
Definition: named_colr.c:7
Number of fields to be defined in History structure.
Definition: raster.h:176
Raster title.
Definition: raster.h:162
void Rast__write_history(struct History *hist, FILE *fp)
Definition: history.c:128
void Rast_set_history(struct History *hist, int field, const char *str)
Set the string of a specific history field.
Definition: history.c:192
int Rast_command_history(struct History *hist)
Save command line to raster history structure.
Definition: history.c:272
const char * G_date(void)
Current date and time.
Definition: date.c:26