timestamp.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. /*!
  2. * \file lib/gis/timestamp.c
  3. *
  4. * \brief GIS Library - Timestamp management
  5. *
  6. * Provides DateTime functions for timestamp management.
  7. *
  8. * The timestamp values must use the format as described in the GRASS
  9. * datetime library. The source tree for this library should have a
  10. * description of the format. For convience, the formats as of Feb, 1996
  11. * are reproduced here:
  12. *
  13. * There are two types of datetime values: absolute and relative. Absolute
  14. * values specify exact dates and/or times. Relative values specify a span
  15. * of time. Some examples will help clarify:
  16. *
  17. * Absolute
  18. *
  19. * The general format for absolute values is:
  20. *
  21. * day month year [bc] hour:minute:seconds timezone
  22. *
  23. * day is 1-31
  24. * month is jan,feb,...,dec
  25. * year is 4 digit year
  26. * [bc] if present, indicates dates is BC
  27. * hour is 0-23 (24 hour clock)
  28. * mintue is 0-59
  29. * second is 0-59.9999 (fractions of second allowed)
  30. * timezone is +hhmm or -hhmm (eg, -0600)
  31. *
  32. * parts can be missing
  33. *
  34. * 1994 [bc]
  35. * Jan 1994 [bc]
  36. * 15 jan 1000 [bc]
  37. * 15 jan 1994 [bc] 10 [+0000]
  38. * 15 jan 1994 [bc] 10:00 [+0100]
  39. * 15 jan 1994 [bc] 10:00:23.34 [-0500]
  40. *
  41. * Relative
  42. *
  43. * There are two types of relative datetime values, year- month and day-second.
  44. *
  45. * The formats are:
  46. *
  47. * [-] # years # months
  48. * [-] # days # hours # minutes # seconds
  49. *
  50. * The words years, months, days, hours, minutes, seconds are literal words,
  51. * and the # are the numeric values.
  52. *
  53. * Examples:
  54. *
  55. * 2 years
  56. * 5 months
  57. * 2 years 5 months
  58. * 100 days
  59. * 15 hours 25 minutes 35.34 seconds
  60. * 100 days 25 minutes
  61. * 1000 hours 35.34 seconds
  62. *
  63. * The following are illegal because it mixes year-month and day-second
  64. * (because the number of days in a month or in a year vary):
  65. *
  66. * 3 months 15 days
  67. * 3 years 10 days
  68. *
  69. * (C) 2001-2009 by the GRASS Development Team
  70. *
  71. * This program is free software under the GNU General Public License
  72. * (>=v2). Read the file COPYING that comes with GRASS for details.
  73. *
  74. * \author Michael Shapiro & Bill Brown, CERL
  75. * \author raster3d functions by Michael Pelizzari, LMCO
  76. * \author Soeren Gebbert, vector timestamp implementation update
  77. */
  78. #include <string.h>
  79. #include <unistd.h>
  80. #include <grass/gis.h>
  81. #include <grass/vect/dig_defines.h>
  82. #include <grass/glocale.h>
  83. #define RAST_MISC "cell_misc"
  84. #define GRID3 "grid3"
  85. /*!
  86. \brief Initialize timestamp structure
  87. \param ts pointer to TimeStamp structure
  88. */
  89. void G_init_timestamp(struct TimeStamp *ts)
  90. {
  91. ts->count = 0;
  92. }
  93. /*!
  94. \brief Set timestamp (single)
  95. \param ts pointer to TimeStamp structure
  96. \param dt pointer to DateTime structure (date/time to be set)
  97. */
  98. void G_set_timestamp(struct TimeStamp *ts, const DateTime * dt)
  99. {
  100. datetime_copy(&ts->dt[0], dt);
  101. ts->count = 1;
  102. }
  103. /*!
  104. \brief Set timestamp (range)
  105. \param ts pointer to TimeStamp structure
  106. \param dt1,dt2 pointer to DateTime structures
  107. */
  108. void G_set_timestamp_range(struct TimeStamp *ts,
  109. const DateTime * dt1, const DateTime * dt2)
  110. {
  111. datetime_copy(&ts->dt[0], dt1);
  112. datetime_copy(&ts->dt[1], dt2);
  113. ts->count = 2;
  114. }
  115. /*!
  116. \brief Read timestamp
  117. \param fd file descriptor
  118. \param[out] ts pointer to TimeStamp structure
  119. \return -2 EOF
  120. \return -1 on error
  121. \return 0 on success
  122. */
  123. int G__read_timestamp(FILE * fd, struct TimeStamp *ts)
  124. {
  125. char buf[1024];
  126. char comment[2];
  127. while (fgets(buf, sizeof(buf), fd)) {
  128. if (sscanf(buf, "%1s", comment) != 1 || *comment == '#')
  129. continue;
  130. return (G_scan_timestamp(ts, buf) > 0 ? 0 : -1);
  131. }
  132. return -2; /* nothing in the file */
  133. }
  134. /*!
  135. \brief Output TimeStamp structure to a file as a formatted string
  136. A handy fd might be "stdout".
  137. \param[in,out] fd file descriptor
  138. \param ts pointer to TimeStamp structure
  139. \return 0 on success
  140. \return -1 on error
  141. */
  142. int G_write_timestamp(FILE * fd, const struct TimeStamp *ts)
  143. {
  144. char buf[1024];
  145. if (G_format_timestamp(ts, buf) < 0)
  146. return -1;
  147. fprintf(fd, "%s\n", buf);
  148. return 0;
  149. }
  150. /*!
  151. \brief Create text string from TimeStamp structure
  152. Fills string *buf with info from TimeStamp structure *ts in a
  153. pretty way. The TimeStamp struct is defined in gis.h and populated
  154. with e.g. G_read_raster_timestamp().
  155. \param ts TimeStamp structure containing time info
  156. \param buf string to receive formatted timestamp
  157. \return 1 on success
  158. \return -1 error
  159. */
  160. int G_format_timestamp(const struct TimeStamp *ts, char *buf)
  161. {
  162. char temp1[128], temp2[128];
  163. *buf = 0;
  164. if (ts->count > 0) {
  165. if (datetime_format(&ts->dt[0], temp1) != 0)
  166. return -1;
  167. }
  168. if (ts->count > 1) {
  169. if (datetime_format(&ts->dt[1], temp2) != 0)
  170. return -1;
  171. }
  172. if (ts->count == 1)
  173. strcpy(buf, temp1);
  174. else if (ts->count == 2)
  175. sprintf(buf, "%s / %s", temp1, temp2);
  176. return 1;
  177. }
  178. /*!
  179. \brief Fill a TimeStamp structure from a datetime string
  180. Populate a TimeStamp structure (defined in gis.h) from a text
  181. string. Checks to make sure text string is in valid GRASS datetime
  182. format.
  183. \param ts TimeStamp structure to be populated
  184. \param buf string containing formatted time info
  185. \return 1 on success
  186. \return -1 error
  187. */
  188. int G_scan_timestamp(struct TimeStamp *ts, const char *buf)
  189. {
  190. char temp[1024], *t;
  191. const char *slash;
  192. DateTime dt1, dt2;
  193. G_init_timestamp(ts);
  194. for (slash = buf; *slash; slash++)
  195. if (*slash == '/')
  196. break;
  197. if (*slash) {
  198. t = temp;
  199. while (buf != slash)
  200. *t++ = *buf++;
  201. *t = 0;
  202. buf++;
  203. if (datetime_scan(&dt1, temp) != 0 || datetime_scan(&dt2, buf) != 0)
  204. return -1;
  205. G_set_timestamp_range(ts, &dt1, &dt2);
  206. }
  207. else {
  208. if (datetime_scan(&dt2, buf) != 0)
  209. return -1;
  210. G_set_timestamp(ts, &dt2);
  211. }
  212. return 1;
  213. }
  214. /*!
  215. \brief Copy TimeStamp into [two] Datetimes structs
  216. Use to copy the TimeStamp information into Datetimes, as the members
  217. of struct TimeStamp shouldn't be accessed directly.
  218. - count=0 means no datetimes were copied
  219. - count=1 means 1 datetime was copied into dt1
  220. - count=2 means 2 datetimes were copied
  221. \param ts source TimeStamp structure
  222. \param[out] dt1 first DateTime struct to be filled
  223. \param[out] dt2 second DateTime struct to be filled
  224. \param[out] count return code
  225. */
  226. void G_get_timestamps(const struct TimeStamp *ts,
  227. DateTime * dt1, DateTime * dt2, int *count)
  228. {
  229. *count = 0;
  230. if (ts->count > 0) {
  231. datetime_copy(dt1, &ts->dt[0]);
  232. *count = 1;
  233. }
  234. if (ts->count > 1) {
  235. datetime_copy(dt2, &ts->dt[1]);
  236. *count = 2;
  237. }
  238. }
  239. /*!
  240. \brief Write timestamp file
  241. \param maptype map type
  242. \param dir directory
  243. \param name map name
  244. \param ts pointer to TimeStamp
  245. \return 1 on success
  246. \return -1 error - can't create timestamp file
  247. \return -2 error - invalid datetime in ts
  248. */
  249. static int write_timestamp(const char *maptype, const char *dir,
  250. const char *name, const struct TimeStamp *ts)
  251. {
  252. FILE *fd;
  253. int stat;
  254. fd = G_fopen_new_misc(dir, "timestamp", name);
  255. if (fd == NULL) {
  256. G_warning(_("Unable to create timestamp file for %s map <%s@%s>"),
  257. maptype, name, G_mapset());
  258. return -1;
  259. }
  260. stat = G_write_timestamp(fd, ts);
  261. fclose(fd);
  262. if (stat == 0)
  263. return 1;
  264. G_warning(_("Invalid timestamp specified for %s map <%s@%s>"),
  265. maptype, name, G_mapset());
  266. return -2;
  267. }
  268. /*!
  269. \brief Read timestamp file
  270. \param maptype map type
  271. \param dir directory
  272. \param name map name
  273. \param mapset mapset name
  274. \param ts pointer to TimeStamp
  275. \return 0 no timestamp file
  276. \return 1 on success
  277. \return -1 error - can't open timestamp file
  278. \return -2 error - invalid datetime values in timestamp file
  279. */
  280. static int read_timestamp(const char *maptype, const char *dir,
  281. const char *name, const char *mapset,
  282. struct TimeStamp *ts)
  283. {
  284. FILE *fd;
  285. int stat;
  286. if (!G_find_file2_misc(dir, "timestamp", name, mapset))
  287. return 0;
  288. fd = G_fopen_old_misc(dir, "timestamp", name, mapset);
  289. if (fd == NULL) {
  290. G_warning(_("Unable to open timestamp file for %s map <%s@%s>"),
  291. maptype, name, mapset);
  292. return -1;
  293. }
  294. stat = G__read_timestamp(fd, ts);
  295. fclose(fd);
  296. if (stat == 0)
  297. return 1;
  298. G_warning(_("Invalid timestamp file for %s map <%s@%s>"),
  299. maptype, name, mapset);
  300. return -2;
  301. }
  302. /*!
  303. \brief Check if timestamp for raster map exists
  304. \param name map name
  305. \param mapset mapset name
  306. \return 1 on success
  307. \return 0 no timestamp present
  308. */
  309. int G_has_raster_timestamp(const char *name, const char *mapset)
  310. {
  311. if (!G_find_file2_misc(RAST_MISC, "timestamp", name, mapset))
  312. return 0;
  313. return 1;
  314. }
  315. /*!
  316. \brief Read timestamp from raster map
  317. \param name map name
  318. \param mapset mapset the map lives in
  319. \param[out] ts TimeStamp struct to populate
  320. \return 1 on success
  321. \return 0 or negative on error
  322. */
  323. int G_read_raster_timestamp(const char *name, const char *mapset,
  324. struct TimeStamp *ts)
  325. {
  326. return read_timestamp("raster", RAST_MISC, name, mapset, ts);
  327. }
  328. /*!
  329. \brief Write timestamp of raster map
  330. \param name map name
  331. \param[out] ts TimeStamp struct to populate
  332. \return 1 on success
  333. \return -1 error - can't create timestamp file
  334. \return -2 error - invalid datetime in ts
  335. */
  336. int G_write_raster_timestamp(const char *name, const struct TimeStamp *ts)
  337. {
  338. return write_timestamp("raster", RAST_MISC, name, ts);
  339. }
  340. /*!
  341. \brief Remove timestamp from raster map
  342. Only timestamp files in current mapset can be removed.
  343. \param name map name
  344. \return 0 if no file
  345. \return 1 on success
  346. \return -1 on error
  347. */
  348. int G_remove_raster_timestamp(const char *name)
  349. {
  350. return G_remove_misc(RAST_MISC, "timestamp", name);
  351. }
  352. /*!
  353. \brief Check if timestamp for vector map exists
  354. \param name map name
  355. \param layer The layer names, in case of NULL, layer one is assumed
  356. \param mapset mapset name
  357. \return 1 on success
  358. \return 0 no timestamp present
  359. */
  360. int G_has_vector_timestamp(const char *name, const char *layer, const char *mapset)
  361. {
  362. char dir[GPATH_MAX];
  363. char path[GPATH_MAX + GNAME_MAX];
  364. char ele[GNAME_MAX];
  365. if(layer != NULL)
  366. G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
  367. else
  368. G_snprintf(ele, GNAME_MAX, "%s_1", GV_TIMESTAMP_ELEMENT);
  369. G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
  370. G_file_name(path, dir, ele, mapset);
  371. G_debug(1, "Check for timestamp <%s>", path);
  372. if (access(path, R_OK) != 0)
  373. return 0;
  374. return 1;
  375. }
  376. /*!
  377. \brief Read timestamp from vector map
  378. \param name map name
  379. \param layer The layer names, in case of NULL, layer one is assumed
  380. \param mapset mapset name
  381. \param[out] ts TimeStamp struct to populate
  382. \return 1 on success
  383. \return 0 no timestamp present
  384. \return -1 Unable to open file
  385. \return -2 invalid time stamp
  386. */
  387. int G_read_vector_timestamp(const char *name, const char *layer,
  388. const char *mapset, struct TimeStamp *ts)
  389. {
  390. FILE *fd;
  391. int stat;
  392. char dir[GPATH_MAX];
  393. char ele[GNAME_MAX];
  394. /* In case no timestamp file is present return 0 */
  395. if (G_has_vector_timestamp(name, layer, mapset) != 1)
  396. return 0;
  397. if(layer != NULL)
  398. G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
  399. else
  400. G_snprintf(ele, GNAME_MAX, "%s_1", GV_TIMESTAMP_ELEMENT);
  401. G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
  402. G_debug(1, "Read timestamp <%s/%s>", dir, ele);
  403. fd = G_fopen_old(dir, ele, mapset);
  404. if (fd == NULL) {
  405. G_warning(_("Unable to open timestamp file for vector map <%s@%s>"),
  406. name, G_mapset());
  407. return -1;
  408. }
  409. stat = G__read_timestamp(fd, ts);
  410. fclose(fd);
  411. if (stat == 0)
  412. return 1;
  413. G_warning(_("Invalid timestamp file for vector map <%s@%s>"),
  414. name, mapset);
  415. return -2;
  416. }
  417. /*!
  418. \brief Write timestamp of vector map
  419. \param name map name
  420. \param layer The layer names, in case of NULL, layer one is assumed
  421. \param[out] ts TimeStamp struct to populate
  422. \return 1 on success
  423. \return -1 error - can't create timestamp file
  424. \return -2 error - invalid datetime in ts
  425. */
  426. int G_write_vector_timestamp(const char *name, const char *layer, const struct TimeStamp *ts)
  427. {
  428. FILE *fd;
  429. int stat;
  430. char dir[GPATH_MAX];
  431. char ele[GNAME_MAX];
  432. if(layer != NULL)
  433. G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
  434. else
  435. G_snprintf(ele, GNAME_MAX, "%s_1", GV_TIMESTAMP_ELEMENT);
  436. G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
  437. G_debug(1, "Write timestamp <%s/%s>", dir, ele);
  438. fd = G_fopen_new(dir, ele);
  439. if (fd == NULL) {
  440. G_warning(_("Unable to create timestamp file for vector map <%s@%s>"),
  441. name, G_mapset());
  442. return -1;
  443. }
  444. stat = G_write_timestamp(fd, ts);
  445. fclose(fd);
  446. if (stat == 0)
  447. return 1;
  448. G_warning(_("Invalid timestamp specified for vector map <%s@%s>"),
  449. name, G_mapset());
  450. return -2;
  451. }
  452. /*!
  453. \brief Remove timestamp from vector map
  454. Only timestamp files in current mapset can be removed.
  455. \param name map name
  456. \param layer The layer names, in case of NULL, layer one is assumed
  457. \return 0 if no file
  458. \return 1 on success
  459. \return -1 on failure
  460. */
  461. int G_remove_vector_timestamp(const char *name, const char *layer)
  462. {
  463. char dir[GPATH_MAX];
  464. char ele[GNAME_MAX];
  465. if(layer)
  466. G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
  467. else
  468. G_snprintf(ele, GNAME_MAX, "%s_1", GV_TIMESTAMP_ELEMENT);
  469. G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
  470. return G_remove(dir, ele);
  471. }
  472. /*!
  473. \brief Check if timestamp for 3D raster map exists
  474. \param name map name
  475. \param mapset mapset name
  476. \return 1 on success
  477. \return 0 no timestamp present
  478. */
  479. int G_has_raster3d_timestamp(const char *name, const char *mapset)
  480. {
  481. if (!G_find_file2_misc(GRID3, "timestamp", name, mapset))
  482. return 0;
  483. return 1;
  484. }
  485. /*!
  486. \brief Read timestamp from 3D raster map
  487. \param name map name
  488. \param mapset mapset name
  489. \param[out] ts TimeStamp struct to populate
  490. \return 1 on success
  491. \return 0 or negative on error
  492. */
  493. int G_read_raster3d_timestamp(const char *name, const char *mapset,
  494. struct TimeStamp *ts)
  495. {
  496. return read_timestamp("raster3d", GRID3, name, mapset, ts);
  497. }
  498. /*!
  499. \brief Write timestamp of 3D raster map
  500. \param name map name
  501. \param[out] ts TimeStamp struct to populate
  502. \return 1 on success
  503. \return -1 error - can't create timestamp file
  504. \return -2 error - invalid datetime in ts
  505. */
  506. int G_write_raster3d_timestamp(const char *name, const struct TimeStamp *ts)
  507. {
  508. return write_timestamp("raster3d", GRID3, name, ts);
  509. }
  510. /*!
  511. \brief Remove timestamp from 3D raster map
  512. Only timestamp files in current mapset can be removed.
  513. \param name map name
  514. \return 0 if no file
  515. \return 1 on success
  516. \return -1 on failure
  517. */
  518. int G_remove_raster3d_timestamp(const char *name)
  519. {
  520. return G_remove_misc(GRID3, "timestamp", name);
  521. }