123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- /*!
- * \file lib/raster/history.c
- *
- * \brief Raster Library - History management
- *
- * (C) 2001-2009 GRASS Development Team
- *
- * This program is free software under the GNU General Public License
- * (>=v2). Read the file COPYING that comes with GRASS for details.
- *
- * \author Original author CERL
- */
- #include <stdarg.h>
- #include <string.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/glocale.h>
- /*!
- * \brief Append a string to a History structure
- *
- *
- * \param hist pointer to History structure which holds history info
- * \param str string to append
- *
- * \return void
- */
- void Rast_append_history(struct History *hist, const char *str)
- {
- hist->lines = G_realloc(hist->lines, (hist->nlines + 1) * sizeof(char *));
- hist->lines[hist->nlines++] = G_store(str);
- }
- /*!
- * \brief Append a formatted string to a History structure
- *
- *
- * \param hist pointer to History structure which holds history info
- * \param fmt a string of format characters
- * \param ... the arguments associated with the format characters
- *
- * \return void
- */
- void Rast_append_format_history(struct History *hist, const char *fmt, ...)
- {
- va_list ap;
- char *str;
- hist->lines = G_realloc(hist->lines, (hist->nlines + 1) * sizeof(char *));
- va_start(ap, fmt);
- G_vasprintf(&str, fmt, ap);
- va_end(ap);
- hist->lines[hist->nlines++] = str;
- }
- int Rast__read_history(struct History *hist, FILE *fp)
- {
- int i;
- for (i = 0; i < HIST_NUM_FIELDS; i++) {
- char buf[4096];
- if (!G_getl(buf, sizeof(buf), fp)) {
- fclose(fp);
- return -1;
- }
- G_ascii_check(buf);
- hist->fields[i] = G_store(buf);
- }
- hist->nlines = 0;
- for (;;) {
- char buf[4096];
- if (!G_getl(buf, sizeof(buf), fp))
- break;
- Rast_append_history(hist, buf);
- }
- fclose(fp);
- return 0;
- }
- /*!
- * \brief Read raster history file
- *
- * This routine reads the history file for the raster map <i>name</i>
- * in <i>mapset</i> into the <i>hist</i> structure.
- *
- * A diagnostic message is printed and -1 is returned if there is an
- * error reading the history file. Otherwise, 0 is returned.
- *
- * \param name map name
- * \param mapset mapset name
- * \param hist pointer to History structure which holds history info
- *
- * \return -1 on error
- * \return 0 on success
- */
- int Rast_read_history(const char *name, const char *mapset,
- struct History *hist)
- {
- FILE *fp;
- G_zero(hist, sizeof(struct History));
- fp = G_fopen_old("hist", name, mapset);
- if (!fp) {
- G_warning(_("Unable to get history information for <%s@%s>"),
- name, mapset);
- return -1;
- }
- if (Rast__read_history(hist, fp) == 0)
- return 0;
- G_warning(_("Unable to get history information for <%s@%s>"),
- name, mapset);
- return -1;
- }
- void Rast__write_history(struct History *hist, FILE *fp)
- {
- int i;
- for (i = 0; i < HIST_NUM_FIELDS; i++)
- fprintf(fp, "%s\n", hist->fields[i] ? hist->fields[i] : "");
- for (i = 0; i < hist->nlines; i++)
- fprintf(fp, "%s\n", hist->lines[i]);
- fclose(fp);
- }
- /*!
- * \brief Write raster history file
- *
- * This routine writes the history file for the raster map
- * <i>name</i> in the current mapset from the <i>hist</i> structure.
- *
- * A diagnostic message is printed and -1 is returned if there is an
- * error writing the history file. Otherwise, 0 is returned.
- *
- * <b>Note:</b> The <i>hist</i> structure should first be initialized
- * using Rast_short_history().
- *
- * \param name map name
- * \param[out] hist pointer to History structure which holds history info
- *
- * \return void
- */
- void Rast_write_history(const char *name, struct History *hist)
- {
- FILE *fp = G_fopen_new("hist", name);
- if (!fp)
- G_fatal_error(_("Unable to write history information for <%s>"), name);
- Rast__write_history(hist, fp);
- }
- /*!
- * \brief Set the string of a specific history field
- *
- *
- * \param hist pointer to History structure which holds history info
- * \param field number of a specific history field, should be accessed with macros (HIST_MAPID, ...)
- *
- * \return string of the history field
- */
- const char *Rast_get_history(struct History *hist, int field)
- {
- return hist->fields[field];
- }
- /*!
- * \brief Set the string of a specific history field
- *
- *
- * \param hist pointer to History structure which holds history info
- * \param field number of a specific history field, should be accessed with macros (HIST_MAPID, ...)
- * \param str string of the history field
- *
- * \return void
- */
- void Rast_set_history(struct History *hist, int field, const char *str)
- {
- if (hist->fields[field])
- G_free(hist->fields[field]);
- hist->fields[field] = str ? G_store(str) : NULL;
- }
- void Rast_format_history(struct History *hist, int field, const char *fmt, ...)
- {
- va_list ap;
- if (hist->fields[field])
- G_free(hist->fields[field]);
- va_start(ap, fmt);
- G_vasprintf(&hist->fields[field], fmt, ap);
- va_end(ap);
- }
- /*!
- * \brief Initialize history structure
- *
- * This routine initializes the <i>hist</i> structure, recording the
- * date, user, module name and the raster map <i>name</i>
- * structure. The <i>type</i> is an anachronism from earlier versions
- * of GRASS and should be specified as "raster".
- *
- * <b>Note:</b> This routine only initializes the data structure. It
- * does not write the history file.
- *
- * \param name map name
- * \param type map type
- * \param hist pointer to History structure which holds history info
- */
- void Rast_short_history(const char *name, const char *type,
- struct History *hist)
- {
- G_zero(hist, sizeof(struct History));
- Rast_set_history(hist, HIST_MAPID, G_date());
- Rast_set_history(hist, HIST_TITLE, name);
- Rast_set_history(hist, HIST_MAPSET, G_mapset());
- Rast_set_history(hist, HIST_CREATOR, G_whoami());
- Rast_set_history(hist, HIST_MAPTYPE, type);
- Rast_format_history(hist, HIST_KEYWRD, _("generated by %s"), G_program_name());
- Rast_set_history(hist, HIST_DATSRC_1, "");
- Rast_set_history(hist, HIST_DATSRC_2, "");
- hist->nlines = 0;
- }
- /*!
- * \brief Save command line to raster history structure
- *
- * This routine takes an existing (run Rast_short_history first() history
- * structure and adds the command line to the end of the comments
- * array, as cleaned & expanded by the parser.
- *
- * - First version had for loops of [i][j] character assignments and ending
- * nulls, but using the string libraries is cleaner and less bug prone.
- * - Second version had white space detection, intelligent wrapping, and
- * indentation of continued lines, but this proved a pain in the neck for
- * things like r.patch which can have long strings without any
- * parser-acceptable breaks.
- * - This is MK-III, simplified, but that's good: it's cut & paste-able.
- *
- * Note: use Rast_write_history() to write the structure.
- *
- * Sample Usage:
- * \code
- * struct History history;
- * Rast_short_history(rasterfile, "raster", &history);
- * Rast_command_history(&history);
- * Rast_write_history(rasterfile, &history);
- * \endcode
- *
- * \param hist pointer to History structure which holds history info
- *
- * \return 0 on success
- * \return 1 on failure (history file full, no change)
- * \return 2 on failure (history file full, added as much as we could)
- */
- int Rast_command_history(struct History *hist)
- {
- char *cmdlin;
- int cmdlen;
- cmdlin = G_recreate_command();
- cmdlen = strlen(cmdlin);
- if (hist->nlines > 0) /* add a blank line if preceding history exists */
- Rast_append_history(hist, "");
- if (cmdlen < 70) /* ie if it will fit on a single line */
- Rast_append_history(hist, cmdlin);
- else { /* multi-line required */
- int j; /* j is the current position in the command line string */
- for (j = 0; cmdlen - j > 70; j += 68) {
- char buf[80];
- memcpy(buf, &cmdlin[j], 68);
- buf[68] = '\\';
- buf[69] = '\0';
- Rast_append_history(hist, buf);
- }
- if (cmdlen - j > 0) /* ie anything left */
- Rast_append_history(hist, &cmdlin[j]);
- }
- G_free(cmdlin);
- return 0;
- }
- void Rast_clear_history(struct History *hist)
- {
- int i;
- for (i = 0; i < hist->nlines; i++)
- G_free(hist->lines[i]);
- if (hist->lines)
- G_free(hist->lines);
- hist->lines = NULL;
- hist->nlines = 0;
- }
- void Rast_free_history(struct History *hist)
- {
- int i;
- for (i = 0; i < HIST_NUM_FIELDS; i++)
- if (hist->fields[i]) {
- G_free(hist->fields[i]);
- hist->fields[i] = NULL;
- }
- Rast_clear_history(hist);
- }
- int Rast_history_length(struct History *hist)
- {
- return hist->nlines;
- }
- const char *Rast_history_line(struct History *hist, int line)
- {
- if (line < 0 || line >= hist->nlines)
- return "";
- return hist->lines[line];
- }
|