history.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. #include <stdarg.h>
  14. #include <string.h>
  15. #include <grass/gis.h>
  16. #include <grass/raster.h>
  17. #include <grass/glocale.h>
  18. /*!
  19. * \brief Append a string to a History structure
  20. *
  21. *
  22. * \param hist pointer to History structure which holds history info
  23. * \param str string to append
  24. *
  25. * \return void
  26. */
  27. void Rast_append_history(struct History *hist, const char *str)
  28. {
  29. hist->lines = G_realloc(hist->lines, (hist->nlines + 1) * sizeof(char *));
  30. hist->lines[hist->nlines++] = G_store(str);
  31. }
  32. /*!
  33. * \brief Append a formatted string to a History structure
  34. *
  35. *
  36. * \param hist pointer to History structure which holds history info
  37. * \param fmt a string of format characters
  38. * \param ... the arguments associated with the format characters
  39. *
  40. * \return void
  41. */
  42. void Rast_append_format_history(struct History *hist, const char *fmt, ...)
  43. {
  44. va_list ap;
  45. char *str;
  46. hist->lines = G_realloc(hist->lines, (hist->nlines + 1) * sizeof(char *));
  47. va_start(ap, fmt);
  48. G_vasprintf(&str, fmt, ap);
  49. va_end(ap);
  50. hist->lines[hist->nlines++] = str;
  51. }
  52. int Rast__read_history(struct History *hist, FILE *fp)
  53. {
  54. int i;
  55. for (i = 0; i < HIST_NUM_FIELDS; i++) {
  56. char buf[4096];
  57. if (!G_getl(buf, sizeof(buf), fp)) {
  58. fclose(fp);
  59. return -1;
  60. }
  61. G_ascii_check(buf);
  62. hist->fields[i] = G_store(buf);
  63. }
  64. hist->nlines = 0;
  65. for (;;) {
  66. char buf[4096];
  67. if (!G_getl(buf, sizeof(buf), fp))
  68. break;
  69. Rast_append_history(hist, buf);
  70. }
  71. fclose(fp);
  72. return 0;
  73. }
  74. /*!
  75. * \brief Read raster history file
  76. *
  77. * This routine reads the history file for the raster map <i>name</i>
  78. * in <i>mapset</i> into the <i>hist</i> structure.
  79. *
  80. * A diagnostic message is printed and -1 is returned if there is an
  81. * error reading the history file. Otherwise, 0 is returned.
  82. *
  83. * \param name map name
  84. * \param mapset mapset name
  85. * \param hist pointer to History structure which holds history info
  86. *
  87. * \return -1 on error
  88. * \return 0 on success
  89. */
  90. int Rast_read_history(const char *name, const char *mapset,
  91. struct History *hist)
  92. {
  93. FILE *fp;
  94. G_zero(hist, sizeof(struct History));
  95. fp = G_fopen_old("hist", name, mapset);
  96. if (!fp) {
  97. G_warning(_("Unable to get history information for <%s@%s>"),
  98. name, mapset);
  99. return -1;
  100. }
  101. if (Rast__read_history(hist, fp) == 0)
  102. return 0;
  103. G_warning(_("Unable to get history information for <%s@%s>"),
  104. name, mapset);
  105. return -1;
  106. }
  107. void Rast__write_history(struct History *hist, FILE *fp)
  108. {
  109. int i;
  110. for (i = 0; i < HIST_NUM_FIELDS; i++)
  111. fprintf(fp, "%s\n", hist->fields[i] ? hist->fields[i] : "");
  112. for (i = 0; i < hist->nlines; i++)
  113. fprintf(fp, "%s\n", hist->lines[i]);
  114. fclose(fp);
  115. }
  116. /*!
  117. * \brief Write raster history file
  118. *
  119. * This routine writes the history file for the raster map
  120. * <i>name</i> in the current mapset from the <i>hist</i> structure.
  121. *
  122. * A diagnostic message is printed and -1 is returned if there is an
  123. * error writing the history file. Otherwise, 0 is returned.
  124. *
  125. * <b>Note:</b> The <i>hist</i> structure should first be initialized
  126. * using Rast_short_history().
  127. *
  128. * \param name map name
  129. * \param[out] hist pointer to History structure which holds history info
  130. *
  131. * \return void
  132. */
  133. void Rast_write_history(const char *name, struct History *hist)
  134. {
  135. FILE *fp = G_fopen_new("hist", name);
  136. if (!fp)
  137. G_fatal_error(_("Unable to write history information for <%s>"), name);
  138. Rast__write_history(hist, fp);
  139. }
  140. /*!
  141. * \brief Set the string of a specific history field
  142. *
  143. *
  144. * \param hist pointer to History structure which holds history info
  145. * \param field number of a specific history field, should be accessed with macros (HIST_MAPID, ...)
  146. *
  147. * \return string of the history field
  148. */
  149. const char *Rast_get_history(struct History *hist, int field)
  150. {
  151. return hist->fields[field];
  152. }
  153. /*!
  154. * \brief Set the string of a specific history field
  155. *
  156. *
  157. * \param hist pointer to History structure which holds history info
  158. * \param field number of a specific history field, should be accessed with macros (HIST_MAPID, ...)
  159. * \param str string of the history field
  160. *
  161. * \return void
  162. */
  163. void Rast_set_history(struct History *hist, int field, const char *str)
  164. {
  165. if (hist->fields[field])
  166. G_free(hist->fields[field]);
  167. hist->fields[field] = str ? G_store(str) : NULL;
  168. }
  169. void Rast_format_history(struct History *hist, int field, const char *fmt, ...)
  170. {
  171. va_list ap;
  172. if (hist->fields[field])
  173. G_free(hist->fields[field]);
  174. va_start(ap, fmt);
  175. G_vasprintf(&hist->fields[field], fmt, ap);
  176. va_end(ap);
  177. }
  178. /*!
  179. * \brief Initialize history structure
  180. *
  181. * This routine initializes the <i>hist</i> structure, recording the
  182. * date, user, module name and the raster map <i>name</i>
  183. * structure. The <i>type</i> is an anachronism from earlier versions
  184. * of GRASS and should be specified as "raster".
  185. *
  186. * <b>Note:</b> This routine only initializes the data structure. It
  187. * does not write the history file.
  188. *
  189. * \param name map name
  190. * \param type map type
  191. * \param hist pointer to History structure which holds history info
  192. */
  193. void Rast_short_history(const char *name, const char *type,
  194. struct History *hist)
  195. {
  196. G_zero(hist, sizeof(struct History));
  197. Rast_set_history(hist, HIST_MAPID, G_date());
  198. Rast_set_history(hist, HIST_TITLE, name);
  199. Rast_set_history(hist, HIST_MAPSET, G_mapset());
  200. Rast_set_history(hist, HIST_CREATOR, G_whoami());
  201. Rast_set_history(hist, HIST_MAPTYPE, type);
  202. Rast_format_history(hist, HIST_KEYWRD, _("generated by %s"), G_program_name());
  203. Rast_set_history(hist, HIST_DATSRC_1, "");
  204. Rast_set_history(hist, HIST_DATSRC_2, "");
  205. hist->nlines = 0;
  206. }
  207. /*!
  208. * \brief Save command line to raster history structure
  209. *
  210. * This routine takes an existing (run Rast_short_history first() history
  211. * structure and adds the command line to the end of the comments
  212. * array, as cleaned & expanded by the parser.
  213. *
  214. * - First version had for loops of [i][j] character assignments and ending
  215. * nulls, but using the string libraries is cleaner and less bug prone.
  216. * - Second version had white space detection, intelligent wrapping, and
  217. * indentation of continued lines, but this proved a pain in the neck for
  218. * things like r.patch which can have long strings without any
  219. * parser-acceptable breaks.
  220. * - This is MK-III, simplified, but that's good: it's cut & paste-able.
  221. *
  222. * Note: use Rast_write_history() to write the structure.
  223. *
  224. * Sample Usage:
  225. * \code
  226. * struct History history;
  227. * Rast_short_history(rasterfile, "raster", &history);
  228. * Rast_command_history(&history);
  229. * Rast_write_history(rasterfile, &history);
  230. * \endcode
  231. *
  232. * \param hist pointer to History structure which holds history info
  233. *
  234. * \return 0 on success
  235. * \return 1 on failure (history file full, no change)
  236. * \return 2 on failure (history file full, added as much as we could)
  237. */
  238. int Rast_command_history(struct History *hist)
  239. {
  240. char *cmdlin;
  241. int cmdlen;
  242. cmdlin = G_recreate_command();
  243. cmdlen = strlen(cmdlin);
  244. if (hist->nlines > 0) /* add a blank line if preceding history exists */
  245. Rast_append_history(hist, "");
  246. if (cmdlen < 70) /* ie if it will fit on a single line */
  247. Rast_append_history(hist, cmdlin);
  248. else { /* multi-line required */
  249. int j; /* j is the current position in the command line string */
  250. for (j = 0; cmdlen - j > 70; j += 68) {
  251. char buf[80];
  252. memcpy(buf, &cmdlin[j], 68);
  253. buf[68] = '\\';
  254. buf[69] = '\0';
  255. Rast_append_history(hist, buf);
  256. }
  257. if (cmdlen - j > 0) /* ie anything left */
  258. Rast_append_history(hist, &cmdlin[j]);
  259. }
  260. G_free(cmdlin);
  261. return 0;
  262. }
  263. void Rast_clear_history(struct History *hist)
  264. {
  265. int i;
  266. for (i = 0; i < hist->nlines; i++)
  267. G_free(hist->lines[i]);
  268. if (hist->lines)
  269. G_free(hist->lines);
  270. hist->lines = NULL;
  271. hist->nlines = 0;
  272. }
  273. void Rast_free_history(struct History *hist)
  274. {
  275. int i;
  276. for (i = 0; i < HIST_NUM_FIELDS; i++)
  277. if (hist->fields[i]) {
  278. G_free(hist->fields[i]);
  279. hist->fields[i] = NULL;
  280. }
  281. Rast_clear_history(hist);
  282. }
  283. int Rast_history_length(struct History *hist)
  284. {
  285. return hist->nlines;
  286. }
  287. const char *Rast_history_line(struct History *hist, int line)
  288. {
  289. if (line < 0 || line >= hist->nlines)
  290. return "";
  291. return hist->lines[line];
  292. }